bangbang加固某银行APP,Frida强检测

535 阅读3分钟

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一下。

github.com/lasting-yan… 在这里插入图片描述

这里也是成功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正常使用 在这里插入图片描述

完结撒花!