Files
live-hub-py/docs/HUYA_HDID_ALGORITHM_GEN.md
T
yml2213 bed53a6586 feat(huya): isNative定案NativeBridge纯Java + GUID值流还原(服务端sGuid签发) + unidbg金测试恢复
- dex直读判定: NativeBridge.b/a/c/g/h/klog全为Java(classes5), NativeEntry全native; .data描述符块=GetStaticMethodID反向调Java的name/sig常量表
- GUID值流完整还原: native getGUID=纯缓存getter(pref hydeviceid_guid -> WupHelper.getGuid() -> b(100) -> 回写)
  YYProtoSdkModule.initHuyaUdbSdk(classes17)->HyDeviceProxy.j(appid,WupHelper.getGuid(),mid)->pnc.a
  WupHelper.getGuid->HalImpl.getGuid->sGuidProperty<--live-launch服务端LiveLaunchRsp.sGuid(32hex硬校验)
- 修正结论: GUID非本地指纹公式, 铸币=服务端doLaunch/device_register按虚拟设备指纹签发sGuid
- unidbg: 新harness回归根因=C++ locale/facet在unidbg libc++上ABI崩溃; 旧harness+当前merged恢复金测试MATCH, 实证native缓存写回流
- 新工具: tools/dex_probe_native.py(dex access_flags判定), tools/dex_scan_calls.py(跨dex调用点扫描)
2026-08-28 18:15:46 +08:00

