首页
社区
课程
招聘
[原创]从Frida源码学习ArtHook
发表于: 2021-8-22 13:02 19459

[原创]从Frida源码学习ArtHook

2021-8-22 13:02
19459

为了填AppInspect的坑,开始研究ArtHook。

从Frida入手是因为的资料多,更新频繁。

坏处是Frida体系庞大,比其他单纯的Hook框架复杂。

Frida的native hook代码在frida-gum,虽然是C语言,但用了gobject框架,对没接触过的人需要一定时间习惯。

Frida的art hook代码在 frida-java-bridge ,纯js代码实现。

通过enumerateLoadedClasses的执行流程,作为入口开始代码走读。

第一步是初始化Runtime,这个Runtime是Art Runtime在js侧的一个代理,是Frida ArtHook的核心。

通过getApi()获取Art Runtime的Api接口。

怎么理解获取Api呢,

Android程序运行时,art运行时会以libart.so等动态库的形式加载在当前进程的地址空间中。那我们能不能像访问libc.so里的函数一样访问里面的函数呢?

答案是肯定的,

从CPU运行流程看,调用一个函数就是,准备好函数的参数,跳到函数地址执行。

这里只有两个问题要解决:

只是如果你在ndk的代码里调用c库的函数,头文件解决了参数问题,而函数地址,在编译时和运行时由链接器帮你填好。

但对于libart.so我们只能自己动手了,好在Linux有一套运行时加载so的机制。

b17K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6@1L8r3c8H3i4K6u0W2L8%4u0Y4i4K6u0r3d9p5!0i4g2p5!0Q4x3V1k6Z5N6r3#2D9i4K6g2X3M7$3W2F1k6$3I4W2i4K6u0r3b7#2)9J5b7W2)9J5b7W2)9J5k6r3c8D9L8%4m8W2L8W2)9J5c8R3`.`.

但在Android 7以后,限制了App直接调用dlopen打开libart.so等系统库,

作为例外libc .so, libandroid.so等在白名单里的不受影响。白名单在/system/etc/public.libraries.txt

除了白名单,还有一个在代码里写死的灰名单,需在编译App时把targetSdk设定为23之前才能有效。

那么怎么绕过这个限制等呢:

有两种方法:

跟踪调用,真正干活的是linker中的do_dlopen函数,它会根据__loader_dlopen传进来的caller_addr,检查调用者所属的模块,然后根据模块查找其对应命名空间,判断是否允许加载。

所以只要传一个系统库中的函数,就能加载其他在同一个命名空间里的系统模块。

如何找一个跟目标模块命名空间相同的地址呢,

方法1,调用dl_iterate_data

The dl_iterate_phdr() function walks through the list of an application's shared objects and calls the function callback once for each object,

参考快手的KOOM

原理就是调用dl_iterate_phdr后,会在callback里返回App加载的所有模块信息,当找到目标模块时,把它基址保存下来,作为__loader_dlopen的caller_addr参数。

方法2,通过/proc/self/maps文件获取到目标模块的基址作为caller_addr。

另外,还有一个更简单的方法是传一个libc里的函数地址,但Android Q以后增加了新的命名空间,libc和libart并不在同一个命名空间里。

Rust版代码验证

看到这里,可能会有个疑问,为什么谷歌这么弱,弄个安全机制这么简单就被破解了,

看看官方对链接器命名空间的介绍,

bf5K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6K6L8%4g2J5j5$3g2Q4x3X3g2S2L8X3c8J5L8$3W2V1i4K6u0W2j5$3!0E0i4K6u0r3k6r3g2$3K9h3y4W2M7#2)9J5c8X3q4J5j5$3S2A6N6r3g2U0N6s2g2J5k6g2)9J5c8Y4k6F1k6r3E0Q4x3V1k6D9K9h3&6C8k6i4u0Q4x3X3c8F1j5h3#2W2M7%4m8S2j5$3g2Q4x3@1k6Z5L8q4)9K6c8s2A6Z5i4K6u0V1j5$3^5`.

链接器命名空间解决的问题是:可以隔离不同链接器命名空间中的共享库,以确保具有相同库名称和不同符号的库不会发生冲突。

所以它不是一种安全机制,只是为了安全的解析符号,前面的操作只是对这种限制的规避,不能算漏洞,谷歌也不会去修复,所以预估能够长期使用。

