本文参考:《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 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,定位到相关指令附近
我们首先尝试将getstatic指令改成返回指令
点击getstatic,然后点击hex视图
可以看到B2 00 02对应这条指令
右键修改B2 为B1,然后右键应用更改
再切回IDA view视图
最后菜单点击Edit-->Patch Program-->Apply patches to input file,将更改应用到文件
在弹出的对话框点确定即可修改class文件
但是这么修改运行的时候会报错,可能是有一些栈和帧的校验
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方法
中间的
.line 8
invokestatic nag.nag_screen()V
这一句就是调用nag()方法,查看对应的hex视图
其中的B8 00 06就是调用这个方法
改成00 00 00(填充3个NOP指令)
对应的IDA view视图
变成了3个nop指令
最后菜单点击Edit-->Patch Program-->Apply patches to input file,将更改应用到文件
修改完看运行效果
修改成功
再看第二个例子
这是一个简单的crackme的例子
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"定位到判断代码附近
其中ifeq指令当栈顶int型数值等于0时跳转 ,栈顶存的是String.equals()方法的返回值
首先我们考虑改跳转的位置,改到line 6后面的getstatic指令那里,那么这个指令对应偏移块是多少呢
点击getstatic,状态栏会显示
这个偏移块是24
目标就是将ifeq met002_35修改成ifeq met002_24
ifeq指令所在偏移块是21,35-21=14对应16进制是E,找出hex视图对应的E
可以看到99 00 0E,所以我们要修改其中的E
那么改成多少呢,24-21=3对应16进制的3,所以将E改成3
再看看IDA view视图符不符合预期
最后菜单点击Edit-->Patch Program-->Apply patches to input file,将更改应用到文件
原作者的修改在JDK1.7下不工作,我这里的JDK1.8也报错了
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
即将图中的2B 12 07 B6 00 08改成04 00 00 00 00 00
改完后看下IDA view视图
改完之后工作正常
原文地址:http://blog.51cto.com/7317859/2106049