当前位置: 首页 > ops >正文

大麦逆向so

解决libmsaoaidsec.so通过dlsym获取pthread_create函数的方案

背景介绍

libmsaoaidsec.so是一个用于生成和获取手机OAID(Open Anonymous Identifier)的SDK。在移动广告生态中,OAID是替代IMEI等设备标识符的重要方案,几乎所有需要接入广告的APP都需要集成此SDK。

问题描述

在某些场景下,libmsaoaidsec.so需要通过dlsym动态获取pthread_create函数。然而,由于Android系统的限制和动态链接库的加载机制,直接调用dlsym可能会失败或引发兼容性问题。

libmsaoaidsec.so版本有很多,而且在很多APP中广泛存在。大致分为两类:

  1. 通过GOT表导入了pthread_create函数,创建了反调试线程。
  2. 使用dlsym动态加载libc.so库来获取pthread_create函数指针。

解决方案

动态加载libc.so并获取函数指针

以下代码展示了如何动态加载libc.so并获取pthread_create函数指针。此技术不仅适用于libmsaoaidsec.so,还可以用于其他高性能应用,例如大麦App的抢票工具。抢票工具通常需要处理高并发请求,因此多线程优化是关键需求:

void *handle = dlopen("libc.so", RTLD_LAZY);
if (handle) {void (*pthread_create_ptr)(...) = dlsym(handle, "pthread_create");if (pthread_create_ptr) {// 创建多个线程处理抢票请求for (int i = 0; i < THREAD_COUNT; i++) {pthread_create_ptr(&threads[i], NULL,抢票逻辑函数, NULL);}} else {// 处理获取失败的情况}dlclose(handle);
}

使用Frida进行动态Hook

以下是一个Frida脚本示例,用于Hook dlsym并替换pthread_create函数的返回值。此技术可以用于抢票工具的反调试机制,防止工具被逆向分析:

var pthread_create_ptr = Module.getExportByName(null, "pthread_create");// 备份原始函数
var original_pthread_create = new NativeFunction(pthread_create_ptr, 'int', ['pointer', 'pointer', 'pointer', 'pointer']);var my_pthread_create = new NativeCallback(function (thread_ptr, attr_ptr, start_routine, arg_ptr) {console.log("[*] 自定义 pthread_create 被调用!");console.log("    thread_ptr:     " + thread_ptr);console.log("    attr_ptr:       " + attr_ptr);console.log("    start_routine:  " + start_routine);console.log("    arg_ptr:        " + arg_ptr);var find_module = Process.findModuleByAddress(start_routine);console.log("这是pthread_create传入的函数地址,你可以再去hook这个函数看看BLR X8指令的位置,然后NOP掉--> Module: " + find_module.name + " offset:" + start_routine.sub(find_module.base));// 直接返回成功状态return 0;
}, 'int', ['pointer', 'pointer', 'pointer', 'pointer']);Interceptor.attach(Module.getExportByName(null, "dlsym"), {onEnter(args) {this.symbol = Memory.readUtf8String(args[1]);},onLeave(retval) {if (this.symbol.indexOf("pthread_create") !== -1) {console.log("[*] dlsym loaded pthread_create, addr:", retval);var backtrace = Thread.backtrace(this.context, Backtracer.ACCURATE);var callerAddress = backtrace[0];var find_module = Process.findModuleByAddress(callerAddress);if (find_module && find_module.name.indexOf("libmsaoaidsec.so") !== -1) {console.log("invoke dlsym |--> Module: " + find_module.name + " offset:" + callerAddress.sub(find_module.base));// 替换返回值为自定义的 pthread_createretval.replace(ptr(my_pthread_create));}}}
});

ELF文件解析与GOT表修改

通过解析libmsaoaidsec.so的ELF文件,可以定位到pthread_create的GOT表项。以下是一个Python脚本示例,用于解析ELF文件并修改GOT表。此技术同样适用于抢票工具的动态库加载需求:

import liefbinary = lief.parse("libmsaoaidsec.so")
for symbol in binary.symbols:if symbol.name == "pthread_create":got_entry = binary.get_symbol(symbol.name).valueprint(f"Found pthread_create GOT entry at 0x{got_entry:x}")# 修改GOT表项binary.patch_address(got_entry, 0xdeadbeef)  # 替换为目标函数地址binary.write("libmsaoaidsec_patched.so")

绕过内存保护机制

Android系统启用了ASLR和RELRO等内存保护机制,直接修改GOT表可能会失败。可以通过以下方法绕过:

  1. 禁用RELRO:在编译时添加-Wl,-z,norelro选项。
  2. 动态计算基址:通过/proc/self/maps获取模块基址,动态计算GOT表地址。

步骤5:动态调试与性能优化

动态调试与性能优化

使用GDB或LLDB在运行时动态修改函数指针:

gdb -p <pid>
(gdb) set *(void**)0x12345678 = 0xdeadbeef  # 替换为目标函数地址

性能优化建议:

  1. 缓存函数指针:避免频繁调用dlsym,缓存函数指针以提高性能。
  2. 延迟加载:在首次调用时加载libc.so,减少启动时间。

抢票工具的技术需求

大麦App的抢票工具通常需要处理高并发请求和快速响应,因此可能涉及以下技术需求:

  1. 多线程优化:通过pthread_create创建多个线程以并发处理抢票请求。
  2. 动态库加载:可能需要动态加载某些库(如加密库或网络库)以支持抢票逻辑。
  3. 反调试机制:防止抢票工具被逆向分析或Hook。

技术实现示例

1. 多线程优化
void *handle = dlopen("libc.so", RTLD_LAZY);
if (handle) {void (*pthread_create_ptr)(...) = dlsym(handle, "pthread_create");if (pthread_create_ptr) {// 创建多个线程处理抢票请求for (int i = 0; i < THREAD_COUNT; i++) {pthread_create_ptr(&threads[i], NULL,抢票逻辑函数, NULL);}}dlclose(handle);
}
2. 动态库加载

抢票工具可能需要动态加载加密库以支持安全通信:

void *crypto_handle = dlopen("libcrypto.so", RTLD_LAZY);
if (crypto_handle) {// 获取加密函数指针void (*encrypt_func)(...) = dlsym(crypto_handle, "AES_encrypt");if (encrypt_func) {// 使用加密函数}dlclose(crypto_handle);
}
3. 反调试机制

通过Hook dlsym防止抢票工具被逆向分析:

Interceptor.attach(Module.getExportByName(null, "dlsym"), {onEnter(args) {this.symbol = Memory.readUtf8String(args[1]);},onLeave(retval) {if (this.symbol.indexOf("ptrace") !== -1) {// 替换为无效函数指针retval.replace(ptr(0x0));}}
});

总结

通过动态加载libc.so并调用dlsym,可以安全地获取pthread_create函数指针。结合ELF文件解析、内存保护绕过和动态调试技巧,我们能够更深入地分析和控制libmsaoaidsec.so的行为。此方案不仅解决了libmsaoaidsec.so的需求,还为类似场景(如大麦App抢票工具的多线程优化和反调试机制)提供了参考。

http://www.xdnf.cn/news/13573.html

相关文章:

  • 第 87 场周赛:比较含退格的字符串、数组中的最长山脉、一手顺子、访问所有节点的最短路径
  • Fiori笔记
  • 华为云Flexus+DeepSeek征文 | 弹性算力实战:Flexus X实例自动扩缩容策略优化
  • Vue开发学习笔记:动态渲染自定义封装的uview-plus的Toast组件
  • LeetCode--29.两数相除
  • 位移传感器远程监控软件说明
  • 【从零学习JVM|第八篇】深入探寻堆内存
  • BERT vs BART vs T5:预训练语言模型核心技术详解
  • MySQL锁机制的优化和MVCC底层原理解释
  • 【 java 虚拟机知识 第二篇 】
  • Vue 生命周期详解(重点:mounted)
  • Tomcat线程模型
  • bash挖矿木马事件全景复盘与企业级防御实战20250612
  • 干货分享|JumpServer PAM特权账号管理功能详解
  • WPF将容器内的组件按比例缩放
  • RAG实战:基于LangChain的《肖申克的救赎》知识问答系统构建指南
  • 医疗集团级“人-机-料-法-环”全流程质控的医疗数据质控方案分析
  • Verilog基础:标识符的定义位置
  • Seedance:字节发布视频生成基础模型新SOTA,能力全面提升
  • Java虚拟机解剖:从字节码到机器指令的终极之旅(一)
  • DRG支付场景模拟器扩展分析:技术实现与应用价值
  • Windows 前端开发环境一键启动 (NVM + Yarn)
  • 第五十一天打卡
  • EtherCAT转CANopen网关与伺服器在汇川组态软件上的配置步骤
  • 【AI论文】Qwen3 嵌入:通过基础模型推进文本嵌入和重新排序
  • JavaWeb期末速成 样题篇
  • JSON 技术:从核心语法到编辑器
  • ruoyi框架添加开始事件自定义属性解释
  • 模拟IC设计基础系列6-差动放大器 Differential AMP
  • 大模型技术30讲-4-彩票假设