某书Frida检测绕过记录
- 前言
- Frida启动APP
- Hook android_dlopen_ext查看加载的库
- 分析libmsaoaidsec.so
- Frida检测绕过
- 后记
前言
本来想要分析请求参数加密过程,结果发现APP做了Frida检测,于是记录一下绕过姿势(暴力但有用)
Frida版本:16.2.1
APP版本:8.31.0
Frida启动APP
frida -U -f 包名,spawn启动APP,直接挂
Hook android_dlopen_ext查看加载的库
function hook_android_dlopen_ext() {
var linker64_base_addr = Module.getBaseAddress("linker64")
var android_dlopen_ext_func_off = 0x0000000000031098
var android_dlopen_ext_func_addr = linker64_base_addr.add(android_dlopen_ext_func_off)
Interceptor.attach(android_dlopen_ext_func_addr, {
onEnter: function (args) {
console.log("android_dlopen_ext -> enter : " + args[0].readCString())
},
onLeave: function (ret) {
console.log("android_dlopen_ext -> leave")
}
})
}
hook_android_dlopen_ext()
可以看到最后的libmsaoaidsec.so只是enter,没有leave
也就是说APP的Frida检测点在libmsaoaidsec.so的初始化过程
分析libmsaoaidsec.so
这里使用GG修改器dump内存,SoFixer修复so文件
习惯性地去看.init_array,发现只是一些初始化
查询资料得知链接器在调用.init_array中的函数前会先调用.init_proc
于是直接替换.init_proc使其为空
此时链接器对libmsaoaidsec.so的android_dlopen_ext可以正常leave
但当链接器调用libmsaoaidsec.so的JNI_OnLoad时出错
错误描述是JNI_OnLoad使用的某个全局变量为空,而该全局变量实际上在.init_proc中被初始化
于是仔细分析.init_proc(D810插件可以直接去掉混淆)
这里觉得sub_1BEC4非常可疑,又是fopen,又是两层if的
sub_1BEC4主要调用两个函数,sub_1B924和sub_1BFAC
sub_1BFAC的hook检测比较明显,就是遍历线程,找gum-js-loop和gmain
sub_1B924->sub_1CEF8->sub_1C544,通过libc.so的pthread_create创建线程实例
sub_1C544开头就是一堆字符串的解密,最终的检测写在while循环里
Frida检测绕过
脚本绕过
function hook_android_dlopen_ext() {
var linker64_base_addr = Module.getBaseAddress("linker64")
var android_dlopen_ext_func_off = 0x0000000000031098
var android_dlopen_ext_func_addr = linker64_base_addr.add(android_dlopen_ext_func_off)
Interceptor.attach(android_dlopen_ext_func_addr, {
onEnter: function (args) {
// console.log("android_dlopen_ext -> enter : " + args[0].readCString())
if (args[0].readCString() != null && args[0].readCString().indexOf("libmsaoaidsec.so") >= 0) {
hook_call_constructors()
}
},
onLeave: function (ret) {
// console.log("android_dlopen_ext -> leave")
}
})
}
function hook_call_constructors() {
var linker64_base_addr = Module.getBaseAddress("linker64")
var call_constructors_func_off = 0x000000000004af0c
var call_constructors_func_addr = linker64_base_addr.add(call_constructors_func_off)
var listener = Interceptor.attach(call_constructors_func_addr, {
onEnter: function (args) {
console.log("call_constructors -> enter")
var module = Process.findModuleByName("libmsaoaidsec.so")
if (module != null) {
Interceptor.replace(module.base.add(0x000000000001BEC4), new NativeCallback(function () {
console.log("replace sub_1BEC4")
}, "void", []))
listener.detach()
}
},
})
}
hook_android_dlopen_ext()
后来想用objection分析java层的调用过程
没有想出同时注入js脚本并启动objection的方法
于是这里的解决方案是直接nop掉libmsaoaidsec.so的sub_1BEC4函数,把patch过的so放到指定路径即可
后记
后面按照网上其他师傅的分析思路
知道x-b3-traceid和x-xray-traceid与当前时间(System.currentTimeMillis())相关
x-legacy-smid、x-legacy-did、x-legacy-fid和x-legacy-sid是固定的(猜测和设备相关但是固定)
x-mini-gid、x-mini-sig和x-mini-mua在libtiny.so(动态跳转混淆)中添加
shield在libxyass.so(控制流混淆)中添加
后面需要学习unidbg去混淆