首页
社区
课程
招聘
[原创] 基于eBPF的安卓逆向辅助工具——stackplz
发表于: 2023-9-8 21:37 17657

[原创] 基于eBPF的安卓逆向辅助工具——stackplz

2023-9-8 21:37
17657

stackplz是一款基于eBPF技术实现的追踪工具,目的是辅助安卓native逆向,仅支持64位进程,主要功能如下:

使用要求:内核 5.10+(开发板+ReDroid也是可以的,当前支持rock5b),该限制主要来自于需要使用bpf_probe_read_user接口

stackplz最初是受到定制bcc/ebpf在android平台上实现基于dwarf的用户态栈回溯启发,加上自己对eBPF技术略有一点研究,然后决定开发这样一款工具

当时核心目的是寻求一种门槛低、不依赖额外环境、能实际落地的方案开发eBPF程序

受限于当时高版本内核安卓设备的普及程度,只实现了寄存器获取与堆栈回溯,限制是内核要求4.14+

经过一年左右的发展,GKI 2.0设备多了起来,各类eBPF相关的内容不断涌现 ,加上之前自己立了flag

于是最近几个月把之前给stackplz立的flag给陆续落地,加上了许多功能,以期能真正将eBPF技术投入实际的安卓逆向分析中

另外KernelSU近期也发布了新的计划:

什么,无限制的eBPF?那真的是太好了! 所以本文再不出,stackplz就要凉啦(>_<)

再次说明要求与限制:内核 5.10+,仅支持64位进程

请前往Releases或者Actions下载使用

注意:每次更新版本请手动执行一次./stackplz --prepare

本文演示过程中没有任何APP受到伤害!

写原理太枯燥你们可能就划走了,下次再写,还是先看看实际效果吧~

硬件断点支持四种类型,即r,w,x,rw,断点长度为4字节

命令中必须提供pid,断点绝对地址或者断点偏移+动态库名,下面是两个示例效果:

说明:

