版权归作者所有,如有转发,请注明文章出处:https://cyrus-studio.github.io/blog/
前言
比如我们像分析某个 so 中偏移为 0x23AD0 的加密函数
IDA 反汇编 so,可以看到 so 中该函数做了混淆

控制流平坦化

Frida Stalker
Frida 的 Stalker 是一个强大的代码追踪工具。
主要功能
-
指令级跟踪:Stalker 可精确到指令级别,对应用的原生代码进行实时监控。
-
代码插桩:支持在指定指令前后插入自定义的代码逻辑。
-
内存访问监控:可以监视内存读写操作,分析数据流向。
-
自定义回调:提供回调函数,方便记录和分析执行轨迹。
文档:https://frida.re/docs/javascript-api/#stalker
目前 Stalker 对于 arm64 支持比较好,但是 arm32 并不是很完善。

https://frida.re/docs/stalker/
关于 Frida 的使用可以参考这篇文章:使用 Frida Hook Android App
onCallSummary(函数调用摘要)
onCallSummary 用于返回函数调用的摘要信息。
Stalker.follow() 使用 onCallSummary 时,不会实时回调,而是在合适的时间点返回已汇总的调用信息。
通常是在:
-
函数执行结束后
-
线程空闲或上下文切换时
-
Stalker缓冲区达到一定大小时
-
Stalker.flush();
因此,你会在目标函数执行完毕后,看到 onCallSummary 输出的调用信息。
summary 数据结构通常类似于以下格式:
{
"函数地址": 调用次数
}
hook 目标函数,跟踪 call 事件并打印 call summary
function onCallSummary() {
// 目标 so
var soName = "libaes.so"
// 目标 so 基址
var baseAddress = Module.findBaseAddress(soName);
// 目标函数地址 = 基址 + 偏移
var targetAddr = baseAddress.add(0x23AD0);
console.log('Target function found at:', targetAddr);
Interceptor.attach(targetAddr, {
onEnter: function (args) {
console.log('Entering target function');
Stalker.follow(Process.getCurrentThreadId(), {
events: {
call: true, // 捕获函数调用
ret: false, // 捕获函数返回
exec: false, // 捕获指令执行
block: false, // 捕获基本块
compile: false // 捕获编译事件
},
onCallSummary: function (summary) {
console.log('Call Summary:');
Object.keys(summary).forEach(function (addr) {
var module = Process.getModuleByAddress(ptr(addr));
// 判断地址是否属于目标 so
if (module && module.name === soName) {
var offset = ptr(addr).sub(module.base);
console.log(`调用函数地址: ${ptr(addr)} | 模块: ${module.name} | 偏移: ${offset} | 次数: ${summary[addr]}`);
}
});
}
});
},
onLeave: function (retval) {
console.log('Leaving target function');
Stalker.unfollow(Process.getCurrentThreadId());
}
});
}
// setImmediate():确保代码在 Frida 环境准备好后执行。
setImmediate(onCallSummary)
启动 frida-server,附加到当前 app 并执行脚本
frida -H 127.0.0.1:1234 -F -l onCallSummary.js
输出如下:
Target function found at: 0x77fdf2ead0
[Remote::AndroidExample]-> Entering target function
Leaving target function
Call Summary:
调用函数地址: 0x77fdf62d50 | 模块: libaes.so | 偏移: 0x57d50 | 次数: 4
调用函数地址: 0x77fdf62d00 | 模块: libaes.so | 偏移: 0x57d00 | 次数: 1
调用函数地址: 0x77fdf62dd0 | 模块: libaes.so | 偏移: 0x57dd0 | 次数: 1
调用函数地址: 0x77fdf62f70 | 模块: libaes.so | 偏移: 0x57f70 | 次数: 3
调用函数地址: 0x77fdf62d80 | 模块: libaes.so | 偏移: 0x57d80 | 次数: 1
调用函数地址: 0x77fdf30f60 | 模块: libaes.so | 偏移: 0x25f60 | 次数: 1
调用函数地址: 0x77fdf62d30 | 模块: libaes.so | 偏移: 0x57d30 | 次数: 1
调用函数地址: 0x77fdf62e00 | 模块: libaes.so | 偏移: 0x57e00 | 次数: 1
调用函数地址: 0x77fdf30b8c | 模块: libaes.so | 偏移: 0x25b8c | 次数: 1
调用函数地址: 0x77fdf34580 | 模块: libaes.so | 偏移: 0x29580 | 次数: 10
调用函数地址: 0x77fdf62ce0 | 模块: libaes.so | 偏移: 0x57ce0 | 次数: 1
调用函数地址: 0x77fdf62db0 | 模块: libaes.so | 偏移: 0x57db0 | 次数: 1
调用函数地址: 0x77fdf62d60 | 模块: libaes.so | 偏移: 0x57d60 | 次数: 13
调用函数地址: 0x77fdf303cc | 模块: libaes.so | 偏移: 0x253cc | 次数: 1
调用函数地址: 0x77fdf62d10 | 模块: libaes.so | 偏移: 0x57d10 | 次数: 1
调用函数地址: 0x77fdf62de0 | 模块: libaes.so | 偏移: 0x57de0 | 次数: 1
调用函数地址: 0x77fdf30bc8 | 模块: libaes.so | 偏移: 0x25bc8 | 次数: 1
调用函数地址: 0x77fdf62eb0 | 模块: libaes.so | 偏移: 0x57eb0 | 次数: 1
调用函数地址: 0x77fdf62d40 | 模块: libaes.so | 偏移: 0x57d40 | 次数: 1
调用函数地址: 0x77fdf62cf0 | 模块: libaes.so | 偏移: 0x57cf0 | 次数: 2
调用函数地址: 0x77fdf62dc0 | 模块: libaes.so | 偏移: 0x57dc0 | 次数: 1
调用函数地址: 0x77fdf62d70 | 模块: libaes.so | 偏移: 0x57d70 | 次数: 1
调用函数地址: 0x77fdf62df0 | 模块: libaes.so | 偏移: 0x57df0 | 次数: 2
调用函数地址: 0x77fdf62ec0 | 模块: libaes.so | 偏移: 0x57ec0 | 次数: 1
调用函数地址: 0x77fdf62da0 | 模块: libaes.so | 偏移: 0x57da0 | 次数: 2
onReceive(接收捕获的事件)
onReceive 在 Stalker 捕获到事件后被调用,它会以批量形式传递事件数据,通常用于实时分析或记录。
onReceive 传递的 events 数据需要用 Stalker.parse() 解析,解析后的数据是数组类型,格式如下:
call,0x789143a16c,0x77a1addf1c,0
ret,0x7890000e34,0x788ff64e68,2
[事件类型], [调用方地址], [目标地址], [附加信息]
跟踪 call 和 ret 事件 并打印日志:

最低0.47元/天 解锁文章
5189

被折叠的 条评论
为什么被折叠?



