多读书多实践,勤思考善领悟

Java逆向基础之七.字符串

本文于1999天之前发表,文中内容可能已经过时。

字符串

字符串也是对象,和其他对象的构造方式相同。(包括数组)

1. 第一个例子

1
2
3
4
5
6
7
public class stringhello {
public static void main(String[] args) {
System.out.println("What is your name?");
String input = System.console().readLine();
System.out.println("Hello, " + input);
}
}

编译

1
javac stringhello.java

反编译

1
javap -c -verbose stringhello.class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=2, args_size=1
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3 // String What is your name?
5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: invokestatic #5 // Method java/lang/System.console:()Ljava/io/Console;
11: invokevirtual #6 // Method java/io/Console.readLine:()Ljava/lang/String;
14: astore_1
15: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
18: new #7 // class java/lang/StringBuilder
21: dup
22: invokespecial #8 // Method java/lang/StringBuilder."<init>":()V
25: ldc #9 // String Hello,
27: invokevirtual #10 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
30: aload_1
31: invokevirtual #10 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
34: invokevirtual #11 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
37: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
40: return

部分指令解释

11: invokevirtual #6 // Method java/io/Console.readLine:()Ljava/lang/String; //调用了readline()方法,字符串引用(由用户提供)被存储在栈顶

14: astore_1 //将字符串引用从操作数栈中弹出,保存在索引为1的局部变量中(即input)

25: ldc #9 // String Hello, //将字符串String Hello,压入栈

27: invokevirtual #10 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; //使用StringBuilder.append方法,返回一个StringBuilder对象的引用压入栈顶,需要从栈顶弹出两个值,一个是StringBuilder的引用,一个是字符串String Hello,

30: aload_1 //将索引为1的局部变量(即input)压入操作数栈

31: invokevirtual #10 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; //使用StringBuilder.append方法,返回一个StringBuilder对象的引用压入栈顶,需要从栈顶弹出两个值,一个是StringBuilder的引用,一个是字符串input变量值

34: invokevirtual #11 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; //使用StringBuilder.toString方法,返回一个String对象的引用压入栈顶,需要从栈顶弹出一个值,是StringBuilder的引用

37: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V //使用PrintStream.println方法,需要从栈顶弹出一个值,是System.out的引用

可以看到字符串的链接由StringBuilder完成

2. 另外一个例子

1
2
3
4
5
6
7
8
9
public class strings {
public static char test(String a) {
return a.charAt(3);
};

public static String concat(String a, String b) {
return a + b;
}
}

反编译

test方法

1
2
3
4
5
6
7
8
9
public static char test(java.lang.String);
descriptor: (Ljava/lang/String;)C
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: aload_0
1: iconst_3
2: invokevirtual #2 // Method java/lang/String.charAt:(I)C
5: ireturn

concat方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static java.lang.String concat(java.lang.String, java.lang.String);
descriptor: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=2, args_size=2
0: new #3 // class java/lang/StringBuilder
3: dup
4: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
7: aload_0
8: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
11: aload_1
12: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
15: invokevirtual #6 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
18: areturn

这里的字符串的连接也使用StringBuilder类完成

部分指令解释

0: new #3 // class java/lang/StringBuilder //创建StringBuilder的引用并压入栈顶

3: dup //复制栈顶值,即StringBuilder的引用

4: invokespecial #4 // Method java/lang/StringBuilder.”“:()V //弹出1个栈顶值,调用方法初始化

另外一个例子

1
2
3
4
5
6
7
public class stringhellotwo {
public static void main(String[] args) {
String s = "Hello!";
int n = 123;
System.out.println("s=" + s + " n=" + n);
}
}

反编译

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=3, args_size=1
0: ldc #2 // String Hello!
2: astore_1
3: bipush 123
5: istore_2
6: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
9: new #4 // class java/lang/StringBuilder
12: dup
13: invokespecial #5 // Method java/lang/StringBuilder."<init>":()V
16: ldc #6 // String s=
18: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
21: aload_1
22: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
25: ldc #8 // String n=
27: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
30: iload_2
31: invokevirtual #9 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
34: invokevirtual #10 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
37: invokevirtual #11 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
40: return

这里的字符串的连接也使用StringBuilder类进行拼接


参考资料
http://www.vuln.cn/7115
《Reverse Engineering for Beginners》Dennis Yurichev著