首页
社区
课程
招聘
[原创]java 无感hook实现(修改jdk)
发表于: 2023-9-24 11:06 11572

[原创]java 无感hook实现(修改jdk)

2023-9-24 11:06
11572

图片描述

图片描述
这里就是Person在内存中的实例,打个比方,我要修改的是b变量,位于20偏移处,这里是10进制,不是16进制

图片描述

工作需要,需要修改一个java的程序逻辑,之前都是用的frida修改的,但是现在的工作场景,重视效率,所以frida这种重工具被pass了,只能重新选其他工具,初始的时候是想用java本身的一些修改工具的,上网发现了很多。比如cglib,javaassist,asm,byte buddy等;
工作需要,需要修改一个java的程序逻辑,之前都是用的frida修改的,但是现在的工作场景,重视效率,所以frida这种重工具被pass了,只能重新选其他工具,初始的时候是想用java本身的一些修改工具的,上网发现了很多。比如cglib,javaassist,asm,byte buddy等;
但是发现,这些都不符合我的应用场景,首先,我这个应用的jar包本身是加密的,需要加载的过程中在自定义的classloader中进行解密才能得到最终的dex文件,而这些工具大多都是通过调用默认的classloader来加载的,直接就会检测当前dex文件不符合文件格式而报错;
 
有一些可以绕过的,又只能修改未加载的dex;
 
后来redefineClass绕过了,发现他只能修改部分逻辑,而我要修改的变量是一个private的,redefineClass不能修改函数的签名,即不能增加一个方法来操作这个private变量;
 
再后来我又绕过了,可以修改了,但是又发现我的判断条件位于上一层,而这个类的实例中所有变量都无法判断我要执行的修改逻辑。。。。
 
越看问题越多,要修改的逻辑也越多;
 
同时程序中本身会打印日志,我修改了字节码,那他的日志中打印的行数也会有问题。。。。感觉爆炸了,最后想到通过修改jdk来实现java逻辑的修改。
但是发现,这些都不符合我的应用场景,首先,我这个应用的jar包本身是加密的,需要加载的过程中在自定义的classloader中进行解密才能得到最终的dex文件,而这些工具大多都是通过调用默认的classloader来加载的,直接就会检测当前dex文件不符合文件格式而报错;
 
有一些可以绕过的,又只能修改未加载的dex;
 
后来redefineClass绕过了,发现他只能修改部分逻辑,而我要修改的变量是一个private的,redefineClass不能修改函数的签名,即不能增加一个方法来操作这个private变量;
 
再后来我又绕过了,可以修改了,但是又发现我的判断条件位于上一层,而这个类的实例中所有变量都无法判断我要执行的修改逻辑。。。。
 
越看问题越多,要修改的逻辑也越多;
 
同时程序中本身会打印日志,我修改了字节码,那他的日志中打印的行数也会有问题。。。。感觉爆炸了,最后想到通过修改jdk来实现java逻辑的修改。
为了修改这个,大概了解了下一个实例在内存中的分布以及jdk的实现。
 
首先想到jdk的类的实现,主要通过两个类来实现,一个是oopDesc,一个是Klass;我是这么理解的,Klass代表一个类的结构,oopDesc代表一个类的实例的结构;这样把实现和实例分离开来,多个类的实例oopDesc也只需要指向同一个Klass结构,这样可以大幅节省空间;
 
我计划的实现hook修改某个实例的大致流程如下:
 
1、在实例初始化的时候获取这个实例的地址
 
2、通过实例指向的Klass结构,找到我想修改的这个变量或方法的偏移地址
 
3、根据偏移,获取我想要的变量地址
 
4、在需要修改的地方,修改之前获取的变量地址中的内存数据。
 
下面一步步来解决:
 
1、我想修改的是某个实例,那么就在某个实例开始的地方来hook他。实例初始化的流程大概是:
 
->加载一个类,也就是把dex解析为一个klass类,存储在内存中
 
->根据klass分配一个指定大小的内存空间
 
->初始化这个内存空间为一个Oop结构
 
->根据Klass的定义,初始化成员变量
 
这里,我是在第二步获取的空间,反正实现就行,后续没跟了。我是用的openjdk17,修改了位于instanceKlass.cpp的allocate_instance函数,其中的oop返回之后,根据函数的入参获取当前的klass 的name,判断是否是自己需要的klass,来定位最终的oop的内存空间
为了修改这个,大概了解了下一个实例在内存中的分布以及jdk的实现。
 
首先想到jdk的类的实现,主要通过两个类来实现,一个是oopDesc,一个是Klass;我是这么理解的,Klass代表一个类的结构,oopDesc代表一个类的实例的结构;这样把实现和实例分离开来,多个类的实例oopDesc也只需要指向同一个Klass结构,这样可以大幅节省空间;
 
我计划的实现hook修改某个实例的大致流程如下:
 
1、在实例初始化的时候获取这个实例的地址
 
2、通过实例指向的Klass结构,找到我想修改的这个变量或方法的偏移地址
 
3、根据偏移,获取我想要的变量地址
 
4、在需要修改的地方,修改之前获取的变量地址中的内存数据。
 
下面一步步来解决:
 
1、我想修改的是某个实例,那么就在某个实例开始的地方来hook他。实例初始化的流程大概是:
 

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2023-9-24 11:11 被hackdaliu编辑 ,原因: 不会贴图
收藏
免费 1
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//