Java逆向基礎之字符串
本文參考:《Reverse Engineering for Beginners》Dennis Yurichev著
字符串
字符串也是對象,和其他對象的構造方式相同。(包括數組)
第一個例子
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); } }
編譯
javac stringhello.java
反編譯
javap -c -verbose stringhello.class
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完成
另外一個例子
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方法
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方法
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."<init>":()V //彈出1個棧頂值,調用<init>方法初始化
另外一個例子
public class stringhellotwo { public static void main(String[] args) { String s = "Hello!"; int n = 123; System.out.println("s=" + s + " n=" + n); } }
反編譯
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類進行拼接
Java逆向基礎之字符串