回到Frida,再看看Frida是怎么解决这个dlopen限制的

因为手头只有Android 10的设备,这里只关注Android29的版本

frida-gum在里查找__dl___loader_dlopen(地址就是libdl.so的loader_dlopen),如果没有找到会通过搜索内存对比指令集特征的方式继续查找。但在Android 10上,这一步就找到了,之后的操作和前述`loader_dlopen`方式一致。

gum_linker_api_try_init

理解了这些基本原理后,后面再回到frida-java-bridge,看看js端如何访问Android 运行时。

参考:

https://bbs.pediy.com/thread-257022.htm

e0fK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6W2K9i4y4Z5N6g2)9J5k6h3#2W2i4K6u0r3x3U0l9I4z5q4)9J5c8U0l9$3i4K6u0r3x3o6N6Q4x3V1k6X3M7X3g2W2i4K6u0V1M7X3g2X3L8r3g2U0N6r3W2G2L8W2)9J5k6r3q4T1L8%4k6W2i4K6u0V1j5h3&6V1M7X3!0A6k6q4)9J5k6s2m8Q4x3V1j5`.

8fdK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6X3j5h3c8W2k6i4k6S2j5W2)9J5k6h3y4G2L8g2)9J5c8X3q4F1k6s2u0G2K9h3c8Q4x3X3c8D9K9h3&6C8k6i4u0Q4x3X3c8F1j5h3#2W2M7%4m8S2j5$3g2Q4x3X3c8K6k6h3y4#2M7X3W2@1P5g2)9J5k6r3k6D9j5i4N6K6i4K6u0r3

 
 
 
 
 
 
 
 
 
 
 
 
 
 
