feat(huya): 🏆 appSign(t1.t0)算法完全破解 — ed0db8逐字节复现 (R15)
公式: appSign = MD5(appId + '_' + appVersion + '_' + k1)
金样本: MD5('5008_13.4.22_865a4924a40897ac1fcfe6b4c2cbb0e3') = ed0db8334cadd236c00cadf7e11ab5a5 ✅
发现链路: createWupProtoInfo@0x273f1c反汇编 -> HuyaMd5(全局单例3串@0x484000+0xe0) -> frida实机读串(5008/13.4.22/k1) -> toString直出ed0db8 -> python标准md5复现
- 修改: hook_otp_capture.js(+appsign/huya-md5 hook, SSO/LONG修正, tostr-hex/ctor-hex)
- docs §11.45: 完整公式+发现链路+结构性解释+工程意义
This commit is contained in:
@@ -270,4 +270,104 @@ for (const name of ['dlopen', 'android_dlopen_ext']) {
|
||||
});
|
||||
}
|
||||
}
|
||||
setImmediate(install);
|
||||
setImmediate(install);
|
||||
// ---- 辅助 (appsign 段用) ----
|
||||
function readStdString(addr) {
|
||||
try {
|
||||
const flag = addr.readU8();
|
||||
if ((flag & 1) === 0) { // SSO
|
||||
const len = flag >> 1;
|
||||
return len === 0 ? '' : addr.readUtf8String(Math.min(len, 64));
|
||||
}
|
||||
// long (libc++ 经典布局: cap@0-LSB, size@8, data-ptr@16)
|
||||
const size = addr.add(8).readU64();
|
||||
const cap = addr.add(16).readU64();
|
||||
if (size > 1024 * 1024 || cap > 16 * 1024 * 1024) return '<bad:' + size + '>';
|
||||
const data = addr.add(16).readPointer();
|
||||
return size === 0 ? '' : data.readUtf8String(Math.min(size, 4096));
|
||||
} catch (e) { return '<err:' + e.message.slice(0, 30) + '>'; }
|
||||
}
|
||||
function btBrief() {
|
||||
try {
|
||||
return Thread.backtrace(this.context, Backtracer.ACCURATE)
|
||||
.slice(0, 4).map(a => {
|
||||
const m = Process.findModuleByAddress(a);
|
||||
const off = m ? a.sub(m.base) : a;
|
||||
return m ? m.name + '!' + off : a.toString();
|
||||
}).join(' <- ');
|
||||
} catch (e) { return ''; }
|
||||
}
|
||||
|
||||
// ================== appSign 真源 hook ==================
|
||||
// createWupProtoInfo(ProtoInfo&) @0x273f1c — appSign = HuyaMd5(全局单例3串 + "_" 拼接)
|
||||
// 全局单例: base+0x484000+0xe0 → obj; 3 个 std::string @ obj+0x10 / +0x28 / +0x40
|
||||
(function () {
|
||||
const targetName = 'libudbauthunify.so';
|
||||
const mod = Process.findModuleByName(targetName);
|
||||
if (mod === null) return;
|
||||
const offsets = [0x273f1c, 0x273f18]; // createWupProtoInfo 入口(含stp前)
|
||||
const hookAddr = mod.base.add(0x273f1c);
|
||||
Interceptor.attach(hookAddr, {
|
||||
onEnter() {
|
||||
const g = mod.base.add(0x484000 + 0xe0).readPointer();
|
||||
if (g.isNull()) { emit({ event: 'appsign', stage: 'global-null', bt: btBrief() }); return; }
|
||||
const s1 = readStdString(g.add(0x10));
|
||||
const s2 = readStdString(g.add(0x28));
|
||||
const s3 = readStdString(g.add(0x40));
|
||||
emit({
|
||||
event: 'appsign', stage: 'enter',
|
||||
proto: this.context.x0.toString(),
|
||||
g3: s3, g2: s2, g1: s1,
|
||||
joined: (s3 || '') + '_' + (s2 || '') + '_' + (s1 || ''),
|
||||
bt: btBrief(),
|
||||
});
|
||||
},
|
||||
});
|
||||
emit({ event: 'hook-installed', needle: 'createWupProtoInfo', address: hookAddr.toString(), pid: Process.id, tid: Process.getCurrentThreadId() });
|
||||
|
||||
// HuyaMd5(const string&) — 输入
|
||||
const md5ctor = Process.getModuleByName(targetName).getExportByName('_ZN7HuyaMd5C1ERKNSt6__ndk112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE');
|
||||
if (md5ctor) {
|
||||
Interceptor.attach(md5ctor, {
|
||||
onEnter(args) {
|
||||
let hex = '';
|
||||
try {
|
||||
const a = args[1];
|
||||
const flag = a.readU8();
|
||||
if ((flag & 1) === 0) {
|
||||
const len = flag >> 1;
|
||||
if (len > 0 && len <= 256) hex = Array.from(new Uint8Array(a.add(1).readByteArray(len))).map(b => b.toString(16).padStart(2, '0')).join('');
|
||||
} else {
|
||||
const size = a.add(8).readU64();
|
||||
if (size <= 256) hex = Array.from(new Uint8Array(a.add(16).readPointer().readByteArray(Number(size)))).map(b => b.toString(16).padStart(2, '0')).join('');
|
||||
}
|
||||
} catch (e) { hex = '<err>'; }
|
||||
emit({ event: 'huya-md5', stage: 'ctor', inHex: hex, inStr: readStdString(args[1]), bt: btBrief() });
|
||||
},
|
||||
});
|
||||
emit({ event: 'hook-installed', needle: 'HuyaMd5C1' });
|
||||
}
|
||||
// HuyaMd5::toString() — 输出
|
||||
const md5ts = Process.getModuleByName(targetName).getExportByName('_ZN7HuyaMd58toStringEv');
|
||||
if (md5ts) {
|
||||
Interceptor.attach(md5ts, {
|
||||
onLeave(retval) {
|
||||
let hex = '', str = '';
|
||||
try {
|
||||
const flag = retval.readU8();
|
||||
if ((flag & 1) === 0) {
|
||||
const len = flag >> 1;
|
||||
if (len > 0) hex = retval.readByteArray(Math.min(len, 64)).then ? '' : Array.from(new Uint8Array(retval.readByteArray(Math.min(len, 64)))).map(b => b.toString(16).padStart(2, '0')).join('');
|
||||
} else {
|
||||
const size = retval.add(8).readU64();
|
||||
const data = retval.add(16).readPointer();
|
||||
if (size <= 96) hex = Array.from(new Uint8Array(data.readByteArray(Number(size)))).map(b => b.toString(16).padStart(2, '0')).join('');
|
||||
}
|
||||
str = readStdString(retval);
|
||||
} catch (e) { hex = '<err:' + e.message.slice(0, 40) + '>'; }
|
||||
emit({ event: 'huya-md5', stage: 'tostr', outHex: hex, outStr: str });
|
||||
},
|
||||
});
|
||||
emit({ event: 'hook-installed', needle: 'HuyaMd58toString' });
|
||||
}
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user