基于eBPF的安卓逆向辅助工具——stackplz

news2024/11/19 4:46:59

前言

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

  • hardware breakpoint 基于pref_event实现的硬件断点功能,在断点处可读取寄存器信息,不会被用户态探测到
    • 前提是需要内核启用CONFIG_HAVE_HW_BREAKPOINT,5.10+内核默认开启
  • uprobe hook 即在用户态对动态库下断点,在断点处可读取寄存器等上下文信息
  • trace syscall 即在内核态对syscall进行追踪,输出syscall信息,无视任何反调试
  • 自动追踪fork产生的进程,可按pid/uid/tid/package等组合进行过滤
  • 在命中hook的时候可发送信号,例如发送SIGSTOP可挂起进程(硬件断点暂未实现发送信号
    • 几乎无视反调试,并且此时可以使用lldb等调试器附加到进程,获取上下文内容
    • 如果进程已经处于相互ptrace的状态,则调试器不可附加,但此时还是可以通过dd等手段获取上下文内容
  • 使用上述功能时,均可回溯堆栈

使用要求:内核 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近期也发布了新的计划:

  • su 使用日志;通过在内核中跟踪 fork, execve 等系统调用,给出调用 su 的进程调用的日志,如时间,命令行参数等。
  • 集成支持硬件断点并提供用户空间接口,为开发和调试提供便利。
  • 在 kernel 中集成 Lua 解释器并为用户空间提供接口;这样可以让内核运行 lua 脚本,等同于无限制的 eBPF,成为 tracing 好帮手。

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

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

请前往Releases或者Actions下载使用

1

2

3

adb push stackplz /data/local/tmp

chmod +x /data/local/tmp/stackplz

cd /data/local/tmp && ./stackplz --prepare

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

功能演示

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

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

1. 硬件断点

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

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

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

说明:

  • --regs 输出寄存器信息
  • --stack 默认获取用户态8192字节的栈上数据用于回溯堆栈
  • --stack-size 可以用于指定要获取的栈上数据大小,必须是8的倍数

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

2. uprobe hook

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

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

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

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

下面是具体效果:

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

说明:

  • --getoff 计算LR与PC的偏移情况,方便快速定位调用位置
  • -l/--lib 指定动态库路径,默认为libc.so
    • 大多数情况下使用库名即可,如果遇到同名不同路径,或者找不到的情况,可手动指定为/proc/{pid}/maps中的完整路径
  • -w/--point 意为观测点,配合动态库指定符号或者偏移,可设置多个,上限6个
    • 语法是{符号/基址偏移}{+偏移}{[参数类型{寄存器/读取地址},参数类型{.f{规则索引}}]}
    • 一个观测点下最多读取10个参数
    • 一个参数下最多应用6个过滤规则
    • 下面是一些使用组合示例,目前支持的类型:int,uint,int64,uint64,str,ptr,buf
    • -w _Z5func1v
    • -w 0x9542c[str,str]
    • -w strstr+0x4[str,str]
    • -w strstr[str,str] -w open[str,int]
    • -w 0xA94E8[int:x1,ptr:sp+0x30-0x2c]
      • 默认按寄存器顺序读取,也可以参考本示例,在第一个位置读取x1为int,在第二个位置读取sp+0x30-0x2c为指针
      • 没错,可以进行简单的计算,这样能够灵活读取栈上的内容
    • -w write[int,buf:x2,int]
    • -w write[int,buf:32,int]
    • -w write[int,buf:0x10,int]
      • buf较为特殊,规则如下:
      • 如果:后面是寄存器表明以该寄存器大小为长度读取数据
      • 如果:后面是十进制或十六进制字符串,则表明以这个数的大小为长度读取数据
    • -w write[buf:x2:x1,int,int]
      • 这里的规则表示,读取第一个参数时,读的是x1寄存器,长度为x2,即:后的第一个内容表示长度,末尾的才是要读取的寄存器
  • -f/--filter 字符串过滤规则,有三种,分别是w/white b/black r/replace,示例如下
    • 规则位于参数的末尾,多个规则以.作为分隔符
    • 替换规则涉及两个字符串,以:::作为分隔符
    • 示例如下,依次为白名单规则、黑名单规则、替换规则:
      • -f w:/data
      • -f b:/sys
      • -f r:/system/bin/su:::/system/bin/zz
    • -w openat[int,str.f0.f1] 意为对符号openat的第二个参数,应用规则0规则1
    • -s openat:f0 这是syscall,先在这里说了,意为对openat系统调用的第一个字符串参数应用规则0,注意分隔符为:

3. trace syscall

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

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

下面是具体效果:

1

./stackplz -n com.sfx.ebpf -s openat,socket,connect

1

./stackplz -n com.sfx.ebpf -s %file,%net --no-syscall openat,recvfrom

1

./stackplz -n ???.???.??? -s openat:f0.f1.f2 -f w:/system -f w:/dev -f b:/system/lib64 -o tmp.log

说明:

  • -s/--syscall 一般情况,追踪多个syscall要用,作为分隔符
    • 还可以使用下面的内容进行分组追踪,避免手打大量syscall名
      • all %attr %file %exec %clone %process %net %signal %kill %stat
    • 对syscall中的参数进行过滤,示例如下,使用:作为起始分隔符,使用.作为多个规则的分隔符
      • -s openat:f0.f1.f2
    • syscall的参数过滤仅支持syscall的首个字符串参数

4. 进阶使用

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

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

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

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

  1. 首先执行第一个命令,该命令意为追踪execveopenat两个系统调用
  2. 打开APP,很快啊,APP就崩溃了;这个时候已经采集到syscall的调用情况了,从日志中检查调用的参数,发现有su相关的访问
  3. 还是执行第一个命令,然后另开一个shell,执行第二个命令,将有关su的访问替换为其他字符串
  4. 打开APP,很快啊,APP还是崩溃了,不过可以发现APP执行得更久一点...
  5. 配合使用--stack--mstack--getoff,进行更准确的分析
  6. 以此往复,最终发现APP还会执行mountwhich su等命令,而且是走的libc.so,于是再开一个shell执行第三个命令

1

2

3

./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

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

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

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

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

1

./stackplz -n ???.???.???,iso -s exit --kill SIGSTOP --stack

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

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

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

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

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

1

./stackplz -n ???.???.???,iso -w __exit --kill SIGSTOP --stack

这是lldb附加上去的效果:

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

5. 其他补充

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

具有黑白名单的选项:

白名单黑名单
-u/--uid--no-uid
-p/--pid--no-pid
-t/--tid--no-tid
--tname--no-tname
-s/--syscall--no-syscall

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

  • --debug -o tmp.log

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

  • -q/--quiet

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

  • --dumphex

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

  • -b/--buffer 默认8M,一般不建议超过32M

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

6. Q & A

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

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1032268.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【计算机网络】子网掩码、子网划分

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; 更多计算机网络知识专栏&#xff1a;计算机网络&#x1f525; 给大家跳段…

为什么曲面函数的偏导数可以表示其曲面的法向量?

为什么曲面函数的偏导数可以表示其曲面的法向量&#xff1f; 引用资料&#xff1a; 1.知乎shinbade&#xff1a;曲面的三个偏导数为什么能表示法向量&#xff1f; 2.Geogebra羅驥韡 (Pegasus Roe)&#xff1a;偏導數、切平面、梯度 曲面 F ( x , y , z ) 0 F(x,y,z)0 F(x,y,…

Direct3D模板缓存

模板缓存是一个用于获得某种特效的离屏缓存&#xff0c;模板缓存的分辨率与后台缓存和深度缓存的分辨率完全相同&#xff0c;所以像素也是一一对应的&#xff0c;模板缓存允许我们动态的&#xff0c;有针对性的决定是否将某个像素写入后台缓存中。 例如实现镜面效果时&#xf…

3、Elasticsearch功能使用

第4章 功能使用 4.1 Java API 操作 随着 Elasticsearch 8.x 新版本的到来&#xff0c;Type 的概念被废除&#xff0c;为了适应这种数据结构的改 变&#xff0c;Elasticsearch 官方从 7.15 版本开始建议使用新的 Elasticsearch Java Client。 4.1.1 增加依赖关系 <propertie…

工作【当van-tab不满足固定在顶部】

背景 需要H5实现一下滑动列表&#xff0c;顶部tab栏可以切换&#xff0c;当向下滑动列表的时候tab栏固定到顶部。果断的看了一下官方文档&#xff1a; 就是这个&#xff0c;我一看还有扩展属性&#xff0c;非常友好。向下滑动查看文档 使用sticky实现的。众所周知&#xff0…

Python 计算三角形面积

"""计算三角形面积介绍&#xff1a;已知三角形边长分别为x、y、z&#xff0c;可以计算三角形半周长q&#xff0c;然后根据海伦公式计算三角形面积S三角形半周长&#xff1a;q (x y z) / 2三角形面积&#xff1a;S (q * (q-x) * (q-y) * (q-z)) ** 0.5知识点…

独辟蹊径”之动态切换进程代理IP

前言 项目中遇到这样一个需求&#xff0c;需要动态切换指定进程Sockets5代理IP&#xff0c;目前了解到可通过编写驱动拦截或者劫持LSP实现&#xff0c;LSP劫持不太稳定&#xff0c;驱动无疑是相对较好的解决方案&#xff0c;奈何水平不足便有了这"蹊径"。 初步尝试…

Mybatis SQL构建器

上一篇我们介绍了在Mybatis映射器中使用SelectProvider、InsertProvider、UpdateProvider、DeleteProvider进行对数据的增删改查操作&#xff1b;本篇我们介绍如何使用SQL构建器在Provider中优雅的构建SQL语句。 如果您对在Mybatis映射器中使用SelectProvider、InsertProvider…

反编译之崩溃定位

反编译之崩溃定位 1.背景问题定位1.首先我们需要找崩溃所在的类和方法2.寻找崩溃的代码行数2.1借用反编译工具jadx查看反编译后的内容 1.背景 线上出了个崩溃(量挺大&#x1f62d;)&#xff0c;但是apk是被混淆过的&#xff0c;一时摸不着头脑。崩溃信息如下&#xff1a; 主要…

yum 快速安装zookeeper、Kafka集群部署 es安装 logstash安装 kibina 分词器 redis

Zookeeper安装 Kafka是基于Zookeeper来实现分布式协调的&#xff0c;所以在搭建Kafka节点之前需要先搭建好Zookeeper节点。而Zookeeper和Kafka都依赖于JDK&#xff0c;我这里先安装好了JDK&#xff1a; 安装jdk yum install java-1.8.0-openjdk* -y 1 [root192.168.99.4 ~]#…

OpenCascade模型解析-详细分解模型结构

OpenCascade提供了gp_trsf、BRepBuilderAPI_Transform&#xff0c;可以用来实现拓扑&#xff08;TopoDS_Shape&#xff09;的变换&#xff1a;平移&#xff0c;&#xff08;点&#xff0c;轴&#xff0c;面&#xff09;镜像&#xff0c;旋转&#xff0c;缩放&#xff0c;移位。…

21 mysql ref 查询

前言 这里主要是 探究一下 explain $sql 中各个 type 诸如 const, ref, range, index, all 的查询的影响, 以及一个初步的效率的判断 这里会调试源码来看一下 各个类型的查询 需要 lookUp 的记录 以及 相关的差异 此系列文章建议从 mysql const 查询 开始看 测试表结构…

爬虫 — Scrapy 框架(一)

目录 一、介绍1、同步与异步2、阻塞与非阻塞 二、工作流程三、项目结构1、安装2、项目文件夹2.1、方式一2.2、方式二 3、创建项目4、项目文件组成4.1、piders/__ init __.py4.2、spiders/demo.py4.3、__ init __.py4.4、items.py4.5、middlewares.py4.6、pipelines.py4.7、sett…

微信小程序开发:新手必备套餐(一)项目环境的搭建

第一步&#xff1a;注册小程序账号 这个专栏的使用的app是微信&#xff0c;微信小程序则是当今社会web小程序开发中最为主流的app 1&#xff1a;进入网页完成账户的注册微信公众平台 点击立即注册 继续完成之后直接登录即可 登录成功之后 第二步&#xff1a;下载小程序开…

【机器学习】回归问题实例(李宏毅老师作业1)

文章目录 任务介绍完成和调参 任务介绍 问题描述 给出美国某一州过去3天的调查结果&#xff0c;然后预测第3天新检测阳性病例的百分比。 数据相关特征feature States&#xff08;34&#xff0c; encode to one-hot vectors&#xff09; 34个州COVID-like illness&#xff0…

使用patch-package保存node_modules包修改

遇到情况&#xff0c;第三方包存在bug或者缺少文件时候&#xff0c;我们手动修改了某个包时候&#xff0c;下次npm安装时候会导致原来的修改呗覆盖 安装 这时候可以用到npm工具包patch-package&#xff0c;项目更目录命令行安装 npm i -D patch-package修改文件 修改好nod…

3D虚拟情景实训系统在英语课堂教学中的应用

3D虚拟情景实训系统在英语课堂教学中的应用&#xff0c;为学生们提供了一个真实且生动的学习环境。 在课堂教学中&#xff0c;系统会模拟各种情景&#xff0c;如商务会议、旅行、饭店订房等&#xff0c;学生可以亲身参与体验学习&#xff0c;从而提高他们的英语口语和听力能力。…

【C++】vector中的常见函数和使用

前言 感觉vector在目前阶段很常用&#xff0c;就总结记录一些vector的用法 方便自己忘记的时候查找 因为是自用&#xff0c;所以我直接放代码了&#xff0c;只说明如何使用&#xff0c;以及一些小的注意点&#xff0c;对于函数具体实现过程&#xff0c;在这篇文章中&#xff…

Spring Boot自动装配原理超详细解析

目录 前言一、什么是SPI&#xff1f;1. JDK中的SPI2. Spring中的SPI2.1 加载配置2.2 实例化 二、Import注解和ImportSelector是什么&#xff1f;1. 代码示例2. 过程解析3. 源码分析 三、Spring Boot的自动装配1.源码分析2.代码示例3.Spring Boot自带的自动装配 四、总结 前言 …

LabVIEW报表生成工具包时出现错误-41106

LabVIEW报表生成工具包时出现错误-41106 使用LabVIEW报表生成工具包创建Excel报告或Word文档时&#xff0c;收到以下错误&#xff1a;Error -41106 occurred at NI_Excel.lvclass:new report subVI.vi ->NI_report.lvclass:New Report.vi -> Export Report With JKI.vi …