移动端安全 结合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工具链
三、检测机制初步分析
-
现象观察:
- Frida注入后进程被快速终止
- 检测逻辑位于native层
-
检测库定位方法:
- 监控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. 关键加载阶段
-
库加载阶段:
do_dlopen(): 实际加载SO文件find_library(): 查找并验证库
-
初始化阶段:
.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中的TracerPidsub_1AB54: 检查TracerPid进程状态sub_1B730: 检查线程状态(stat文件)
sub_11FA4: 调用sub_234E0(动态解密并终止进程)
六、绕过方案实现
1. 整体绕过策略
- 在
libmsaoaidsec.so初始化前注入 - 替换检测线程创建函数
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);
七、技术要点总结
-
关键Hook点:
android_dlopen_ext: 监控SO加载call_constructors: 捕获初始化时机sub_1B924: 直接替换检测函数
-
时机控制:
- 必须在检测逻辑初始化前完成注入
- 精确控制Hook链的执行顺序
-
检测特征:
- TracerPid检查
- 线程状态监控
- 动态代码解密执行
八、防御与对抗演进
-
可能的增强检测:
- 多阶段检测机制
- 反Hook技术
- 运行时完整性检查
-
进一步绕过思路:
- 内存补丁
- 动态库替换
- 内核级Hook
九、参考资源
- Android linker源码分析
- ELF文件格式规范
- Frida高级用法文档
- 逆向工程实践指南
通过本方案,我们成功实现了对Bilibili应用libmsaoaidsec.so检测机制的稳定绕过,为Android逆向工程中的对抗提供了系统性的解决方案。