总目录
网上有好多都是反编译,然后拷贝到项目下,进行修改。这种只能针对没有混淆源码的class文件。
还有就是用 javassist.jar 包修改的,这种针对混淆源码厉害的,也是无能为力。
下面是我自己的修改方法,在网上找了好多资料才整理出来的。
修改原理
1、使用反编译器查看源码(经测试 luyten 比较好,对于混淆严重的也支持),找到要修改的位置(找不到就不用说了)
2、然后使用 classpy 查看字节码 ,并且可以查看字节码对应的16进制位置 (自己搜索如何查看字节码)
3、找到要修改的代码,并且找到要修改后的字符对应的字节码,再根据字节码转换为16进制
4、将找到的16进制数字替换原16进制数字
5、再反编译修改后的class文件,看是否已经修改正确
需要用到的工具在资源中,也可以自行下载
修改流程
直接看具体例子
1、使用反编译查看源码
下载 luyten.exe 打开class 或者 jar 包即可 ( 资源链接中包含了)
2、classpy.jar 查看字节码
如果不会看字节码,学习链接
Java虚拟机字节码指令 https://www.cnblogs.com/yelao/p/9492238.html
java 虚拟机字节码指令表 https://blog.csdn.net/YY_xiaozhu/article/details/81108601
首先运行
java -jar classpy-0.6.jar
打开 CtPrimitiveType.class 文件
这里解释下code下这几行的意思:
对应代码
public void isPrimitive() {
int a = 32;
if(a > 100){
int b = 1000;
}
}
代码 16进制数 字节码意思 行意义
00: bipush 32 10 20 将单字节的常量值(-128~127) 推送至栈顶 10 对应 bipush ,32的16进制是20
02: istore_1 3C 将栈顶 int 型数值存入第二个局部变量 3C 对应 istore_1
03: iload_1 1B 将第二个 int 型局部变量推送至栈顶 1B 对应 iload_1
04: bipush 100 10 64 将单字节的常量值(-128~127) 推送至栈顶 10 对应 bipush ,100的16进制是64
06: if_icmple 13 A4 00 07 比较栈顶两 int 型数值大小,当结果小于等于 0 时跳转到13行 A4 对应 if_icmple ,13 我也不清楚为啥用 00 07 表示
09: sipush 1000 11 03 E8 将一个短整型常量值(-32768~32767) 推送至栈顶 11 对应 sipush ,1000的16进制是 03 E8
12: istore_2 3D 将栈顶 int 型数值存入第三个局部变量 3D 对应 istore_2
13: _return B1 从当前方法返回 void B1 对应 _return
3、修改字节码
3.1 先修改大于号
A4 对应的是 小于等于,然后跳到13行结束,咱们要改为 a<100,就是要 大于等于 的时候结束
大于等于 对应的 16 进制是 A2 ,修改 A4 为 A2
使用 MadEdit.exe 打开 class 文件修改后保存
反编译修改后的文件,已经修改成功
3.2 修改 32 为 2100000000
这个修改需要涉及到常量池,栈顶不能直接存储 2100000000 这个数值,所以只能从常量池中取。
1、存储 2100000000 到常量池
首先修改常量池中常量的个数,由14 改为 15
然后在常量池的最后添加一个常量:int 类型的 2100000000
int 的16进制字节码是 03 (为什么是03,自己写一段包含常量的代码 如 int a = 2100000000,看看字节码就知道了)
2100000000 的16进制字节码是 7d 2b 75 00 (下图改错了,改为了 7b 2b 75 00 ,意思差不多)
2、引用常量池中的变量替换32这个数字
使用 ldc 或者 ldc_w,“宽索引”的意思就是“常量的索引” 用2位“16进制数”无法表示,得用4位
这里使用 ldc 即可
咱们增加常量的时候,是在19后边添加的,所以新加的常量索引是20,用 “ldc 字节码 + 索引号的16进制 ” 即可
应该是 12 14
保存后反编译查看
4、反编译class文件查看
已经修改成功