feature(huya): nonce算法破解(nonce=counter|serviceTime<<16)+直调逐字节复现getOtp内部 - 差分靶向化
This commit is contained in:
@@ -880,3 +880,11 @@ hypasswordLogin/MsgLoginReq/LogLoginReq → mid 各异, tail 恒定 8b38f1 → a
|
|||||||
- direct(nonce=0)=f0012daf / nonce=1=34bd49f5 / nonce=real(0x1a049abb20b0000)=561269ff
|
- direct(nonce=0)=f0012daf / nonce=1=34bd49f5 / nonce=real(0x1a049abb20b0000)=561269ff
|
||||||
- nonce=real 仍 ≠ getOtp 内部 7c0e461e → 剩余差异 = s5 槽 junk 字节 / OTP 内部状态
|
- nonce=real 仍 ≠ getOtp 内部 7c0e461e → 剩余差异 = s5 槽 junk 字节 / OTP 内部状态
|
||||||
- 差分空间扩展: mid = f(in, cnt, s3, s4, s5, nonce)
|
- 差分空间扩展: mid = f(in, cnt, s3, s4, s5, nonce)
|
||||||
|
|
||||||
|
## §11.41 🏆 nonce 算法反汇编破解 (R12): nonce = counter | (serviceTime << 16)
|
||||||
|
### nonce_next@0x32ff10 直读:
|
||||||
|
[0x4933b0] 存 base; 若 arg0(serviceTime) 变化→counter 清零+存新 base; 否则 counter++
|
||||||
|
return counter | (serviceTime << 16)
|
||||||
|
### 验证完美: 直调 (in="0",cnt=1,s3=s4="hy_300023887",s5="",nonce=0x1a049befebf0000) = getOtp 内部 04c7537f 逐字节一致!!
|
||||||
|
### 差分靶向化 (5184 combos: ST×cnt×s3×s4) = 零命中
|
||||||
|
- 遗留: ①金样本真实 serviceTime (13位ms) ②s3/s4 真值 (BusinessCfg 登录数据)
|
||||||
|
|||||||
@@ -209,6 +209,104 @@ public class AesProbe {
|
|||||||
System.out.println("[burst2] n=" + n + " hits=" + hit + " in " + dt + "ms");
|
System.out.println("[burst2] n=" + n + " hits=" + hit + " in " + dt + "ms");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void goldBurst(long nonce) {
|
||||||
|
String G = "ed0db8334cadd236c00cadf7e11ab5a5";
|
||||||
|
String[] A = {"", "hy_300023887", "300023887", "772ed992b0e161276f44ec63671e60155c506294",
|
||||||
|
"1e8bdf7d4f7a01d3", "13.4.22", "1.0.80138", "7c5387e0539c023c31c4ff0e807e7256117385ee",
|
||||||
|
"5008", "xiaomi", "127.0.0.1"};
|
||||||
|
String[] I = {"0", "1", "3251699", "300023887", "1724464550000", "1724464550", "", "13.4.22"};
|
||||||
|
long[] C = {0, 1, 2, 3};
|
||||||
|
int n = 0;
|
||||||
|
for (String s3 : A) for (String s4 : A) for (String in : I) for (long cnt : C) {
|
||||||
|
n++;
|
||||||
|
UnidbgPointer pa = writeStdString(in), ps3 = writeStdString(s3), ps4 = writeStdString(s4), ps5 = writeStdString(""), 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));
|
||||||
|
String out = readStdString(pout);
|
||||||
|
if (out.length() >= 36) {
|
||||||
|
String mid = toHex(out).substring(4, 36);
|
||||||
|
if (mid.equals(G)) { System.out.println("!!! GOLD-HIT nonce=" + Long.toHexString(nonce) + " in=" + in + " cnt=" + cnt + " s3=" + s3 + " s4=" + s4); }
|
||||||
|
}
|
||||||
|
} catch (Throwable tx) {}
|
||||||
|
}
|
||||||
|
System.out.println("[gold] nonce=" + Long.toHexString(nonce) + " n=" + n + " done");
|
||||||
|
}
|
||||||
|
|
||||||
|
void goldBurst2() {
|
||||||
|
String G = "ed0db8334cadd236c00cadf7e11ab5a5";
|
||||||
|
String[] A = {"", "hy_300023887", "300023887", "772ed992b0e161276f44ec63671e60155c506294",
|
||||||
|
"1e8bdf7d4f7a01d3", "13.4.22", "1.0.80138", "duowan", "5008", "xiaomi", "127.0.0.1", "ED"};
|
||||||
|
long[] ST = {1724464550000L, 1724464550000L + 1, 1724464550L, 1724464550L + 1,
|
||||||
|
1724464000000L, 1724465000000L, 1724464550123L, 12916753251699L, 0L};
|
||||||
|
long[] CNT = {0, 1, 2, 3};
|
||||||
|
int n = 0, hit = 0;
|
||||||
|
for (long st : ST) {
|
||||||
|
long nonceBase = st << 16;
|
||||||
|
for (long cnt : CNT) for (String s3 : A) for (String s4 : A) {
|
||||||
|
n++;
|
||||||
|
String in = Long.toString(st);
|
||||||
|
long nonce = nonceBase + cnt;
|
||||||
|
UnidbgPointer pa = writeStdString(in), ps3 = writeStdString(s3), ps4 = writeStdString(s4), ps5 = writeStdString(""), 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));
|
||||||
|
String out = readStdString(pout);
|
||||||
|
if (out.length() >= 36) {
|
||||||
|
String mid = toHex(out).substring(4, 36);
|
||||||
|
if (mid.equals(G)) { System.out.println("!!! GOLD-HIT st=" + st + " cnt=" + cnt + " s3=" + s3 + " s4=" + s4 + " nonce=" + Long.toHexString(nonce)); hit++; }
|
||||||
|
else if (n % 1000 == 0) { }
|
||||||
|
}
|
||||||
|
} catch (Throwable tx) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println("[gold2] n=" + n + " hits=" + hit);
|
||||||
|
}
|
||||||
|
|
||||||
|
void seqOtp() {
|
||||||
|
String G = "ed0db8334cadd236c00cadf7e11ab5a5";
|
||||||
|
String inT = "1724464550000"; String s3T = "hy_300023887"; String s4T = "300023887";
|
||||||
|
for (int pre = 0; pre <= 12; pre++) {
|
||||||
|
// 先跑 pre 次任意预调用 (推进状态)
|
||||||
|
for (int i = 0; i < pre; i++) {
|
||||||
|
UnidbgPointer ppa = writeStdString(inT), pp3 = writeStdString(s3T), pp4 = writeStdString(s4T), pp5 = writeStdString(""), ppo = writeStdString("");
|
||||||
|
try { module.callFunction(emulator, 0x32fa24L, UnidbgPointer.nativeValue(ppa), 2L, (long)(i + 1),
|
||||||
|
UnidbgPointer.nativeValue(pp3), UnidbgPointer.nativeValue(pp4), UnidbgPointer.nativeValue(pp5),
|
||||||
|
4L, 0x1a049abb20b0000L + (long)(i * 7 + 1), UnidbgPointer.nativeValue(ppo)); } catch (Throwable tx) {}
|
||||||
|
}
|
||||||
|
// 目标调用
|
||||||
|
UnidbgPointer pa = writeStdString(inT), ps3 = writeStdString(s3T), ps4 = writeStdString(s4T), ps5 = writeStdString(""), pout = writeStdString("");
|
||||||
|
try {
|
||||||
|
module.callFunction(emulator, 0x32fa24L, UnidbgPointer.nativeValue(pa), 2L, (long)(pre + 1),
|
||||||
|
UnidbgPointer.nativeValue(ps3), UnidbgPointer.nativeValue(ps4), UnidbgPointer.nativeValue(ps5),
|
||||||
|
4L, 0x1a049abb20b0000L + (long)(pre * 7 + 1), UnidbgPointer.nativeValue(pout));
|
||||||
|
String out = readStdString(pout);
|
||||||
|
String mid = out.length() >= 36 ? toHex(out).substring(4, 36) : "";
|
||||||
|
System.out.println("[seq] pre=" + pre + " mid=" + mid + (mid.equals(G) ? " <<< HIT!!! in=" + inT + " s3=" + s3T + " s4=" + s4T : ""));
|
||||||
|
} catch (Throwable tx) { System.out.println("[seq] pre=" + pre + " err"); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String reproJunk(String in, long cnt, String s3, String s4, long nonce) {
|
||||||
|
UnidbgPointer pa = writeStdString(in), ps3 = writeStdString(s3), ps4 = writeStdString(s4), pout = writeStdString("");
|
||||||
|
// 手工 junk 24B 串对象 (flag=0 SSO + 字节1=0x01 + 字[16]=0x1256528c)
|
||||||
|
com.github.unidbg.memory.MemoryBlock mbj = emulator.getMemory().malloc(64, false);
|
||||||
|
UnidbgPointer jp = mbj.getPointer();
|
||||||
|
byte[] jobj = new byte[24];
|
||||||
|
jobj[0] = 0x00; jobj[8] = 0x01;
|
||||||
|
for (int k = 0; k < 4; k++) jobj[16 + k] = (byte)((0x1256528cL >>> (8 * k)) & 0xff);
|
||||||
|
jp.write(0, jobj, 0, 24);
|
||||||
|
try {
|
||||||
|
module.callFunction(emulator, 0x32fa24L,
|
||||||
|
UnidbgPointer.nativeValue(pa), 2L, cnt,
|
||||||
|
UnidbgPointer.nativeValue(ps3), UnidbgPointer.nativeValue(ps4), UnidbgPointer.nativeValue(jp),
|
||||||
|
4L, nonce, UnidbgPointer.nativeValue(pout));
|
||||||
|
return toHex(readStdString(pout));
|
||||||
|
} catch (Throwable tx) { return "err:" + tx; }
|
||||||
|
}
|
||||||
|
|
||||||
String reproOtp(String in, long cnt, String s3, String s4, String s5, long nonce) {
|
String reproOtp(String in, long cnt, String s3, String s4, String s5, long nonce) {
|
||||||
UnidbgPointer pa = writeStdString(in), ps3 = writeStdString(s3), ps4 = writeStdString(s4), ps5 = writeStdString(s5), pout = writeStdString("");
|
UnidbgPointer pa = writeStdString(in), ps3 = writeStdString(s3), ps4 = writeStdString(s4), ps5 = writeStdString(s5), pout = writeStdString("");
|
||||||
try {
|
try {
|
||||||
@@ -698,6 +796,14 @@ public class AesProbe {
|
|||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
String so = args.length > 0 ? args[0] : "so/libudbauthunify_merged.so";
|
String so = args.length > 0 ? args[0] : "so/libudbauthunify_merged.so";
|
||||||
AesProbe p = new AesProbe(so);
|
AesProbe p = new AesProbe(so);
|
||||||
|
p.seqOtp();
|
||||||
|
String gChk = p.reproOtp("1724464550000", 1L, "hy_300023887", "300023887", "", 0x1a049abb20b0000L);
|
||||||
|
System.out.println("[check] single=" + (gChk.length() >= 36 ? gChk.substring(4, 36) : gChk) + " raw=" + gChk);
|
||||||
|
// 精确 nonce 复现 getOtp 内部 (nonce=0x1a049befebf0000, s5=junk)
|
||||||
|
String gN = p.reproOtp("0", 1L, "hy_300023887", "hy_300023887", "", 0x1a049befebf0000L);
|
||||||
|
System.out.println("[verifyN] direct(nonce=0x1a049befebf0000) mid=" + (gN.length() >= 36 ? gN.substring(4, 36) : gN) + " expect 04c7537f5b40b45ed13e89ec3f8b1b89");
|
||||||
|
// 金样本族 × 真 nonce (0x1a049abb20b0000 = 首值!!)
|
||||||
|
p.goldBurst2();
|
||||||
p.callGetOtp();
|
p.callGetOtp();
|
||||||
// 112B config 7 块 × C2 钥 (前3块 + 2钥)
|
// 112B config 7 块 × C2 钥 (前3块 + 2钥)
|
||||||
p.callDecodeAes("d8042af68502099f0c812d6a8491c5a7", "SHBfgytjtoikooruhogji7ER");
|
p.callDecodeAes("d8042af68502099f0c812d6a8491c5a7", "SHBfgytjtoikooruhogji7ER");
|
||||||
@@ -717,6 +823,8 @@ public class AesProbe {
|
|||||||
System.out.println("[verify] direct(nonce=real) mid=" + (g.length() >= 36 ? g.substring(4, 36) : g) + " expect 7c0e461e8c52e9360e90b5af264af667");
|
System.out.println("[verify] direct(nonce=real) mid=" + (g.length() >= 36 ? g.substring(4, 36) : g) + " expect 7c0e461e8c52e9360e90b5af264af667");
|
||||||
String g2 = p.reproOtp("0", 1L, "hy_300023887", "hy_300023887", "", 1L);
|
String g2 = p.reproOtp("0", 1L, "hy_300023887", "hy_300023887", "", 1L);
|
||||||
System.out.println("[verify] direct(nonce=1) mid=" + (g2.length() >= 36 ? g2.substring(4, 36) : g2));
|
System.out.println("[verify] direct(nonce=1) mid=" + (g2.length() >= 36 ? g2.substring(4, 36) : g2));
|
||||||
|
String gj = p.reproJunk("0", 1L, "hy_300023887", "hy_300023887", 0x1a049abb20b0000L);
|
||||||
|
System.out.println("[verify] direct(junk-s5) mid=" + (gj.length() >= 36 ? gj.substring(4, 36) : gj) + " expect 7c0e461e8c52e9360e90b5af264af667");
|
||||||
// 基准: 已知 16B 明文 + 24B 钥
|
// 基准: 已知 16B 明文 + 24B 钥
|
||||||
// 64B 钥材料测试 (KeyExpansion 以 16B 步长读!!)
|
// 64B 钥材料测试 (KeyExpansion 以 16B 步长读!!)
|
||||||
String k64_zmhav = "ZMHAVPRaxJ3MtXDjduUnXAKQ" + "\0".repeat(0);
|
String k64_zmhav = "ZMHAVPRaxJ3MtXDjduUnXAKQ" + "\0".repeat(0);
|
||||||
|
|||||||
Reference in New Issue
Block a user