当前位置: 首页 > news >正文

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

前言

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

相关文章:

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

前言 stackplz是一款基于eBPF技术实现的追踪工具&#xff0c;目的是辅助安卓native逆向&#xff0c;仅支持64位进程&#xff0c;主要功能如下&#xff1a; hardware breakpoint 基于pref_event实现的硬件断点功能&#xff0c;在断点处可读取寄存器信息&#xff0c;不会被用户…...

十大排序——4.堆排序

前面我们讲了堆&#xff0c;现在我们来看一下队排序。 堆排序的步骤&#xff1a; 首先将一个无序数组建立成一个大顶堆然后&#xff0c;将堆顶的元素和堆低的元素进行交换&#xff08;即将最大的元素交换的到堆底&#xff09;&#xff0c;缩小并下潜调整堆重复上一步&#xf…...

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

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

redis漏洞修复:(CNVD-2019-21763)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、漏洞内容二、镜像准备1.确认镜像版本2.下载镜像 三、配置文件准备1.获取配置文件2.修改配置文件 四、启动redis容器五、修改iptables文件总结 前言 漏扫发…...

手刻 Deep Learning -第壹章-PyTorch入门教学-基础概念与再探线性回归

一、前言 本章会需要 微分、线性回归与矩阵的基本观念 这次我们要来做 PyTorch 的简单教学&#xff0c;我们先从简单的计算与自动导数&#xff08; auto grad / 微分 &#xff09;开始&#xff0c;使用优化器与误差计算&#xff0c;然后使用 PyTorch 做线性回归&#xff0c;还有…...

深入学习 Redis - 如何使用 Redis 作缓存?缓存更新策略?使用需要注意哪些问题(工作/重点)

目录 一、Redis 作为缓存 1.1、缓存的基本概念 1.1.1、理解 1.1.2、缓存存什么样的数据&#xff1f;二八定律 1.2、如何使用 redis 作为缓存 1.3、缓存更新策略&#xff08;redis 内存淘汰机制 / 重点&#xff09; 1.3.1、定期生成 1.3.2、实时生成 内存淘汰策略&#…...

好用的软件测试框架有哪些?测试框架的作用是什么?

软件测试框架是现代软件开发过程中至关重要的工具&#xff0c;它可以帮助开发团队更加高效地进行测试和验证工作&#xff0c;从而大大提高软件质量和用户体验。 一、好用的软件测试框架 1. Selenium&#xff1a;作为一种开源的自动化测试框架&#xff0c;Selenium具有功能强大…...

PAT 1035 插入与归并

PAT 1035 插入与归并 题目描述思路讲解代码展示 题目描述 思路讲解 分析&#xff1a;先将i指向中间序列中满足从左到右是从小到大顺序的最后一个下标&#xff0c;再将j指向从i1开始&#xff0c;第一个不满足a[j] b[j]的下标&#xff0c;如果j顺利到达了下标n&#xff0c;说明…...

K-means 聚类算法学习笔记

K-means 聚类算法 是一种无监督学习算法&#xff0c;用来将 n n n 个样本点分成 k k k 类&#xff0c;使得整个数据集的误差平方和 S S E SSE SSE 最小。在本例中&#xff0c;样本点是指平面直角坐标系上的点&#xff0c;聚类中心也是平面直角坐标系上的点&#xff0c;而每个…...

API文档搜索引擎

导航小助手 一、认识搜索引擎 二、项目目标 三、模块划分 四、创建项目 五、关于分词 六、实现索引模块 6.1 实现 Parser类 6.2 实现 Index类 6.2.1 创建 Index类 6.2.2 创建DocInfo类 6.2.3 创建 Weight类 6.2.4 实现 getDocInfo 和 getInverted方法 6.2.5 实现 …...

文案内容千篇一律,软文推广如何加深用户印象

随着互联网技术的发展&#xff0c;企业营销的方式逐渐转向软文推广&#xff0c;但是现在软文推广的内容同质化越来越严重&#xff0c;企业应该如何让自己的软文推广保持差异性&#xff0c;在用户心中留下独特的印象呢&#xff1f;下面就让媒介盒子告诉你。 一、 找出产品独特卖…...

十二、流程控制-循环

流程控制-循环 1.while循环语句★2.do...while语句★3.for循环语句 —————————————————————————————————————————————————— 1.while循环语句★ while语句也称条件判断语句&#xff0c;它的循环方式是利用一个条件来控制是否…...

五、回溯(trackback)

文章目录 一、算法定义二、经典例题&#xff08;一&#xff09;排列1.[46.全排列](https://leetcode.cn/problems/permutations/description/)&#xff08;1&#xff09;思路&#xff08;2&#xff09;代码&#xff08;3&#xff09;复杂度分析 2.[LCR 083. 全排列](https://le…...

什么是分布式锁?他解决了什么样的问题?

相信对于朋友们来说&#xff0c;锁这个东西已经非常熟悉了&#xff0c;在说分布式锁之前&#xff0c;我们来聊聊单体应用时候的本地锁&#xff0c;这个锁很多小伙伴都会用 ✔本地锁 我们在开发单体应用的时候&#xff0c;为了保证多个线程并发访问公共资源的时候&#xff0c;…...

Ubuntu 12.04增加右键命令:在终端中打开增加打开文件

Ubuntu 12.04增加右键命令&#xff1a;在终端中打开 软件中心&#xff1a;搜索nautilus-open-terminal安装 用快捷键CtrlT打开命令行输入&#xff1a; sudo apt-get install nautilus-open-terminal 重新加载文件管理器 nautilus -q 或注销再登录即要使用...

Centos 7 访问局域网windows共享文件夹

