首页
社区
课程
招聘
11
[原创]无壳app的libmsaoaidsec.so frida反调试绕过姿势
发表于: 2025-3-2 13:37 37073

[原创]无壳app的libmsaoaidsec.so frida反调试绕过姿势

2025-3-2 13:37
37073

当前许多应用通过集成 libmsaoaidsec.so 实现针对 Frida 的反调试机制,其核心逻辑是在应用启动过程中,当加载 libmsaoaidsec.so 动态库时,会通过 pthread_create() 创建独立线程,并在该线程内执行反调试函数,主动扫描 Frida 进程、端口、内存特征等痕迹。若检测到 Frida 存在,则触发进程终止或崩溃。
针对这种机制的绕过思路可以从破坏反调试线程的加载或执行入手,文章会对不同的app进行测试,对于使用libmsaoaidsec.so来进行反调试的app,思路是一样的。

通过hook dlopen()函数根据最后加载的so文件来确定程序是在加载哪个so之后退出的

如下,可以看到加载完libmsaoaidsec.so之后程序就退出了。

接下来我们找一个时机,就是在加载libmsaoaidsec.so的时候打印它里面创建的线程

如下看打印结果,有兴趣的小伙伴可以利用IDA反编译libmsaoaidsec.so跳转到这些地址去看这些函数都干了什么事情

现在已经知道了是哪些函数来检测的frida,然后一个很重要的事情就是找到一个时机去把这几个函数都替换掉或者nop掉。
如果去IDA里分析的话,跳转到这几个函数的地址,通过交叉引用查看他们的上一级函数,会发现最终他们都会聚集到init_proc函数里,这是一个初始化函数,在so加载时会自动被调用,而且是so加载过程中最先执行的函数,那么就要找一个比init_proc函数执行更早的一个时机来把检测frida的函数替换掉或者nop掉。
在so文件的链接过程中linker里的call_constructors()函数会触发构造函数,对初始化函数进行注册,然后执行初始化函数,注册的初始化函数会放在.init_array函数列表里,可以在调用call_constructors()函数的时候动态替换so文件里检测frida的函数的地址,使它指向自定义的空函数。

替换函数

如下成功绕过了

nop函数

如下也可以绕过

参考文章:
https://mp.weixin.qq.com/s/mBJzRqP-0bGsiTqp6aJSAg
https://mp.weixin.qq.com/s/RyJiHrSO4CU9QLJitC7Tqg
https://bbs.kanxue.com/thread-284816.htm

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){
            console.log("leave!");
        }
    })
}
hook_dlopen()
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){
            console.log("leave!");
        }
    })
}
hook_dlopen()
function hook_dlopen(){
    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();
                if(path.indexOf("libmsaoaidsec.so")!=-1){
                    console.log("android_dlopen_ext:",path);
                    hook_pthread()
                }
            }
        },
        onLeave:function(retvel){
             
        }
    })
}
 
function hook_pthread() {
    var pth_create = Module.findExportByName("libc.so", "pthread_create");
    console.log("[pth_create]", pth_create);
    Interceptor.attach(pth_create, {
        onEnter: function (args) {
            var module = Process.findModuleByAddress(args[2]);
            if (module != null) {
                console.log("address", module.name, args[2].sub(module.base));
            }
        },
        onLeave: function (retval) {}
    });
}
 
function main(){
    hook_dlopen()
}
 
main()
function hook_dlopen(){
    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();
                if(path.indexOf("libmsaoaidsec.so")!=-1){
                    console.log("android_dlopen_ext:",path);
                    hook_pthread()
                }
            }
        },
        onLeave:function(retvel){
             
        }
    })
}
 
function hook_pthread() {
    var pth_create = Module.findExportByName("libc.so", "pthread_create");
    console.log("[pth_create]", pth_create);
    Interceptor.attach(pth_create, {
        onEnter: function (args) {
            var module = Process.findModuleByAddress(args[2]);
            if (module != null) {
                console.log("address", module.name, args[2].sub(module.base));
            }
        },
        onLeave: function (retval) {}
    });
}
 
function main(){
    hook_dlopen()
}
 
main()
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();
                if(path.indexOf("libmsaoaidsec.so")!=-1){
                    console.log("android_dlopen_ext:",path);
                    hook_call_constructors()
                }
            }
        },
        onLeave:function(retvel){
            //console.log("leave!");
        }
    })
}
 
function hook_call_constructors() {
    let linker = null;
    if (Process.pointerSize === 4) {
        linker = Process.findModuleByName("linker");
    } else {
        linker = Process.findModuleByName("linker64");
    }
    let call_constructors_addr, get_soname
    let symbols = linker.enumerateSymbols();
    for (let index = 0; index < symbols.length; index++) {
        let symbol = symbols[index];
        if (symbol.name === "__dl__ZN6soinfo17call_constructorsEv") {
            call_constructors_addr = symbol.address;
        } else if (symbol.name === "__dl__ZNK6soinfo10get_sonameEv") {
            get_soname = new NativeFunction(symbol.address, "pointer", ["pointer"]);
        }
    }
    console.log(call_constructors_addr)
    var listener = Interceptor.attach(call_constructors_addr, {
        onEnter: function (args) {
            console.log("hooked call_constructors")
            var module = Process.findModuleByName("libmsaoaidsec.so")
            if (module != null) {
                Interceptor.replace(module.base.add(0x1c544), new NativeCallback(function () {
                    console.log("0x1c544:替换成功")
                }, "void", []))
                Interceptor.replace(module.base.add(0x1b8d4), new NativeCallback(function () {
                    console.log("0x1b8d4:替换成功")
                }, "void", []))
                Interceptor.replace(module.base.add(0x26e5c), new NativeCallback(function () {
                    console.log("0x26e5c:替换成功")
                }, "void", []))
                listener.detach()
            }
             
        },
    })
}
function main(){
    hook_dlopen()
}
 
