libmsaoaidsec.so 完整业务与安全加固分析
1. 结论
libmsaoaidsec.so 不是普通的设备标识符库。它由 APK 在 ContentProvider 阶段提前加载,外层本体实现了 DEX 完整性门控、LZMA1/NAOP 载荷解码、私有 AArch64 ELF 加载器、Android linker 元数据写入,以及反调试、Frida、Hook、环境与安装布局检查。其内嵌受保护载荷经离线恢复后是 com.bun.miitmdid 的 OAID SDK 原生实现,负责按 OEM 采集 OAID、VAID、AAID 等设备标识符。
外层保护和内嵌 OAID 业务必须分开看待:
System.loadLibrary("msaoaidsec")
-> 外层 _init:环境/完整性门控、NAOP 加载器、检测守护
-> 外层 JNI_OnLoad:解析并调用内嵌映像的 JNI_OnLoad
-> NAOP 载荷 JNI 桥初始化
-> 调用方显式进入 OAID 初始化 JNI 导出时,才进行 OEM 标识符采集
静态证据可以证明外层存在并实现了以下检测能力:
| 类别 | 已验证规则 | 处置或影响 |
|---|---|---|
| APK 完整性 | ZIP 内的 classes*.dex 流式 CRC32 与运行期预期表比较 |
失败时不进入正常受保护加载路径 |
| Frida 本地痕迹 | gum-js-loop、gmain、FD 目标 linjector、/data/local/tmp 下 agent ELF 的 SONAME/符号 |
三类 Frida 命中直接 exit(0) |
| ART Hook | art::PrettyMethod 入口为 0x58000050/0x58000051 |
公共 exit_group(0) 失败桩 |
| 调试/暂停 | TracerPid、跟踪者亲缘关系、线程状态 T |
公共 exit_group(0) 失败桩 |
| ADB | sys.usb.config 含 adb,并结合充电状态评估 |
受运行期开关控制,可能进入失败桩 |
| Magisk 痕迹 | maps 候选内存内容含 MAGISKTMP |
命中时跳过后续受保护初始化,不是直接退出 |
| 运行环境 | /data/dalvik-cache/x86 映射路径 |
受开关控制,命中时 exit_group(0) |
| APK 布局 | 配置驱动的 base/split APK 容器发现 | 受开关控制,失败时 exit_group(0) |
不能据此证明的事项:任何检测分支在一次具体运行中是否已触发、soinfo 写入的唯一动机、内嵌 OAID 入口是否必然被调用、以及 OAID 回调接收方后续如何使用标识符。本文只描述本版本 libmsaoaidsec.so 及它嵌入的 NAOP 载荷,不覆盖 APK 其他 SO、下载组件或原应用业务。
2. 范围、样本与方法
| 项目 | 值 |
|---|---|
| 外层样本 | Loader/lib/arm64-v8a/libmsaoaidsec.so |
| 外层 SHA-256 | 38757CC75418654893B029D8C0410C4A08CC143DCBBF9D0D387736075BEC65D0 |
| 外层大小 | 685,960 bytes |
| 解包 DEX | Loader/classes.dex |
| DEX SHA-256 | 80BF63AC681A5C78B17B35CD0FCADCC259F5CD3E4728781802AA5CB2CD7D178E |
| 内嵌载荷重建文件 | bin/libmsaoaidsec_naop_payload.elf |
| 载荷 SHA-256 | 8C945EF9812C066E10374DB748EB5AAB13251AD4FFB7BB4FB3AC51F17B101070 |
| 外层自标识 | NagaLinker v8.83 |
| 分析方式 | 静态 DEX、ELF、反汇编与既有 IDB;离线重建 NAOP 为 ELF |
未执行 APK、未加载载荷、未附加调试器、未改写进程内存,也未访问网络。地址均为外层 SO 的相对虚拟地址;“载荷地址”单独标识为重建 ELF 中的相对地址。
3. 加载时序与外层状态机
3.1 提前加载点
DEX 中可恢复的最早调用链为:
MundoSupervisorProvider.onCreate
-> 混淆静态分发方法
-> System.loadLibrary("msaoaidsec")
该 Provider 在 Application 常规业务之前创建。ABI 判断允许 arm64-v8a、armeabi-v7a、x86 和 x86_64 后加载同名库。因此外层保护先于 OAID 的调用方业务运行。
3.2 _init 与 JNI_OnLoad
| 入口 | 地址 | 作用 |
|---|---|---|
_init |
0x1472C |
读取 Android/进程环境,执行门控,启动外层加载器与检测线程。 |
导出 JNI_OnLoad |
0x13A4C |
打印 NagaLinker v8.83,从私有加载器上下文解析内嵌 JNI_OnLoad 并调用。 |
_init 会读取 /proc/<pid>/cmdline。无 : 后缀的主进程才会进入主要监控和加载器初始化;带后缀的 Android 子进程不走这条主流程。若前置 Magisk 门控命中,后续主流程整体被跳过。
导出 JNI_OnLoad 不等于最终业务函数。它取得 JNIEnv、记录 SDK/RELEASE,然后以 sub_8734(qword_49248, "JNI_OnLoad", &fn) 查找私有对象中的同名符号;sub_8734 再经 sub_ED8C 按内部对象类型选择解析路径。解析成功后,外层用 (JavaVM *, NULL) 调用该内嵌函数,并检查返回的 JNI 版本。
4. DEX 完整性门控
sub_13728 是受保护加载器的前置入口,依次调用 sub_198D8 -> sub_19694。后者的可验证步骤如下:
- 通过库内 ZIP 读取器打开当前 APK。
- 依次定位
classes.dex、classes2.dex、classes3.dex等实际存在的 DEX 条目。 - 逐块读取条目;压缩条目先经 deflate 解压。
- 用
sub_16720计算 CRC32。 - 将每个结果与运行时填入的期望 CRC 表比较,同时检查预期 DEX 数量。
sub_16720 是表驱动 CRC32:初值 0xFFFFFFFF、逐字节查表、最终按位取反。ZIP 条目读取器 sub_1FD68 也实际调用 inflate/crc32,因此这不是仅从导入表猜测的能力。
期望 CRC 不是固定常量:表区 0x483A4 在文件初值为零,计数初值为 0xFFFFFFFF,说明期望值由后续初始化提供或解码。静态分析只能确认“校验存在且是加载门槛”,不能列出本次运行的真实期望 CRC。门控失败会令 sub_13728 在正常 NAOP 加载前返回。
5. 内嵌 NAOP 映像与离线重建
5.1 容器格式
外层库偏移 0x5E000 处保存长 0x3967B 的内嵌容器。sub_2337C 调用内部 LZMA1 解码器 sub_23178,参数和输出如下:
| 属性 | 值 |
|---|---|
| LZMA 属性 | 0x5D,即 lc=3, lp=0, pb=2 |
| 字典大小 | 0x100000 bytes |
| 解码长度 | 0x115078 bytes |
| 解码内容 SHA-256 | 6346CE8C2FCB0C46D3772C46932C9BD40F9DEA3565484F852D0B434B91B00BB9 |
| 自定义 magic / 版本 | NAOP / 2 |
sub_148F0 显式验证 NAOP magic,错误时输出 Bad AOP magic。通过后,输入由 sub_16444/sub_16590 的按键流变换继续解码;它不是直接可交给系统 linker 的 ELF。sub_FD08 为内存映像预留匿名 RWX 区域、复制及修正映像数据,sub_DF74 为包装对象使用 LIBVIEW! 类型标签。
5.2 重建协议与输出
现有 extract_msaoaidsec_naop.py 仅离线读取外层文件,重建步骤为:
- 从
0x5E000取 raw LZMA1 流并解码。 - 以偏移
0x8的种子解码 NAOP 头。 - 用 body 种子
0x3D336421解码0x114000bytes 映像。 - 对
0x112A58的 type-2 区域执行种子0x5443D492、长0x210的变换。 - 将 NAOP 动态表的
(d_val, d_tag)排列还原成标准 ELF 的(d_tag, d_val)。 - 依据 NAOP 段表补回 ELF64 文件头/程序头;不伪造 section-header 表。
重建产物经 readelf 验证为 ELF64、ET_DYN、EM_AARCH64:
| 元数据 | 值 |
|---|---|
| SONAME | libnllvm1721807282928253066.so |
可执行 PT_LOAD |
[0x0, 0x102000),R-X |
可写 PT_LOAD |
[0x111000, 0x113000),RW- |
PT_DYNAMIC |
0x112A58,0x210 bytes |
| GNU RELRO 范围 | [0x111000, 0x113000) |
DT_NEEDED |
liblog.so、libc.so、libm.so、libstdc++.so、libdl.so |
DT_RELA / 大小 |
0x10568 / 0x24A8 |
DT_JMPREL |
0x12A10 |
DT_INIT_ARRAY |
0x111C90,16 bytes |
e_entry=0 且没有可恢复的 section-header 表是共享对象允许的状态;分析工具可依据程序头、动态表、导入和重定位处理该文件。
6. 私有 AArch64 ELF 加载器
6.1 对象模型与依赖策略
sub_DF74 管理有序 LIBVIEW! 包装器列表。私有映像包装器 magic 为 0xCDEF2387,系统对象包装器 magic 为 0x02387CEF。对象保存库名和引用计数;重名对象复用时递增计数,若私有对象要求的固定地址不一致则拒绝。
sub_119DC 遍历动态表,只对 DT_NEEDED 调 sub_D1F8,并在主映像重定位前加载依赖。sub_D1F8 有两种路径:
| 条件 | 路径 |
|---|---|
内部加载标志未设置,或名称为 libhdog.so、libresh.so、libvenh.so |
读取文件并走私有 ELF 映射。 |
| 其余已设标志依赖 | dlopen 后建立系统对象包装器。 |
这是按名称选择的混合加载策略,不是普通 dlopen 封装。当前 APK ARM64 目录没有前三个文件名,不能把它们写成当前样本已携带或已加载的依赖。
6.2 ELF 校验、映射与权限
| 阶段 | 函数 | 可验证行为 |
|---|---|---|
| ELF 头校验 | sub_ABD4 |
要求 ELF magic、64-bit、小端、ET_DYN、版本 1、EM_AARCH64(183)。 |
| 程序头读取 | sub_AD28 |
限制程序头数量,读取页对齐的程序头缓冲区。 |
| 地址空间保留 | sub_AE10 |
计算 PT_LOAD 跨度,以 mmap 保留映射;固定地址请求必须精确满足。 |
| 段映射 | sub_AF54 |
依据 p_flags 设置权限,按 load bias 映射 PT_LOAD,清零 BSS 和间隙。 |
| 动态元数据校验 | sub_B110 / sub_C21C |
要求 PT_DYNAMIC 且动态段/程序头位于加载段内。 |
NAOP 路径与文件 ELF 路径共享后续链接逻辑,但输入先经自定义解密和内存映射;原始 NAOP 缓冲区不能被直接当作 ELF。
6.3 符号、重定位与构造函数
sub_C014 解析 Elf64_Dyn,要求 DT_SYMTAB 和 DT_STRTAB,并记录 SysV/GNU hash。sub_C160 按 hash 查找符号;sub_D960 在私有对象与其 DT_NEEDED 闭包中解析符号,正常定义优先,弱定义仅回退。系统包装对象走系统解析路径。
sub_B290 解析普通动态/PLT 重定位与 Android packed relocation(DT_ANDROID_REL/DT_ANDROID_RELA);sub_B8A4 解码 APS2 SLEB128 分组;sub_B540 临时写开放加载段、应用重定位后按 p_flags 恢复权限。最终 AArch64 写入由 sub_BF28 执行:
| 类型 | 值 | 行为 |
|---|---|---|
R_AARCH64_ABS64 |
257 | 写入解析符号地址加 addend。 |
R_AARCH64_COPY |
1024 | 共享库路径明确拒绝。 |
R_AARCH64_GLOB_DAT |
1025 | 写入解析符号地址加 addend。 |
R_AARCH64_JUMP_SLOT |
1026 | 写入解析符号地址加 addend。 |
R_AARCH64_RELATIVE |
1027 | 写入 load bias 加 addend;非零符号索引拒绝。 |
不支持的重定位或未解析的非弱符号会使加载失败。二进制有 RELRO 相关诊断字符串,但未静态恢复到可靠调用点,故不能据此断言外层实际启用了 RELRO 保护。
依赖和重定位完成后,sub_111B8 依次执行非零 DT_INIT 与 DT_INIT_ARRAY 项;sub_118A0 查找内嵌 JNI_OnLoad、加上映像基址并调用。这是外层分发到 OAID 载荷的实际桥接路径。
7. Android linker 元数据写入
sub_C7F4/sub_11F38 获取外层库对应加载记录。需要手工定位时,sub_2082C 在 /proc/self/maps 查找系统/APEX linker64,从磁盘 ELF 的 .symtab/.strtab 找名称含 solist 的符号以推导 linker 链表;sub_20BDC 按库名遍历,并按 Android API 版本选择 soinfo 布局偏移。
sub_95C8 对保存 libmsaoaidsec.so 的 soinfo 页调用 mprotect(PROT_READ|PROT_WRITE),必要时先作内部 CRC,然后把多个地址、长度、动态/ELF 元数据及表计数从私有对象复制至系统 linker 记录。目标偏移依 Android API 而变,函数末尾未见恢复页权限的路径。
可确定的是“外层主动修改本库的 linker 私有记录”。这可能用于把手工准备的映像元数据接入 linker 状态,也可能改变可见元数据;在没有修改前后 soinfo 或 maps 快照时,不能把动机唯一归结为隐藏或伪装。
8. 反分析、完整性与环境检测
8.1 公共失败桩
sub_234E0(0x234E0)、sub_260B0(0x260B0)、sub_269AC(0x269AC)会匿名映射 28-byte 可执行内存,解码 AArch64 代码、刷新指令缓存并调用。还原后的前 12 bytes 为:
mov x8, #0x5e
svc #0
ret
0x5e 是 AArch64 Android/Linux 的 exit_group 系统调用号;调用点以 x0=0 进入时,映射/执行成功会结束整个进程、退出码为 0。部分 Frida 规则不走此桩,而是直接使用 exit(0)。
8.2 周期性内存 CRC
sub_8CAC 锁定加载器状态,对受保护对象中配置的两段内存计算 CRC32,比较 sub_CDA4()/sub_CEA4() 返回的预期值,然后 usleep(0x2DC6C0),即 3 秒后重复。失配调用 sub_260B0 或 sub_269AC。
该线程的创建不是当前静态初值下的无条件路径:_init 的上游条件为 sub_C830()!=1 或 sub_95C8()!=0,随后 sub_9150 还要求 sub_CDE4()==204 或 sub_CEE4()==203。相关 dword_48838/dword_4883C 文件初值为 0,且未见直接静态写入。因此可以确认它具备周期性原生完整性监控及终止能力,不能称其为本样本每次必然启动的线程。
8.3 Frida 与通用 ART Hook 检测
sub_1BEC4 -> sub_1B924 -> sub_1CEF8 会动态解析 pthread_create,在主进程、非 Firefly-RK3399 机型且运行期调用成功时创建 sub_1C544。其中 sub_CAA8()==248 的当前文件初值满足。该线程以三字节循环 XOR 密钥 0x99/0xA7/0xA9 还原规则,每 4 秒循环:
sub_1C544
-> sub_1BFAC : 线程名规则
-> sub_1C158 : 文件描述符规则
-> sub_1C26C : 映像/ELF 身份规则
-> sub_26334 : ART PrettyMethod 入口规则
-> sleep(4)
| 面 | 函数 | 命中条件 | 结果 |
|---|---|---|---|
| Frida 线程 | sub_1BFAC |
枚举 /proc/self/task 并读 status,文本含 gum-js-loop 或 gmain |
直接 exit(0) |
| 注入器 FD | sub_1C158 |
枚举 /proc/self/fd,readlink 目标含 linjector |
直接 exit(0) |
| Frida agent 映像 | sub_1C26C / sub_1806C |
/proc/self/maps 具有 r、x 且路径含 /data/local/tmp;候选文件为 ELF,DT_SONAME 含 frida-agent,或动态符号名含 _AGENT_1.0 且 STT_OBJECT |
直接 exit(0) |
| ART inline hook | sub_25B30(0x25B30)/ sub_26334(0x26334) |
PrettyMethod 首 32-bit 指令等于 0x58000050 或 0x58000051 |
公共 exit_group(0) 桩 |
关键解码字符串的内存地址包括:
| 地址 | 值 |
|---|---|
0x49020 / 0x49030 |
/proc/self/task、/proc/self/task/%s/status |
0x4904A / 0x49056 |
gum-js-loop、gmain |
0x4905C / 0x4906A |
/proc/self/fd、linjector |
0x49074 / 0x49084 |
/proc/self/maps、/data/local/tmp |
0x49094 / 0x4909F |
_AGENT_1.0、frida-agent |
agent 检测不是“路径含 frida 即命中”:先用路径/权限筛选,再由 sub_18774 映射候选文件、sub_18240 解析 ELF 头/节/动态信息、sub_1806C 检查 SONAME 与符号。这降低了路径误报,但也限定了本规则的覆盖面。
sub_1CEF8 依 API 版本在 libart.so 解析一个符号:API 21-22 使用 _ZN3art12PrettyMethodEPNS_6mirror9ArtMethodEb;23-25 使用 _ZN3art12PrettyMethodEPNS_9ArtMethodEb;26 及以上使用 _ZN3art9ArtMethod12PrettyMethodEb。规则接受的两个首指令分别是 LDR X16, #8 与 LDR X17, #8 形式的 AArch64 字面量跳板开头。它是通用 ART 入口篡改/inline-hook 特征,并非 Frida 独有;代码未继续校验后续 BR 或跳板目标,因此不是完整跳板结构验证。符号无法解析时会返回未命中,而不是退出。
当前可见实现未发现针对 frida-server、TCP 27042、D-Bus 握手或 socket 端口的检查链,不能扩大结论为“检测所有 Frida 形态”。
8.4 反调试、暂停线程与 ptrace 守护
sub_1B8D4 最短每 2 秒检查一次:
sub_1B8D4
-> sub_1AE48:读取 /proc/<self>/status 的 TracerPid
-> sub_1AB54:读取 /proc/<tracer>/status,验证 PPid 关系
-> sub_1B730:枚举 /proc/<self>/task/*/stat,检查 State == T
-> 异常 -> sub_11FA4 -> 公共失败桩
它不是简单地把所有非零 TracerPid 立即视为失败。若跟踪者是受保护进程的子进程,sub_1AB54 接受该亲缘关系;无法读取状态、未知跟踪者或停止态线程才会进入失败处理。
另有 sub_1B380 父子 ptrace 守护:以 prctl(PR_SET_DUMPABLE, 1) 后 fork,子进程由 sub_1A34C 对父进程和线程 PTRACE_ATTACH,父进程以 waitpid、PTRACE_SETOPTIONS、PTRACE_GETSIGINFO、PTRACE_CONT 处理事件,sub_1AB2C 每 2 秒把子进程 State: Z 视为异常。它受 sub_CAE8()!=249 控制,而 0x48814 当前初值为 249,所以不能称作当前静态默认路径。
8.5 ADB、Magisk、x86 与安装布局门控
| 规则 | 条件与证据 | 当前静态状态 | 命中后可确认效果 |
|---|---|---|---|
| ADB | sub_19E0C 每 3 秒读 sys.usb.config,含 adb 时结合 BATTERY_CHANGED/plugged 评估 |
仅 sub_CA28()==167 时创建;0x48394 初值 0 |
可能进入公共失败桩 |
| Magisk | sub_23B18 只在主进程解析 maps,搜索 MAGISKTMP |
仅 sub_CC64()==218;dword_48850 初值 0 |
_init 跳过监控、DEX 门控、NAOP 引导和 soinfo 写入;没有直接 exit |
| x86 Dalvik | sub_23734 搜索 /data/dalvik-cache/x86 |
仅 sub_CCE4()==213;dword_48828 初值 0 |
公共 exit_group(0) 桩 |
| APK/Split 布局 | sub_1678C 以运行期词表查 /data/app/<token>-<1..10>.apk、base.apk、split_config.arm64_v8a.apk 等 |
仅 sub_C930() 返回 1..12;dword_48130 初值 0xFFFFFFFF,词表为空 |
校验失败进入公共失败桩 |
MAGISKTMP 是 Magisk 临时挂载/重定向路径的常见标记,故这是一条明确的 Magisk 痕迹规则;但其处置是“阻断后续保护初始化”,不是本函数直接终止。x86 路径规则可识别不符合 ARM64 预期的 Dalvik 缓存环境,但单凭该规则不能把它扩展成全量模拟器检测。
在此版本外层库的静态可见代码中,没有恢复到 su 路径、Magisk 管理器包名、Zygisk/Riru、Xposed/LSPosed 或常见模拟器型号黑名单。该负向结论不涵盖运行期配置和 NAOP 载荷。
8.6 旧系统 LD_PRELOAD 兼容路径
内部加载器在旧 Android 版本会读取 LD_PRELOAD,拆分库名,并把能够打开的对象加入内部列表。这是受版本门控的加载兼容逻辑,不能仅据此把它标记为 Frida 或注入检测。
9. 内嵌 OAID 载荷业务
9.1 定位与激活边界
重建载荷是 com.bun.miitmdid 移动设备标识符 SDK 的 NLLVM/JNI 实现,目标是本地选择 OEM 标识符服务并回调 OAID、VAID、AAID。载荷 JNI_OnLoad 位于 0x14330,只建立 JNI/NLLVM 类型桥接;它不直接发起标识符采集。
主采集导出为:
0x37C0C Java_com_bun_miitmdid_e_a__Landroid_content_Context_2
Lcom_bun_miitmdid_interfaces_IIdentifierListener_2
因此“外层壳已被加载”只能证明 OAID SDK 可用,不能证明采集入口在每次进程启动时都被调用。
9.2 前置状态、主流程与结果码
| 入口 | 地址 | 作用 |
|---|---|---|
e.a(Context, IIdentifierListener) |
0x37C0C |
主初始化、提供者选择、同步/异步调度。 |
e.a(Context, IPermissionCallbackListener) |
0x39A88 |
OAID 权限申请。 |
e.a(Context, String) |
0x39C00 |
调用 Java CertChecker.verifyCert,写入主入口门控。 |
e.a(ZZZ) |
0x3A080 |
设置 OAID/VAID/AAID 三个请求标志。 |
e.b() |
0x3A224 |
返回 SDK 构建值 20240726。 |
主入口先要求两个证书/启用状态为真,否则通过 listener 回报 1008616,不创建提供者。三个标识符请求位由调用方控制,故不能静态断言这个 APK 默认同时请求 OAID、VAID、AAID。
e.a(Context, listener)
-> Context.getApplicationContext
-> f.a(context):不适宜/模拟器环境门控
-> p.b(context):提供者配置/探针
-> p.a(context, config):OEM IIdProvider 工厂
-> IIdProvider.setGetIdFlag(OAID, VAID, AAID)
-> doStartSync 或 doStartInThreadPool
-> o.onSupport -> IIdentifierListener.onSupport(IdSupplierImpl)
| 结果码 | 静态路径 |
|---|---|
1008610 |
同步提供者完成并返回结果。 |
1008611 |
厂商或环境不支持。 |
1008612 |
已选设备/提供者不支持。 |
1008613 |
提供者配置不可用。 |
1008614 |
异步提供者已启动,结果延迟。 |
1008616 |
SDK 前置状态或证书门控拒绝初始化。 |
o.onSupport 位于 0x54B3C,创建 IdSupplierImpl(OAID, VAID, AAID, isSupported, isLimited, isSupportRequestOAIDPermission)。不支持时清空 OAID/VAID;已支持但 OAID 为空或为配置的空值占位时可标为受限。结果通过进程内 IIdentifierListener.onSupport 交付。
9.3 OEM 分发与标识符来源
p.a(Context, c)(0x563E4)依配置创建 IIdProvider。已恢复的 OEM 路线如下:
| 键 | 提供者/路线 |
|---|---|
| 1 | Asus:SupplementaryDIDManager / IDidAidlInterface |
| 2 | Freeme:com.android.msasdk.FreemeIds |
| 3 | Huawei:HMS Advertising/OpenDevice/AAID API |
| 4 | Honor:AdvertisingIdClient |
| 5-6 | Lenovo/ZUI:OpenDeviceId Binder 服务 |
| 7-9 | Meizu:Flyme OpenID Provider / OpenIdHelper |
| 10 | Nubia:NubiaIdentityImpl |
| 11-13 | Oppo/Heytap:OpenIDSDK |
| 14 | Samsung:DeviceIdService |
| 15 | Vivo:IdentifierManager,含 OAID 权限状态 |
| 16-17 | Xiaomi:provider.xiaomi.IdentifierManager |
| 18 | ZTE:android.app.ZteDeviceIdentifyManager |
| 19 | Prize:KeyguardManager.obtainOaid/Vaid/Aaid |
| 20 | Coolpad:IDeviceIdManager 服务 |
| 21 | EEBBK:反射 com.sdid.id.IdentifierManager |
| 22 | Qiku/360:QikuIdmanager |
| 23 | Xiaodu:IdentifierManager |
| 24 | Tencent:android.tencent.sdid.TencentIdentifierManager |
代表性访问包括:Huawei 的 AdvertisingIdClient、OpenDevice 和 HmsInstanceId;Asus/Lenovo/Coolpad 的 Binder 接口;Meizu/Vivo 的 ContentProvider/管理器;Oppo 的 OpenIDSDK;以及其他厂商的隐藏或公开管理类。它们均是在本地调用 Android/OEM 服务,不是载荷自身的网络传输。
p.b(Context)(0x57844)的配置获取顺序为缓存、Qiku/Tencent 系统属性探针、可选 supplierconfig.json、最后的 Freeme/Coolpad/Meizu/Prize/Xiaodu/Tencent 回退探针。资源读取分支 0x2FD6C 解析 supplierconfig.json 的 supplier JSON 节点;当前解包 APK assets 中未发现该文件,因此依赖这一资源的 Android 9 及以下路径可能返回 1008613。它与外部业务配置无关。
9.4 OAID 权限、缓存与环境门控
环境门控 f.a(Context)(0x3B50C)检查 Build.FINGERPRINT 的 generic/vbox/test-keys,MODEL 的 google_sdk/Emulator/Android SDK built for x86,MANUFACTURER=Genymotion,generic brand/device/product,以及电话运营商名 android。它返回 11..21 的检测码;主入口将非零视为 OEM 标识符服务不支持。该部分只影响 OAID 初始化,不执行注入或反作弊处理。
公共缓存 m 保留进程内 OAID/VAID/AAID、支持与受限状态。cleanCache(0x4DD88)清空它们;doAsyncCallBefore(0x4E8F8)记录起始时间;doAsyncCallAfter(0x4E23C)按可配置超时处理结果;handleIfAsyncOverTime(0x4EE70)在 currentTimeMillis - start > timeout - 500ms 时丢弃迟到结果并回调缓存回退。载荷没有把这些值写入本地文件、SQLite 或 SharedPreferences。
权限入口会用 FLAG_ACTIVITY_NEW_TASK 启动 PermissionTransparentActivity。一般 OEM 路径调用 IdSupplier.requestOAIDPermission;Vivo 调 IdentifierManager.requestOaidStatePermission(0x30E24),Oppo 调 OpenIDSDK.requestOAIDPermission(0x686FC)。
9.5 载荷的负向证据
重建载荷导入 pthread、内存分配、日志、C++ 运行时和 ELF 支持函数;未见 socket、connect、send/recv、HTTP/TLS、shell、进程创建或 /proc 访问导入。字符串中未恢复 http://、https://、frida、xposed、anogs、tersafe、inject、root、Runtime.exec 等。该证据支持有限结论:OAID 载荷本身没有静态可见的网络外传、root、注入、反作弊或 Frida 检测路线;不代表 listener 接收方不会在外层使用结果。
10. 关键证据索引
| 地址/文件 | 角色 |
|---|---|
外层 0x1472C / 0x13A4C |
_init 与导出 JNI_OnLoad。 |
外层 0x19694 / 0x198D8 / 0x16720 |
APK DEX ZIP/CRC32 门控。 |
外层 0x5E000 / 0x148F0 / 0xFD08 |
NAOP 容器、校验和映射。 |
外层 0xDF74 / 0xD1F8 / 0x119DC |
私有依赖与对象编排。 |
外层 0xABD4 / 0xAE10 / 0xAF54 |
ELF64/AArch64 校验与段映射。 |
外层 0xB290 / 0xB540 / 0xBF28 |
重定位解析、写入和权限恢复。 |
外层 0x111B8 / 0x118A0 |
构造函数与内嵌 JNI_OnLoad 调用。 |
外层 0x2082C / 0x20BDC / 0x95C8 |
solist 定位和 soinfo 元数据写入。 |
外层 0x8CAC |
周期性内存 CRC。 |
外层 0x1B8D4 / 0x1B380 |
常规反调试及备用 ptrace 守护。 |
外层 0x1CEF8 / 0x1C544 |
ART Hook 初始化及 Frida/Hook 轮询。 |
外层 0x1BFAC / 0x1C158 / 0x1C26C / 0x1806C |
Frida 线程、FD、agent ELF 检测。 |
外层 0x25A48 / 0x23B18 |
Magisk MAGISKTMP 门控。 |
外层 0x23AD4 / 0x23734 |
x86 Dalvik 映射检测。 |
外层 0x26E5C / 0x1678C |
配置驱动 APK/Split 布局检查。 |
载荷 0x14330 |
载荷 JNI_OnLoad。 |
载荷 0x37C0C |
OAID 主初始化入口。 |
载荷 0x3B50C / 0x563E4 / 0x57844 |
OAID 环境门控、OEM 工厂、配置。 |
载荷 0x54B3C |
IdSupplierImpl 构造与 listener 回调。 |
11. 静态分析边界
- 运行期填充的 DEX CRC 表、环境开关和完整性预期值不在外层文件的初始数据中,不能由静态样本还原。
pthread_create、dlopen、dlsym、匿名映射和 linker 结构均受设备/API/进程条件影响;“创建线程/调用失败桩的代码存在”不等于一次具体运行已经执行。soinfo写入已被证实,但没有操作前后内存快照时不能给出唯一动机。- Frida 规则只覆盖已恢复的进程内本地痕迹和一个 ART 入口特征;未观察到网络端口或协议检查。
- OAID 载荷负责本地提供者调用和回调,静态结果不能证明调用方会否随后上传、存储或关联这些标识符。
评论
- 还没有评论,来说点什么吧。