移动端安全 结合android so加载机制绕过libmsaoaidsec
字数 1383 2025-08-23 18:31:34

Android SO加载机制与绕过libmsaoaidsec检测机制深度分析

一、背景与目标

本文详细分析如何利用Android SO加载机制绕过Bilibili应用(版本7.76.0)中的libmsaoaidsec.so库的Frida检测机制。通过逆向分析SO加载流程和检测逻辑,最终实现稳定的Frida注入。

二、环境与工具准备

  • 测试设备: Pixel 2 (Android 10)
  • 目标应用: Bilibili 7.76.0 APK
  • 分析工具:
    • Frida 16.1.4
    • IDA Pro
    • adb工具链

三、检测机制初步分析

  1. 现象观察:

    • Frida注入后进程被快速终止
    • 检测逻辑位于native层
  2. 检测库定位方法:

    • 监控SO加载过程,观察哪个库加载后Frida被终止

四、Android SO加载机制深度解析

1. Java层加载入口

System.loadLibrary("libraryName");

调用链:

System.loadLibrary() 
-> Runtime.loadLibrary0() 
-> nativeLoad()

2. Native层加载流程

关键函数调用链:

Runtime_nativeLoad() 
-> JVM_NativeLoad() 
-> LoadNativeLibrary() 
-> OpenNativeLibrary()
-> android_dlopen_ext() 
-> __loader_android_dlopen_ext() 
-> do_dlopen()

3. 关键加载阶段

  1. 库加载阶段:

    • do_dlopen(): 实际加载SO文件
    • find_library(): 查找并验证库
  2. 初始化阶段:

    • .init段: ELF初始化代码
    • .init_array: 函数指针数组
    • JNI_OnLoad: 库初始化入口

五、检测机制逆向分析

1. 检测库定位

使用Frida Hook android_dlopen_ext:

function hook_android_dlopen_ext() {
    Interceptor.attach(Module.findExportByName(null, "android_dlopen_ext"), {
        onEnter: function(args) {
            this.fileName = args[0].readCString();
            console.log(`dlopen onEnter: ${this.fileName}`);
        },
        onLeave: function(retval) {
            console.log(`dlopen onLeave fileName: ${this.fileName}`);
        }
    });
}

确认libmsaoaidsec.so为检测库。

2. 检测时机分析

通过Hook验证检测逻辑执行位置:

if(this.fileName.indexOf("libmsaoaidsec.so") >= 0){
    let JNI_OnLoad = Module.getExportByName(this.fileName, 'JNI_OnLoad');
    console.log(`JNI_OnLoad: ${JNI_OnLoad}`);
}

确认检测逻辑在.init.init_array阶段执行。

3. 关键检测函数分析

Hook call_constructors定位检测点:

let linker64_base_addr = Module.getBaseAddress('linker64');
let offset = 0x50cf8; // __dl__ZN6soinfo17call_constructorsEv
let call_constructors = linker64_base_addr.add(offset);

4. 检测线程分析

Hook pthread_create监控检测线程:

Interceptor.attach(Module.findExportByName('libc.so', 'pthread_create'), {
    onEnter(args) {
        let func_addr = args[2];
        console.log(`Thread function address: ${func_addr}`);
    }
});

5. IDA静态分析

关键函数:

  • sub_1B8D4: 主检测循环
    • sub_1AE48: 检查/proc/pid/status中的TracerPid
    • sub_1AB54: 检查TracerPid进程状态
    • sub_1B730: 检查线程状态(stat文件)
  • sub_11FA4: 调用sub_234E0(动态解密并终止进程)

六、绕过方案实现

1. 整体绕过策略

  1. libmsaoaidsec.so初始化前注入
  2. 替换检测线程创建函数sub_1B924

2. 完整Frida脚本

function hook_dlopen() {
    Interceptor.attach(Module.findExportByName(null, "android_dlopen_ext"), {
        onEnter: function(args) {
            this.fileName = args[0].readCString();
            if(this.fileName && this.fileName.indexOf("libmsaoaidsec.so") >= 0) {
                hook_linker_call_constructors();
            }
        }
    });
}

function hook_linker_call_constructors() {
    let linker64_base_addr = Module.getBaseAddress('linker64');
    let offset = 0x50cf8; // __dl__ZN6soinfo17call_constructorsEv
    let call_constructors = linker64_base_addr.add(offset);
    
    let listener = Interceptor.attach(call_constructors, {
        onEnter: function(args) {
            let secmodule = Process.findModuleByName("libmsaoaidsec.so");
            if(secmodule != null) {
                hook_sub_1b924();
                listener.detach();
            }
        }
    });
}