如果要给内核空间的地址下硬件断点,可以使用pid+绝对地址的方式,pid给定一个存在的进程即可(不过目前没有回溯内核堆栈的功能,所以给内核空间地址下硬件断点聊胜于无

其原理是替换目标位置动态库的指令为brk指令,执行到目标位置的时候会陷入内核,执行eBPF虚拟机中的代码

美中不足的是,这个brk指令是可以被扫描出来的,但优势也是只有这一个brk指令,没有inlinehook那么多特征

如果确实担心被扫描,那么可以采用硬件断点先检查下^_^

基于该能力,stackplz可以在断点位置读取上下文的内容,在逆向时以最小的侵入力度获取想要的内容,尽可能避开检测

下面是具体效果:

说明:

原理是将eBPF程序挂载到raw_tracepoint/sys_enterraw_tracepoint/sys_exit,然后根据预设配置解析参数

追踪syscall的时候自然也是能输出堆栈的,不过限于篇幅,下面的例子中就不演示了,加--stack即可

下面是具体效果:

说明:

下面将演示如何过root检查,虽然对于eBPF来说做这个事情比较鸡肋,但是还是值得演示一下

核心原理就是通过bpf_probe_write_user方法修改内存数据,这里过root检查就是简单替换下相关的字符串

再次说明:本文演示过程中没有任何APP受到伤害!

这里请一位不愿透露姓名的APP做演示,过程如下:

使用--mstack,该选项意为手工解析堆栈,因为某些情况下默认的方案可能无法给出详细的堆栈(全是unknown

在后面两个命令同时使用的情况下,最终能走到APP的启动页面:

不过使用eBPF过这个检查实在是麻烦...所以stackplz的定位是辅助分析,这里仅仅演示一下eBPF修改内存的能力

对了,APP怎么老是退出,想个办法让它不要退出好不好哇(

这样每次调用exit的时候,都会发送SIGSTOP信号,可以把整个进程挂起

每次挂起后如果要恢复进程运行,那么执行kill -SIGCONT {pid}这样的命令即可

不过有一个需要注意的问题,那就是发信号的时候,syscall还是会执行,也就是说如果在exit这个系统调用处发信号,进程有可能还是没办法挂起

那么可以配合使用--stack--mstack--getoff来判断从用户态的什么地方调用,从上面的结果来看,是libc.so的__exit

那么使用下面的命令进行追踪,这样就可以真正在执行到__exit的时候挂起,上下文也会保持在__exit的状态

这是lldb附加上去的效果:

这里的iso指追踪isolated进程,-n/--name选项可以给定进程分组,目前的分组是root system shell app iso

如果单条命令hook无法一次性实现想要的追踪内容,那么多开stackplz即可,以及同一个位置多次下hook都是支持的

具有黑白名单的选项:

在某些情况下,stackplz无法解析到偏移、堆栈,可以设置debug和输出日志到文件,然后根据日志中的各类事件信息进行分析

仅将日志输出到文件,不输出到终端,这对于进行大量追踪的时候,有助于减少数据丢失

默认情况下,buf类型的数据打印为ASCII + hex,使用下面的选项将打印为hexdump

追踪一些特别频繁的调用时,可能会出现部分数据丢失的情况,这个时候请适当增加eBPF的数据缓冲区大小

更多命令,请执行./stackplz --help查看

Q: 不能修改寄存器吗
A: 是的,eBPF中无法修改寄存器,只能修改给定地址处的内存数据

Q: 运行不了
A: 首先请使用5.10+内核的设备,如果确实不行请反馈至issue

Q: 技术架构等
A: 语言:Golang + C
A: 三方库:ebpf + ebpfmanager + libbpf
A: 预编译:BTFHubForAndroid + unwinddaemon
A: 其他:ndk clang + Makefile

adb push stackplz /data/local/tmp
chmod +x /data/local/tmp/stackplz
cd /data/local/tmp && ./stackplz --prepare
adb push stackplz /data/local/tmp
chmod +x /data/local/tmp/stackplz
cd /data/local/tmp && ./stackplz --prepare
./stackplz -p 37919 --brk 0xf3a4:x --brk-lib libnative-lib.so --stack
./stackplz -p 37919 --brk 0xf3a4:x --brk-lib libnative-lib.so --stack
./stackplz -p 37919 --brk 0x763e6103a4:x --regs --stack --stack-size 4096
./stackplz -p 37919 --brk 0x763e6103a4:x --regs --stack --stack-size 4096
./stackplz -n com.sfx.ebpf --point strstr[str,str] --getoff --stack
./stackplz -n com.sfx.ebpf --point strstr[str,str] --getoff --stack
./stackplz -n com.sfx.ebpf -l libnative-lib.so -w _Z5func4i[int] --regs
./stackplz -n com.sfx.ebpf -l libnative-lib.so -w _Z5func4i[int] --regs
./stackplz -n com.sfx.ebpf -w open64[str,int] -f w:/data
./stackplz -n com.sfx.ebpf -w open64[str.f0,int] -f w:/data
./stackplz -n com.sfx.ebpf -w open64[str.f0.f1.f2,int] -f w:/data -f b:/sys -f w:/proc
./stackplz -n com.sfx.ebpf -w open64[str,int] -f w:/data
./stackplz -n com.sfx.ebpf -w open64[str.f0,int] -f w:/data
./stackplz -n com.sfx.ebpf -w open64[str.f0.f1.f2,int] -f w:/data -f b:/sys -f w:/proc
./stackplz -n com.sfx.ebpf -s openat,socket,connect
./stackplz -n com.sfx.ebpf -s openat,socket,connect
./stackplz -n com.sfx.ebpf -s %file,%net --no-syscall openat,recvfrom
./stackplz -n com.sfx.ebpf -s %file,%net --no-syscall openat,recvfrom
./stackplz -n ???.???.??? -s openat:f0.f1.f2 -f w:/system -f w:/dev -f b:/system/lib64 -o tmp.log
./stackplz -n ???.???.??? -s openat:f0.f1.f2 -f w:/system -f w:/dev -f b:/system/lib64 -o tmp.log
./stackplz -n ???.???.???,iso -s execve,openat -o tmp_s.log
./stackplz -n ???.???.???,iso -s execve:f3,openat:f0.f1.f2 -f r:/sbin/su:::/xx -f r:/system/bin/su:::/xx -f r:/system/xbin/su:::/xx -f r:/system/bin/getprop:::/xx
./stackplz -n ???.???.???,iso -w popen[str.f0.f1] -f r:mount:::mounx -f "r:which su:::which zz" --stack
./stackplz -n ???.???.???,iso -s execve,openat -o tmp_s.log
./stackplz -n ???.???.???,iso -s execve:f3,openat:f0.f1.f2 -f r:/sbin/su:::/xx -f r:/system/bin/su:::/xx -f r:/system/xbin/su:::/xx -f r:/system/bin/getprop:::/xx
./stackplz -n ???.???.???,iso -w popen[str.f0.f1] -f r:mount:::mounx -f "r:which su:::which zz" --stack
./stackplz -n ???.???.???,iso -s exit --kill SIGSTOP --stack
./stackplz -n ???.???.???,iso -s exit --kill SIGSTOP --stack
./stackplz -n ???.???.???,iso -w __exit --kill SIGSTOP --stack
./stackplz -n ???.???.???,iso -w __exit --kill SIGSTOP --stack
白名单 黑名单
-u/--uid --no-uid
-p/--pid --no-pid
-t/--tid --no-tid
--tname --no-tname
-s/--syscall --no-syscall
1
2
3
adb push stackplz /data/local/tmp
chmod +x /data/local/tmp/stackplz
cd /data/local/tmp && ./stackplz --prepare
1
./stackplz -p 37919 --brk 0xf3a4:x --brk-lib libnative-lib.so --stack
1
./stackplz -p 37919 --brk 0x763e6103a4:x --regs --stack --stack-size 4096
1
./stackplz -n com.sfx.ebpf --point strstr[str,str] --getoff --stack
1
./stackplz -n com.sfx.ebpf -l libnative-lib.so -w _Z5func4i[int] --regs
1
2
3
./stackplz -n com.sfx.ebpf -w open64[str,int] -f w:/data
./stackplz -n com.sfx.ebpf -w open64[str.f0,int] -f w:/data
./stackplz -n com.sfx.ebpf -w open64[str.f0.f1.f2,int] -f w:/data -f b:/sys -f w:/proc

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2023-9-8 21:49 被seeeseee编辑 ,原因: 调整语序
收藏
免费 21
支持
分享
最新回复 (15)
雪    币: 2484
活跃值: (3251)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
2
好用,爱用,牛逼!
2023-9-8 21:45
0
雪    币: 525
活跃值: (773)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
3
我没看,但是我先来评论,脸哥牛的
2023-9-8 22:02
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
4
牛逼
2023-9-8 22:12
0
雪    币: 2141
活跃值: (7221)
能力值: ( LV11,RANK:180 )
在线值:
发帖
回帖
粉丝
5
2023-9-9 01:33
0
雪    币: 2328
活跃值: (10364)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
太强了
2023-9-9 09:01
0
雪    币: 21
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
7
2023-9-9 18:44
0
雪    币: 2948
活跃值: (30846)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
感谢分享
2023-9-9 18:58
1
雪    币: 943
活跃值: (2828)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
脸哥牛逼 
2023-9-9 20:34
0
雪    币: 893
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
10
牛逼
2023-9-12 09:25
0
雪    币: 1671
活跃值: (215817)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
11
tql
2023-9-12 09:34
0
雪    币: 507
活跃值: (1742)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12

谢谢各位支持,最新版加入了以下内容:


- 加入了`--dumpret`选项,可以输出含有给定符号关键词的RET指令偏移,符号本身偏移信息,拿到这些偏移信息后,可以对函数返回值进行快速追踪

- 修复`--reg`选项未按预期工作的情况,该选项可用于计算给定寄存器的偏移情况

- 修复hexdump含有`%`时出现格式化异常的情况

- 修正了指针类型参数的读取,现在可以通过指示`*int`对特定位置进行读取

- 添加了`%dup`和`%epoll`两组快速追踪

- 支持IOVEC类型数据详细解析,即可以详细输出`readv/writev/preadv/pwritev/process_vm_readv/process_vm_writev`的内容了



详细效果请移步Releases查看,最新版请在Actions下载

2023-9-18 09:31
0
雪    币: 507
活跃值: (1742)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
Ylarod 好用,爱用,牛逼!
2023-9-18 09:31
0
雪    币: 1
活跃值: (55)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
2023-9-18 19:22
0
雪    币: 213
活跃值: (147)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
终于有人用到perf了,可以进一步看看kernel里的perf开关
2023-9-21 17:58
0
雪    币: 116
活跃值: (1012)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
6
2023-10-31 18:10
0
游客
登录 | 注册 方可回帖
返回
//