吾爱破解 - LCG - LSG |安卓破解|病毒分析|破解软件|www.40881110.com

 ?#19968;?#23494;码
 注册[Register]

QQ登录

只需一步£¬快速开始

查看: 5434|回复: 48
上一主题 下一主题

[Android 原创] 开源Hook框架-epic-实现浅析(1)

  [复制链接]
跳转到指定楼层
楼主
S18 发表于 2019-3-27 22:51 回帖奖励
本帖最后由 S18 于 2019-3-27 23:30 编辑

epic是weishu大神开源的一个Hook框架£¬支持ART上的Java方法HOOK¡£
实现原理£ºhttp://weishu.me/2017/11/23/dexposed-on-art/

本文走马观花一下¡£

epic相当于ART上的Dexposed£¬所以也是Xposed-Style Method Hook¡£

从DexposedBridge.findAndHookMethod开始跟踪代码£º


取出最后一个?#38382;ýcallback£¬然后调用XposedHelpers.findMethodExact得到想要Hook的method£¬最后调用DexposedBridge.hookMethod进行Hook¡£

XposedHelpers.findMethodExact的实现在之前的笔记中已经看过了£¬这里不看了¡£

直接看DexposedBridge.hookMethod£º


所有已经Hook过的method及其对应的callbacks£¬全部存储在hookedMethodCallbacks中£¬这是一个HashMap¡£如果该method已经Hook过£¬那直?#24433;Ñcallback回调对象加入到其对应的callbacks集?#29616;?#23601;可以了¡£这样在该method被调用时£¬callbacks集?#29616;?#25152;有回调都会被遍历执行¡£
如果该method没有被Hook过£¬那就调用Epic.hookMethod进行Hook¡£

£¨这里以Method为例£¬Constructor的Hook大同小异£©


先看一下ArtMethod.of£º



ArtMethod.of是以Method对象作为?#38382;ý£?#21019;建一个me.weishu.epic.art.Epic.ArtMethod对象¡£
  • artOrigin. method保存原始的Java Method对象¡£
  • artOrigin. address保存的是原始的Method对象在ART中对应的art::mirror::ArtMethod对象的地址¡£
  • artOrigin. objectAddress保存的是原始的Java Method对象£¨Java Object£©在内存中的地址¡£
£¨EpicNative.getMethodAddress和Unsafe.getObjectAddress的实现代码先不贴了¡£getMethodAddress的实现很简单£¬getObjectAddress的实现稍复杂£¬但也不难理解¡£这里先跟踪主要代码£¬忽略旁枝末节¡££©
继续看Epic.hookMethod(ArtMethod artOrigin)£º

£¨这个函数的实现有点长£¬分段贴£©


首先创建一个MethodInfo对象£¬用于保存方法信息¡£其中methodInfo.method保存了原始的Method对象对应的me.weishu.epic.art.method.ArtMethod对象¡£

然后将MethodInfo对象保存到originSigs中¡£originSigs是一个Map对象£¬key是Method对象对应的art::mirror::ArtMethod对象的地?#32602;¬value是MethodInfo¡£


调用setAccessible(true)£¬取消Java方法调用时的访问权限检查¡£


调用ensureResolved£¬保证静态方法完成解析¡£为什么要这么干£¬已经写在注释里了¡£


如果要Hook的方法还未编译£¬则调用ArtMethod.compile主动进行编译£¬这么做也是因为epic是¡°dynamic callee-side rewriting¡±¡£

ArtMethod.compile是通过调用JIT的jit_compile_method来完成方法编译的¡£

最后£¬compiled_code入口点会保存到originEntry变量中¡£


为原Method创建一个备份£¬保存到Epic.backupMethodsMapping中¡£


前面是铺垫£¬最重要的一步来了£¬具体看注释¡£

哪些不同的Java方法会具有相同的compiled_code入口点呢£¿

1¡¢所有ART版本上未被resolve的static函数

2¡¢Android N 以上的未被编译的所有函数

3¡¢代码逻辑一模一样的函数

4¡¢JNI函数

其中£¬情况1和2在上面已经处理过了£¬应该不会遇到了£¬剩下3和4¡£

对于JNI函数£¬因为不会涉及到?#32440;?#30721;编译£¬也没有对应的compiled_code£¬所以其compiled_code入口点会统一设置为GetQuickGenericJniStub£¬即art_quick_generic_jni_trampoline¡£

继续跟Trampoline.install£¬看看是如何安装跳板代码来最终完成Hook的¡£


这个函数的功能描述已经写到注释里了¡£核心操作有两点£º

