在Android逆向工程中,Frida作为最流行的动态插桩工具,自然成为了App防护体系的首要针对目标。厂商们设计了层层检测机制,其中基于线程的检测是一种常见且有效的手段。本文将深入探讨这类检测的原理,并分享一种更为优雅的绕过思路。
很多App的检测逻辑会单独开辟一个线程,在后台持续运行各种检测任务——扫描端口、检查/proc文件系统、检测Frida特征等等。这种设计让主线程得以保持流畅,同时检测逻辑得以持续运行。
既然检测在新线程中执行,一个直接的想法便应运而生:拦截线程的创建过程,在检测线程启动之前就将其扼杀在摇篮里。
pthread_create函数是创建新线程的函数,hook这个函数,似乎可以绕过检测?
厂商们同样清楚pthread_create的重要性,早已将其纳入检测范围。如果你尝试Hook这个函数,检测代码会立即触发告警——这是一个典型的"陷阱API"。过度依赖这个入口,等于自己走进了包围圈。我们只能深入pthread_create 内部去找其他的hook点
pthread_create函数的执行流程如下:
pthread_create-> ... -> clone-> 新线程 -> __start_thread-> __pthread_start-> 执行用户代码
__start_thread是新线程的入口函数,它将执行__pthread_start函数__pthread_start是新线程的入口函数,它在新线程环境中执行
IDA分析
libc.so是Android系统中C标准库的动态链接实现,libc最重要的作用是封装Linux系统调用,为上层应用提供统一的调用接口。
所以我们需要将libc.so文件拖入到ida中进行分析,先将libc.so文件导出到本地
adb pull /system/lib64/libc.so拖入到ida中直接搜索对应的pthread_create 函数,我们往下翻

这里有一个clone函数,clone() 是 Linux 中一个强大的系统调用,用于创建新的进程或线程。它是 fork() 的增强版本,可以更精细地控制父子进程之间共享的资源。
__pthread_start是新线程启动后执行的函数,这是 glibc 线程库的内部启动函数,最终会调用用户定义的线程函数,我们追进去看

这里就是一个回调函数,去调用用户自定义的函数,我们hook这个__pthread_start函数的时候我们可以hook到线程的创建行为,并且还可以拿到用户定义的线程函数的函数地址
我们把鼠标放在这里按下tab键,查看汇编代码

这里在做的事情就是先从 X19+60内存 中成对加载数据到X8、X0寄存器,BLR指令就是函数的间接调用,X8就是用户定义的函数,那么这个X19是什么呢?我们往上找

这个X19就是从X0来的,也就是__pthread_start函数的第一个参数
hook __pthread_start
function addr2nice(addr) {
// 把地址转换为模块名和偏移,例如:libc.so!0x1234
var module = Process.findModuleByAddress(addr);
if (module) {
return module.name + "!" + (addr - module.base).toString(16);
} else {
return addr.toString(16);
}
}
function hook_start_thread() {
var libc = Process.findModuleByName("libc.so");
var addr_start_thread = libc.base.add(0xEB828); // args 这里要根据实际情况修改成对应的偏移地址
var original_start_thread = new NativeFunction(addr_start_thread, "void", ["pointer"]);
Interceptor.replace(addr_start_thread, new NativeCallback(function (thread) {
// args 这里0x60需要替换成实际的偏移
// 函数第一个参数的地址值偏移60得到用户定义函数的地址
var user_func_addr = thread.add(0x60).readPointer();
var nice_addr = addr2nice(user_func_addr);
console.log("thread start:" + nice_addr);
if (nice_addr.includes("libfrida.so")) {
// 检测是否为恶意模块创建的线程
console.log("frida check thread detected");
} else {
// 只有不是恶意模块创建的线程才执行原函数
original_start_thread(thread);
}
}, "void", ["pointer"]));
}
hook_start_thread()
评论