feat(huya): 登录路径OTP全链LIVE验证 + appSign≠getOtp结构性证伪 (R14)
- 决定性捕获(hook_huya_crypto.js全链): xxtea密钥=账号稳定uid(1199666914671) getkey(1,2)=MKDK/1,3=nskdI7, md5输入=k1+getkey, AES明文=[02][0c00][12B xxtea][7200][114B cred] 逐字节验证 - frida入口arg0读""为误读(SSO读取bug), 内部xxtea钩子为真值 - GOLD模式(正确uid)346k+J2 6.2M+I 6.3M+H 1.39M 全零 -> ~14.3M差分终态 - 结构性证明: appSign跨账号稳定 vs getOtp账号级(cred轮换) -> t1.t0≠OTP-mid QED - 更正旧文档: in=uid非空串; 登录可带frida; 金样本uid=1199666914671 - 下一步: createWupRequestData@0x38dab0 appSign填充点反汇编
This commit is contained in:
@@ -72,6 +72,32 @@ public class GoldSweep {
|
||||
return p;
|
||||
}
|
||||
|
||||
/** 空串按 LONG 形态写 (cap=1/size=0/data->0x1400) — libc++ 经典布局 */
|
||||
UnidbgPointer writeStdStringEmptyLong(String tag) {
|
||||
Memory mem = emulator.getMemory();
|
||||
UnidbgPointer p = mem.malloc(24, false).getPointer();
|
||||
byte[] buf = new byte[24];
|
||||
buf[0] = 1; // cap=1, LSB=1 (long)
|
||||
p.write(0, buf, 0, 22);
|
||||
UnidbgPointer heap = mem.malloc(8, false).getPointer();
|
||||
heap.write(0, tag.getBytes(), 0, Math.min(1, tag.length()));
|
||||
p.write(16, new byte[8], 0, 8); // data ptr slot
|
||||
byte[] ptrBytes = new byte[8];
|
||||
long pv = UnidbgPointer.nativeValue(heap);
|
||||
for (int i = 0; i < 8; i++) ptrBytes[i] = (byte) (pv >> (8 * i));
|
||||
p.write(16, ptrBytes, 0, 8);
|
||||
return p;
|
||||
}
|
||||
|
||||
/** 空串按 SSO 形态写 */
|
||||
UnidbgPointer writeStdStringEmptySso() {
|
||||
Memory mem = emulator.getMemory();
|
||||
UnidbgPointer p = mem.malloc(24, false).getPointer();
|
||||
byte[] buf = new byte[24];
|
||||
p.write(0, buf, 0, 24); // 全零: byte0=0 -> SSO len0
|
||||
return p;
|
||||
}
|
||||
|
||||
UnidbgPointer writeStdString(String s) {
|
||||
Memory mem = emulator.getMemory();
|
||||
byte[] data = s.getBytes();
|
||||
@@ -140,6 +166,17 @@ public class GoldSweep {
|
||||
}
|
||||
|
||||
/** 直调 OTP, 返回 [04][cnt][16B mid][16B tail] 的 hex; 出错返回 null */
|
||||
String otpHexPtrs(UnidbgPointer pa, long cnt, UnidbgPointer ps3, UnidbgPointer ps4, UnidbgPointer ps5, long nonce) {
|
||||
UnidbgPointer pout = writeStdString("");
|
||||
try {
|
||||
module.callFunction(emulator, 0x32fa24L,
|
||||
UnidbgPointer.nativeValue(pa), 2L, cnt,
|
||||
UnidbgPointer.nativeValue(ps3), UnidbgPointer.nativeValue(ps4), UnidbgPointer.nativeValue(ps5),
|
||||
4L, nonce, UnidbgPointer.nativeValue(pout));
|
||||
return toHex(readStdString(pout));
|
||||
} catch (Throwable tx) { System.out.println("[otpHexPtrs EXC] " + tx); return null; }
|
||||
}
|
||||
|
||||
String otpHex(String in, long cnt, String s3, String s4, String s5, long nonce) {
|
||||
UnidbgPointer pa = writeStdString(in);
|
||||
UnidbgPointer ps3 = writeStdString(s3);
|
||||
@@ -152,7 +189,7 @@ public class GoldSweep {
|
||||
UnidbgPointer.nativeValue(ps3), UnidbgPointer.nativeValue(ps4), UnidbgPointer.nativeValue(ps5),
|
||||
4L, nonce, UnidbgPointer.nativeValue(pout));
|
||||
return toHex(readStdString(pout));
|
||||
} catch (Throwable tx) { return null; }
|
||||
} catch (Throwable tx) { System.out.println("[otpHex EXC] " + tx); return null; }
|
||||
}
|
||||
|
||||
/** 直调 OTP (s5 二进制) */
|
||||
@@ -168,7 +205,7 @@ public class GoldSweep {
|
||||
UnidbgPointer.nativeValue(ps3), UnidbgPointer.nativeValue(ps4), UnidbgPointer.nativeValue(ps5),
|
||||
4L, nonce, UnidbgPointer.nativeValue(pout));
|
||||
return toHex(readStdString(pout));
|
||||
} catch (Throwable tx) { return null; }
|
||||
} catch (Throwable tx) { System.out.println("[otpHexB EXC] " + tx); return null; }
|
||||
}
|
||||
|
||||
static byte[] hexBytes(String h) {
|
||||
@@ -551,6 +588,35 @@ public class GoldSweep {
|
||||
System.out.println("[I] DONE " + n + " calls");
|
||||
break;
|
||||
}
|
||||
case "GOLD": { // 正确UID重扫: in="1199666914671"(hy_300023887稳定uid) s3="5008" s5=金cred — 单点+全窗
|
||||
String T = "ed0db8334cadd236c00cadf7e11ab5a5";
|
||||
String credHex = "0a80ee56427cac9512d4b1efb6de70f89d402e40cbf4a224e127c8f588f523a917113306f36b1596b3a47f6c0765e5ce3acb549adecb0c9bdcf88f8464155289e0ef46becb08217e4fae6fa87d8702b9e641baa1ebf3e0347669cb9b40bf4c38331020b680c89df4982ab935d5c381a91f";
|
||||
byte[] cb = hexBytes(credHex);
|
||||
long[] sts = {1787595090906L, 1787595102531L, 1787595167182L, 1787595172449L, 1787595172452L, 1787595172455L, 1787595172458L};
|
||||
for (long st : sts)
|
||||
for (long cnt = 1; cnt <= 15; cnt++)
|
||||
for (long nc = 0; nc <= 2; nc++) {
|
||||
long nonce = (nc & 0xffffL) | (st << 16);
|
||||
String out = p.otpHexB("1199666914671", cnt, "5008", K1C, cb, nonce);
|
||||
if (out != null && out.length() >= 34 && out.substring(2, 34).equals(T)) {
|
||||
System.out.println("!!! REAL-HIT cnt=" + cnt + " st=" + st + " nc=" + nc);
|
||||
}
|
||||
}
|
||||
System.out.println("[K] singles done");
|
||||
long n = 0;
|
||||
for (long cnt = 1; cnt <= 15; cnt++)
|
||||
for (long st = 1787595165000L; st <= 1787595172700L; st += 1)
|
||||
for (long nc = 0; nc <= 2; nc++) {
|
||||
long nonce = (nc & 0xffffL) | (st << 16);
|
||||
String out = p.otpHexB("1199666914671", cnt, "5008", K1C, cb, nonce);
|
||||
if (out != null && out.length() >= 34 && out.substring(2, 34).equals(T)) {
|
||||
System.out.println("!!! REAL-HIT cnt=" + cnt + " st=" + st + " nc=" + nc);
|
||||
}
|
||||
if (++n % 50000 == 0) System.out.println("[K] " + n + " (st=" + st + ")");
|
||||
}
|
||||
System.out.println("[K] DONE " + n + " calls");
|
||||
break;
|
||||
}
|
||||
case "J": { // 正确语义: in="", s3="", s4=k1, s5=金样本cred — 单点+全窗
|
||||
String T = "ed0db8334cadd236c00cadf7e11ab5a5";
|
||||
String credHex = "0a80ee56427cac9512d4b1efb6de70f89d402e40cbf4a224e127c8f588f523a917113306f36b1596b3a47f6c0765e5ce3acb549adecb0c9bdcf88f8464155289e0ef46becb08217e4fae6fa87d8702b9e641baa1ebf3e0347669cb9b40bf4c38331020b680c89df4982ab935d5c381a91f";
|
||||
@@ -608,6 +674,33 @@ public class GoldSweep {
|
||||
System.out.println("[J2] DONE " + n + " calls");
|
||||
break;
|
||||
}
|
||||
case "K3": { // 复验 live 捕获: otp("",2,"",k1, s5=0a30fb..., nonce=0x1a04a405a7c0000) == 0402bfe6496f...
|
||||
byte[] s5 = hexBytes("0a30fb7b0617ae74fd0a4defe5e1059ff6e2781dd245bbfa304133d379f3465fc49bf462bc7c96678b1f314c26fc87ebc9adf05983500435bed7a0310856c995a30ca1a41af034236445b1c48478378c1181d7186e763c18794ba9a4335c2ac5b381fbf6f99830f26ffc3c4a4c2046c642eb");
|
||||
String out = p.otpHexB("", 2L, "", K1C, s5, 0x1a04a405a7c0000L);
|
||||
System.out.println("K3 out=[" + out + "]");
|
||||
// 空串变体测试: SSO-empty vs LONG-empty
|
||||
UnidbgPointer paL = p.writeStdStringEmptyLong("k");
|
||||
UnidbgPointer ps3L = p.writeStdStringEmptyLong("s");
|
||||
UnidbgPointer paS = p.writeStdStringEmptySso();
|
||||
UnidbgPointer ps3S = p.writeStdStringEmptySso();
|
||||
UnidbgPointer ps4 = p.writeStdString(K1C);
|
||||
UnidbgPointer ps5 = p.writeStdStringBytes(s5);
|
||||
long nonce = 0x1a04a405a7c0000L;
|
||||
String[] outs = new String[4];
|
||||
outs[0] = p.otpHexPtrs(paS, 2L, ps3S, ps4, ps5, nonce); // SSO/SSO
|
||||
outs[1] = p.otpHexPtrs(paL, 2L, ps3S, ps4, ps5, nonce); // LONG/SSO
|
||||
outs[2] = p.otpHexPtrs(paS, 2L, ps3L, ps4, ps5, nonce); // SSO/LONG
|
||||
outs[3] = p.otpHexPtrs(paL, 2L, ps3L, ps4, ps5, nonce); // LONG/LONG
|
||||
for (int i = 0; i < 4; i++) {
|
||||
System.out.println("K3-var" + i + " -> [" + (outs[i]==null?"null":outs[i].substring(0, Math.min(16, outs[i].length()))) + "]");
|
||||
}
|
||||
if (out != null) {
|
||||
System.out.println("K3 firstblock=" + out.substring(2, 34));
|
||||
System.out.println("K3 need =bfe6496f781fa7005df2051bea5e0dce");
|
||||
System.out.println("K3 MATCH=" + out.substring(2, 34).equals("bfe6496f781fa7005df2051bea5e0dce"));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "V2": { // 复验: 真实 146B, s5=完整 114B cred, 精确 nonce — 比对输出[2:34](真值 首块=cipher[0:16])
|
||||
String credHex = "0a6028ce6a24d74b0e9b503050db127e3390d37d4a696ef46530804aaec7f9fa6ddc2142035729b8cecd102bf9402930aac60f21c293697e3b9b54fdbf976819b70078c2fa8b64bd9d14246eb4adc807ecf6bfdcc585f9a7b39524f88bea62135eb229e65512e6acd7a831ba772d5f374bf3";
|
||||
byte[] s5 = hexBytes(credHex);
|
||||
|
||||
Reference in New Issue
Block a user