Refer: centos7 访问windows系统的共享文件夹_centos访问windows共享_三希的博客-CSDN博客 一、在CentOS中配置CIFS网络存储服务 CIFS&#xff08;Common Internet File System&#xff09;是一种在网络上共享文件的协议&#xff0c;也称为SMB&#xff08;Server Message Blo…...

GDB的TUI模式(文本界面)

2023年9月22日&#xff0c;周五晚上 今晚在看GDB的官方文档时&#xff0c;发现GDB居然有文本界面模式 TUI (Debugging with GDB) (sourceware.org) GDB开启TUI的条件 GDB的文本界面的开启条件是&#xff1a;操作系统有适当版本的curses库 The TUI mode is supported only on…...

深入了解Python和OpenCV:图像的卡通风格化

前言 当今数字时代&#xff0c;图像处理和美化已经变得非常普遍。从社交媒体到个人博客&#xff0c;人们都渴望分享独特且引人注目的图片。本文将介绍如何使用Python编程语言和OpenCV库创建令人印象深刻的卡通风格图像。卡通风格的图像具有艺术性和创意&#xff0c;它们可以用…...

【算法挨揍日记】day06——1004. 最大连续1的个数 III、1658. 将 x 减到 0 的最小操作数

1004. 最大连续1的个数 III 1004. 最大连续1的个数 III 题目描述&#xff1a; 给定一个二进制数组 nums 和一个整数 k&#xff0c;如果可以翻转最多 k 个 0 &#xff0c;则返回 数组中连续 1 的最大个数 。 解题思路&#xff1a; 首先题目要我们求出的最多翻转k个0后&#x…...

华为云HECS安装docker

1、运行安装指令 yum install docker都选择y&#xff0c;直到安装成功 2、查看是否安装成功 运行版本查看指令&#xff0c;显示docker版本&#xff0c;证明安装成功 docker --version 或者 docker -v 3、启用并运行docker 3.1启用docker 指令 systemctl enable docker …...

SkyWalking 10.2.0 SWCK 配置过程

SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外&#xff0c;K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案&#xff0c;全安装在K8S群集中。 具体可参…...

树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频

使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...

使用分级同态加密防御梯度泄漏

抽象 联邦学习 &#xff08;FL&#xff09; 支持跨分布式客户端进行协作模型训练&#xff0c;而无需共享原始数据&#xff0c;这使其成为在互联和自动驾驶汽车 &#xff08;CAV&#xff09; 等领域保护隐私的机器学习的一种很有前途的方法。然而&#xff0c;最近的研究表明&…...

Map相关知识

数据结构 二叉树 二叉树&#xff0c;顾名思义&#xff0c;每个节点最多有两个“叉”&#xff0c;也就是两个子节点&#xff0c;分别是左子 节点和右子节点。不过&#xff0c;二叉树并不要求每个节点都有两个子节点&#xff0c;有的节点只 有左子节点&#xff0c;有的节点只有…...

解决:Android studio 编译后报错\app\src\main\cpp\CMakeLists.txt‘ to exist

现象&#xff1a; android studio报错&#xff1a; [CXX1409] D:\GitLab\xxxxx\app.cxx\Debug\3f3w4y1i\arm64-v8a\android_gradle_build.json : expected buildFiles file ‘D:\GitLab\xxxxx\app\src\main\cpp\CMakeLists.txt’ to exist 解决&#xff1a; 不要动CMakeLists.…...

MySQL 索引底层结构揭秘:B-Tree 与 B+Tree 的区别与应用

文章目录 一、背景知识&#xff1a;什么是 B-Tree 和 BTree&#xff1f; B-Tree&#xff08;平衡多路查找树&#xff09; BTree&#xff08;B-Tree 的变种&#xff09; 二、结构对比&#xff1a;一张图看懂 三、为什么 MySQL InnoDB 选择 BTree&#xff1f; 1. 范围查询更快 2…...

WebRTC从入门到实践 - 零基础教程

WebRTC从入门到实践 - 零基础教程 目录 WebRTC简介 基础概念 工作原理 开发环境搭建 基础实践 三个实战案例 常见问题解答 1. WebRTC简介 1.1 什么是WebRTC&#xff1f; WebRTC&#xff08;Web Real-Time Communication&#xff09;是一个支持网页浏览器进行实时语音…...

uniapp 集成腾讯云 IM 富媒体消息(地理位置/文件)

UniApp 集成腾讯云 IM 富媒体消息全攻略&#xff08;地理位置/文件&#xff09; 一、功能实现原理 腾讯云 IM 通过 消息扩展机制 支持富媒体类型&#xff0c;核心实现方式&#xff1a; 标准消息类型&#xff1a;直接使用 SDK 内置类型&#xff08;文件、图片等&#xff09;自…...

在鸿蒙HarmonyOS 5中使用DevEco Studio实现指南针功能

指南针功能是许多位置服务应用的基础功能之一。下面我将详细介绍如何在HarmonyOS 5中使用DevEco Studio实现指南针功能。 1. 开发环境准备 确保已安装DevEco Studio 3.1或更高版本确保项目使用的是HarmonyOS 5.0 SDK在项目的module.json5中配置必要的权限 2. 权限配置 在mo…...

基于小程序老人监护管理系统源码数据库文档

摘 要 近年来&#xff0c;随着我国人口老龄化问题日益严重&#xff0c;独居和居住养老机构的的老年人数量越来越多。而随着老年人数量的逐步增长&#xff0c;随之而来的是日益突出的老年人问题&#xff0c;尤其是老年人的健康问题&#xff0c;尤其是老年人产生健康问题后&…...