首页
社区
课程
招聘
[原创]最新版某货app bypassFrida检测
发表于: 5天前 1985

[原创]最新版某货app bypassFrida检测

5天前
1985

文章中所有内容仅供学习交流使用,不用于其他任何目的,抓包内容、敏感网址、数据接口均已做脱敏处理。严正声明禁止用于商业和非法用途,否则由此产生的一切后果与作者本人无关。

本篇文章并不会对该app的各项参数进行逆向分析,只是记录下学习Frida工具时遇到的检测,以及绕过检测的过程。

简单说下使用到的工具:

环境准备

启动Frida

注入失败

加载so文件

未找到so文件

搜索SDK

定位外部函数

定位外部函数

获取偏移地址

检测函数

检测函数

检测函数

function hook_dlopen(so_name) {
    let dlopen = Module.findExportByName(null, so_name);
    if (dlopen) {
        Interceptor.attach(dlopen, {
            onEnter: function (args) {
                let pathPtr = args[0];
                if (pathPtr != undefined && pathPtr != null) {
                    let path = pathPtr.readCString();
                    if (path.indexOf("libmsaoaidsec.so") >= 0) {
                        console.log("load so::> ", path)
                        this.hookTarget = true;
                        hook_pthread_creat()
                    }
                }
            },
            onLeave: function (retval) {
                if (this.hookTarget) {
                    console.log("over!!")
                }
            }
        })
    }
};

function hook_pthread_creat() {
    let pthread_create = Module.findExportByName("libc.so", "pthread_create");
    let libmsaoaidsec = Process.findModuleByName("libmsaoaidsec.so");

    if (!libmsaoaidsec) {
        console.log("libmsaoaidsec.so is not found!!")
        return;
    }

    if (pthread_create) {
        Interceptor.attach(pthread_create, {
            onEnter: function (args) {
                let pthreadAddr = args[2];
                if (pthreadAddr.compare(libmsaoaidsec.base) >= 0 && pthreadAddr.compare(pthreadAddr.add(libmsaoaidsec.size)) <= 0) {
                    console.log("libmsaoaidsec.so addr: " + pthreadAddr, "offset: ", pthreadAddr.sub(libmsaoaidsec.base))
                }
            },
            onLeave: function (retval) { }
        })
    }
};

function main() {
    hook_dlopen("android_dlopen_ext")
};

setImmediate(main)


var hookPtrheadCreat = false;

function hook_dlopen(so_name) {
    let dlopen = Module.findExportByName(null, so_name);
    if (dlopen) {
        Interceptor.attach(dlopen, {
            onEnter: function (args) {
                let pathPtr = args[0];
                if (pathPtr != undefined && pathPtr != null) {
                    let path = pathPtr.readCString();
                    if (path.indexOf("libmsaoaidsec.so") >= 0) {
                        console.log("load so::> ", path)
                        this.hookTarget = true;
                        hook_system_property_get();
                        // hook_pthread_creat()
                    }
                }
            },
            onLeave: function (retval) {
                if (this.hookTarget) {
                    console.log("over!!")
                }
            }
        })
    }
};

function hook_pthread_creat() {
    let pthread_create = Module.findExportByName("libc.so", "pthread_create");
    let libmsaoaidsec = Process.findModuleByName("libmsaoaidsec.so");

    if (!libmsaoaidsec) {
        console.log("libmsaoaidsec.so is not found!!")
        return;
    }

    if (pthread_create) {
        Interceptor.attach(pthread_create, {
            onEnter: function (args) {
                let pthreadAddr = args[2];
                if (pthreadAddr.compare(libmsaoaidsec.base) >= 0 && pthreadAddr.compare(libmsaoaidsec.base.add(libmsaoaidsec.size)) < 0) {
                    console.log("libmsaoaidsec.so addr: " + pthreadAddr, "offset: ", pthreadAddr.sub(libmsaoaidsec.base));
                }
            },
            onLeave: function (retval) { }
        })
    }
};

// _system_property_get("ro.build.version.sdk", v1);
function hook_system_property_get() {
    let _system_property_get = Module.findExportByName("libc.so", "__system_property_get");
    if (_system_property_get) {
        Interceptor.attach(_system_property_get, {
            onEnter: function (args) {
                let argName = args[0].readCString();
                if (argName === "ro.build.version.sdk") {
                    let callerAddr = this.returnAddress;

                    let module = Process.findModuleByAddress(callerAddr);

                    if (module && module.name.indexOf("libmsaoaidsec.so") >= 0) {
                        if (!hookPtrheadCreat) {
                            hook_pthread_creat();
                            hookPtrheadCreat = true;
                        }
                    }
                }
            },
            onLeave: function (retval) { }
        })
    }
};

function main() {
    hook_dlopen("android_dlopen_ext")
};

setImmediate(main)



var hookPtrheadCreat = false;