main()
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();
                if(path.indexOf("libmsaoaidsec.so")!=-1){
                    console.log("android_dlopen_ext:",path);
                    hook_call_constructors()
                }
            }
        },
        onLeave:function(retvel){
            //console.log("leave!");
        }
    })
}
 
function hook_call_constructors() {
    let linker = null;
    if (Process.pointerSize === 4) {
        linker = Process.findModuleByName("linker");
    } else {
        linker = Process.findModuleByName("linker64");
    }
    let call_constructors_addr, get_soname
    let symbols = linker.enumerateSymbols();
    for (let index = 0; index < symbols.length; index++) {
        let symbol = symbols[index];
        if (symbol.name === "__dl__ZN6soinfo17call_constructorsEv") {
            call_constructors_addr = symbol.address;

[注意]看雪招聘,专注安全领域的专业人才平台!

收藏
免费 11
支持
分享
赞赏记录
参与人
雪币
留言
时间
suminglan
感谢你分享这么好的资源!
5天前
vVv一
为你点赞!
2025-3-16 11:28
Damn7Kx
感谢你分享这么好的资源!
2025-3-14 16:17
Ive_406746
这个讨论对我很有帮助,谢谢!
2025-3-14 16:08
逆天而行
你的分享对大家帮助很大,非常感谢!
2025-3-4 18:34
WMBa0
你的帖子非常有用,感谢分享!
2025-3-3 17:23
残月_374878
你的分享对大家帮助很大,非常感谢!
2025-3-3 15:29
你瞒我瞒
这个讨论对我很有帮助,谢谢!
2025-3-3 09:42
山间清爽的风
为你点赞!
2025-3-3 01:38
sinker_
感谢你的贡献,论坛因你而更加精彩!
2025-3-3 00:59
Our_OT
为你点赞!
2025-3-2 14:20
最新回复 (10)
雪    币: 4327
活跃值: (4154)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
能否弄个中邮的分析下
2025-3-3 10:11
0
雪    币: 1507
活跃值: (2408)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
3
写的很nice,Android越来越卷啦????
2025-3-3 17:24
1
雪    币: 143
活跃值: (2418)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
不错,现在方子越来月多了
2025-3-6 02:22
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
5
so 删掉就好了 
2025-3-7 11:17
0
雪    币: 223
活跃值: (70)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
wx_Lyg_548 so 删掉就好了

兄弟不行啊,直接删除,应用都打不开了

最后于 2025-3-17 12:08 被weiyangs编辑 ,原因:
2025-3-14 14:57
0
雪    币: 223
活跃值: (70)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
WMBa0 写的很nice,Android越来越卷啦????
卷死了,现在这个so又进化了,加了检测,反hook
2025-3-14 14:58
0
雪    币: 2687
活跃值: (7263)
能力值: ( LV7,RANK:102 )
在线值:
发帖
回帖
粉丝
8
JNI_ONLOAD,INIT啥的,函数全部干掉试试呢
2025-3-14 15:21
0
雪    币: 10
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
9

same
同样的库,甚至函数偏移都一样。
我以spawn模式启动,会出现空指针异常。
我跟踪了strstr函数,needle 记录依次为
"/system/bin/linker64",
"/bionic/bin/linker64",
"/apex/com.android.runtime/bin/linker64",
"solist" 
经过多次测试当needle指向"solist" ,haystack为无效指针,然后进程终止。

LOAD:0000000000020CA8                 LDR             X0, [X20,#0x198] ; haystack 

LOAD:0000000000020CAC                 CBZ             X0, loc_20CC0

LOAD:0000000000020CB0                 MOV             X1, X19 ; needle

LOAD:0000000000020CB4                 BL              strstr

LOAD:0000000000020CB8                 CMP             X0, #0

LOAD:0000000000020CBC                 CSEL            X21, X21, X20, EQ

上传的附件:
2025-4-2 18:20
0
雪    币: 200
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
10

一hook就crash,想了很久没想清楚怎么崩的

崩溃处附近的汇编

LOAD:0000000000018648 69 0A 40 F9                   LDR             X9, [X19,#0x10]

LOAD:000000000001864C 3F 01 08 EB                   CMP             X9, X8

LOAD:0000000000018650 40 F9 FF 54                   B.EQ            loc_18578

LOAD:0000000000018650

LOAD:0000000000018654 73 16 40 F9                   LDR             X19, [X19,#0x28]

LOAD:0000000000018658 93 FF FF B5                   CBNZ            X19, loc_18648

似乎是一直改X19的值然后直到空指针crash?


上传的附件:
2025-4-8 16:01
0
雪    币: 0
活跃值: (62)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
厉害, 学习
2025-4-16 08:43
0
游客
登录 | 注册 方可回帖
返回

账号登录
验证码登录

忘记密码?
没有账号?立即免费注册