function hook_sub_1b924() {
    let secmodule = Process.findModuleByName("libmsaoaidsec.so");
    Interceptor.replace(secmodule.base.add(0x1B924), new NativeCallback(
        function() {
            console.log(`Bypass sub_1B924 successfully`);
        }, 'void', []));
}

setImmediate(hook_dlopen);

七、技术要点总结

  1. 关键Hook点:

    • android_dlopen_ext: 监控SO加载
    • call_constructors: 捕获初始化时机
    • sub_1B924: 直接替换检测函数
  2. 时机控制:

    • 必须在检测逻辑初始化前完成注入
    • 精确控制Hook链的执行顺序
  3. 检测特征:

    • TracerPid检查
    • 线程状态监控
    • 动态代码解密执行

八、防御与对抗演进

  1. 可能的增强检测:

    • 多阶段检测机制
    • 反Hook技术
    • 运行时完整性检查
  2. 进一步绕过思路:

    • 内存补丁
    • 动态库替换
    • 内核级Hook

九、参考资源

  1. Android linker源码分析
  2. ELF文件格式规范
  3. Frida高级用法文档
  4. 逆向工程实践指南

通过本方案,我们成功实现了对Bilibili应用libmsaoaidsec.so检测机制的稳定绕过,为Android逆向工程中的对抗提供了系统性的解决方案。

Android SO加载机制与绕过libmsaoaidsec检测机制深度分析 一、背景与目标 本文详细分析如何利用Android SO加载机制绕过Bilibili应用(版本7.76.0)中的libmsaoaidsec.so库的Frida检测机制。通过逆向分析SO加载流程和检测逻辑,最终实现稳定的Frida注入。 二、环境与工具准备 测试设备: Pixel 2 (Android 10) 目标应用: Bilibili 7.76.0 APK 分析工具: Frida 16.1.4 IDA Pro adb工具链 三、检测机制初步分析 现象观察: Frida注入后进程被快速终止 检测逻辑位于native层 检测库定位方法: 监控SO加载过程,观察哪个库加载后Frida被终止 四、Android SO加载机制深度解析 1. Java层加载入口 调用链: 2. Native层加载流程 关键函数调用链: 3. 关键加载阶段 库加载阶段 : do_dlopen() : 实际加载SO文件 find_library() : 查找并验证库 初始化阶段 : .init 段: ELF初始化代码 .init_array : 函数指针数组 JNI_OnLoad : 库初始化入口 五、检测机制逆向分析 1. 检测库定位 使用Frida Hook android_dlopen_ext : 确认 libmsaoaidsec.so 为检测库。 2. 检测时机分析 通过Hook验证检测逻辑执行位置: 确认检测逻辑在 .init 或 .init_array 阶段执行。 3. 关键检测函数分析 Hook call_constructors 定位检测点: 4. 检测线程分析 Hook pthread_create 监控检测线程: 5. IDA静态分析 关键函数: sub_1B8D4 : 主检测循环 sub_1AE48 : 检查 /proc/pid/status 中的TracerPid sub_1AB54 : 检查TracerPid进程状态 sub_1B730 : 检查线程状态(stat文件) sub_11FA4 : 调用 sub_234E0 (动态解密并终止进程) 六、绕过方案实现 1. 整体绕过策略 在 libmsaoaidsec.so 初始化前注入 替换检测线程创建函数 sub_1B924 2. 完整Frida脚本 七、技术要点总结 关键Hook点 : android_dlopen_ext : 监控SO加载 call_constructors : 捕获初始化时机 sub_1B924 : 直接替换检测函数 时机控制 : 必须在检测逻辑初始化前完成注入 精确控制Hook链的执行顺序 检测特征 : TracerPid检查 线程状态监控 动态代码解密执行 八、防御与对抗演进 可能的增强检测: 多阶段检测机制 反Hook技术 运行时完整性检查 进一步绕过思路: 内存补丁 动态库替换 内核级Hook 九、参考资源 Android linker源码分析 ELF文件格式规范 Frida高级用法文档 逆向工程实践指南 通过本方案,我们成功实现了对Bilibili应用libmsaoaidsec.so检测机制的稳定绕过,为Android逆向工程中的对抗提供了系统性的解决方案。