diff --git a/docs/HUYA_HDID_ALGORITHM_GEN.md b/docs/HUYA_HDID_ALGORITHM_GEN.md index 27d002d..918037d 100644 --- a/docs/HUYA_HDID_ALGORITHM_GEN.md +++ b/docs/HUYA_HDID_ALGORITHM_GEN.md @@ -1504,3 +1504,26 @@ full: 7c da | 11 | 69 c9 f5 28 9c 4d 46 | 95 6f 21 | 10 bb 80 1. hook mfa b87_@25c98/27DA4 + ga 27DBC/23DF8 (JNI impl 直挂!) — 关键参数 (byte[], map, mode!) 2. 或: mfa 动态符号/内部调用大范围探 (OLLVM 静态已尽) 3. 解密器待 key: cprivate.py (Cprivate.a 全等直译) 已就绪 — key 一到即解 3 个新密文! + +## §11.63 R32: 8 密文集 + 全钩零调用定论 + Java/native 差分 (2026-08-29) + +### 8 密文集 (存 evidence/dfp_live/) +4384/4267/4261/4263/4267/4261/4261/4263...B POSTs + bodies (magic 10B 一致 @70!) +- 0647-0856: 8 个活体 POST (同配方重注册触发!) +- 头部同族: 7cda 11 {session} {cnt} {stable} — 计数位 28/34 递增等 + +### 三重钩全零调用铁证 (原生 25 JNI + XTEA 2 核 + Java 2 钩!) +- mfa 11 JNI (a87_@25680..k87_@27b74) + ga 14 JNI (a209202@1fcb8..n209202@43900) = 全部安装且 0 次触发! +- mfa sub_24D58 + ga sub_1F1CC XTEA 核心 = 0 次! +- Java ga.private(Cprivate).b + Perseus.a = 0 次! +- → 报告密文 = 隐藏 native 路径 (JNI 方法族之外!) + +### Java Cprivate 与 native sub_24D58 差分 +- Java (decompile 直读) = 标准 XXTEA (sum-=DELTA!) +- native (OLLVM 模糊!) — known pair 校准失败 (44B: native ct 45542bb3... vs python 全部变体) +- → native 核心 = 变体 (OLLVM 掩码深处) 或 harness 参数语义差异 (raw-core vs envelope-len-word) +- rtk_known/ 存校准对 — 后续对照用 + +### 下一步 (R33) +1. native 信封/收集器全钩: mfa 2E164/2E250/25234/252EC/34B98/34A00/2E4A4 + ga 1F918/1F9C8/27DBC/27CE0/23DF8! +2. 或用已知对差分出 native 变体的确切公式 (再校验 Java 解密器) diff --git a/evidence/dfp_live/dfpReport_body_0856.bin b/evidence/dfp_live/dfpReport_body_0856.bin new file mode 100644 index 0000000..c0db004 Binary files /dev/null and b/evidence/dfp_live/dfpReport_body_0856.bin differ diff --git a/evidence/dfp_live/dfpReport_post_0856.bin b/evidence/dfp_live/dfpReport_post_0856.bin new file mode 100644 index 0000000..191d82f Binary files /dev/null and b/evidence/dfp_live/dfpReport_post_0856.bin differ diff --git a/tools/frida/hook_jnitab.js b/tools/frida/hook_jnitab.js new file mode 100644 index 0000000..9a3a5f2 --- /dev/null +++ b/tools/frida/hook_jnitab.js @@ -0,0 +1,218 @@ +'use strict'; +function emit(row) { try { send(row); } catch (e) {} } +function btOk(ctx) { try { return Thread.backtrace(ctx, Backtracer.ACCURATE).slice(0, 40).map(a => { const m = Process.findModuleByAddress(a); return m ? m.name + '!' + a.sub(m.base) : a.toString(); }).join(' <- '); } catch (e) { return ''; } } +let fired = false, writes = 0; +for (const mod of Process.enumerateModules()) { + let addr = null; + try { addr = mod.getExportByName('SSL_write'); } catch (e) {} + if (addr === null) continue; + Interceptor.attach(addr, { + onEnter(args) { + writes++; + if (fired) return; + if (writes % 40 === 0) emit({ event: 'ssl-heartbeat', module: mod.name, writes }); + const buf = args[1], num = args[2].toInt32(); + if (num < 60) return; + try { + const u = new Uint8Array(buf.readByteArray(Math.min(num, 30000))); + // 编码成可检索串 (简化: 只查 ascii 子串) + let s = ''; + for (let i = 0; i < u.length; i++) s += (u[i] >= 32 && u[i] < 127) ? String.fromCharCode(u[i]) : '.'; + if (s.indexOf('dfpReport') < 0 && s.indexOf('hyudbwebuif') < 0) return; + fired = true; + const hex = Array.from(u).map(x => x.toString(16).padStart(2, '0')).join(''); + emit({ event: 'str-magic', module: mod.name, num, full: hex, bt: btOk(this.context) }); + // ---- co-located: 命中后立即在 turing 区域 + 全堆扫第二处魔数/明文特征 ---- + const MAG = [0x57, 0x18, 0x82, 0xcf, 0x66, 0x4b, 0xb3, 0x94, 0x01, 0xee]; + setTimeout(() => { + try { + const regions = []; + for (const m of Process.enumerateModules()) { + if (/turing|Turin/.test(m.name)) regions.push({ name: m.name, p: m.base, n: Math.min(m.size, 2 * 1024 * 1024) }); + } + // 附加: 加载库里的映射区域 (含 .turing.dat mmap) — 用 Process.enumerateRanges 'r--' 太广, 只挑 map 文件路径含 turing 的 + for (const r of Process.enumerateRanges('r--')) { + try { + const f = r.file ? r.file.path : ''; + if (/turing|\.dat/.test(f) && !/\.so/.test(f)) regions.push({ name: f.slice(-40), p: r.base, n: Math.min(r.size, 512 * 1024) }); + } catch (e) {} + } + let nFound = 0; + for (const rg of regions) { + try { + const buf = new Uint8Array(rg.p.readByteArray(rg.n)); + for (let i = 0; i + 10 < rg.n; i++) { + let ok = true; + for (let j = 0; j < 10; j++) if (buf[i+j] !== MAG[j]) { ok = false; break; } + if (!ok) continue; + nFound++; + if (nFound > 12) break; + // 邻域 ASCII 提取 + const as = []; + for (let k = -128; k < 1024; k += 64) { + try { + const c = Array.from(new Uint8Array(rg.p.add(i + k).readByteArray(64))); + const str = c.map(x => (x >= 32 && x < 127) ? String.fromCharCode(x) : '.').join(''); + if (/[A-Za-z0-9_\-\.\/:]{10,}/.test(str)) as.push({ k, s: str }); + } catch (e) {} + } + emit({ event: 'co-magic', mod: rg.name, off: '0x' + i.toString(16), ascii: as.slice(0, 10) }); + } + } catch (e) {} + } + emit({ event: 'co-done', n: nFound, regions: regions.length }); + } catch (e) { emit({ event: 'co-err', msg: String(e).slice(0, 120) }); } + }, 0); + } catch (e) {} + }, + }); + emit({ event: 'ssl-hooked', module: mod.name }); +} + +// ===== 附加: Java 密钥钩子 (Cprivate.b 明文+密钥 / Perseus.a 会话密钥) ===== +setTimeout(function(){ + function S(o){ try { send(o); } catch(e){} } + try { + Java.perform(function(){ + var hooked = 0; + try { + var Cpr = null, Melon = null; + Java.enumerateClassLoaders({ + onMatch: function(loader){ + try { + Java.classFactory.loader = loader; + var c = Java.use('com.tencent.turingfd.sdk.ams.ga.private'); + if (c) { Cpr = c; Melon = Java.use('com.tencent.turingfd.sdk.ams.ga.Melon'); } + } catch(e){} + }, + onComplete: function(){} + }); + if (!Cpr) { Cpr = Java.use('com.tencent.turingfd.sdk.ams.ga.private'); Melon = Java.use('com.tencent.turingfd.sdk.ams.ga.Melon'); } + var Melon = Java.use('com.tencent.turingfd.sdk.ams.ga.Melon'); + Cpr.b.overload('[B','[B').implementation = function(a, b){ + var out = this.b(a, b); + try { + S({event:'cpr-b', dlen:a.length, klen:b.length, + key:Melon.a(b), dhead:(Melon.a(a)||'').substring(0,300)}); + } catch(e){ S({event:'cpr-err', e:String(e)}); } + return out; + }; + hooked++; + } catch(e){ S({event:'cpr-nohook', e:String(e).substring(0,120)}); } + try { + var Perseus = Java.use('com.tencent.turingfd.sdk.ams.ga.Perseus'); + var Guava = Java.use('com.tencent.turingfd.sdk.ams.ga.Guava'); + Perseus.a.implementation = function(){ + this.a(); + try { + var g = this.b.value; + if (g) S({event:'perseus-key', c:g.c.value, b1:g.a.value, blen: g.b.value ? g.b.value.length : -1}); + } catch(e){} + }; + hooked++; + } catch(e2){ S({event:'cpr-noperseus', e:String(e2).substring(0,120)}); } + S({event:'cpr-installed', hooked:hooked}); + }); + } catch(e) { S({event:'cpr-perm', e:String(e).substring(0,120)}); } + }, 200); + +// ===== native 实参钩子: ga b209202(0x20110) / k209202(0x219d8) — 抓 16B 块输入! ===== +setTimeout(function(){ + try { + var mod = Process.findModuleByName('libturingga.so'); + if (!mod) { send({event:'nat-nomod'}); return; } + function hookFn(off, name, nargs){ + var addr = mod.base.add(off); + try { + Interceptor.attach(addr, { + onEnter: function(args){ + var regs = ''; + for (var i=2;i { const m = Process.findModuleByAddress(a); return m ? m.name + '!' + a.sub(m.base) : a.toString(); }).join(' <- '); } catch (e) { return ''; } } +let fired = false, writes = 0; +for (const mod of Process.enumerateModules()) { + let addr = null; + try { addr = mod.getExportByName('SSL_write'); } catch (e) {} + if (addr === null) continue; + Interceptor.attach(addr, { + onEnter(args) { + writes++; + if (fired) return; + if (writes % 40 === 0) emit({ event: 'ssl-heartbeat', module: mod.name, writes }); + const buf = args[1], num = args[2].toInt32(); + if (num < 60) return; + try { + const u = new Uint8Array(buf.readByteArray(Math.min(num, 30000))); + // 编码成可检索串 (简化: 只查 ascii 子串) + let s = ''; + for (let i = 0; i < u.length; i++) s += (u[i] >= 32 && u[i] < 127) ? String.fromCharCode(u[i]) : '.'; + if (s.indexOf('dfpReport') < 0 && s.indexOf('hyudbwebuif') < 0) return; + fired = true; + const hex = Array.from(u).map(x => x.toString(16).padStart(2, '0')).join(''); + emit({ event: 'str-magic', module: mod.name, num, full: hex, bt: btOk(this.context) }); + // ---- co-located: 命中后立即在 turing 区域 + 全堆扫第二处魔数/明文特征 ---- + const MAG = [0x57, 0x18, 0x82, 0xcf, 0x66, 0x4b, 0xb3, 0x94, 0x01, 0xee]; + setTimeout(() => { + try { + const regions = []; + for (const m of Process.enumerateModules()) { + if (/turing|Turin/.test(m.name)) regions.push({ name: m.name, p: m.base, n: Math.min(m.size, 2 * 1024 * 1024) }); + } + // 附加: 加载库里的映射区域 (含 .turing.dat mmap) — 用 Process.enumerateRanges 'r--' 太广, 只挑 map 文件路径含 turing 的 + for (const r of Process.enumerateRanges('r--')) { + try { + const f = r.file ? r.file.path : ''; + if (/turing|\.dat/.test(f) && !/\.so/.test(f)) regions.push({ name: f.slice(-40), p: r.base, n: Math.min(r.size, 512 * 1024) }); + } catch (e) {} + } + let nFound = 0; + for (const rg of regions) { + try { + const buf = new Uint8Array(rg.p.readByteArray(rg.n)); + for (let i = 0; i + 10 < rg.n; i++) { + let ok = true; + for (let j = 0; j < 10; j++) if (buf[i+j] !== MAG[j]) { ok = false; break; } + if (!ok) continue; + nFound++; + if (nFound > 12) break; + // 邻域 ASCII 提取 + const as = []; + for (let k = -128; k < 1024; k += 64) { + try { + const c = Array.from(new Uint8Array(rg.p.add(i + k).readByteArray(64))); + const str = c.map(x => (x >= 32 && x < 127) ? String.fromCharCode(x) : '.').join(''); + if (/[A-Za-z0-9_\-\.\/:]{10,}/.test(str)) as.push({ k, s: str }); + } catch (e) {} + } + emit({ event: 'co-magic', mod: rg.name, off: '0x' + i.toString(16), ascii: as.slice(0, 10) }); + } + } catch (e) {} + } + emit({ event: 'co-done', n: nFound, regions: regions.length }); + } catch (e) { emit({ event: 'co-err', msg: String(e).slice(0, 120) }); } + }, 0); + } catch (e) {} + }, + }); + emit({ event: 'ssl-hooked', module: mod.name }); +} + +// ===== 附加: Java 密钥钩子 (Cprivate.b 明文+密钥 / Perseus.a 会话密钥) ===== +setTimeout(function(){ + function S(o){ try { send(o); } catch(e){} } + try { + Java.perform(function(){ + var hooked = 0; + try { + var Cpr = null, Melon = null; + Java.enumerateClassLoaders({ + onMatch: function(loader){ + try { + Java.classFactory.loader = loader; + var c = Java.use('com.tencent.turingfd.sdk.ams.ga.private'); + if (c) { Cpr = c; Melon = Java.use('com.tencent.turingfd.sdk.ams.ga.Melon'); } + } catch(e){} + }, + onComplete: function(){} + }); + if (!Cpr) { Cpr = Java.use('com.tencent.turingfd.sdk.ams.ga.private'); Melon = Java.use('com.tencent.turingfd.sdk.ams.ga.Melon'); } + var Melon = Java.use('com.tencent.turingfd.sdk.ams.ga.Melon'); + Cpr.b.overload('[B','[B').implementation = function(a, b){ + var out = this.b(a, b); + try { + S({event:'cpr-b', dlen:a.length, klen:b.length, + key:Melon.a(b), dhead:(Melon.a(a)||'').substring(0,300)}); + } catch(e){ S({event:'cpr-err', e:String(e)}); } + return out; + }; + hooked++; + } catch(e){ S({event:'cpr-nohook', e:String(e).substring(0,120)}); } + try { + var Perseus = Java.use('com.tencent.turingfd.sdk.ams.ga.Perseus'); + var Guava = Java.use('com.tencent.turingfd.sdk.ams.ga.Guava'); + Perseus.a.implementation = function(){ + this.a(); + try { + var g = this.b.value; + if (g) S({event:'perseus-key', c:g.c.value, b1:g.a.value, blen: g.b.value ? g.b.value.length : -1}); + } catch(e){} + }; + hooked++; + } catch(e2){ S({event:'cpr-noperseus', e:String(e2).substring(0,120)}); } + S({event:'cpr-installed', hooked:hooked}); + }); + } catch(e) { S({event:'cpr-perm', e:String(e).substring(0,120)}); } + }, 200); + +// ===== native 实参钩子: ga b209202(0x20110) / k209202(0x219d8) — 抓 16B 块输入! ===== +setTimeout(function(){ + try { + var mod = Process.findModuleByName('libturingga.so'); + if (!mod) { send({event:'nat-nomod'}); return; } + function hookFn(off, name, nargs){ + var addr = mod.base.add(off); + try { + Interceptor.attach(addr, { + onEnter: function(args){ + var regs = ''; + for (var i=2;i3R^ \ No newline at end of file diff --git a/tools/unidbg/hydev/rtk_known/key.bin b/tools/unidbg/hydev/rtk_known/key.bin new file mode 100644 index 0000000..27c18ed --- /dev/null +++ b/tools/unidbg/hydev/rtk_known/key.bin @@ -0,0 +1 @@ +^x03ĺȩ%g~: \ No newline at end of file diff --git a/tools/unidbg/hydev/rtk_known/pt.bin b/tools/unidbg/hydev/rtk_known/pt.bin new file mode 100644 index 0000000..932f433 Binary files /dev/null and b/tools/unidbg/hydev/rtk_known/pt.bin differ