1、什么是 Frida 检测?
Frida 检测是指目标应用通过特定的技术手段,检查自身是否被 Frida 工具附加(attached)或注入了脚本。这种检测通常出现在需要保护知识产权、防止作弊或避免敏感数据泄露的应用中,例如:游戏防作弊、移动支付应用的安全防护、银行或金融类应用的安全保障。如果检测到 Frida 的存在,应用可能会采取以下措施:终止运行、上报异常行为、屏蔽某些功能
2、尝试注入frida
APP:dGFpemhvdXlpbmhhbmc=
版本:3.0.0.5
frida版本:官网frida16.5.2
2.1首先改一下frida端口,狐妖面具配置一下MagiskHider,排除下root检测以及端口检测后注入,发现直接闪退。
2.2 使用mt管理器查看下是哪个加固
确定是bangbnag
2.3 看一下加载了打开了哪些第三方so文件
function hook_dlopen(){
//Android8.0之后加载so通过android_dlopen_ext函数
var android_dlopen_ext = Module.findExportByName(null,"android_dlopen_ext");
console.log("addr_android_dlopen_ext",android_dlopen_ext);
Interceptor.attach(android_dlopen_ext,{
onEnter:function(args){
var pathptr = args[0];
if(pathptr!=null && pathptr != undefined){
var path = ptr(pathptr).readCString();
console.log("android_dlopen_ext:",path);
}
},
onLeave:function(retvel){
}
})
}
hook_dlopen()
function create_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
console.log("pthread_create", so_name, "0x" + parg2.sub(baseAddr).toString(16), "0x" + parg3.toString(16))
// 成功的返回值是0
return pthread_create(parg0, parg1, parg2, parg3)
}, "int", ["pointer", "pointer", "pointer", "pointer"])
}
// 或者
function replace_thread() {
var new_pthread_create = create_pthread_create()
var pthread_create_addr = Module.findExportByName(null, "pthread_create")
// 函数替换
Interceptor.replace(pthread_create_addr, new_pthread_create);
}
replace_thread()
加载完libDexHelper.so直接闪退说明这里有问题
查看下libDexHelper.so的JNI_OnLoad是否加载完成
const module = Process.findModuleByName('libDexHelper.so');
const JNI_OnLoad = module.findExportByName("JNI_OnLoad");
Interceptor.attach(JNI_OnLoad, {
onEnter: function () {
console.log('进来')
},
onLeave: function () {
console.log('离开')
}
})
发现并没有加载完成,说明监测点大概率在JNI_OnLoad
3 、使用Stalker trace
3.1 使用ida64反汇编一下libDexHelper.so,发现搜不到,但是我们hook又加载了,所以应该是有壳,用一下yang神大佬的工具dump一下。
https://github.com/lasting-yang/frida_dump
这里也是成功dump下来
再次搜索,可以搜索到。这里取一下JNI_OnLoad函数开始地址以及函数结束地址
3 、Stalker trace 执行了哪些汇编指令
Interceptor.attach(JNI_OnLoad, {
onEnter: function () {
const threadId = Process.getCurrentThreadId();
const base = module.base;
const startBase = JNI_OnLoad;
const size = 开始地址- 结束地址;
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()
}
}
})
},
onLeave: function () {
console.log("成功结束")
}
})
最后一个代码块执行到0x31a3c,最后一个指令是 0x73ac687af0 <+180>: bl #0x73ac68494c,打开ida看一下,这里是一个函数的开头,看一下这个函数做了什么,再次使用Stalker,改一下0x31a3c函数起始位置以及0x31a3c函数结束位置,再次执行
这里执行到了0x32a48这个代码块,最后通过br指令跳转到x11寄存器存储的内存地址继续执行代码。这段指令将立即数 0x10DC 装载到寄存器 W11 中。由于没有后续指令修改 X11 的值,可以推断 X11 的值为 0x10DC。
通过ida查看这段地址,发现是一段死代码,返回去看一下C
通过检测libc.so来检测,如果有frida特征返回1,然后通过JUMPOUT跳转到死代码,这样就好办了,我们直接修改sub_4B2E0(*v71, “libc.so”, format);的返回值为0就可以了
Interceptor.attach(base.add(0x4B2E0),{
onLeave:function (retval){
retval.replace(ptr(0));
}
})
这里libDexHelper.so成功加载并结束,app,frida api正常使用
完结撒花!