基于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 |
|
注意:每次更新版本请手动执行一次./stackplz --prepare
功能演示
本文演示过程中没有任何APP受到伤害!
写原理太枯燥你们可能就划走了,下次再写,还是先看看实际效果吧~
1. 硬件断点
硬件断点支持四种类型,即r,w,x,rw
,断点长度为4字节
命令中必须提供pid,断点绝对地址
或者断点偏移+动态库名
,下面是两个示例效果:
1 |
|
1 |
|
说明:
--regs
输出寄存器信息--stack
默认获取用户态8192字节的栈上数据用于回溯堆栈--stack-size
可以用于指定要获取的栈上数据大小,必须是8的倍数
如果要给内核空间的地址下硬件断点,可以使用pid+绝对地址的方式,pid给定一个存在的进程即可(不过目前没有回溯内核堆栈的功能,所以给内核空间地址下硬件断点聊胜于无
2. uprobe hook
其原理是替换目标位置动态库的指令为brk指令,执行到目标位置的时候会陷入内核,执行eBPF虚拟机中的代码
美中不足的是,这个brk指令是可以被扫描出来的,但优势也是只有这一个brk指令,没有inlinehook那么多特征
如果确实担心被扫描,那么可以采用硬件断点先检查下^_^
基于该能力,stackplz可以在断点位置读取上下文的内容,在逆向时以最小的侵入力度获取想要的内容,尽可能避开检测
下面是具体效果:
1 |
|
1 |
|
1 2 3 |
|
说明:
--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,即
:
后的第一个内容表示长度,末尾的才是要读取的寄存器
- 这里的规则表示,读取第一个参数时,读的是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_enter
和raw_tracepoint/sys_exit
,然后根据预设配置解析参数
追踪syscall的时候自然也是能输出堆栈的,不过限于篇幅,下面的例子中就不演示了,加--stack
即可
下面是具体效果:
1 |
|
1 |
|
1 |
|
说明:
-s/--syscall
一般情况,追踪多个syscall要用,
作为分隔符- 还可以使用下面的内容进行分组追踪,避免手打大量syscall名
all %attr %file %exec %clone %process %net %signal %kill %stat
- 对syscall中的参数进行过滤,示例如下,使用
:
作为起始分隔符,使用.
作为多个规则的分隔符-s openat:f0.f1.f2
- syscall的参数过滤仅支持syscall的首个字符串参数
- 还可以使用下面的内容进行分组追踪,避免手打大量syscall名
4. 进阶使用
下面将演示如何过root检查,虽然对于eBPF来说做这个事情比较鸡肋,但是还是值得演示一下
核心原理就是通过bpf_probe_write_user
方法修改内存数据,这里过root检查就是简单替换下相关的字符串
再次说明:本文演示过程中没有任何APP受到伤害!
这里请一位不愿透露姓名的APP做演示,过程如下:
- 首先执行第一个命令,该命令意为追踪
execve
和openat
两个系统调用 - 打开APP,很快啊,APP就崩溃了;这个时候已经采集到syscall的调用情况了,从日志中检查调用的参数,发现有su相关的访问
- 还是执行第一个命令,然后另开一个shell,执行第二个命令,将有关su的访问替换为其他字符串
- 打开APP,很快啊,APP还是崩溃了,不过可以发现APP执行得更久一点...
- 配合使用
--stack
、--mstack
和--getoff
,进行更准确的分析 - 以此往复,最终发现APP还会执行
mount
和which su
等命令,而且是走的libc.so,于是再开一个shell执行第三个命令
1 2 3 |
|
使用--mstack
,该选项意为手工解析堆栈,因为某些情况下默认的方案可能无法给出详细的堆栈(全是unknown
在后面两个命令同时使用的情况下,最终能走到APP的启动页面:
不过使用eBPF过这个检查实在是麻烦...所以stackplz的定位是辅助分析,这里仅仅演示一下eBPF修改内存的能力
对了,APP怎么老是退出,想个办法让它不要退出好不好哇(
1 |
|
这样每次调用exit的时候,都会发送SIGSTOP
信号,可以把整个进程挂起
每次挂起后如果要恢复进程运行,那么执行kill -SIGCONT {pid}
这样的命令即可
不过有一个需要注意的问题,那就是发信号的时候,syscall还是会执行,也就是说如果在exit这个系统调用处发信号,进程有可能还是没办法挂起
那么可以配合使用--stack
、--mstack
和--getoff
来判断从用户态的什么地方调用,从上面的结果来看,是libc.so的__exit
那么使用下面的命令进行追踪,这样就可以真正在执行到__exit
的时候挂起,上下文也会保持在__exit
的状态
1 |
|
这是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技术实现的追踪工具,目的是辅助安卓native逆向,仅支持64位进程,主要功能如下: hardware breakpoint 基于pref_event实现的硬件断点功能,在断点处可读取寄存器信息,不会被用户…...

十大排序——4.堆排序
前面我们讲了堆,现在我们来看一下队排序。 堆排序的步骤: 首先将一个无序数组建立成一个大顶堆然后,将堆顶的元素和堆低的元素进行交换(即将最大的元素交换的到堆底),缩小并下潜调整堆重复上一步…...

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

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

手刻 Deep Learning -第壹章-PyTorch入门教学-基础概念与再探线性回归
一、前言 本章会需要 微分、线性回归与矩阵的基本观念 这次我们要来做 PyTorch 的简单教学,我们先从简单的计算与自动导数( auto grad / 微分 )开始,使用优化器与误差计算,然后使用 PyTorch 做线性回归,还有…...

深入学习 Redis - 如何使用 Redis 作缓存?缓存更新策略?使用需要注意哪些问题(工作/重点)
目录 一、Redis 作为缓存 1.1、缓存的基本概念 1.1.1、理解 1.1.2、缓存存什么样的数据?二八定律 1.2、如何使用 redis 作为缓存 1.3、缓存更新策略(redis 内存淘汰机制 / 重点) 1.3.1、定期生成 1.3.2、实时生成 内存淘汰策略&#…...
好用的软件测试框架有哪些?测试框架的作用是什么?
软件测试框架是现代软件开发过程中至关重要的工具,它可以帮助开发团队更加高效地进行测试和验证工作,从而大大提高软件质量和用户体验。 一、好用的软件测试框架 1. Selenium:作为一种开源的自动化测试框架,Selenium具有功能强大…...

PAT 1035 插入与归并
PAT 1035 插入与归并 题目描述思路讲解代码展示 题目描述 思路讲解 分析:先将i指向中间序列中满足从左到右是从小到大顺序的最后一个下标,再将j指向从i1开始,第一个不满足a[j] b[j]的下标,如果j顺利到达了下标n,说明…...
K-means 聚类算法学习笔记
K-means 聚类算法 是一种无监督学习算法,用来将 n n n 个样本点分成 k k k 类,使得整个数据集的误差平方和 S S E SSE SSE 最小。在本例中,样本点是指平面直角坐标系上的点,聚类中心也是平面直角坐标系上的点,而每个…...

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 实现 …...

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

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

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

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

Ubuntu 12.04增加右键命令:在终端中打开增加打开文件
Ubuntu 12.04增加右键命令:在终端中打开 软件中心:搜索nautilus-open-terminal安装 用快捷键CtrlT打开命令行输入: sudo apt-get install nautilus-open-terminal 重新加载文件管理器 nautilus -q 或注销再登录即要使用...
Centos 7 访问局域网windows共享文件夹
Refer: centos7 访问windows系统的共享文件夹_centos访问windows共享_三希的博客-CSDN博客 一、在CentOS中配置CIFS网络存储服务 CIFS(Common Internet File System)是一种在网络上共享文件的协议,也称为SMB(Server Message Blo…...

GDB的TUI模式(文本界面)
2023年9月22日,周五晚上 今晚在看GDB的官方文档时,发现GDB居然有文本界面模式 TUI (Debugging with GDB) (sourceware.org) GDB开启TUI的条件 GDB的文本界面的开启条件是:操作系统有适当版本的curses库 The TUI mode is supported only on…...
深入了解Python和OpenCV:图像的卡通风格化
前言 当今数字时代,图像处理和美化已经变得非常普遍。从社交媒体到个人博客,人们都渴望分享独特且引人注目的图片。本文将介绍如何使用Python编程语言和OpenCV库创建令人印象深刻的卡通风格图像。卡通风格的图像具有艺术性和创意,它们可以用…...

【算法挨揍日记】day06——1004. 最大连续1的个数 III、1658. 将 x 减到 0 的最小操作数
1004. 最大连续1的个数 III 1004. 最大连续1的个数 III 题目描述: 给定一个二进制数组 nums 和一个整数 k,如果可以翻转最多 k 个 0 ,则返回 数组中连续 1 的最大个数 。 解题思路: 首先题目要我们求出的最多翻转k个0后&#x…...

华为云HECS安装docker
1、运行安装指令 yum install docker都选择y,直到安装成功 2、查看是否安装成功 运行版本查看指令,显示docker版本,证明安装成功 docker --version 或者 docker -v 3、启用并运行docker 3.1启用docker 指令 systemctl enable docker …...
C++:std::is_convertible
C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...

【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...

最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...

Keil 中设置 STM32 Flash 和 RAM 地址详解
文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...
什么是EULA和DPA
文章目录 EULA(End User License Agreement)DPA(Data Protection Agreement)一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA(End User License Agreement) 定义: EULA即…...

微信小程序云开发平台MySQL的连接方式
注:微信小程序云开发平台指的是腾讯云开发 先给结论:微信小程序云开发平台的MySQL,无法通过获取数据库连接信息的方式进行连接,连接只能通过云开发的SDK连接,具体要参考官方文档: 为什么? 因为…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...
Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?
在大数据处理领域,Hive 作为 Hadoop 生态中重要的数据仓库工具,其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式,很多开发者常常陷入选择困境。本文将从底…...

LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf
FTP 客服管理系统 实现kefu123登录,不允许匿名访问,kefu只能访问/data/kefu目录,不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...