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

Java逆向基础之十.简单的补丁

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

本文需要用到IDA

简单的补丁

1. 看一个例子

1
2
3
4
5
6
7
8
9
10
public class nag {
public static void nag_screen() {
System.out.println("This program is not registered");
};

public static void main(String[] args) {
System.out.println("Greetings from the mega-software");
nag_screen();
}
}

我们怎样去掉打印”This program is not registered”这个字符串?

编译后用IDA载入class文件

作者的IDA view视图同步显示了hex的值,可能装了插件或者改了设置,这里的IDA view视图与hex需要切换视图

ALT+T,搜索文本This program is not registered,定位到相关指令附近

截图 (1).png

我们首先尝试将getstatic指令改成返回指令

点击getstatic,然后点击hex视图

截图 (2).png

可以看到B2 00 02对应这条指令

右键修改B2 为B1,然后右键应用更改

截图 (3).png

再切回IDA view视图

截图 (4).png

最后菜单点击Edit–>Patch Program–>Apply patches to input file,将更改应用到文件

截图 (5).png

在弹出的对话框点确定即可修改class文件

但是这么修改运行的时候会报错,可能是有一些栈和帧的校验

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
C:\Users\admin\Desktop>java nag
Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.VerifyError: Expecting a stack map frame
Exception Details:
Location:
nag.nag_screen()V @1: nop
Reason:
Error exists in the bytecode
Bytecode:
0x0000000: b100 0212 03b6 0004 b1

at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Unknown Source)
at java.lang.Class.privateGetMethodRecursive(Unknown Source)
at java.lang.Class.getMethod0(Unknown Source)
at java.lang.Class.getMethod(Unknown Source)
at sun.launcher.LauncherHelper.validateMainClass(Unknown Source)
at sun.launcher.LauncherHelper.checkAndLoadMain(Unknown Source)

原作者在JDK1.7下不工作,我在1.8下也是,报的是栈帧映射异常

既然此路不通,那么就选另一条路,去掉nag()方法的调用

找到main方法

截图 (6).png

中间的

.line 8

invokestatic nag.nag_screen()V

这一句就是调用nag()方法,查看对应的hex视图

截图 (7).png

其中的B8 00 06就是调用这个方法

改成00 00 00(填充3个NOP指令)

截图 (8).png

对应的IDA view视图

截图 (9).png

变成了3个nop指令

最后菜单点击Edit–>Patch Program–>Apply patches to input file,将更改应用到文件

修改完看运行效果

截图 (10).png

修改成功

2. 再看第二个例子

这是一个简单的crackme的例子

1
2
3
4
5
6
7
8
9
10
public class password {
public static void main(String[] args) {
System.out.println("Please enter the password");
String input = System.console().readLine();
if (input.equals("secret"))
System.out.println("password is correct");
else
System.out.println("password is not correct");
}
}

反编译后的class用IDA打开

搜索字符串”secret”定位到判断代码附近

截图 (12).png

其中ifeq指令当栈顶int型数值等于0时跳转 ,栈顶存的是String.equals()方法的返回值

首先我们考虑改跳转的位置,改到line 6后面的getstatic指令那里,那么这个指令对应偏移块是多少呢

点击getstatic,状态栏会显示

截图 (13).png

这个偏移块是24

目标就是将ifeq met002_35修改成ifeq met002_24

ifeq指令所在偏移块是21,35-21=14对应16进制是E,找出hex视图对应的E

截图 (14).png

可以看到99 00 0E,所以我们要修改其中的E

那么改成多少呢,24-21=3对应16进制的3,所以将E改成3

截图 (15).png

再看看IDA view视图符不符合预期

截图 (16).png

最后菜单点击Edit–>Patch Program–>Apply patches to input file,将更改应用到文件

原作者的修改在JDK1.7下不工作,我这里的JDK1.8也报错了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
C:\Users\admin\Desktop>java password
Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.VerifyError: Expecting a stackmap frame at branch target 24
Exception Details:
Location:
password.main([Ljava/lang/String;)V @21: ifeq
Reason:
Expected stackmap frame at this location.
Bytecode:
0x0000000: b200 0212 03b6 0004 b800 05b6 0006 4c2b
0x0000010: 1207 b600 0899 0003 b200 0212 09b6 0004
0x0000020: a700 0bb2 0002 120a b600 04b1
Stackmap Table:
append_frame(@35,Object[#20])
same_frame(@43)

at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Unknown Source)
at java.lang.Class.privateGetMethodRecursive(Unknown Source)
at java.lang.Class.getMethod0(Unknown Source)
at java.lang.Class.getMethod(Unknown Source)
at sun.launcher.LauncherHelper.validateMainClass(Unknown Source)
at sun.launcher.LauncherHelper.checkAndLoadMain(Unknown Source)

这里必须要提的是,这种改法再JDK1.6上是可以运行的

我们也尝试将if eq 这个占用3个字节的指令用0(NOP指令)填充,结果也是校验失败,不能工作

貌似再JDK1.7上比1.6多了更多的帧栈校验

接下来我们尝试替换整个equals方法,并用iconst_1将常数1压入栈顶,这样后面ifeq判断的时候值始终为flase,就不往偏移块35跳转了

iconst_1的指令是0x04

截图 (17).png

即将图中的2B 12 07 B6 00 08改成04 00 00 00 00 00

改完后看下IDA view视图

截图 (18).png

改完之后工作正常


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