这篇文章上次修改于 304 天前,可能其部分内容已经发生变化,如有疑问可询问作者。
前言
本文将演示如何利用eBPF手段快速定位frida反调试(简单版)
2024/01/23: 基础使用教学请看README,或者这篇文章
环境
- 可以运行stackplz的手机
- stackplz
目标
- Y29tLndvZGkud2hv 64位版
步骤
首先打开APP,啥也不动,就让它正常运行着就行
总所周知,frida反调试中最高频的是libc.so
的strstr
函数
我们选择对该函数进行堆栈追踪,命令如下:
./stackplz --name com.wodi.who stack --symbol strstr --regs --unwindstack
注,stackplz 2.x起的版本使用如下命令:
./stackplz --name com.wodi.who -w strstr[str,str] --regs --stack
PS,stackplz默认设定了hook的库是/apex/com.android.runtime/lib64/bionic/libc.so
,查看帮助信息请执行./stackplz stack --help
很快啊,我们就得到了如下的日志(简化):
stack_2022/11/28 03:10:06 StackMod hook info:libc.so + strstr
stack_2022/11/28 03:10:06 start 1 modules
stack_2022/11/28 03:10:10 [libc.so + strstr] PID:28875, Comm:com.wodi.who, TID:28925, Regs:
{"lr":"0x7c2ecada7c","pc":"0x7f4c793200","sp":"0x7c2ec8e7c0","x0":"0x7c2ec8e7d8","x1":"0x7c2ecd804a","x10":"0x1ea","x11":"0x1","x12":"0x7c2ec8ddda","x13":"0xe1137761","x14":"0x10","x15":"0x0","x16":"0x7c2ecd6ac0","x17":"0x7f4c793200","x18":"0x64","x19":"0xb400007e088de7a0","x2":"0x1","x20":"0x7c2ecbf933","x21":"0x7c2ecbf932","x22":"0x7c2ecd8030","x23":"0x7c2ecd804a","x24":"0x7c2ecd8056","x25":"0xa9","x26":"0x7c2ec8f000","x27":"0x7c2ec8e7c8","x28":"0x7c2ec8e7d8","x29":"0x12","x3":"0x1","x4":"0x1","x5":"0x4","x6":"0x6174732f","x7":"0x73757461","x8":"0xa","x9":"0xc8349a5f5e975c78"}
Stackinfo:
#00 pc 0000000000095200 /apex/com.android.runtime/lib64/bionic/libc.so (strstr)
#01 pc 000000000001aa78 /data/app/~~edmZjLa9WVogYX0ek9xfLw==/com.wodi.who-zBzvEwdTiPkB-l2ix5dW2w==/lib/arm64/libmsaoaidsec.so
#02 pc 000000000001b870 /data/app/~~edmZjLa9WVogYX0ek9xfLw==/com.wodi.who-zBzvEwdTiPkB-l2ix5dW2w==/lib/arm64/libmsaoaidsec.so
#03 pc 00000000000b1690 /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+204)
#04 pc 00000000000510ac /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64)
...
stack_2022/11/28 03:10:12 [libc.so + strstr] PID:28875, Comm:com.wodi.who, TID:28926, Regs:
{"lr":"0x7c2ecacfa0","pc":"0x7f4c793200","sp":"0x7c2eb903e0","x0":"0x7c2eb903f0","x1":"0x7c2eb903e0","x10":"0x70fe","x11":"0x70fe","x12":"0x9","x13":"0x1","x14":"0x1","x15":"0xa","x16":"0x7c2ecd6ac0","x17":"0x7f4c793200","x18":"0x64","x19":"0xb400007de88780c0","x2":"0xd","x20":"0x7f4c7c0000","x21":"0x7c2eb91000","x22":"0x70cb","x23":"0x70cb","x24":"0x7c2eb90cb0","x25":"0x7c2eb90cb0","x26":"0x7c2eb90ff8","x27":"0xfc000","x28":"0xfe000","x29":"0x7c2eb90c50","x3":"0xb400007da8923e20","x4":"0xb400007da8923e29","x5":"0x7c2eb903fd","x6":"0x6950726563617254","x7":"0xa30093a64695072","x8":"0x0","x9":"0x1"}
Stackinfo:
#00 pc 0000000000095200 /apex/com.android.runtime/lib64/bionic/libc.so (strstr)
#01 pc 0000000000019f9c /data/app/~~edmZjLa9WVogYX0ek9xfLw==/com.wodi.who-zBzvEwdTiPkB-l2ix5dW2w==/lib/arm64/libmsaoaidsec.so
#02 pc 000000000001a584 /data/app/~~edmZjLa9WVogYX0ek9xfLw==/com.wodi.who-zBzvEwdTiPkB-l2ix5dW2w==/lib/arm64/libmsaoaidsec.so
#03 pc 00000000000b1690 /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+204)
#04 pc 00000000000510ac /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64)
可以发现调用来源主要是两个地方:
libmsaoaidsec.so + 0x1aa78
libmsaoaidsec.so + 0x19f9c
这两个地方很可疑,谁没事开个线程不停调用strstr,这两个地方大概率就是反调试了
这个时候再用estrace看下都在打开什么文件
libmsaoaidsec.so + 0x1aa78
前面是用的fopen
,libmsaoaidsec.so + 0x19f9c
则是openat
而fopen
最后也是要走到openat
的,所以使用estrace
执行如下命令看看参数:
./estrace --name com.wodi.who --syscall openat
得到如下日志(简化):
syscall_03:33:47 start 1 modules
syscall_03:33:49 [com.wodi.who] type:2 pid:28875 tid:28925 nr:openat arg_index:1 arg_str:/proc/self/task
syscall_03:33:49 [com.wodi.who] type:1 pid:28875 tid:28925 nr:openat {"lr":"0x7f4c758c34","pc":"0x7f4c79b658","sp":"0x7c2ec8e740","x0":"0x0","x1":"0x7c2ecd8020","x2":"0x0","x3":"0x0"}
syscall_03:33:49 [com.wodi.who] type:3 pid:28875 tid:28925 nr:openat ret:0x5
syscall_03:33:49 [com.wodi.who] type:2 pid:28875 tid:28925 nr:openat arg_index:1 arg_str:/proc/self/task/28875/status
syscall_03:33:49 [com.wodi.who] type:1 pid:28875 tid:28925 nr:openat {"lr":"0x7f4c758dc8","pc":"0x7f4c79b658","sp":"0x7c2ec8e690","x0":"0x0","x1":"0x7c2ec8e9d8","x2":"0x0","x3":"0x0"}
syscall_03:33:49 [com.wodi.who] type:3 pid:28875 tid:28925 nr:openat ret:0xa9
syscall_03:33:49 [com.wodi.who] type:2 pid:28875 tid:28925 nr:openat arg_index:1 arg_str:/proc/self/task/28887/status
syscall_03:33:49 [com.wodi.who] type:1 pid:28875 tid:28925 nr:openat {"lr":"0x7f4c758dc8","pc":"0x7f4c79b658","sp":"0x7c2ec8e690","x0":"0x0","x1":"0x7c2ec8e9d8","x2":"0x0","x3":"0x0"}
syscall_03:33:49 [com.wodi.who] type:3 pid:28875 tid:28925 nr:openat ret:0xa9
...
syscall_03:33:49 [com.wodi.who] type:2 pid:28875 tid:28925 nr:openat arg_index:1 arg_str:/proc/self/fd
syscall_03:33:49 [com.wodi.who] type:1 pid:28875 tid:28925 nr:openat {"lr":"0x7f4c758c34","pc":"0x7f4c79b658","sp":"0x7c2ec8e6f0","x0":"0x0","x1":"0x7c2ecd805c","x2":"0x0","x3":"0x0"}
syscall_03:33:49 [com.wodi.who] type:3 pid:28875 tid:28925 nr:openat ret:0x5
syscall_03:33:49 [com.wodi.who] type:2 pid:28875 tid:28925 nr:openat arg_index:1 arg_str:/proc/self/maps
syscall_03:33:49 [com.wodi.who] type:1 pid:28875 tid:28925 nr:openat {"lr":"0x7f4c758b20","pc":"0x7f4c79b658","sp":"0x7c2ec8c9d0","x0":"0x0","x1":"0x7c2ecd8074","x2":"0x0","x3":"0x0"}
syscall_03:33:49 [com.wodi.who] type:3 pid:28875 tid:28925 nr:openat ret:0x5
syscall_03:33:50 [uploadChecker t] type:2 pid:28875 tid:29012 nr:openat arg_index:1 arg_str:
syscall_03:33:50 [uploadChecker t] type:1 pid:28875 tid:29012 nr:openat {"lr":"0x7f4c758c34","pc":"0x7f4c79b658","sp":"0x7beb4d6e60","x0":"0x0","x1":"0xb400007cd88b9d10","x2":"0x0","x3":"0x0"}
syscall_03:33:50 [uploadChecker t] type:3 pid:28875 tid:29012 nr:openat ret:0x5
果然是在打开/proc/self/task
和/proc/self/maps
,没跑了
再用IDA对上面两处调用strstr
进行交叉引用,发现有创建线程,将对应位置nop,patch得到新so,替换手机内的
经过测试frida attach上去再也不崩了!
定位到的创建线程位置如图所示(不止一处,这里就不完整贴出来了):
总结
通过eBPF hook用户态的库关键函数来定位frida反调试当然是可行的,不过首先得知道frida反调试的基础知识
结合一些经验也是能定位出来反调试点的,当然本文只是演示了一个很简单的例子
本文主要以演示stackplz
和estrace
效果为主,如果要更加灵活,建议还是上bcc环境
在bcc下直接读取strstr参数也会比较方便,可以参考eBPF on Android之hook libc.so open
Q: 如果是更复杂的反调试呢?
A: 那可以对所有的syscall调用进行追踪(estrace不会被检查到),找到调用位置,深入分析逻辑,一步步逆推也是能定位的;但这样很耗时,更多的时候还是建议结合反调试的手段,针对性hook和分析
已有 2 条评论
--unwindstack 参数在新版本变成 --stack 了吧
@rxkotlin 是的