function hook_dlopen(so_name) {
    let dlopen = Module.findExportByName(null, so_name);
    if (dlopen) {
        Interceptor.attach(dlopen, {
            onEnter: function (args) {
                let pathPtr = args[0];
                if (pathPtr != undefined && pathPtr != null) {
                    let path = pathPtr.readCString();
                    if (path.indexOf("libmsaoaidsec.so") >= 0) {
                        console.log("load so::> ", path)
                        this.hookTarget = true;
                        hook_system_property_get();
                        // hook_pthread_creat()
                    }
                }
            },
            onLeave: function (retval) {
                if (this.hookTarget) {
                    console.log("over!!")
                }
            }
        })
    }
};

function hook_pthread_creat() {
    let pthread_create = Module.findExportByName("libc.so", "pthread_create");
    let libmsaoaidsec = Process.findModuleByName("libmsaoaidsec.so");

    if (!libmsaoaidsec) {
        console.log("libmsaoaidsec.so is not found!!")
        return;
    }

    let base = libmsaoaidsec.base;
    let size = libmsaoaidsec.size;

    if (pthread_create) {
        Interceptor.attach(pthread_create, {
            onEnter: function (args) {
                let pthreadAddr = args[2];
                let offset = pthreadAddr.sub(base);
                if (pthreadAddr.compare(base) >= 0 && pthreadAddr.compare(base.add(size)) < 0) {
                    console.log("libmsaoaidsec.so addr: " + pthreadAddr, "offset: ", offset);
                    replace_func(pthreadAddr, offset);
                }
            },
            onLeave: function (retval) { }
        })
    }
};

// _system_property_get("ro.build.version.sdk", v1);
function hook_system_property_get() {
    let _system_property_get = Module.findExportByName("libc.so", "__system_property_get");
    if (_system_property_get) {
        Interceptor.attach(_system_property_get, {
            onEnter: function (args) {
                let argName = args[0].readCString();
                if (argName === "ro.build.version.sdk") {
                    let callerAddr = this.returnAddress;

                    let module = Process.findModuleByAddress(callerAddr);

                    if (module && module.name.indexOf("libmsaoaidsec.so") >= 0) {
                        if (!hookPtrheadCreat) {
                            hook_pthread_creat();
                            hookPtrheadCreat = true;
                        }
                    }
                }
            },
            onLeave: function (retval) { }
        })
    }
};

function replace_func(base, offset) {
    let module = Process.findModuleByAddress(base);
    if (module) {
        Interceptor.replace(module.base.add(offset), bypass())
    }
};

function bypass() {
    return new NativeCallback(function () {
        console.log("replace is ok!!!")
    }, 'void', [])
};

function main() {
    hook_dlopen("android_dlopen_ext")
};

