立即注册,突破游客限制,与技术大牛交流切磋,畅享海量资源,让你的技术之路不再孤单!
您需要 登录 才可以下载或查看,没有账号?立即注册
×
前言当前许多应用通过集成 libmsaoaidsec.so 实现针对 Frida 的反调试机制,其核心逻辑是在应用启动过程中,当加载 libmsaoaidsec.so 动态库时,会通过 pthread_create() 创建独立线程,并在该线程内执行反调试函数,主动扫描 Frida 进程、端口、内存特征等痕迹。若检测到 Frida 存在,则触发进程终止或崩溃。
针对这种机制的绕过思路可以从破坏反调试线程的加载或执行入手,文章会对不同的app进行测试,对于使用libmsaoaidsec.so来进行反调试的app,思路是一样的。 定位通过hook dlopen()函数根据最后加载的so文件来确定程序是在加载哪个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){
- console.log("leave!");
- }
- })
- }
- hook_dlopen()
复制代码
如下,可以看到加载完libmsaoaidsec.so之后程序就退出了。 接下来我们找一个时机,就是在加载libmsaoaidsec.so的时候打印它里面创建的线程 - 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()
复制代码
如下看打印结果,有兴趣的小伙伴可以利用IDA反编译libmsaoaidsec.so跳转到这些地址去看这些函数都干了什么事情 反调试绕过现在已经知道了是哪些函数来检测的frida,然后一个很重要的事情就是找到一个时机去把这几个函数都替换掉或者nop掉。
如果去IDA里分析的话,跳转到这几个函数的地址,通过交叉引用查看他们的上一级函数,会发现最终他们都会聚集到init_proc函数里,这是一个初始化函数,在so加载时会自动被调用,而且是so加载过程中最先执行的函数,那么就要找一个比init_proc函数执行更早的一个时机来把检测frida的函数替换掉或者nop掉。
在so文件的链接过程中linker里的call_constructors()函数会触发构造函数,对初始化函数进行注册,然后执行初始化函数,注册的初始化函数会放在.init_array函数列表里,可以在调用call_constructors()函数的时候动态替换so文件里检测frida的函数的地址,使它指向自定义的空函数。 姿势1替换函数 - 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()
复制代码
如下成功绕过了 姿势2nop函数 - function nop_addr(addr) {
- Memory.protect(addr, 4 , 'rwx');
- var w = new Arm64Writer(addr);
- w.putRet();
- w.flush();
- w.dispose();
- }
-
- 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) {
- nop_addr(module.base.add(0x1c544))
- console.log("0x1c544:替换成功")
- nop_addr(module.base.add(0x1b8d4))
- console.log("0x1b8d4:替换成功")
- nop_addr(module.base.add(0x26e5c))
- console.log("0x26e5c:替换成功")
- listener.detach()
- }
-
- },
- })
- }
- function main(){
- hook_dlopen()
- }
-
- main()
复制代码
如下也可以绕过
|