某厂商安全Android加固之so层检测初步分析
WMBa0 发表于 河南 技术文章 1414浏览 · 2024-09-20 05:39

最近遇到了一个采用了某厂商的安全加固

该APP在离线环境下不存在检测功能,如果在线环境下会载入Java层和so层的检测功能。
脱壳使用Xposed框架的ditor可以脱掉,使用frida-dexdump不太行,存在检测。
本文章主要介绍如何绕过so层的检测,关于Java层检测,可以自行研究。

1、hook android_dlopen_ext

经典的hook dlopen函数,主要来看看加载哪个so文件使app退出了
这里属于so文件加载的知识,不了解的朋友可以阅读so文件加载流程

function hook_dlopen() {
    Interceptor.attach(Module.findExportByName(null, "android_dlopen_ext"),
        {
            onEnter: function (args) {
                var pathptr = args[0];
                if (pathptr !== undefined && pathptr != null) {
                    var path = ptr(pathptr).readCString();
                    console.log("load " + path);
                }
            }
        }
    );
}

setImmediate(hook_dlopen)


可以看到加载了
libmsaoaidsec.so使程序退出了
那么久分析该文件
同时,我的pixel3手机是64位ARM架构,后文patch的时候有一些区别

2、hook JNI_ONLoad函数

确定了so文件,接下来需要确定是JNI_ONLoad函数之前存在检测,还是JNI_ONLoad之后存在检测。


我的JNI_Onload函数位置是0x13A4C,64位arm模式

function hook_dlopen(soName = '') {
    Interceptor.attach(Module.findExportByName(null, "android_dlopen_ext"),
        {
            onEnter: function (args) {
                var pathptr = args[0];
                if (pathptr !== undefined && pathptr != null) {
                    var path = ptr(pathptr).readCString();
                    if (path.indexOf(soName) >= 0) {
                        this.is_can_hook = true;
                    }
                }
            },
            onLeave: function (retval) {
                if (this.is_can_hook) {
                    hook_JNI_OnLoad()
                }
            }
        }
    );
}

function hook_JNI_OnLoad(){
    let module = Process.findModuleByName("libmsaoaidsec.so")
    Interceptor.attach(module.base.add(0x13A4C), {
        onEnter(args){
            console.log("call JNI_OnLoad")
        }
    })
}

//传递参数  libmsaoaidsec.so
setImmediate(hook_dlopen, "libmsaoaidsec.so")


发现app仍然退出,那么进一步缩小了范围,在JNI_Onload之前就是init系列函数了。
本样本so文件的相关段给去掉了,采用搜索函数的方式定位


init_xxx函数的运行结束的时机是在android_dlopen_ext运行时,当android_dlopen_ext运行结束时,init_xxx已经结束了。
我尝试在android_dlopen_ext结束时进行hook init_Proc 发现hook不上,验证了这一说法,同时Android源码也可验证。
解决方法是在.init_proc函数中找一个调用了外部函数的位置
一般是__system_property_get函数

同时本样本存在ollvm控制流混淆


问题不大,d810可以一把去除,主要干扰项是字符串的加密

function hook_dlopen(soName = '') {
    Interceptor.attach(Module.findExportByName(null, "android_dlopen_ext"),
        {
            onEnter: function (args) {
                var pathptr = args[0];
                if (pathptr !== undefined && pathptr != null) {
                    var path = ptr(pathptr).readCString();
                    if (path.indexOf(soName) >= 0) {
                        locate_init()
                    }
                }
            }
        }
    );
}

function locate_init() {
    let secmodule = null
    Interceptor.attach(Module.findExportByName(null, "__system_property_get"),
        {
            // _system_property_get("ro.build.version.sdk", v1);
            onEnter: function (args) {
                secmodule = Process.findModuleByName("libmsaoaidsec.so")
                var name = args[0];
                if (name !== undefined && name != null) {
                    name = ptr(name).readCString();
                    if (name.indexOf("ro.build.version.sdk") >= 0) {
                        // 这是.init_proc刚开始执行的地方,是一个比较早的时机点
                        console.log("ok")
                    }
                }
            }
        }
    );
}