setImmediate(main)



  • appName:某货(v8.65.0
  • 签名状态V1 + V2
  • 加固状态:未加固(伪几维安全)
  • 手机:谷歌 Pxiel 6(安卓13系统)
  • 系统环境Linux-kali
  • Frida16.5.9版本
  • Python3.11.14版本
  • IDA Pro:9.3版本
  • libmsaoaidsec.so文件的 Frida使用这个代码,几乎可以通杀,经测试某 BLBL也可以成功绕过。
  • 像我一样的小白一定要死记硬背:INIT --> INIT_ARRAY --> JNI_OnLoad --> dlopen
  • 本篇内容没有对每一处监测点进行绕过,感觉没什么必要(太懒了)。
  • 还得继续学习,安卓要学习的知识点太多了,一个 Frida学习了好久。55555
  1. 开启手机,连接到kali虚拟机,打开我们要测试的 app程序。正常的流程我们可以先抓包,找到要逆向分析的参数,然后使用 Jadx或者 JEB去反编译 app程序,在 JAVA层先进行追踪需要分析的参数,不过这不是本篇文章的重点,本篇文章目前只研究如果绕过 appFrida检测。ok那么我们直接使用 Fridaapp进行 Hook
  2. 俺习惯使用微软大战代码,来进行 hook,如图:
  1. 使用 adb shell进入设备的 shell环境。
  1. 启动好 Frida-server后,我们对 app进行 Hook
  1. 这里可以看到 Frida给我们的报错。进程直接被中止了。(这里我用的是 -f Spawn的方式进行的注入,其实用 Attach也是一样的结果,有兴趣的小伙伴可以自行尝试。)
  2. 遇到这种情况,一般就是有 Frida检测。(Frida的检测点,网上文章巨多,我这里就不在赘述了。)
  3. 最容易过的就是检测 Frida服务端的进程命是否有 frida字样,如果存在则直接关闭 app。其二是端口检测,Frida的默认通信端口是 27042,有些 app会检测是否开启该端口,如果开启则直接关闭 app
  4. 第一点,我们在给手机传入 Frida-server时,就直接修改了名字,当前案例 app未检测端口,所以我就没有修改端口号。
  5. 其他的检测点,我们后边遇到再说。
  6. Frida的检测一般是 Native配合 Java层,所以我们可以 Hook dlopen函数来看,是加载到哪个 so文件,app被强制关闭的,Frida检测代码,一般就在最后加载的 so文件中。
  1. 可以看到最后加载的 so文件是 libmsaoaidsec.so文件,我们把该文件拖到桌面上,稍后会用到。
  2. 这时候基本可以确认,检测代码是在这个文件中,可是我们后边该怎么做呢?我们该报着什么思路去做呢?
  3. 有个前置知识点,so文件的加载流程,网上有很多的大佬文章,我也是个小白,这里简单提几句,详细的内容可以看看其他大佬写的。从 System.loadLibrary开始,加载 so文件,从 Java层到底层 linker(链接器),核心就是将二进制文件映射到内存、解析符合,并初始化代码。而在 linker链接器时,有 DT_INITDT_INIT_ARRAY俩个函数,用来初始化。他们的执行逻辑是:INIT --> INIT_ARRAY --> JNI_OnLoad --> dlopen
  4. 小白可以这么浅的理解,实际情况是有所差距的,正是调用了 dlopen函数,才会执行前面的一系列初始化操作。上面说的执行逻辑,可以理解成 hook时机的先后。邪修可以先按我这个逻辑死记硬背。
  5. 说完这个前置知识,我们回到正题,确定了检测 so文件后,我们来 hook pthread_create 看看这个 so文件创建了那些线程。为什么要看创建的线程呢?很简单的道理,进程是有自己的工作的,它们负责保证 app正常运行,提供正常服务,而创建出来的线程就负责检测,有没有 Frida注入进来干坏事。就像公司之间分工明确,老板负责赚钱,牛马负责给老板赚钱一样。牛马就是线程,老板就是进程。
  1. 再次执行这个代码,如图:
  1. 这里报错文件未找到,说明没 Hook到。为什么?这就用到了前置知识的内容。
  2. 就是因为此时的Hook时机不对,虽然 Hook到了该 so文件的路径,其实这个时候刚刚加载到 so文件,还没有把符号表映射到内存,所以我们 hook显示找不到,那就要寻找其他的 hook时机才行,就是更早的 init阶段。
  3. 这时候我们使用 ida反编译 libmsaoaidsec.so文件。
  1. 这里我们站在巨人的肩膀,在字符串窗口直接搜索 “sdk”,这个方法是用来抓取手机的 sdk版本的。方法内部如图:
  1. 看下图,这里可以看到,这个方法实际在 init_proc阶段有被调用过,所以也符合我们的 hook时机。
  1. 接下来修改我们的 hook代码,重新再试一下。
  1. 这个 offset就是检测函数的偏移,偏移地址一般是不会变的,so文件加载进内存的地址是不固定的,所以我们每次都需要重新获取,获取到 so文件的基址加上这个偏移地址,就是检测函数的位置。
  2. 可以用 ida来简单看下检测函数。(0x1c544)
  1. 这是其中的一个检测位置,fd检测,通俗的讲,就是检查 frida进程的句柄数量与进程的软链接指向。再看(0x1b8d4)
  1. 这个是在检测线程 ID相关的内容,检测线程 ID句柄中有没有与 Frida相关的。比如:frida、gmain、gum-js-loop、pool-frida等。再看最后一个(0x26e5c)
  1. 读取 proc/self/maps进行检测,如果不是魔改的 frida,依旧会在该目录中留下敏感的字眼,比如:frida、gum-js-loop等。
  2. 那么这些监测点该怎么绕过呢?可以针对每一处检测位置做 hook,给他伪装成无 frida痕迹的样子。也可以直接把这三个偏移函数置空。
  3. 建议是优先置空操作,如果置空后 app无法正常运行,那么就针对每一处监测点做 hook。本篇文章直接做了置空,已验证,可以绕过。
  1. 这样就可以绕过 Frida检测,可以愉快的逆向分析加密参数啦!
  • appName:某货(v8.65.0
  • 签名状态V1 + V2
  • 加固状态:未加固(伪几维安全)

  • [培训]Windows内核深度攻防:从Hook技术到Rootkit实战!

    收藏
    免费 4
    支持
    分享
    最新回复 (3)
    雪    币: 0
    能力值: ( LV1,RANK:0 )
    在线值:
    发帖
    回帖
    粉丝
    2
    666
    3天前
    0
    雪    币: 24
    活跃值: (777)
    能力值: ( LV2,RANK:10 )
    在线值:
    发帖
    回帖
    粉丝
    3

    额,怕是没法复现了,直接……

    版本8.69.1

    6小时前
    0
    雪    币: 786
    活跃值: (335)
    能力值: ( LV3,RANK:20 )
    在线值:
    发帖
    回帖
    粉丝
    4
    新版本有变化吗?应该没有吧
    3小时前
    0
    游客
    登录 | 注册 方可回帖
    返回