首页
社区
课程
招聘
[原创]SandHook 第三弹 - 性能优化 & Xposed 模块 & 阻止 ART Inline 优化
发表于: 2019-2-22 22:58 8527

[原创]SandHook 第三弹 - 性能优化 & Xposed 模块 & 阻止 ART Inline 优化

2019-2-22 22:58
8527

上两贴:
https://bbs.pediy.com/thread-249163.htm
https://bbs.pediy.com/thread-249378.htm

前面有提到过 SandHook 需要手动写一个 Hook 方法作为 Hook 的入口,所以想要兼容 Xposed Callback 式 API 就必须凭空生成一个 Hook 方法来转发 Xposed Callback 逻辑。

所以我选择了 DexMaker,但是 Dexmaker 生成代码并且加载的时候还是太慢了,尽管只需要第一次生成(后面只需要加载即可),第一次 Hook 一个函数大概需要耗费 100ms 的时间。

至于 Backup 方法,则可写可不写,如果不写,则可以直接 New 一个 Method,将原 ArtMethod 中的数据填充进去,但是这里有个比较蛋疼的问题。真实存在的 ArtMethod 是在 Non-Moving 堆中的,也就是说,原版的 ArtMethod 不会 Moving GC,而 New 出来的只是一个普通对象,GC 的时候地址就会移动,每次调用 backup 方法之前都需要检查是否被移动。
当然 SandHook 预先写了一堆空方法备用。

其实优化方案很简单,依然是预先写一堆 Stub 函数,但是这些 Stub 变成了 hook 函数,并不仅仅在 Non-Moving Space 中占一个坑。他还需要接收原方法的参数,调用 XposedBridge,并且返回返回值。

Epic 是到栈中将参数一个个捞出来,而 SandHook 则将参数全部设为 long(32bit 为 int)

原因很简单:

如何转换?

对象地址使用 jweak JavaVMExt::AddWeakGlobalRef(Thread* self, ObjPtr<mirror::Object> obj) 转换成 java 对象。

可以用 dlsym/fake_dlsym 搜索到。

long 可以直接转成 int char byte short 等等,boolean 判断是不是 0 即可,float 和 double 则是存在浮点寄存器,而 long 是在通用寄存器,在参数列表和返回值中发现这两个类型直接转用 dexmaker 即可,一般这两种参数也少。
另外在 32bit 下 long/double 是 8 字节,参数列表中间夹了这两种类型参数会造成参数列表混乱,直接跳过走 Dexmaker。

最后写了个 python 脚本自动生成 stub 函数,基本 9 成以上的函数 hook 直接走 stub,耗时仅仅 1 - 3ms。

最后结合 VirtualApp 简单实现了一个类似 VXP 的免 Root Xposed 容器,目前测了 Q++, 应用变量,XPrivacyLua,MDWechat 等模块可以使用。

https://github.com/ganyao114/SandVXposed

VM 的 Inline 优化一直是我们 Hook 的最大阻碍,这里做个实验:

Android 7.1:

主要修改了原方法的返回值

前 1 s,方法 Hook 正常,输出 Hook 后的返回值:

1s 之后:

这说明不到一秒,由于被 Hook 方法过于简单,而调用该方法的方法热度较高,调用者发生了 Inline 优化并且进行了栈上替换。

研究 ART 源码发现:
当被 inline 方法的 code units 大于设置的阈值的时候,方法 Inline 失败。
这个阈值是 CompilerOptions -> inline_max_codeunits

那么想办法把这个阈值设为 0 就可以了。

经过搜索,CompilerOptions 一般与 JitCompiler 绑定:

而 ART 的 JitCompiler 为全局单例:

ok,那么我们就得到了 “static void* jit_compilerhandle” 的 C++ 符号 “_ZN3art3jit3Jit20jit_compiler_handle_E“

最后修改里面的值就可以了。

 
 
 

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

最后于 2019-2-25 09:57 被坑大编辑 ,原因: 增加 “阻止 ART Inline 优化”
收藏
免费 3
支持
分享
打赏 + 2.00雪花
打赏次数 1 雪花 + 2.00
 
赞赏  junkboy   +2.00 2019/02/22 感谢分享~
最新回复 (4)
雪    币: 11716
活跃值: (133)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
支持
2019-2-22 23:29
0
雪    币: 1395
活跃值: (526)
能力值: ( LV9,RANK:160 )
在线值:
发帖
回帖
粉丝
3
启动之前就已经 Inline 的是没办法解决的,只有在沙箱内部可以控制
2019-2-25 09:59
0
雪    币: 1385
活跃值: (5609)
能力值: ( LV3,RANK:25 )
在线值:
发帖
回帖
粉丝
4
你要在after函数里面进行替换啊,你替换了。before,感觉有问题呢。
2019-2-27 09:20
0
雪    币: 1395
活跃值: (526)
能力值: ( LV9,RANK:160 )
在线值:
发帖
回帖
粉丝
5
supperlitt 你要在after函数里面进行替换啊,你替换了。before,感觉有问题呢。
设置返回值之和 after 函数是不会执行的
2019-2-28 13:24
0
游客
登录 | 注册 方可回帖
返回
//