1£©创建Trampoline£¨包括¡°二段跳板¡±BridgeJump£¬和CallOrigin£©
2£©创建和安装¡°一段跳板?#20445;?#23436;成Hook¡£
简单看一下epic的基本原理图£º


epic的Hook机制是¡°dynamic callee-side rewriting¡±¡£具体点说£º

1£©保证要Hook的method完成compile£¬也就是运行?#24065;?#25191;行其compiled_code¡£
2£©根据要Hook的method对应的art::mirror::ArtMethod找到compiled_code入口点¡£
3£©在compiled_code的开始位置放置一段很短的跳转代码£¬称为¡°一段跳板?#20445;?#20316;用是跳转到二段跳板¡£之所以弄一个一段跳板£¬是怕二段跳板太长£¬原方法的compiled_code区域放不下¡£
4£©二段跳板会将一些必要的?#38382;?#25171;包£¬调用Java-Bridge方法£¬并将打包在一起的?#38382;ý£?#36890;过r3传递给Java-Bridge¡£
5£©Java-Bridge方法取出传递进来的?#38382;ý£?#28982;后根据r1¡¢r2¡¢r3以及sp£¨以Thumb2为例£¬除了r0~r3£¬剩余的?#38382;?#20250;通过sp传递£©£¬构造出原方法的?#38382;ý£?#26368;后调用DexposedBridge.handleHookedArtMethod¡£
6£©由DexposedBridge.handleHookedArtMethod调用beforeHookedMethod¡¢原方法和afterHookedMethod¡£
二段跳板的创建由Trampoline.create方法完成£¬一段跳板的创建和安装由Trampoline. activate方法完成¡£

先看Trampoline.create£º


那这里创建的BridgeJump£¨二段跳板£©和CallOrigin是什么样子的呢£¿分别看一下Trampoline. createTrampoline和shellCode.createCallOrigin方法¡£

先看Trampoline. createTrampoline£º


先调用Entry.getBridgeMethod返回一个Bridge方法£¬这个Bridge是一个Java方法¡£然后调用shellCode.createBridgeJump创建BridgeJump£¨二段跳板£©¡£

我们先看shellCode.createBridgeJump£¨以Thumb2为例£©创建的BridgeJump£¨二段跳板£©£¬然后再去看Entry.getBridgeMethod返回的Bridge方法¡£调用shellCode.createBridgeJump时传入的各个?#38382;?#30340;含义已经写到注释里了¡£


这里创建的就是上面原理图中的二段跳板代码£¬详情看注释¡£重点有两处£º

1£©art::mirror::ArtMethod对象地址的比较
2£©打包?#38382;ý£?#28982;后跳转到Java-Bridge£¬打包之后的?#38382;?#36890;过r3传递¡£
现在可以去看上面由Entry.getBridgeMethod返回的Bridge方法了£¨以32位运行时为例£©¡£


假设returnType是Object.class£¬那么返回的Bridge方法就是Entry.referenceBridge£º


从前面的二段跳板代码可知£¬传递给referenceBridge的第3个?#38382;ýstruct是一个结构体指针¡£

按照之前的规则£¬?#26469;?#21462;出sp¡¢r2¡¢r3和sourceMethod¡£sourceMethod是原Method对应的art::mirror::ArtMethod对象在内存中的地址¡£然后根据r1¡¢r2¡¢r3以及self¡¢sp£¨以Thumb2为例£¬除了r0~r3£¬剩余的?#38382;?#20250;通过sp传递£©£¬构造出原方法的?#38382;ý¡?#28982;后根据returnType的不同£¬分别调用onHookXXX函数¡£

Entry.constructArguments的实现逻辑不难理解£¬但是从weishu大神的处理来看£¬不同情况下的兼容还是最头疼的问题¡£

还是假设returnType是Object.class£¬看一下Entry. onHookObject£º


其实就是调用了DexposedBridge.handleHookedArtMethod¡£

DexposedBridge.handleHookedArtMethod的逻辑£¬熟悉Xposed的人应该?#24049;?#29087;悉¡£前面的whale笔记也跟踪过代码了£¬这里就不看了¡£beforeHookedMethod¡¢原方法和afterHookedMethod都是在DexposedBridge.handleHookedArtMethod里面调用的¡£

回到Trampoline.create£¬再看一下shellCode.createCallOrigin£º


创建CallOrigin的逻辑就比较简单了£¬先是compiled_code的原前8个?#32440;?#30340;指令£¨以Thumb2为例£©£¬然后是一条跳转指令£¬跳转到原Method对应的compiled_code的偏移8个?#32440;?#30340;位置£¬也就是一段跳板代码的后面£¬去执行原Method的compiled_code中剩余的指令¡£

