feat(huya): R32 8密文集+三重钩全零调用定论+known-pair校准

- 8活体POST存 evidence (magic 10B@70 一致, 头同族7cda11)
- 25 JNI + 2 XTEA核 + 2 Java = 全0调用 (报告=隐藏native路径!)
- rtk_known/ 44B known pair (native ct 45542bb3...) 后续差分用
This commit is contained in:
yml2213
2026-08-29 09:01:51 +08:00
parent 08fcf5c34c
commit b76ec96573
8 changed files with 422 additions and 0 deletions
+23
View File
@@ -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!) 1. hook mfa b87_@25c98/27DA4 + ga 27DBC/23DF8 (JNI impl 直挂!) — 关键参数 (byte[], map, mode!)
2. 或: mfa 动态符号/内部调用大范围探 (OLLVM 静态已尽) 2. 或: mfa 动态符号/内部调用大范围探 (OLLVM 静态已尽)
3. 解密器待 key: cprivate.py (Cprivate.a 全等直译) 已就绪 — key 一到即解 3 个新密文! 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 解密器)
Binary file not shown.
Binary file not shown.
+218
View File
@@ -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<Math.min(nargs,7);i++) regs += ' a'+i+'='+args[i].toString(16);
send({event:'nat-ent', name:name, regs:regs});
this.t = Date.now();
},
onLeave: function(ret){
send({event:'nat-ret', name:name, ret:ret.toString(16), dt:Date.now()-this.t});
}
});
} catch(e){ send({event:'nat-fail', name:name, e:String(e).substring(0,80)}); }
}
hookFn(0x20110, 'b209202', 7);
hookFn(0x219d8, 'k209202', 4);
hookFn(0x1f918, 'xtea-enc', 5);
send({event:'nat-hooked'});
} catch(e){ send({event:'nat-exc', e:String(e).substring(0,100)}); }
}, 200);
// ===== 核心: XTEA 核心内部调用钩 — 抓密钥指针! =====
setTimeout(function(){
function findBase(name){
try { return Process.findModuleByName(name); } catch(e){ return null; }
}
function hookXtea(mod, off, name, inOffset){
if (!mod) { send({event:'xtea-nomod', name:name}); return; }
var addr = mod.base.add(off);
try {
Interceptor.attach(addr, {
onEnter: function(args){
try {
// XTEA: a1=buf(输入), a2=±n, a3=key!
var n = args[1].toInt32();
var kp = args[2];
var key = kp.readByteArray(16);
var khex = Array.prototype.map.call(new Uint8Array(key), function(x){return ('0'+x.toString(16)).slice(-2)}).join('');
// buf 头 (inOffset 字节开读: 输入轮回)
var bh = '';
try {
var inb = args[inOffset].readByteArray(8);
bh = Array.prototype.map.call(new Uint8Array(inb), function(x){return ('0'+x.toString(16)).slice(-2)}).join('');
} catch(e){}
send({event:'xtea-got', name:name, n:n, key:khex, bufH:bh});
} catch(e){ send({event:'xtea-err', name:name, e:String(e).substring(0,80)}); }
}
});
send({event:'xtea-hooked', name:name});
} catch(e){ send({event:'xtea-fail', name:name, e:String(e).substring(0,80)}); }
}
hookXtea(findBase('libturingmfa.so'), 0x24D58, 'mfa-xtea', 0);
hookXtea(findBase('libturingga.so'), 0x1F1CC, 'ga-xtea', 0);
}, 200);
// ===== mfa JNI 全族 + ga 全表钩子 =====
setTimeout(function(){
var mfa = Process.findModuleByName('libturingmfa.so');
var ga = Process.findModuleByName('libturingga.so');
var table = [];
if (mfa) table.push(['mfa', mfa, [
[0x25680,'a87_'], [0x25c98,'b87_'], [0x262a8,'c87_'], [0x26418,'d87_'],
[0x26768,'e87_'], [0x26edc,'f87_'], [0x271d0,'g87_'], [0x274c0,'h87_'],
[0x276d0,'i87_'], [0x27a78,'j87_'], [0x27b74,'k87_']
]]);
if (ga) table.push(['ga', ga, [
[0x1fcb8,'a209202'], [0x20110,'b209202'], [0x20574,'c209202'], [0x20688,'d209202'],
[0x20984,'e209202'], [0x20fc4,'f209202'], [0x211e8,'g209202'], [0x21468,'h209202'],
[0x21624,'i209202'], [0x21948,'j209202'], [0x219d8,'k209202'], [0x42d50,'l209202'],
[0x21bdc,'m209202'], [0x43900,'n209202']
]]);
var hooked = 0;
table.forEach(function(t){
var nm = t[0], mod = t[1];
t[2].forEach(function(h){
try {
Interceptor.attach(mod.base.add(h[0]), {
onEnter: function(args){
var r = '';
for (var i=2;i<6;i++) { try { r += ' a'+i+'='+args[i].toString(16); } catch(e){} }
send({event:'jni-ent', f:nm+'/'+h[1], regs:r});
this.t = Date.now();
},
onLeave: function(ret){
send({event:'jni-ret', f:nm+'/'+h[1], ret:ret.toString(16), dt:Date.now()-this.t});
}
});
hooked++;
} catch(e){ send({event:'jni-fail', f:nm+'/'+h[1], e:String(e).substring(0,60)}); }
});
});
send({event:'jni-table', hooked:hooked});
}, 200);
+179
View File
@@ -0,0 +1,179 @@
'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<Math.min(nargs,7);i++) regs += ' a'+i+'='+args[i].toString(16);
send({event:'nat-ent', name:name, regs:regs});
this.t = Date.now();
},
onLeave: function(ret){
send({event:'nat-ret', name:name, ret:ret.toString(16), dt:Date.now()-this.t});
}
});
} catch(e){ send({event:'nat-fail', name:name, e:String(e).substring(0,80)}); }
}
hookFn(0x20110, 'b209202', 7);
hookFn(0x219d8, 'k209202', 4);
hookFn(0x1f918, 'xtea-enc', 5);
send({event:'nat-hooked'});
} catch(e){ send({event:'nat-exc', e:String(e).substring(0,100)}); }
}, 200);
// ===== 核心: XTEA 核心内部调用钩 — 抓密钥指针! =====
setTimeout(function(){
function findBase(name){
try { return Process.findModuleByName(name); } catch(e){ return null; }
}
function hookXtea(mod, off, name, inOffset){
if (!mod) { send({event:'xtea-nomod', name:name}); return; }
var addr = mod.base.add(off);
try {
Interceptor.attach(addr, {
onEnter: function(args){
try {
// XTEA: a1=buf(输入), a2=±n, a3=key!
var n = args[1].toInt32();
var kp = args[2];
var key = kp.readByteArray(16);
var khex = Array.prototype.map.call(new Uint8Array(key), function(x){return ('0'+x.toString(16)).slice(-2)}).join('');
// buf 头 (inOffset 字节开读: 输入轮回)
var bh = '';
try {
var inb = args[inOffset].readByteArray(8);
bh = Array.prototype.map.call(new Uint8Array(inb), function(x){return ('0'+x.toString(16)).slice(-2)}).join('');
} catch(e){}
send({event:'xtea-got', name:name, n:n, key:khex, bufH:bh});
} catch(e){ send({event:'xtea-err', name:name, e:String(e).substring(0,80)}); }
}
});
send({event:'xtea-hooked', name:name});
} catch(e){ send({event:'xtea-fail', name:name, e:String(e).substring(0,80)}); }
}
hookXtea(findBase('libturingmfa.so'), 0x24D58, 'mfa-xtea', 0);
hookXtea(findBase('libturingga.so'), 0x1F1CC, 'ga-xtea', 0);
}, 200);
+1
View File
@@ -0,0 +1 @@
ET+³ Ñ<HŒ1ˆVmåŠ_DÙ¹á‹û"¤æQÊÛ>3ãõ±ÖÞýýRˆõ^Å
+1
View File
@@ -0,0 +1 @@
^x03ĺȩ%g~:
Binary file not shown.