302 lines
21 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 虎牙 32hex hdid 算法生成路径分析(不用采集,纯算法铸币)
> 前置结论(见 `HUYA_HDID_RESEARCH.md`):32hex hdidWUP 登录帧 field1.tag0=
> `com.huya.security.hydeviceid.NativeEntry.getGUID()`;真机 M2102J2SC 金值
> `0a7dfaa882938a6ab502511452142c57`getGUID 是 getter,值在 `init()`(偏移 0x20e6e4
> 时由 `libhydeviceid.so`OLLVM 混淆 + datadiv 壳)算出并缓存。
>
> 用户约束:**不能用真机采集设备池;必须用算法生成**(在代码里根据可控输入铸出
> 一套又一套服务端认可的设备身份)。本文是"如何继续"的完整分析。
>
> 时间:2026-08-28`0c6aff6`/`022357a` 之后)。
## 一、任务再定义:什么是"算法生成"
设备身份是**纯函数**
```
getGUID() = F_guid(种子集 S) → 32hex
getCDID() = F_cdid(种子集 S) → 40hex
getHDID() = F_hdid(种子集 S) → 40hex
getMID() = F_mid(种子集 S) → 16hex
getSDID() = F_sdid(种子集 S) → base64 180B
```
- **S = 设备的指纹输入集合**(属性/文件/系统值/持久化密钥,详见 §三)。
- "算法生成" = 我们在**任意环境**(纯 Python / unidbg 仿真)里把 F 跑出来,
输出不依赖任何物理设备;换一套 S 就铸一个新身份。
- **关键澄清**:"单机不可铸造"只证明 `{ro.serialno, ANDROID_ID, files/hydevice/}`
不在 S 里(改它们 GUID 不变);**不证明 S 不可控**。在仿真里 S 由我们提供;
而 S 只要有一丁点可变化的空间(IMEI/qimei/SoC 序列号/密钥文件),铸币空间就是无限的。
## 二、本轮新证据(对 decrypt dump 的静态分析)
`evidence/diag_phone/libhydeviceid_dump.so`(datadiv 已就地解密的内存镜像)做常量/结构扫描:
### 2.1 lib 内置**标准密码学原语**(这是静态移植可行性的决定性地雷)
| 原语 | dump 内偏移 | 说明 |
|---|---|---|
| AES S-box(完整 256B,精确匹配) | `0x36be82` | 有 AES(256 位密钥可能性大) |
| MD5 IV 常量(`01 23 45 67 89 ab cd ef fe dc ba 98 76 54 32 10` | `0x36c190` | 有 MD5 |
| SHA1 轮常量 K(小端,4×u32 | `0x36c1a0` | 有 SHA1 |
| base64 字母表 | `0x3e8880` | 有 base64SDID 180B 的编码) |
→ 32hex 输出=MD5 类、40hex 输出=SHA1 类、SDID=AES+base64 的组合推测是**标准构造 + 内置密钥**,
不是自研魔改算法 → **不需要解全部 OLLVM 平坦化**,只需定位"哪些函数把哪些输入喂给这些原语"。
### 2.2 .data 里已提取的固定密钥 / 盐候选(datadiv 解密后的明文)
| 常量 | 形态 | 角色猜测 |
|---|---|---|
| `7jbF5IiqqIDdgEtiNQLzJSuTZmRk8sbc`32B,出现 8+ 次) | base64 风格 32 字符 | **AES-256 固定密钥**(最可能) |
| `HuyaUdb1928374650qwertyuiop`(27B,出现 2 次) | 明文 | UDB 体系固定密钥/加盐串 |
| `865a4924a40897ac1fcfe6b4c2cbb045` / `...abc798` | 32hex ×2(只差 4B | appid 对密钥哈希 / dfpReport 通道常量 |
| `961c151d2e87f2686a955a9be24d316f1362bf21 3.11.3` | 40hex + 版本 | SHA1 固定值(某固定材料摘要) |
| `400e18d7b4c8070374bd216279da774b` / `473c8798375341d8849804154d181acc` | 32hex ×2 | 运行时/渠道相关常量 |
| `0123456789abcdef0123456789abcdef` | 32hex | 默认 GUID 模板 / 输入填充 |
> 注意:`getDfpConfig` 是**服务端下发**的接口名(.data 里有),这些 32hex 常量里
> 可能有运行时应答替换的值——金样本对拍时要用真机实测值逐一对账(§五)。
### 2.3 getGUID0x20f8c8)反汇编现场 = 标准 OLLVM 平坦化
`0x20f8c8` 处可见典型 dispatcher 模式(`mov w16,#case; cmp w16,w13; b.gt/b.le/b.eq` 状态机跳转),
函数体完整存在于 dump 中(壳已解密)。Stalker 记录其内部调用锚点(模块偏移):
`0x46140``0x1d6e68` 等(`0x46140` 紧邻 `0x45f20/0x45890/0x45aa0/0x46fd0` 小偏移簇 =
hex/base64/CRC 类工具函数区)。**这些锚点是静态还原的切入点**:先在这些地址反汇编,
认出"读 S → 拼接 → MD5/SHA1/AES 调用"的骨架即可,不需要全量反平坦化。
## 三、种子集 S 的候选清单(当前输入图缺口)
从 .data 字符串、init 窗口 openat 记录、probe 事件三方交叉(**都只是候选,待 E2 定案**):
| 类别 | 具体项 | 备注 |
|---|---|---|
| 属性 | `ro.product.{model,manufacturer,board,device,name,brand,marketname,vendor.model}` | .data 出现完整名单 |
| 系统文件 | `/proc/cpuinfo`(含 `Serial:`)、`/proc/version``/proc/meminfo` | `cat /proc/cpuinfo` 字符串直接出现 |
| 持久化 APP 密钥 | **`fileshydckey`**init() 窗口 open 过 1 次) | 疑似"设备密钥",**是否每次安装重新生成 = 决定性** |
| 腾讯 QIMEI | `qimei16` / `qimei36`(.data 出现 3 组) | 腾讯灯塔设备 ID,持久化于 shared_prefs**清数据会再生成** |
| 蓝牙/WiFi | 蓝牙名称/地址、WiFi 信息 | .data 有读取代码路径 |
| 缓存/上报 | `files/hydevice/resinfo`、上报链路字段 | 已确认与 GUID 值无关(实验删过不变) |
| 硬件锚(待验证) | IMEI、`/sys/devices/soc0/serial_number`、TEE/Keystore 密钥 | 上一轮推断"硬锚 SoC"的落点,**尚无直接实验** |
**为什么上一轮"不可铸造"实验不完整**:它们没有覆盖 `fileshydckey` 删除、全量清数据/
卸载重装(会影响 qimei 与可能重生成的文件)、IMEI 变更。只要 E1/E3 里任一项变了
GUID,就说明 S 里有可再生的成分 → 铸币空间立刻打开。
## 四、决定性实验清单(真机在线:`5dd8c93f`,通道稳定,1~2 天)
- **E1**:全量清数据 / 卸载重装 → getGUID 变不变?(若有持久化种子:变了 = 单机
"重装即新设备",先于一切;不变 = 硬件锚确证)
- **E2(最高价值工件)**init()0x20e6e4**库内定向 Stalker**:只跟踪
libhydeviceid 内部调用 + 库内触发的 `__system_property_get/open/read/ioctl`
带**参数值快照**(属性名+值、文件路径+读入的前 N 字节、ioctl 解码)→ 得到
**完整输入图 + 每个种子的实测值**。上一轮 getguid_init.json 是全 App 启动噪音
窗口,需要收紧到库内。
- **E3**IMEI 变更(root + 模块)→ getGUID 变不变?(确定 IMEI 是否在 S 中)
- **E4**:补记 E2 之外的硬锚路径实测值(`/sys/devices/soc0/serial_number`
`/proc/cmdline` 的 androidboot 段、`getprop ro.boot.*` 值)→ 这些直接把"不可改
硬件"变成"可仿真输入"。
**副产品(对拍语料)**:上述每次变更都记录 `(S 的逐项值 → 5 个输出值)`,形成
**差分语料库**。这是 E2 之外静态移植的主要"答案纸":能直接看出哪个输出依赖哪些输入、
以及单输入变化时的输出变化模式(MD5 雪崩 vs 局部字节变化 → 立刻排除/确认构造)。
## 五、执行路径对比
### 路径 A:纯静态还原 → 纯 Python 生成器(最终形态,周级)
1. E2 输入图 + E4 硬锚值 → 复原"种子串拼接格式"(大概率就是若干固定前缀 + S 逐项);
2. 用金样本 pair(本节 §2.2 常量 + 真机 S)在 Python 里**穷举组合对拍**
`MD5(盐‖S)``SHA1(盐‖S)``AES-ECB/CBC``HMAC-MD5/SHA1` × 各候选密钥/盐;
3. 命中即纯 Python 版本直接成立(**无需解一个字节的 OLLVM**);未命中再走 Ghidra+
锚点反汇编看拼接/变换细节;
4. 产出 `tools/hdid_mint.py` + `core/huya/device_mint.py`(零 native 依赖)。
要点:dump 已解密、原语已定位、密钥候选已提取 —— 静态路上最贵的 "OLLVM
平坦化全解" **不是必需项**,先用黑盒对拍把算法筛出来。
### 路径 B:unidbg 仿真执行(天级,**推荐先行**)
1. 装 JDK(本机 JVM 失效:`/usr/bin/java` 空壳、sdkman 空目录 → brew/sdkman 装
OpenJDK 17/21);拉 unidbgzhkl0228/unidbg);
2. 把 decrypt dump 载入 ARM64 仿真,hookJNI env、`__system_property_get`
`open/read``ioctl`、TelephonyManager 等 JNI 桩;
3. **金测试**:喂真机 S 实测值 → 期望输出 `0a7dfaa8...`;对上了 = 整个算法已在
PC 上可执行;
4. 之后每套虚拟 S 跑一次 init+get* 即铸一套身份 —— **这就是"算法生成"的落地形式**
5. 风险:OLLVM 仿真慢(毫秒级可接受)、反调试(TracerPid 读取,可 hook)、
若算法依赖 Java 服务调用需补 JNI 桩(init 是 `()V` 无参,依赖面小)。
### 路径 C:有根模拟器 / 重装循环(备用,仅对拍用)
lib 内置大量模拟器检测串(qemu_pipe / mumuvmm / genymotion / windroyed…),
此前模拟器直接闪退;且服务端对模拟器身份可能单独风控。**不作为主路径**。
## 六、服务端验收闭环(从第一天起就验,避免白做)
- 验收口径:铸出的身份 → 现有**纯代码 dfpReport 设备注册链**`tools/dfp_gen.py` /
`core/huya` 已有零设备注册)+ **现有 WUP 密码登录链**`core/huya/app_login.py`)→
拿到有效 Cookie/登录态 = 服务端接受该身份。
- 关键测试:用**每个账号一套全新虚拟身份**跑完整登录(替换现在全账号共用的金样本
`ed0db8...`),观察:注册是否成功、登录是否放行、滑块/风控是否升级。
- 若服务端只校验"格式/自洽/已注册",铸币路径畅通;若校验设备库真实性,则需评估
深层对抗(那是另一个量级的问题,先实测出结论再投入)。
## 七、推荐执行序列(蓝线)
| 阶段 | 动作 | 依赖 | 产出 |
|---|---|---|---|
| D01~2 天) | E1/E2/E3/E4 真机实验 | 真机 + 稳定通道(现成) | 输入图、种子实测值、差分语料库 |
| D1(并行) | Python 黑盒对拍(§五-A2 | D0 语料 + §2.2 常量 | 是/否命中标准构造 |
| D1(并行) | 路径 BJDK + unidbg + 金测试 | D0 输入图 | 仿真铸币机(保底形态) |
| D2 | 铸币 → 注册 → 登录闭环实测 | D1 任一成果 | 服务端接受度结论 |
| D3 | `device_mint.py` 接入 `app_login.py`(每账号独立设备) | D2 通过 | 生产落地 |
## 八、风险清单
1. 种子含 TEE/Keystore 级硬锚且无再生路径 → 仿真下仍可铸(S 自拟),但服务端可能
拒绝"无对应真实硬件"的身份 → 以第六节实测为准;
2. §2.2 常量为运行时下发替代 → 对拍用真机实测值逐个对账,避免拿死值硬套;
3. qimei 参与 GUID 时,qimei 本身依赖 AndroidID/IMEI → 铸币需把 qimei 一并纳入
虚拟 S(unidbg 下可控);
4. OLLVM 全量反平坦化(数周)**不作为必经路线**——只有黑盒对拍全失败才需要;
5. 服务端风控升级(针对新设备登录的滑块/验证)→ 已有 safe_auth 自动过验能力可兜底。
---
## 九、执行进展(2026-08-28 晚,本次会话落地)
### 9.1 输入图彻底打开(真机 E2 + unidbg 双证)
- **库窗口内系统调用只有三类**:反模拟器 faccessat 探测(qemu/mumu/nox/bluestacks 路径)、
反调试 `/proc/self/task/*/status`(TracerPid)、自身持久化文件检查。**零硬件文件读取**。
- **种子不在属性层**X1 改 `ro.product.*` 全家族、X2 改 IMEI 属性/`ro.boot.cpuid`/serialno
GUID 均不变(与全清数据 E1 一致)。属性只参与上报,不影响 GUID。
- **JNI 面由 unidbg 暴露**`NativeEntry.init()``AppGlobals.currentApplication`
`getSharedPreferences("table")` → **读/写 key: `hydeviceid_config`(服务端下发) `androidId`
(加密态) `old_androidId` `cdid_version` `hydeviceid_guid`** → `NativeBridge.b(102)`(=MID/androidId)
`getDataDir`。getGUID 读 `hydeviceid_guid` → 空则 `WupHelper.getGuid()``NativeBridge.b(100)`
### 9.2 unidbg 金测试通过(决定性)
- 解密 FULL dumpr--+rw- 全段,`phone_dump_hydev_full.py`+ 解密数据合入原文件
`merge_decrypted.py`,unidbg 重定位自会覆盖指针槽)。
- 喂真机种子(ANDROID_ID / hydeviceid_config / NativeBridge.b 实测值):
- **`androidId` pref = `PDSuHxt854IZRR5Y7AGyaQ==` —— 与真机逐字节一致**(采集器 AES 加密可复现)
- **getGUID = `0a7dfaa882938a6ab502511452142c57` —— 与真机一致**
- 工具链:JDK21brew+ unidbgModule 冲突补丁/JDK21、getrlimit/setrlimit 兜底)+ harness
`tools/unidbg/hydev`JNI 桩:NativeBridge.b/klog、Settings.Secure、SharedPreferences 日志化)。
### 9.3 遗留的最后一块(下一轮主攻)
- **`NativeBridge.b(100)` 的原生实现归属库未定**:不在 libhydeviceid(静态无 xref、注册表 23 条
无它)、不在 libudbauthunify(解密 dump 无该串)、不在 libnative-device-util/libjsiwup。
RegisterNatives 长窗口探测全程 0 次命中(时机/环境因素存疑)。当前 harness 用**真机实测值桩**顶替。
- **结论修正**:此前"单机不可铸造/硬锚 SoC"判断错误 —— 实际链路是
`GUID = b(100) = f(androidId加密态, hydeviceid_config(服务端), MID)`,输入全部可控可计算。
- 下一步两条线(任选其一即可闭环铸币):
1. **unidbg 双库/三库加载**:找到并加载 b 原生所在库(可疑:运行期 dex 动态下载的另一个 .so,
需在真机 dlopen 全拦截清单里补齐),让 b(100) 真实计算;
2. **静态还原 b(100) 公式**:基于 (ANDROID_ID→GUID) 差分对拍(unidbg 内改 ANDROID_ID 即可批量
产对),用 .data 密钥(`7jbF5I...`/`HuyaUdb...`/config 解密链)猜 MD5/SHA1/AES 结构。
## 十、Hook 阶段结果(2026-08-28 深夜续)
### 10.1 NativeBridge 归属排查(穷尽运行时手段)
- **动态 JNI 排除**:全模块 `Java_*` 导出扫描,自研库仅 libhypopup/libjsiwup/AI 库有——无
`Java_com_huya_security_hydeviceid_NativeBridge_*`
- **RegisterNatives 排除**:①v7 注册表(23 条)= NativeEntry(19@hydeviceid)+HuyaAuthCore(4@udb)
无 NativeBridge;②dlopen→JNI_OnLoad 拦截各库(hydeviceid/udb0 命中;③健康进程 attach+
重触发 init/getGUIDRN 全程 0 命中。
- **unidbg verbose 实锤**hydeviceid JNI_OnLoad 只 `FindClass(NativeBridge)+NewGlobalRef`(不注册),
udb JNI_OnLoad 只注册 HuyaAuthCoreNativeBridge.b/klog 在 unidbg 内经 JNI 以"未注册 native"
路由到 AbstractJni(桩)。
- **定位到的关键静态物证**hydeviceid .data@0x3e21e4 起为内联方法描述符块
`klog()(L...Z)V``b (I)L..``c (I)J``h ()L..``g (L)L..`、getDataDir/getPath…),
类名字符串 `com/huya/security/hydeviceid/NativeBridge`@0x3e2f20 紧随其后;但代码无任何
ADRP/GOT 引用该页(间接/运行期构建)。完整 {name,sig,fnPtr} 指针表未以静态形式存在。
- **新输入候选**:采集器还读写 `udb_deviceID`/`udb_deviceID_encode`/`oaid`prefs+
`NativeBridge.b(104)`oaid 相关);`Build.*` 静态字段读。
### 10.2 双库 unidbg 已打通但 b 仍未真注册
- libudbauthunifyJNI_OnLoad@0x262620RN 调用点 0x2629bc)解密合并后 unidbg 加载成功;
- merge_decrypted.py 升级为**段驱动**vaddr→文件偏移,支持 .rodata/delta 各段)+ .dynamic 保留
+ .init_array 置零 + 仅重定位槽指针清理(避免误伤字符串);
- 卡点:NativeBridge natives 从未在任何可见路径注册 → b(100) 仍走桩。
### 10.3 设备稳定性注意(重要)
- 反复 `pm clear` + frida attach 探测会清空应用数据(弹协议)并导致 App 闪退;
已确认无 frida 冷启动 App 健康(首页焦点正常)。**后续禁 pm clear、attach 探测收敛**。
### 10.4 静态还原重启点(step-2 方案,全部 PC 侧)
1. **歧义清除**:确认 NativeBridge.b/klog 到底是否 nativedex 反射 isNative,用 SPAWN+bypass
轻探,一次即可);若 native → 在 hydeviceid 代码中用"运行期构建表"模式(构造
{name,sig,fnPtr} 时 ldr 常量页)找注册函数;若 Java → 直接读运行期 dex 里 getGuid/b 逻辑。
2. **oracle 差分**unidbg 侧可控 ANDROID_ID/Settings.Secure 已证明 androidId 密文会变;
b 一旦真注册,`(ANDROID_ID → GUID)` 差分对即可在 unidbg 内批量生成 → MD5/SHA1/AES 对拍。
3. b 的 fnPtr 兜底获取:运行期 dump hydeviceid .data 时同时读 JNINativeMethod 运行期构造表
spawn+bypass 一次抓全,附 base 校验)。
## 十一、静态还原定案(2026-08-29 凌晨,PC 侧完成,无需 SPAWN/真机)
### 11.1 isNative 判定 = 纯 Javadex 直读,比 SPAWN 更硬)
- 工具 `tools/dex_probe_native.py`(dex 解析器)扫全部 18 个 classes*.dex
- `NativeBridge`classes5.dex):`b(I)L..;``a/c/g/h/klog/i1/i2/j` **全部为 Java**(有 code_off),
**无任何 native 方法** —— 10.1 的怪象全部解释:JNI_OnLoad 只 FindClass+NewGlobalRef 是因为
没有任何 native 需要注册;.data@0x3e31e4(vaddr 0x3e41e4) 的描述符块(klog/b/c/h/g/getDataDir/getPath
+类名 com/huya/security/hydeviceid/NativeBridge + com/duowan/biz/wup/WupHelper) =
**native 代码运行期 GetStaticMethodID 反向调用 Java 的 name/sig 常量表**
- `NativeEntry`getGUID/getCDID/getHDID/getMID/getSDID/init 全部 nativecode_off=0RN 19 条已实锤)。
- `NativeBridge.b(I)` = `fj3.c(I)` 分发器(DeviceInfo.java),`b(100)``pnc.c()` → 静态 `pnc.a`
### 11.2 GUID 值流完整还原(GUID ≠ 本地指纹公式!)
- **native getGUID = 纯缓存 getter**unidbg 旧配置金测试实证):
`pref hydeviceid_guid` → 空则 Java `WupHelper.getGuid()``NativeBridge.b(100)` → 回写 pref 并返回。
即 unidbg 金测试的"GUID 一致"= Java 桩直喂 golden 的闭环,**从未验证过本地公式**。
- Java 链(每环唯一调用者/写入者,交叉验证):
```
YYProtoSdkModule.initHuyaUdbSdk (classes17.dex, code@0x3834d0)
→ HyDeviceProxy.j(HY_APPID, WupHelper.getGuid(), mid) (setAppInfoId)
→ pnc.k(guid) → pnc.a
→ NativeBridge.b(100) → fj3.c(100) → pnc.c()
WupHelper.getGuid() (classes12.dex) = ((IHal)hlf.i(IHal.class)).getGuid()
→ HalImpl.getGuid() = sGuidProperty.get()
→ sGuidProperty 仅两处写入: initCache() 与 initialInner 网络回调 →
LiveLaunchRsp.sGuid (live-launch/doLaunch 服务端响应, 32hex 硬校验: 非32位触发 mIllegalGuidCallBack)
```
- **结论修正(推翻 §9.3"GUID=f(androidId密, config, MID)"**:铸币本体不是本地算法,而是
**服务端 doLaunch/device_register 按设备指纹签发 sGuid**。doLaunch 请求携带
`LiveUserbase{tUAEx.sDeviceId(Config 持久化), sIMEI, sMId} + tId(userId.sGuid=当前guid, lUid)}`
响应 `sGuid` 即后续所有登录帧 tag0 的 32hex hdid。
- 与既有认知吻合:旧实验"改 ANDROID_ID/全清数据 GUID 不变"(服务端签发+本地缓存)、
`tools/` 注记"hdid 服务端硬锚/不可铸造"。
### 11.3 新工具(PC 侧,无设备依赖)
- `tools/dex_probe_native.py`dex 类/方法 access_flags 判定(含 class_data fields 跳过修复)。
- `tools/dex_scan_calls.py`:跨 dex 指令级扫描指定方法的调用点(找 setAppInfoId→j() 即用此)。
- 用法:`python3 tools/dex_probe_native.py work/apk_extract` /
`python3 tools/dex_scan_calls.py work/apk_extract Lcom/hy/HyDeviceProxy; j "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"`
### 11.4 unidbg 金测试回归修复(重要教训)
- 症状:新 harness(加入 libudbauthunify 第二库 + 扩展桩)后 getGUID/getCDID/… 全 null
init 阶段 Dynarmic "assertion failed" 崩溃(PC 跳 libc++ 零区)。
- 根因:**C++ locale/facet 路径**`std::locale::use_facet`、`ios_base::getloc` 等)在 unidbg
内置 libc++ 上 ABI 不兼容;第二库加载改变了执行路径触达该处。
- 修复/验证:**14:16 金测试同款 harness(无 udb 第二库,git 70621cf+ 当前 merged so →
getGUID = 0a7dfaa882938a6ab502511452142c57 MATCH**,并首次实证 native 缓存写回流程
WupHelper.getGuid→null → b(100)→golden → prefs-put hydeviceid_guid → return)。
- dump 真实运行基址 = **0x7814200000**(非 probe 记录的 0x7813211000);merge v3 重定位结果
正确(merged = dump - 0x7814200000 = 模块内偏移)。
### 11.5 铸币路径重定义(下一步蓝线)
1. **服务端签发复现**:用现有纯 Python WUP 链(tools/huya_wup_encoder.py 等)构造虚拟设备指纹的
`doLaunch`/`device_register` 请求(deviceId/IMEI/mid 取自虚拟 profile)→ 收 sGuid →
**先验确定性**:同一指纹多次请求 sGuid 是否一致 / sGuid 是否 = f(请求设备字段)。
2. 若确定性签发:`device_mint.py` = 虚拟指纹 → doLaunch → sGuid →(可选 dfpReport 注册)
→ 现有 WUP 登录链验证服务端接受度(用户既有"每账号一套全新虚拟身份"验收口径不变)。
3. 若 sGuid 随机签发(仅库内下发),则评估"锁定身份"的现实等价物:设备指纹→注册→登录
全链路用同一份虚拟 profile 保持一致性,铸币=整套身份模板随机化。
- 真机/未决项:sGuid 签发是否依赖 qimei16/36、hdid/cdid/sdid 上报(采集器还是把设备信息上报
给 dfpReport 侧),这些在 §六 的注册链实测中一并验证。