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

原文地址:http://blog.51cto.com/7317859/2105935

时间: 2024-07-31 10:06:45

Java逆向基础之异常的相关文章

Java逆向基础之简单的补丁

本文参考:http://www.vuln.cn/7118 本文参考:<Reverse Engineering for Beginners>Dennis Yurichev著 本文需要用到IDA 简单的补丁 看一个例子 public class nag { public static void nag_screen() { System.out.println("This program is not registered"); }; public static void ma

Java逆向基础之动态生成类

为什么有这个东西,一方面时AOP框架的需要,另一方面是增加软件逆向的难度 动态生成类的技术目前大体上分为两类,一类是通过操作字节码框架如cglib/Javassist去实现,另一类就是JNI方式,调用dll/so库,内存中动态还原.这两种方式都能实现隐藏类 看一个Javassist动态生成类的例子 package com.vvvtimes; import java.lang.reflect.Modifier; import javassist.ClassPool; import javassis

Java逆向基础之初识javaagent

首先说一下javaagent是什么 javaagent是一种能够在不影响正常编译的情况下,修改字节码. 在逆向中javaagent可以完成对类的拦截和增强. 看一个例子 在Eclipse新建如下MyAgent结构的项目 MyAgent.java文件内容 package com.vvvtimes.demo.agent; import java.lang.instrument.Instrumentation; public class MyAgent {     public static void

Java逆向基础之导出内存中的类一

为什么需要这个,因为在之前的博文中提到,为了增加逆向的难度,部分软件会对部分关键方法和类进行隐藏,所以我们需要把这个类从内存中拿出来. 本文介绍使用javaagent的方法,下一篇介绍dumpclass,两种方法各有利弊. 本文需要用到第三方jar为:javassist-3.20.0-GA.jar,不过我们需要的是它的源码javassist-3.20.0-GA-sources.jar 新建名为DumpClassAgent的项目,项目结构如下 将下载到的源码复制到src目录下 DumpClassA

Java逆向基础之JDB动态调试

本文参考:https://docs.oracle.com/javase/8/docs/technotes/tools/windows/jdb.html JDB在有源代码的时候可以实现调试远程机器上的java程序,但是在逆向中源码很难分析出来,不过还是能够调试得到一部分信息的 本文主要获取两个信息 1.动态调用混淆类中的方法,因为实践过程中我们去手动补全相关代码比较难 2.打印调用栈 以下例子以调试ZKM.jar为例 JDB无源代码调试调用方法 启动Xdebug调试 java -Xdebug -X

Java逆向基础之ODB动态调试

说明: 1在<透视JAVA-反编译修补和逆向工程技术>提到了这个工具,这里简单介绍一些 2ODB(即Omniscient Debugger)最新版本已经迁移到github上 3ODB支持的最高JDK版本是1.6,用来分析新版本的jar包和类会报各种异常,从内心的角度来说还是不太想介绍这个工具的 OmniscientDebugger ODB的使用 下载 github方式 https://github.com/OmniscientDebugger/LewisOmniscientDebugger/r

Java逆向基础之AspectJ的Around方法修改方法体

在逆向中,我们往往通过修改某个方法达到目的,在javaassist中有insertBefore,insertAfter,setBody,在AspectJ中也可以通过Around实现类似的功能. 看一个简单的例子 java文件Main.java //Main.java package com.vvvtimes; public class Main { public int add(int x, int y) { return x + y; } public int add(int x, int y

Java逆向基础之操作数栈

本文参考:http://www.vuln.cn/7115 本地变量和操作数栈 本地变量数组(Local Variable Array) 本地变量的数组包括方法执行所需要的所有变量,包括 this 的引用,所有方法参数和其他本地定义的变量.对于那些方法(静态方法 static method)参数是以零开始的,对于实例方法,零为 this 保留. 所有的类型都在本地变量数组中占一个槽(entry),而 long 和 double 会占两个连续的槽,因为它们有双倍宽度(64-bit 而不是 32-bi

Java逆向基础之函数

本文参考http://www.vuln.cn/7115 本文提到的函数(function)和方法(method)为同一个意思 例子1,方法名的定义 public class HalfRandom { public static double f() { return Math.random()/2; } } 编译 javac HalfRandom.java 反编译 javap -c -verbose HalfRandom.class ... major version: 52 ... #2 =