Files
live-hub-py/docs/dfpReport破解进度.md
T
2026-08-26 18:28:33 +08:00

16 KiB
Raw Blame History

dfpReport 破解进度总结 (待破解#2)

当前状态:加密算法已确定为逐字节 XOR keystream(非 XXTEA),明文 JSON 已全部拿到。 剩余关键问题:keystream 每会话动态生成,需找到其生成函数/种子。 IDA 已导出两个 so 的完整反编译+反汇编:/Users/yml/Downloads/so/{libhydeviceid,libudbauthunify}.so_export_for_ai


一、已确定的结论(铁证)

1. dfpReport 加密 = 逐字节 XOR keystream(不是 XXTEA!)

证据链:

  • 同会话 5 次 dfpReport(wire 间隔 3-6s),密文两两 XOR 非零位置 3947/3984 → keystream 每会话动态
  • 密文前 10B 魔数恒定 57 18 82 cf 66 4b b3 94 01 ee(跨天、跨会话)→ 魔数是明文头 XOR 固定值或者固定前缀
  • 8.23 各样本位置 11-22 部分相同 → 是明文固定字段,不是 keystream 泄漏
  • 若为 XXTEA(hyudbxxt),则密文任何字节变化会扩散到全部 → 但实测前 10B 不动 → 排除 XXTEA

2. tag2 密文结构(3984B)

tag2 = [魔数 10B][XOR密文 3974B?]
  • 明文 ≈ JSON(554B) + 采集二进制(3420B) ≈ 3974B,与"密文长度-魔数"吻合
  • 但注意:3954B 对齐实验(偏移 0..9 all ~1% 相同率)未找到明文精确起点 → 加密输入可能不是纯 JSON,JSON 只是其中一部分(pa 结构待最终确认)

3. 明文 JSON 完整捕获(554B,可铸造)

{"appId":"5008","appVer":"13.4.22","appkey":"865a4924a40897ac1fcfe6b4c2cbb0e3",
 "channel":"xiaomi","deviceId":"02df398797432eadefcc12767119ad5e80999389",
 "deviceName":"M2102J2SC","hdid":"7c5387e0539c023c31c4ff0e807e7256117385ee",
 "heightPixels":"2120","isCloud":0,"isForbidLog":1,"isHome":0,"isPre":0,"openAppId":"",
 "savePath":"/data/user/0/com.duowan.kiwi/files/huyaudb","sdkVer":"1.0.80138",
 "servantName":"huyaudbwebui","shareAppDataPath":"/data/user/0/com.duowan.kiwi/files/huyaudb",
 "systemInfo":"android","systemVer":"M2102J2SC,30,11","terminalType":1,"testEnv":0,"widthPixels":"1080"}
  • hdid 字段 = 服务端返回的 device_id (t5) 7c5387... → 服务端回显本地明文,本地可完全控制设备身份!
  • appkey 865a...cbb0e3 ≠ 静态 t1 865a...cbb045 → appkey 来自运行时配置

4. 响应回显验证(t1/t5 本地可铸造)

  • 重放任意 wire body → HTTP 200,344B 响应,同一 t1+t5,全新 t2
  • t1(865a4924a40897ac1fcfe6b4c2cbb045) 静态埋于 libhydeviceid .data(0x3bb190, 0x3bb230, 0x3e0e50),datadiv 加载时解密
  • patch 明文实验:改明文 JSON 的 hdid/appkey/deviceId(等长替换)后 app 崩溃 → 说明有校验或时序问题,但方向正确(见下"待办")

5. keystream 前 24B(从 5 组同步 pair 恢复)

# 修正对齐 off=0 (密文[10:] XOR 明文[0:]):
t=1379: 07 f8 60 f9 b8 bc 30 bf 76 4e d4 8d a8 f6 54 21 31 fa 47 53 72 63 ef 29
t=7268: 17 f9 70 e5 b8 3c 6c be 77 e6 ac cb c3 2a 6a 8c ef aa cd ce eb e5 67 a7
t=3695: 17 f9 70 f9 b1 3c 4c be 77 74 14 ee 5e 7c e0 88 3a e2 c3 2c 72 63 8c 10
...

各会话 keystream 不同 → 动态生成,极可能种子 = 时间戳或会话随机 + 固定密钥


二、IDA 导出可用资源(用户新提供,重点!)

/Users/yml/Downloads/so/libhydeviceid.so_export_for_ai/
  decompile/     # 3895 个 C 反编译
  disassembly/   # 逐函数汇编
  exports.txt    # 1832 个导出 (含 70 个 .datadiv_decode)
  function_index.txt, strings.txt, memory/...
/Users/yml/Downloads/so/libudbauthunify.so_export_for_ai/
  decompile/252700.c  # hyudbxxt::xxtea_encrypt 标准 XXTEA (dfp 无关,登录用)

优先排查的加密函数:

  • decompile/1107CC.c 引用 0x5718 魔数常量 ×3!(sub_1107CC,调用者 0xa6a3c)← 最可疑是真加密/解密函数
  • decompile/1D52C8.c1D5844.c294FB0.c7BF8C.c 也含 0x5718
  • 大 XOR 循环候选:17F75C, 212B04, 21F98C, 2332D4, 23755C, 23C534, 26D7B0, 274BBC, B5A18

三、动态 hook 关键资产

抓同步 (明文, 密文) 对 —— 已成功!

scripts/capture_pair_sync.py:spawn+bp3 绕过 → SSL_write 命中 dfpReport 时 80ms 后全内存扫描 {"appId":"5008" → 同时刻明文。5 组同步 pair 在 evidence/dfp_pair_sync.json

环境

  • RE repo venv: /Users/yml/codes/Reverse-Engineering-Agent-Universal-v3.0/.venv/bin/python -u
  • 远程 frida: adb forward tcp:31877 tcp:31877 + frida.get_device_manager().add_remote_device("127.0.0.1:31877")
  • 绕过:spawn 后先 bypass_msaoaid_maps_art_callsite.js + mask_frida_maps_only.js → resume → 11s 后 patch_guard_block_termination.js
  • hook 规则:后台任务 + tail 实时看 + 命中即 pkill(见 docs/Hook脚本运行与捕获约定.md)

四、下一步行动(按优先级)

  1. 读 IDA 反编译确认加密:重点 decompile/1107CC.c(引用 0x5718!)及其调用者链 0xa6a3c → 找 keystream 生成函数(输入时间戳/随机种子 + 固定 key,输出 3974B 流)
  2. hook 加密函数:定位后 hook,抓 (明文输入, key/种子, 密文输出) 三元组 → 直接复现纯 Python 加密
  3. 验证 keystream 种子假设:比对 5 组 keystream 的 Δ 与 wire 时间戳 Δ(3-6s 间隔,keystream 差异是否对应计数/时间)→ 若种子=时间戳,纯代码可复现
  4. patch 明文实验修复:上次改明文崩溃可能因 datadiv 重解码或时序;改用 hook 加密函数输入 buffer 后直接改明文再放行,避免物理内存写
  5. 最终目标:纯 Python 生成 dfpReport 请求体 = 构造明文 JSON(改 hdid/deviceId/appkey 铸造新设备) + 魔数 + 复现 keystream 加密 → 重放得到全新 t1/t5

五、账号/数据资产

  • 账号 hy_300026595 / aa778899(老 ref hy_300024708)
  • HAR:/Users/yml/Desktop/抓包/hy/8.23/登录-{1,2,3,5}.har(6 个 dfpReport wire,t2 len 3408-4237)
  • 同一设备(小米 M2102J2SC, Android 11, 快照 5dd8c93f)所有 wire 魔数头相同
  • 关键回显:hdid 7c5387e0539c023c31c4ff0e807e7256117385ee = 明文 hdid = 响应 t5

六、关键文件索引

文件 内容
evidence/dfp_pair_sync.json 5 组同步 (密文+明文) pair(最新最有价值)
evidence/dfp_pair.json 早期 3 组 pair(wire len 4278/4397/4413)
evidence/dfp_wire_stack.json 8 事件 5 dfpReport wire HEX
evidence/dfp_plain_big.json 187 个堆命中(明文 JSON @0x7814096d19 等)
evidence/dfp_datadiv_full.json .data 7895 个已解码字符串(t1 所在)
scripts/capture_pair_sync.py 同步 pair 抓取脚本(可复用)
/Users/yml/Downloads/so/libhydeviceid.so_export_for_ai/ IDA 反编译(新!)

七、新会话起点(最重要的下一步)

IDA 反编译确认加密:/Users/yml/Downloads/so/libhydeviceid.so_export_for_ai/decompile/1107CC.c

  • 引用 0x5718 魔数 ×3,调用者 0xa6a3c → 极可能是 dfpReport 加解密核心
  • 同时看:1D52C8.c, 1D5844.c, 294FB0.c, 7BF8C.c(均含 0x5718)
  • 反汇编对应文件在 disassembly/.asm

验证 keystream 种子:evidence/dfp_pair_sync.json 有 5 组同步 pair, 两组 keystream 差 vs 时间戳差 → 判断种子是否时间戳/计数器。


八、本会话重大发现(新!)

1. 输入结构确定: [恒定JSON 554B][collection ~3400B 每轮变化]

  • 恒定 JSON(554B,已有全部字段,含 hdid/deviceId):{"appId":"5008",...,"widthPixels":"1080"}
  • collection 是大 JSON:{"touch_events":[...],"net_intfs":"...","phoneInfo":"{...}","qimei16/36":"...","risk_apps":"com.topjohnwu.magisk|bin.mt.plus|","scanned_appname":"<binary ~2900B>",...}
  • collection 尾部含 Poseidon 反 frida 检测字段:"Poseidon_D1":"libhydeviceid.so|hooked:libhydeviceid.so|hooked:libc.so|", Poseidon_D3:"zygisk|", Poseidon_D5:"/product/bin/su\n|", adb_input_list:"device_name=Virtual|"(huyaudb 读 /proc/self/maps 检测 hook)
  • collection 每轮变化(触摸事件/权限/网络/反检测结果/扫描二进制)

2. keystream 每轮变化,但跨轮/跨会话有强共享结构(非纯随机!)

多 session(6+ 个 pipeline 证据文件)9+ 轮 ks[0..553]=cipher[:554]^JSON 分析:

  • 跨会话模板复用:相同 10B 前缀在多个独立 session 反复出现!
    • 07f970f9b8bc50be774e ×3(155601-r1, 160316-r1, 160316-r2)
    • 17f97019b93c6cbe7764 ×3(155601-r3, 160316-r3, 160855-r2, 170031-r2)
    • 17f97ef9b83c6cbe774a ×3(args session 多轮)
    • 07f870f9b8bc50be774e ×2(v2)
  • 同一 session 连续轮次可完全相同(160316: r1 = r2 = 07f970f9b8bc50be774e)
  • 每位置 ks 值域很小:8 轮样本中大部分位置只有 28 个不同值(随机期望 8),前 6 字节仅 23 个值
  • 高共享对:r2(160855,t=18273) vs r5(170031,t=100816) 共享 140/554B(25%;随机期望 0.4%),最长连续 20B;r0 vs r4 共享 80B
  • 结论:keystream 不是每会话随机种子动态生成,而更像 固定模板库 + 状态选择(生成器需进一步确认,但"所有字节每轮全新随机"的假设被推翻)

3. 反 frida 检测: hook 了 libhydeviceid 的事件, collection JSON 的 Poseidon 字段值相应变化(每轮检测结果不同)

4. 骨架 pipeline hook 已稳定(轻量,符合约定)

  • scripts/hook_dfp_pipeline.py 只 hook 6 函数(topA_20e924/midA_5a938/cryptoA_5b1f4/copy_61098/pktA_7f744/pktB_92128)
  • 必须遵守 hook 约定:spawn → bypass x2 → resume+11s → patch_guard → 最后加载主 hook JS(顺序颠倒会卡启动界面,已踩坑多次)
  • 事件每轮:copy_61098 ×2(MAGIC 缓冲)、pktA/pktB(MAGIC + taf 段)、wire(密文全长)、jsonhits(内存搜 JSON 完整 554B)
  • GOT 桩方案已放弃:144 个 br x17 桩 hook 太重,App 卡启动/卡点击(动态间接调用表 0x3ba000/0x3b9000 运行时才解密,静态也解不出)

5. 本地 capstone 反汇编(ELF vaddr==fileoff)

  • cryptoA_5b1f4: 16 个 bl 目标(0x5f1b4 首调、0x45aa0×26、0x76ab0×9、0x461c0×6、0x6ec68×4、0x7398c×3、0x1f07ec×2…)
  • 0x461c0/0x45aa0 = 间接调用桩(adrp x16;ldr x17,[x16,#off];br x17),GOT 表运行时解密失败静态解析
  • 0x5f1b4 = 字符串构建函数(状态机混淆),非生成器;cryptoA 主体无标量/NEON XOR 循环 → XOR 内核在间接调用或查表中

6. 下一步(铸造路线评估,优先!)

  • 服务端旧结论:重放任意 wire body → HTTP 200,hdid/device_id = 明文回显
  • 若 keystream 真是模板库,铸造新设备 = 改明文 JSON(hdid/deviceId) + 复用任意一轮 keystream XOR → 重放
  • 行动:纯 Python 构造新设备 t2(改明文 + 模板 ks)重放验证 200 → 若成功,铸造路线打通,生成器破解降级为可选

九、铸造路线实验(本会话最新,部分成功!)

1. 纯 Python 重放 100% 可行(不需要 keystream!)

  • scripts/forge_replay.py:取证据里一帧完整 wire → 重构 HTTP/1.1 POST(Content-Length 等长) → socket+TLS 直连 wsapi.huya.com:443原样重放返回 HTTP/1.1 200 OK + 344B 响应(稳定复现)
  • XOR 自反性铸造:新密文 = 原密文 XOR (原JSON XOR 新JSON),JSON 区(554B)等长替换 hdid/deviceId/appkey,collection 区不动 → 不需要 ks、不需要生成器、不需要设备!
  • 服务端确实解析 t2 明文(见下),不是纯透传 200

2. 响应结构(344B taf/wup 包)

  • 4B 总长 + 头 + huyaudbwebui dfpReport + 字段:
    • t1 (tag22): 865a4924a40897ac1fcfe6b4c2cbb045 + & + base64(~43B,每次变化,像会话加密数据)
    • tag70: actionV(<40hex> (设备标识回显)
  • 40hex 之后有 taf 尾字段(0x0b 8c... 未解析)

3. 服务端行为(受控实验)

请求 actionV(40hex)
baseline 原样 7c5387e0...17385ee(= 明文 hdid!)
只改 hdid 新值(≠ 新 hdid,每次实验都不同)
只改 deviceId 新值(≠ 新 deviceId)
用 actionV1 当 hdid 再上报 又一个新值(不稳定)
  • actionV 对 hdid/deviceId 变化均敏感 → 服务端解密解析了 t2 明文
  • baseline 时 actionV == 明文 hdid(服务端回显/认可当前设备)
  • 改身份后 actionV 每次都是新值且不稳定 → 未确认"下发新设备身份"机制,可能 actionV 含时间戳/会话随机,或需配合后续登录流程

4. 待验证决策点

  1. actionV 是否 = HMAC/带时间戳编码(需要多次同明文请求对照:两次同明文 → actionV 相同则与明文确定性相关;不同则含随机)
  2. 需要抓完整登录流程(登录请求也用同一 hdid?)确认铸造出的新身份能否通过登录
  3. 若 actionV 含随机/时间戳 → 服务端可能靠 t1 或其它字段做设备绑定 → 需重新审视铸造入口

十、29 轮 keystream 全量分析(决定性结论!)

合并 6+ session、29 轮 ks[0..553] 分析:

1. keystream 前缀模板复用(铁证)

17f97019b93c6cbe7764  x4: 160316r3, 160855r2, 170031r2, 175740r2   ← 4 个不同 session 同轮次位置!
07f970f9b8bc50be774e  x3: 155601r1, 160316r1, 160316r2
17f97ef9b83c6cbe774a  x3: args.j r3/4/5
07f870f9b8bc50be774e  x2: v2 r1/r2
  • 完整 10B 前缀跨 session 精确重复,不是随机

2. 同 session 完全重复

  • args.j r3 = r4 = r5: ks[0..553] 全部 554 字节相同!(shared=554)
  • v2 r1≈r2(51 共享),160316 r1≈r2(36 共享)

3. 高共享对(跨 session)

  • 160855r2 vs 170031r2: 140/554 共享,最长连续 20B
  • 170031r3 vs 175740r3: 97 共享
  • 170031r2 vs 175740r2: 70 共享,最长连续 31B
  • 160855r1 vs 160855r4: 80 共享(同 session 首尾)

4. 结论

  • keystream 与"轮次序号/状态"强相关,同一序号位置在多个 session 复用相同(或高相似)ks
  • 不是每 session 随机种子;更像 固定生成器 + 状态/序号选择(同轮次位置 → 同 ks)
  • 对铸造的含义:任意一帧真实 ks 即可加密伪造明文(服务端行为见下节,这是关键限制)

5. 服务端铸造验证(forge_replay.py 实测,重要!)

  • 原样重放:HTTP 200,344B 响应稳定,actionV = 7c5387...(= 真 hdid,稳定回显)
  • 改明文 JSON 任何身份字段(hdid/deviceId/appkey):200 OK,但 actionV 变为 [32hex 类MD5] + "10" + [6hex] 动态 token,同明文两次上报 token 不同
  • 响应 t1(tag22)恒定 865a4924a40897ac1fcfe6b4c2cbb045&base64(base64 部分每次变化)
  • 推论:服务端识别"真设备"靠 明文三元组 (hdid, deviceId, appkey) 与库匹配; 纯改明文不匹配 → 动态 token → 铸造新设备需同时伪造三元组一致的完整设备身份 (可能还要 collection 里 qimei/device_id 对应)否则服务端不认可

6. 下一步两个方向

A. 铸造:找出服务端设备三元组的匹配逻辑(抓真实 App 首次注册流程/或抓登录后的完整身份链), 纯 Python 全真伪造(JSON+collection 齐改)重放验证 actionV 稳定性 B. 生成器:既然 ks 与轮次序号相关,继续定位生成函数(0x5f1b4 初始化 + cryptoA 调用链), 复现 keystream 生成,任意轮次任意长度可算


十一、服务端设备绑定校验(差分实验定论!)

对 t2 密文做逐区差分修改重放,观察服务端响应:

修改内容 actionV 结果
baseline 原样 稳定回显真 hdid 7c5387...
JSON 非身份字段(widthPixels 1080→1081) 稳定回显真 hdid(不受影响!)
JSON 身份字段 hdid 动态 token [MD5样式32hex]10[6hex],每次不同
JSON 身份字段 deviceId 动态 token
JSON 身份字段 appkey 动态 token
collection 区任意 1 字节(@560/@617/@753/@953 等) 动态 token(波及全 collection)

结论:服务端绑定校验 = (hdid, deviceId, appkey 三元组) + (collection 完整性)

  • 服务端解密 t2 → 解析 JSON 三元组 + collection → 与库中设备匹配 → 匹配则回显设备 hdid,不匹配则返回动态 token
  • 动态 token 不可复用(同明文两次上报不同)→ 不是"注册下发",更像"未知设备拒绝标记"
  • 铸造的真正瓶颈不是加密(已破解),而是服务端以 (三元组, collection) 识别设备
  • collection 含 qimei16/36、scanned_appname 等指纹 → 需与三元组自洽才能被服务端认可

后续(铸造完整方案待定)

  1. 抓真实 App 首次注册/重置设备后的第一帧 dfpReport(看服务端如何初始分配设备 id)
  2. 或逆向 collection 的指纹算法(哪些字段参与绑定)
  3. 验证"设备上等长 patch hdid + App 自行生成 t2"路线(修复 patch 崩溃:可能因 JSON 长度校验/内存写坏)