setImmediate(hook_dlopen, "libmsaoaidsec.so")

3、hook pthread_create

frida的检测通常会使用openat、open、strstr、pthread_create等等函数
检测文件又可以是maps等文件
这里直接 hook pthread_create
因为样本混淆太多了,字符串都是加密状态,hook 其他的函数都需要字符串来定位。

// 创建线程
    if (pthread_create(&thread, NULL, thread_function, &arg) != 0) {
        perror("pthread_create");
        return 1;
    }

这是pthread_create函数原型

function hook_dlopen(soName = '') {
    Interceptor.attach(Module.findExportByName(null, "android_dlopen_ext"),
        {
            onEnter: function (args) {
                var pathptr = args[0];
                if (pathptr !== undefined && pathptr != null) {
                    var path = ptr(pathptr).readCString();
                    if (path.indexOf(soName) >= 0) {
                        locate_init()
                    }
                }
            }
        }
    );
}

function locate_init() {
    let secmodule = null
    Interceptor.attach(Module.findExportByName(null, "__system_property_get"),
        {
            // _system_property_get("ro.build.version.sdk", v1);
            onEnter: function (args) {
                secmodule = Process.findModuleByName("libmsaoaidsec.so")
                var name = args[0];
                if (name !== undefined && name != null) {
                    name = ptr(name).readCString();
                    if (name.indexOf("ro.build.version.sdk") >= 0) {
                        hook_pthread_create()
                    }
                }
            }
        }
    );
}

function hook_pthread_create(){
    var base = Process.findModuleByName("libmsaoaidsec.so").base
    console.log("libmsaoaidsec.so --- " + base)
    Interceptor.attach(Module.findExportByName("libc.so", "pthread_create"),{
        onEnter(args){
            let func_addr = args[2]
            console.log("The thread function address is " + func_addr + " offset:" + (func_addr-base).toString(16))
        }
    })
}

setImmediate(hook_dlopen, "libmsaoaidsec.so")

输出结果

[Pixel 3::xxxx ]-> libmsaoaidsec.so --- 0x733584b000
The thread function address is 0x7446631b3c offset:110de6b3c
The thread function address is 0x7446631b3c offset:110de6b3c
The thread function address is 0x7446631b3c offset:110de6b3c
The thread function address is 0x7446631b3c offset:110de6b3c
The thread function address is 0x7446631b3c offset:110de6b3c
The thread function address is 0x7446631b3c offset:110de6b3c
The thread function address is 0x7446631b3c offset:110de6b3c
The thread function address is 0x7335867544 offset:1c544
The thread function address is 0x7446631b3c offset:110de6b3c
The thread function address is 0x73358668d4 offset:1b8d4
The thread function address is 0x7335871e5c offset:26e5c
The thread function address is 0x7446631b3c offset:110de6b3c
The thread function address is 0x7446631b3c offset:110de6b3c
The thread function address is 0x7446631b3c offset:110de6b3c
The thread function address is 0x7446631b3c offset:110de6b3c
The thread function address is 0x7446631b3c offset:110de6b3c

4、hook 检测函数

关注线程地址:
0x1c544
0x1b8d4
0x26e5c


均为检测函数
那么剩下的就是hook咯
方法比较多,这里采用直接hook 调用处函数,动态进行patch操作

5、总结

  • 该so文件存在大量字符串解密,总体使用了模式
    mingwen = miwen ^ key[ i % ken_len]
  • 使用了OLLVM控制流平坦化混淆,但是没有魔改,使用d810插件可以去除
  • 该so文件还存在其他的检测方案,比如:检测了NOP操作,在检测函数里面进行相关值初始化和设置,避免了整体nop
2 条评论
某人
表情
可输入 255