feat(huya): 🎯 完整加密链 deflate+XTEA 闭环验证成功 (R27)

- sub_2E164=deflate+sub_25234=XTEA封套 (pad+4Blen+24D58加密) 源链闭环
- harness: Java-deflate+真25234 产出52B密文
- 关键坑: GOT RELRO只读页 mprotect后导入补丁才生效 (所有-1的真相!)
- 捕获=[13B头][XTEA-wrap(key=设备派生)]; 密钥推导=下一步
This commit is contained in:
yml2213
2026-08-29 07:48:05 +08:00
parent 51962b8bf2
commit 0ef95a5c0e
2 changed files with 130 additions and 0 deletions
@@ -25,6 +25,14 @@ public class TuringProbe {
/** 全量补 JUMP_SLOT 导入槽 (懒绑定未解析) */
void patchImports(com.github.unidbg.Module m) {
int ok = 0, miss = 0;
try {
long relroStart = m.base + 0x45648;
emulator.getMemory().mprotect(relroStart, 0x3440, 7); // RELRO -> RWX
} catch (Throwable t) {}
try {
long bss = m.base + 0x48a88;
emulator.getMemory().mprotect(bss, 0x800, 7);
} catch (Throwable t) {}
for (int i = 0; i < IMPORT_SLOTS.length; i++) {
String name = IMPORT_NAMES[i];
try {
@@ -392,6 +400,96 @@ public class TuringProbe {
}
}
/** etest2: 直调 sub_2E164 加密链 (deflate+XTEA) — (in, len, &out, &outlen, key@3DF88) */
void etest2(String blobPath) {
try {
DalvikModule dm = vm.loadLibrary(new File("/Users/yml/codes/douyu_login_py/evidence/dfp_live/libturingmfa.so"), false);
com.github.unidbg.Module m = dm.getModule();
long gapBase = m.base + 0x45000;
try { emulator.getMemory().mmap2(gapBase, 0x648, 7, 0x32, -1, 0); } catch (Throwable t) {}
byte[] blob = new java.io.FileInputStream(blobPath).readAllBytes();
com.github.unidbg.pointer.UnidbgPointer inPtr = emulator.getMemory().mmap(blob.length + 32, 7);
for (int i=0;i<blob.length;i++) inPtr.setByte(i, blob[i]);
com.github.unidbg.pointer.UnidbgPointer outSlot = emulator.getMemory().mmap(16, 7);
com.github.unidbg.pointer.UnidbgPointer lenSlot = emulator.getMemory().mmap(16, 7);
long keyPtr = m.base + 0x3DF88;
System.out.println("[TP] etest2 ENC(deflate+XTEA) in=" + blob.length);
Number ret = m.callFunction(emulator, 0x2E164, inPtr.peer, blob.length, outSlot.peer, lenSlot.peer, keyPtr);
System.out.println("[TP] etest2 ret=" + ret);
long outAddr = outSlot.getLong(0); long outLen = lenSlot.getLong(0);
System.out.println("[TP] etest2 cipher=" + Long.toHexString(outAddr) + " len=" + outLen);
if (outAddr != 0 && outLen > 0 && outLen < 300000) {
byte[] c = com.github.unidbg.pointer.UnidbgPointer.pointer(emulator, outAddr).getByteArray(0, (int) outLen);
java.io.FileOutputStream fos = new java.io.FileOutputStream("/tmp/mfa_enc_out.bin"); fos.write(c); fos.close();
System.out.println("[TP] etest2 cipher head: " + java.util.HexFormat.of().formatHex(java.util.Arrays.copyOf(c, Math.min(c.length, 32))));
// 解密对偶: sub_252EC (XTEA-dec + len) - 直接调用
com.github.unidbg.pointer.UnidbgPointer cPtr = emulator.getMemory().mmap(c.length + 8, 7);
for (int i=0;i<c.length;i++) cPtr.setByte(i, c[i]);
com.github.unidbg.pointer.UnidbgPointer doutSlot = emulator.getMemory().mmap(16, 7);
com.github.unidbg.pointer.UnidbgPointer dlenSlot = emulator.getMemory().mmap(16, 7);
Number dr = m.callFunction(emulator, 0x252EC, cPtr.peer, c.length, doutSlot.peer, dlenSlot.peer, keyPtr);
long dAddr = doutSlot.getLong(0); long dLen = dlenSlot.getLong(0);
System.out.println("[TP] etest2 dec252EC ret=" + dr + " dout=" + dLen);
if (dAddr != 0 && dLen > 0 && dLen < 300000) {
byte[] d = com.github.unidbg.pointer.UnidbgPointer.pointer(emulator, dAddr).getByteArray(0, (int) dLen);
java.io.FileOutputStream fos2 = new java.io.FileOutputStream("/tmp/mfa_dec_out.bin"); fos2.write(d); fos2.close();
// inflate 对照 (sub_34A00 = java inflate 等价)
java.util.zip.Inflater inf = new java.util.zip.Inflater();
inf.setInput(d);
byte[] buf = new byte[300000];
int got = inf.inflate(buf);
System.out.println("[TP] etest2 inflate got=" + got + " match=" + java.util.Arrays.equals(java.util.Arrays.copyOf(buf, got), blob));
}
}
} catch (Throwable t) {
System.out.println("[TP] etest2 EXC " + t);
t.printStackTrace(System.out);
}
}
/** etest3: Java deflate -> 真 sub_25234 XTEA 封装 —— 验证捕获格式 */
void etest3(String blobPath) {
try {
DalvikModule dm = vm.loadLibrary(new File("/Users/yml/codes/douyu_login_py/evidence/dfp_live/libturingmfa.so"), false);
com.github.unidbg.Module m = dm.getModule();
long gapBase = m.base + 0x45000;
try { emulator.getMemory().mmap2(gapBase, 0x648, 7, 0x32, -1, 0); } catch (Throwable t) {}
patchImports(m);
byte[] blob = new java.io.FileInputStream(blobPath).readAllBytes();
// Java 标准 deflate (zlib!)
java.util.zip.Deflater def = new java.util.zip.Deflater(6, true); // raw? 试默认 zlib
def.setInput(blob); def.finish();
byte[] buf = new byte[blob.length * 2 + 64];
int dn = def.deflate(buf);
byte[] z = java.util.Arrays.copyOf(buf, dn);
System.out.println("[TP] etest3 deflate " + blob.length + "->" + dn + " head=" + java.util.HexFormat.of().formatHex(java.util.Arrays.copyOf(z, Math.min(z.length, 12))));
// 真 sub_25234 (XTEA 封装!)
com.github.unidbg.pointer.UnidbgPointer inPtr = emulator.getMemory().mmap(z.length + 32, 7);
for (int i=0;i<z.length;i++) inPtr.setByte(i, z[i]);
com.github.unidbg.pointer.UnidbgPointer outSlot = emulator.getMemory().mmap(16, 7);
com.github.unidbg.pointer.UnidbgPointer lenSlot = emulator.getMemory().mmap(16, 7);
Number ret = m.callFunction(emulator, 0x25234, inPtr.peer, z.length, outSlot.peer, lenSlot.peer, m.base + 0x3DF88);
long outAddr = outSlot.getLong(0); long outLen = lenSlot.getLong(0);
System.out.println("[TP] etest3 XTEA-wrap ret=" + ret + " len=" + outLen);
// 验证 GOT 关键槽
for (long s : new long[]{0x45978, 0x45980, 0x45988, 0x45990, 0x45968, 0x45970}) {
long v = com.github.unidbg.pointer.UnidbgPointer.pointer(emulator, m.base + s).getLong(0);
System.out.println("[TP] GOT 0x" + Long.toHexString(s) + " = " + (v == 0 ? "ZERO!!" : Long.toHexString(v)));
}
if (outAddr != 0 && outLen > 0) {
byte[] c = com.github.unidbg.pointer.UnidbgPointer.pointer(emulator, outAddr).getByteArray(0, (int) outLen);
java.io.FileOutputStream fos = new java.io.FileOutputStream("/tmp/mfa_xt ea.bin".replace(" ",""));
fos.write(c); fos.close();
System.out.println("[TP] etest3 cipher head: " + java.util.HexFormat.of().formatHex(java.util.Arrays.copyOf(c, Math.min(c.length, 40))));
byte[] captured = java.util.Arrays.copyOfRange(new java.io.FileInputStream("/tmp/cipher_only.bin").readAllBytes(), 0, Math.min(c.length, 40));
System.out.println("[TP] etest3 captured hd: " + java.util.HexFormat.of().formatHex(captured));
}
} catch (Throwable t) {
System.out.println("[TP] etest3 EXC " + t);
t.printStackTrace(System.out);
}
}
/** gacall: ga 注册原生直调 — k209202([B)[B @0x219d8 */
void gacall(String blobPath) {
try {
@@ -470,6 +568,8 @@ public class TuringProbe {
TuringProbe p = new TuringProbe();
String which = args.length > 0 ? args[0] : "both";
p.preResolveClasses();
if (which.equals("etest3")) { p.etest3(args[1]); return; }
if (which.equals("etest2")) { p.etest2(args[1]); return; }
if (which.equals("gacall2")) { p.gacall2(args[1]); return; }
if (which.equals("gacall")) { p.gacall(args[1]); return; }
if (which.equals("etest")) { p.etest(args[1]); return; }