1. 程式人生 > >Java逆向基礎之異常

Java逆向基礎之異常

java異常

本文參考:http://www.vuln.cn/7116

本文參考:《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逆向基礎之異常