最后£¬再回到Trampoline.install£¬看一下Trampoline. activate是如何创建和安装一段跳板的¡£


Trampoline. activate直接调用EpicNative.activateNative¡£

1£©?#38382;ýjumpToAddress原Method的compiled_code入口点¡£

2£©?#38382;?#26159;pc是Trampoline代码的首地?#32602;?#21363;£º前面创建的一块内存£¬里面是二段跳板BridgeJump和CallOrigin¡£

3£©最后一个?#38382;?#26159;一段跳板代码£¬由shellCode.createDirectJump(pc)创建¡£

看一下shellCode.createDirectJump是如何创建一段跳板的£¨以Thumb2为例£©£º


很简单£¬就是一条ldr指令£¬将要跳转的地?#32602;?#20108;段跳板的代码地?#32602;?#36171;给pc¡£

最后£¬看一下EpicNative.activateNative£¬这是一个native方法£¬实现代码如下£º


这个函数的实现也很简单¡£就是将一段跳板的代码?#22870;?#21040;原Method对应的compiled_code的开始处£¬类似native函数的InlineHook¡£和Whale一样£¬这里在安装一段跳板前也暂停了ART的所有线程£¬原因已经写在注释里了¡£另外£¬在arm?#25945;?#19979;£¬更新完指令要记得cacheflush¡£
至此£¬epic的Hook就算完成了¡£

本篇笔记只是草草的跟踪一下代码£¬并未将所有的实现细节全部看完¡£但主干代码和实现原理已经算是清楚了¡£

文/十八垧

免费评分

参与人数 17吾爱币 +11 热心值 +17 收起 理由
appzy + 1 + 1 大佬
cxp521 + 1 + 1 牛逼
极黑 + 1 谢谢@Thanks£¡
0xroot + 1 谢谢@Thanks£¡
youhen233 + 1 + 1 谢谢@Thanks£¡
麻木不忍 + 1 + 1 ?#34892;?#21457;布原创作?#32602;?#21566;爱破解论坛因你更精彩£¡
laughingsir38 + 1 + 1 我很赞同£¡
Vsir + 1 + 1 我很赞同£¡
larf + 1 + 1 谢谢@Thanks£¡
丨丶钟情 + 1 我很赞同£¡
冰点唯银 + 1 + 1 谢谢@Thanks£¡
淡蓝Biner + 1 用心讨论£¬?#19981;?#25552;升£¡
li584360811 + 1 + 1 热心回复£¡
德德de + 1 用心讨论£¬?#19981;?#25552;升£¡
Anonymous¡¢ + 2 + 1 用心讨论£¬?#19981;?#25552;升£¡
Mr.Eleven + 1 用心讨论£¬?#19981;?#25552;升£¡
user2019 + 1 谢谢@Thanks£¡

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用¡¾论坛搜索¡¿功能£¬那里可能会有你要找的答案或者已经有人发布过相同内容了£¬请勿重复发帖¡£

推荐
hi123456 发表于 2019-4-4 09:16
我是一个小?#21331;?#21040;那么多代码  我心理面默默的说声大佬
推荐
xiexie 发表于 2019-4-20 23:11
我是一个小?#21331;?#21040;那么多代码  我心理面默默的说声大佬
4#
BY丶显示 发表于 2019-3-27 23:14
5#
woshiweijie 发表于 2019-3-27 23:54
我一个小?#21331;?#21040;那么多代码  我心理面默默的说声大佬
6#
xingjm 发表于 2019-3-28 06:16
讨厌看别人的代码£¬?#20174;?#19981;得不看真的难受£¬?#32454;?#25105;佩服你哈哈哈哈哈哈
7#
sangaqiao 发表于 2019-3-28 08:28
?#34892;?#20998;享£¡
8#
smnk 发表于 2019-3-28 10:14

我一个小?#21331;?#21040;那么多代码  我心理面默默的说声大佬
9#
xdreamseeker 发表于 2019-3-28 10:44
?#34892;?#20998;享£¡
10#
lyliucn 发表于 2019-3-28 13:53
?#34892;?#20998;享£¡
11#
sighforever 发表于 2019-3-28 14:18
看完了还是看不懂
12#
井谦 发表于 2019-3-28 18:07
谢谢楼主的分享£¡
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 提醒£º禁止复制他人回复等¡º恶意灌水¡»行为£¬违者重罚£¡

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2019-4-22 23:58

Powered by Discuz!

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表
Çò̽ÍøÀºÇòÖ¸Êý