绕过台州银行App Frida检测的过程分析笔记
1. 背景介绍
在移动应用安全领域,反调试技术是开发者常用的手段之一,用于防止恶意用户对App进行逆向工程或分析。近期,我在学习App逆向的过程中,对台州银行App的frida反调试进行了深入研究,尝试绕过frida检测。以下是我在这个过程中所学到的知识和经验总结。
2. frida检测机制简介
Frida是一款强大的动态 instrumentation 工具,常用于分析和hook native函数或JavaScript代码。然而,许多App开发者会在应用中集成反Frida检测机制,阻止攻击者使用Frida进行分析或注入。台州银行App正是采用了类似的机制,以防止用户分析或篡改其内部逻辑。
3. 初期探索:尝试定位检测函数
3.1 杀线程尝试绕过
在刚拿到app时 我直接使用frida注入一个简单的打印脚本,果不其然闪退了。
查看了一下app的厂商信息 如下
尝试杀线程绕过
function pthread_create() {
const pthread_create_addr = Module.findExportByName(null, "pthread_create")
const pthread_create = new NativeFunction(pthread_create_addr, "int", ["pointer", "pointer", "pointer", "pointer"]);
return new NativeCallback((parg0, parg1, parg2, parg3) => {
const module = Process.findModuleByAddress(parg2);
const so_name = module.name;
const baseAddr = module.base;
if (so_name.indexOf("libDexHelper.so") !== -1) {
console.log("pthread_create", so_name, "0x" + parg2.sub(baseAddr).toString(16), "0x" + parg3.toString(16))
return 0;
}
return pthread_create(parg0, parg1, parg2, parg3)
}, "int", ["pointer", "pointer", "pointer", "pointer"])
}
pthread_create()
在运行脚本后,app直接闪退。
3.2 hook dlopen尝试找到检测点
function hook_dlopen(so_name) {
Interceptor.attach(Module.findExportByName(null, "android_dlopen_ext"), {
onEnter: function (args) {
var pathptr = args[0];
if (pathptr !== undefined && pathptr != null) {
var path = ptr(pathptr).readCString();
console.log(path)
if (path.indexOf(so_name) !== -1) {
this.match = true
}
}
},
onLeave: function (retval) {
if (this.match) {
console.log(so_name, "加载成功")
}
}
});
}
hook_dlopen("libDexHelper.so")
这里显示梆梆的so文件加载成功,但是不知道在这里有没有加载其他的so了,有没有可能在jni函数里面,继续hook一下jni函数
const JNI_OnLoad = Process.findModuleByName(so_name).findExportByName("JNI_OnLoad");
Interceptor.attach(JNI_OnLoad,{
onEnter:function (){
console.log("成功开始");
},
onLeave:function (){
console.log("成功结束")
}
})
只打印了成功开始,没有结束 说明就是在jni函数里做了检测。
4. 深入分析:使用Stalker寻找检测函数
为了更好地理解App的frida反调,使用Stalker(潜行者)来跟踪App在运行时的行为。首先了解一下stalker是什么。
Frida Stalker 是 Frida 提供的一个强大动态分析工具,用于实时监控和跟踪目标进程的执行流。它允许你对目标应用程序的指令执行进行深入分析,从而可以捕捉程序中的关键函数、系统调用、内存操作等细节。
Stalker 的最大优势在于它能够以极高的精度,实时地获取应用程序的指令执行情况,帮助开发人员和安全研究人员识别代码路径、定位函数调用、分析反调试机制等。
4.1 Frida Stalker 的主要功能
- 指令级别的跟踪:Stalker 可以在指令级别进行跟踪,精确捕捉每一条 CPU 指令的执行。
- 执行流监控:Stalker 还可以监控进程的执行流,分析程序是如何跳转、调用函数、执行条件判断等。
- 支持多种分析类型:你可以设置 Stalker 来分析具体的函数调用、内存访问、系统调用等,从而实现对程序行为的全面理解。
- 高级调试与逆向工程:Stalker 常用于动态分析与逆向工程,帮助开发者分析程序中的安全性问题或理解应用程序的复杂逻辑。
4.2 使用Stalker跟踪函数调用
Stalker 的工作方式基于 Frida 的“插桩”技术(instrumentation)。通过插入跟踪点,Frida Stalker 可以在运行时动态地监控目标进程的执行过程。当你启动 Stalker 时,它会挂钩到目标进程的代码执行流中,并且根据配置的规则(如监控特定函数、内存地址或指令)输出执行日志。
Stalker.follow(threadId, {
transform: function (iterator) {
let instruction = iterator.next();
const baseFirstAddress = instruction.address;
const isModuleCode = baseFirstAddress.compare(startBase) >= 0 &&
baseFirstAddress.compare(startBase.add(size)) <= 0;
if (isModuleCode) {
if (module) {
const name = "libDexHelper.so";
const offset = baseFirstAddress.sub(base);
console.log(`[transform] start: ${baseFirstAddress} name:${name} offset: ${offset} base: ${base}`);
} else {
console.log(`[transform] start: ${baseFirstAddress}`);
}
}
do {
const curRealAddr = instruction.address;
const curOffset = curRealAddr.sub(baseFirstAddress);
const curOffsetInt = curOffset.toInt32()
const instructionStr = instruction.toString()
if (isModuleCode) {
console.log("\t" + curRealAddr + " <+" + curOffsetInt + ">: " + instructionStr);
}
iterator.keep();
} while ((instruction = iterator.next()) !== null);
if (isModuleCode) {
console.log()
}
}
})
这样打印出来的信息太多,不好筛选分析 下面用ida找一下JNI_OnLoad的范围大小,做一下筛选。
知道开始和结束之后将范围大小筛选一下,打印出来的结果清晰很多 每次都在 0x31314 代码块结束。
ida跳转一下 0x31314 代码块 再次筛选代码块范围 0x37260 - 0x31A3C
得到更准确的日志 在 0x32a48 代码块 出现异常 ida看看0x32a48做了什么 ,计算一下这段汇编代码的结果 得到 0x10DC
ida 跳转 0x10DC
进入到无效代码块,进入 sub_4B2E0 函数查看
5. 总结经验教训
通过这次分析,我学到了以下几点:
- 初期方法的局限性:单纯地使用Frida的基础功能(如杀线程)可能会触发目标App的反检测机制。这种方法虽然简单,但在面对复杂的反调试机制时往往难以奏效。
- 深入分析的重要性:通过使用Frida Stalker等工具,从汇编层面深入分析目标App的行为,可以帮助我们更好地理解其检测逻辑,从而找到绕过检测的方法。
- 多层次防护:现代App的反调试机制往往不止一种,developer会采用多种策略来防止分析。这就要求我们需要从多个角度入手,才能成功绕过检测。
6. 解决方案:绕过Frida检测的具体方法
在确认检测函数后,通过hook检测函数达到绕过效果:
- 修改端口:在启动server的时候修改端口号
- hook检测函数:直接hook
0x4B2E0
函数,将其返回值修改为0,从而达到绕过App的检测的目的。 - 优化注入逻辑:在注入代码时尽量减少异常行为,避免触发其他反调试机制。
以下是部分实现代码:
Interceptor.attach(base.add(0x4B2E0), {
onLeave: function (retval) {
retval.replace(ptr(0));
}
})
7. 总结
如果有想要学习安卓逆向 frida反调试相关技术的 xiaojiaya2025 温柔老师。
这次学习让我对Frida的工作原理以及App的反调试机制有了更深刻的理解。在实际操作中,我们需要根据目标App的具体实现,灵活调整自己的方法。希望这篇笔记能够为其他开发者提供一些参考,同时也欢迎大家分享更多的反调试和绕过检测的技巧。