Java逆向基礎之異常
本文參考:《Reverse Engineering for Beginners》Dennis Yurichev著
異常
由之前月份處理修改的例子
//清單1IncorrectMonthException.java
public class IncorrectMonthException extends Exception { private int index; public IncorrectMonthException(int index) { this.index = index; } public int getIndex() { return index; } }
//清單2Month2.java
class Month2 { public static String[] months = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; public static String get_month(int i) throws IncorrectMonthException { if (i < 0 || i > 11) throw new IncorrectMonthException(i); return months[i]; }; public static void main(String[] args) { try { System.out.println(get_month(100)); } catch (IncorrectMonthException e) { System.out.println("incorrect month index: " + e.getIndex()); e.printStackTrace(); } }; }
編譯
javac Month2.java
只寫一個Month2.java,這裏是IncorrectMonthException.java也會自動編譯
反編譯
javap -c -verbose Month2.class javap -c -verbose IncorrectMonthException.class
IncorrectMonthException方法
public IncorrectMonthException(int); descriptor: (I)V flags: ACC_PUBLIC Code: stack=2, locals=2, args_size=2 0: aload_0 1: invokespecial #1 // Method java/lang/Exception."<init>":()V 4: aload_0 5: iload_1 6: putfield #2 // Field index:I 9: return
本質上,IncorrectMonthException類只是做了對象構造,還有訪問器方法。IncorrectMonthException類是繼承於Exception類,所以,IncorrectMonthException類構造之前,構造父類Exception,然後傳遞整數給IncorrectMonthException類作為唯一的屬性值
getIndex方法
public int getIndex(); descriptor: ()I flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: getfield #2 // Field index:I 4: ireturn
getIndex()只是一個訪問器,引用到IncorrectMonthException類,被傳到局部變量的索引值0的位置(this指針),用aload_0指令取得, 用getfield指令取得對象的整數值,用ireturn指令將其返回。
再看Month2.class的get_month方法
public static java.lang.String get_month(int) throws IncorrectMonthException; descriptor: (I)Ljava/lang/String; flags: ACC_PUBLIC, ACC_STATIC Code: stack=3, locals=1, args_size=1 0: iload_0 1: iflt 10 4: iload_0 5: bipush 11 7: if_icmple 19 10: new #2 // class IncorrectMonthException 13: dup 14: iload_0 15: invokespecial #3 // Method IncorrectMonthException."<init>":(I)V 18: athrow 19: getstatic #4 // Field months:[Ljava/lang/String; 22: iload_0 23: aaload 24: areturn
部分指令解釋
0: iload_0 //第0個變量(即變量i)壓入操作數棧
1: iflt 10 //當棧頂int型數值小於0時跳轉到偏移塊10(這裏是從棧頂彈出一個值進行比較)
4: iload_0 //第0個變量(即變量i)壓入操作數棧
5: bipush 11 //將11壓入操作數棧
7: if_icmple 19 //會從棧中彈出兩個值進行比較,如果第二個(變量i)小於或者等於第一個(數字11),那麽跳轉到偏移位19
10: new #2 // class IncorrectMonthException //創建IncorrectMonthException對象的引用並壓入棧頂
13: dup //復制棧頂值壓入棧頂
14: iload_0 //第0個變量(即變量i)壓入操作數棧
15: invokespecial #3 // Method IncorrectMonthException."<init>":(I)V //調用IncorrectMonthException的"<init>"方法,這裏需要從棧頂彈出兩個值,1是IncorrectMonthException對象的引用,2是變量i
18: athrow //將棧頂的異常拋出
19: getstatic #4 // Field months:[Ljava/lang/String; //獲取靜態成員months數組的引用壓入棧
22: iload_0 //第0個變量(即變量i)壓入操作數棧
23: aaload //棧頂彈出兩個值,將引用型數組指定索引的值推送至棧頂,這裏索引i為第一個彈出值,數組引用months為第二個彈出值,即months[i]的值送入棧頂
24: areturn //返回棧頂值
Month2.class的main方法
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 #5 // Field java/lang/System.out:Ljava/io/PrintStream; 3: bipush 100 5: invokestatic #6 // Method get_month:(I)Ljava/lang/String; 8: invokevirtual #7 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 11: goto 47 14: astore_1 15: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream; 18: new #8 // class java/lang/StringBuilder 21: dup 22: invokespecial #9 // Method java/lang/StringBuilder."<init>":()V 25: ldc #10 // String incorrect month index: 27: invokevirtual #11 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 30: aload_1 31: invokevirtual #12 // Method IncorrectMonthException.getIndex:()I 34: invokevirtual #13 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder; 37: invokevirtual #14 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 40: invokevirtual #7 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 43: aload_1 44: invokevirtual #15 // Method IncorrectMonthException.printStackTrace:()V 47: return Exception table: from to target type 0 11 14 Class IncorrectMonthException
註意Exception table:文字以及下面的表數據
異常表的第一行數據表示從0到11行若發生異常,則跳轉到偏移塊14的位置,同時也指明異常的類型為IncorrectMonthException類
異常從偏移塊14開始執行,如果沒有這個異常表的數據,則偏移塊14後的指令不會被執行
這有個例子,IDA是如何顯示異常表:
原作者用的自己電腦裏的random.class,這裏用剛才的Month2.class替代
.catch IncorrectMonthException from met003_begin to met003_11 using met003_14
Java逆向基礎之異常