void* handle = dlopen("./hello.so", RTLD_LAZY);
typedef void (*hello_t)();
hello_t hello = (hello_t) dlsym(handle, "hello");
hello();
void* handle = dlopen("./hello.so", RTLD_LAZY);
typedef void (*hello_t)();
hello_t hello = (hello_t) dlsym(handle, "hello");
hello();
void* handle = dlopen("libart.so", RTLD_LAZY);
LOGD("dlopen %p",handle); //返回0
void* handle = dlopen("libart.so", RTLD_LAZY);
LOGD("dlopen %p",handle); //返回0
 
 

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2021-8-22 17:43 被whx编辑 ,原因:
收藏
免费 10
支持
分享
最新回复 (10)
雪    币: 230
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2
2021-8-22 15:35
0
雪    币: 180
活跃值: (3901)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
3
文中关于dlopen相关的,frida的实现应该是在frida-core中的,9b7K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6X3M7X3W2V1j5g2)9J5c8X3k6J5K9h3c8S2i4K6u0V1j5$3!0J5k6g2)9J5c8X3u0D9L8$3u0Q4x3V1j5I4j5e0N6U0k6h3x3&6y4X3p5I4x3h3t1&6k6h3y4T1y4U0l9#2x3o6q4S2y4X3u0X3x3U0N6U0y4r3j5H3z5e0j5K6j5$3t1@1y4r3c8W2i4K6u0r3M7%4u0U0i4K6u0r3L8r3W2F1N6i4S2Q4x3V1k6X3M7X3W2V1j5g2)9J5k6r3S2W2L8s2m8W2M7W2)9J5k6r3u0S2j5$3E0W2L8X3c8Q4x3X3c8Y4L8s2g2W2i4K6u0W2j5#2)9J5x3@1H3K6x3o6p5@1i4K6t1$3L8X3u0K6M7q4)9K6b7X3k6J5K9h3c8S2i4@1f1$3i4@1t1K6i4@1p5^5i4@1f1#2i4K6R3#2i4@1p5#2i4@1f1%4i4K6W2m8i4K6R3@1i4@1f1^5i4@1u0r3i4K6R3%4i4@1f1%4i4@1p5^5i4K6S2n7i4@1f1@1i4@1t1&6i4K6W2r3i4@1f1$3i4K6V1^5i4@1q4r3i4@1f1&6i4K6R3H3i4K6W2m8i4@1f1^5i4@1u0r3i4K6R3%4i4@1f1^5i4@1u0r3i4K6V1&6i4@1f1&6i4K6R3%4i4K6S2o6i4@1f1$3i4K6R3&6i4@1u0q4i4@1f1#2i4K6R3^5i4@1t1H3i4@1f1%4i4K6W2n7i4@1q4q4i4@1f1$3i4@1p5H3i4K6R3%4i4@1f1^5i4@1u0r3i4K6W2n7i4@1f1%4i4@1p5^5i4K6S2n7i4@1f1%4i4K6W2m8i4K6R3@1L8r3W2T1j5#2!0q4y4#2)9&6b7g2)9^5y4q4)9J5b7#2!0q4y4#2)9^5y4q4!0n7y4W2!0q4y4g2)9&6x3q4)9^5c8g2!0q4y4g2)9^5y4W2)9^5c8q4!0q4y4q4!0n7c8q4!0n7c8W2!0q4y4#2)9&6y4q4!0m8z5r3I4A6j5X3y4Q4c8e0N6Q4z5f1q4Q4z5o6c8E0L8h3q4H3M7#2!0q4y4W2!0n7x3#2!0m8z5q4!0q4y4g2)9^5y4W2)9^5b7%4y4G2i4K6u0o6i4@1f1#2i4K6R3$3i4K6S2p5i4@1f1@1i4@1u0p5i4@1u0r3i4@1f1%4i4K6V1@1i4@1p5^5k6r3I4G2M7r3g2F1i4@1f1#2i4K6V1J5i4K6S2o6k6r3I4K6P5h3#2Q4c8e0g2Q4z5p5q4Q4b7e0m8Q4c8e0S2Q4b7V1c8Q4b7V1c8Q4x3X3g2Q4c8e0g2Q4z5o6g2Q4b7U0N6Q4c8e0c8Q4b7V1c8Q4z5e0y4Q4c8e0N6Q4z5f1q4Q4z5o6c8Q4c8e0g2Q4z5p5k6Q4b7f1k6Q4c8e0c8Q4b7V1u0Q4b7e0g2Q4c8e0N6Q4z5f1y4Q4z5p5u0Q4x3@1p5`.
1feK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6X3M7X3W2V1j5g2)9J5k6i4u0W2i4K6u0r3M7$3I4A6k6r3g2K6i4K6u0r3L8%4y4V1j5#2)9J5k6o6t1H3x3e0g2Q4x3X3c8@1K9r3g2Q4x3X3c8W2L8X3N6A6L8X3g2W2M7X3W2F1k6#2)9J5k6r3u0W2K9r3W2F1k6q4)9J5k6s2c8Z5k6g2)9J5k6s2u0W2N6X3g2J5M7$3g2Q4x3X3c8W2L8X3N6A6L8X3g2W2M7X3W2F1k6#2)9J5k6i4m8V1k6R3`.`.
1daK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2&6L8%4g2@1N6h3u0W2i4K6u0W2j5$3!0E0i4K6u0r3N6$3q4@1j5$3S2Q4x3@1k6$3i4K6y4p5N6h3x3I4L8h3u0z5z5f1g2v1d9#2p5`.

有什么不正确的欢迎指正,互相学习.
2021-8-23 14:52
0
雪    币: 188
活跃值: (529)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
whx
4
frida-core是host侧用来注入和通讯的,Android上的hook是由frida-gum来做的,不依赖frida-core。

我没仔细看frida-core的代码,估计是host侧注入的时候需要类似的操作加载so吧
2021-8-23 15:19
0
雪    币: 188
活跃值: (529)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
whx
5

不知道为什么,我这边一到下午访问看雪就特别卡


刚跟新了第二部分 欢迎批评指正  从Frida源码学习ArtHook(二)

2021-8-23 15:24
0
雪    币: 18
活跃值: (1076)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
学习了
2021-9-2 18:46
0
雪    币: 156
活跃值: (1352)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
学习了
2021-9-3 08:09
0
雪    币: 156
活跃值: (1352)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
学习了
2021-9-3 08:09
0
雪    币: 1113
活跃值: (1297)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
学习了。
2021-9-3 09:02
0
雪    币: 34
活跃值: (805)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
存在一个模拟器架构转换后,如何执行的问题,比如模拟器是x86,使用native_briage后,可以运行arm的指令,这个时候,又要如何处理呢
2023-11-28 17:46
0
雪    币: 156
活跃值: (1352)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
复习了
2023-12-4 18:16
0
游客
登录 | 注册 方可回帖
返回