feat(huya): OTP-OUT内容捕获成功!结构=[04][cnt][16B mid][16B tail] - 差分闭环就绪

This commit is contained in:
yml2213
2026-08-29 02:48:48 +08:00
parent d714249e24
commit dd883c02d8
2 changed files with 34 additions and 5 deletions
+9
View File
@@ -858,3 +858,12 @@ hypasswordLogin/MsgLoginReq/LogLoginReq → mid 各异, tail 恒定 8b38f1 → a
- BusinessCfg 诸符号: load/saveLoginData/getLoginData@0x26984c etc. (+0x10/+0x40 = 登录数据字段源) - BusinessCfg 诸符号: load/saveLoginData/getLoginData@0x26984c etc. (+0x10/+0x40 = 登录数据字段源)
- 注入 +0x10/+0x40 (name/sha1) 后 getOtp 流程 269280-2692a4 段 = 新 UC_ERR_READ_UNMAPPED (s4 拷贝路径) - 注入 +0x10/+0x40 (name/sha1) 后 getOtp 流程 269280-2692a4 段 = 新 UC_ERR_READ_UNMAPPED (s4 拷贝路径)
→ 实例字段注入 = SSO 布局细节需修 (s4 拷贝读 [x8+0x10+0x10] cap 越界?) → 实例字段注入 = SSO 布局细节需修 (s4 拷贝读 [x8+0x10+0x10] cap 越界?)
## §11.37 🎯 OTP-OUT 内容捕获成功! (R11c)
### getOtp 内部 OTP 输出完整读取:
content=0401 7c0e461e8c52e9360e90b5af264af667 0f127c3af8c69c3428ef3d1e9b7a8618 (34B)
结构 = [04=ver][cnt=1][16B mid][16B tail]
- libc++ 长串对象: [0-7]cap [8-15]size [16-23]ptr → 内容读取法定案
- SSO-only 注入 (s3=s4="hy_300023887") 后 getOtp 全流程 985 hooks 无错误!
### mid = f(in, cnt, s3, s4, s5) (s5 也入 mid!) — 差分闭环就绪
### 下步: 全组合爆破 (in/cnt/s3/s4/s5 候选族) → mid == ed0db8
+25 -5
View File
@@ -305,6 +305,21 @@ public class AesProbe {
StringBuilder asc = new StringBuilder(); StringBuilder asc = new StringBuilder();
for (byte bb2 : head) asc.append((bb2 >= 0x20 && bb2 < 0x7f) ? (char) bb2 : '.'); for (byte bb2 : head) asc.append((bb2 >= 0x20 && bb2 < 0x7f) ? (char) bb2 : '.');
System.out.println("[otp-OUT] @" + Long.toHexString(outSlot[0]) + " head=" + hx + " asc=" + asc); System.out.println("[otp-OUT] @" + Long.toHexString(outSlot[0]) + " head=" + hx + " asc=" + asc);
// libc++ 长串: [0-7]cap [8-15]size [16-23]ptr -> 读内容
long capw = oP.getLong(0), sizew = oP.getLong(8), ptrw = oP.getLong(16);
if (ptrw > 0x10000L && sizew > 0 && sizew < 0x200) {
UnidbgPointer cp = UnidbgPointer.pointer(emulator, ptrw);
if (cp != null) {
byte[] content = new byte[(int) sizew];
try { cp.read(0, content, 0, content.length);
StringBuilder cx = new StringBuilder();
for (byte bb2 : content) cx.append(String.format("%02x", bb2 & 0xff));
System.out.println("[otp-OUTC] size=" + sizew + " content=" + cx);
String mid = content.length >= 20 ? cx.toString().substring(4, 36) : cx.toString();
System.out.println("[otp-OUTC] mid16=" + mid + (mid.equals("ed0db8334cadd236c00cadf7e11ab5a5") ? " <<< ED0DB8 MATCH!!!" : ""));
} catch (Throwable tc) { System.out.println("[otp-OUTC] read err " + tc); }
}
}
outSlot[0] = 0; outSlot[0] = 0;
} }
} }
@@ -345,12 +360,12 @@ public class AesProbe {
writeStrAt(pv, 0x40, ""); // mobileMask "" writeStrAt(pv, 0x40, ""); // mobileMask ""
writeStrAt(pv, 0x58, ""); // passport "" writeStrAt(pv, 0x58, ""); // passport ""
writeStrAt(pv, 0x70, "*hZrPb62GskrEeTYcLeUTL1fJ1OR8ky3x9qXQq0s6ICJV5v9T"); writeStrAt(pv, 0x70, "*hZrPb62GskrEeTYcLeUTL1fJ1OR8ky3x9qXQq0s6ICJV5v9T");
// 注入登录数据到 BusinessCfg 实例 +0x10/+0x40 (s4/s3 源) // 注入 SSO-only 短串 (避免 heap 构造器越界)
try { try {
UnidbgPointer ip = UnidbgPointer.pointer(emulator, thisPtr); UnidbgPointer ip2 = UnidbgPointer.pointer(emulator, thisPtr);
writeStrAt(ip, 0x10, "hy_300023887"); writeStrAt(ip2, 0x10, "hy_300023887");
writeStrAt(ip, 0x40, "772ed992b0e161276f44ec63671e60155c506294"); writeStrAt(ip2, 0x40, "hy_300023887");
System.out.println("[getOtp] injected login-data into instance"); System.out.println("[getOtp] injected SSO login-data");
} catch (Throwable ti) { System.out.println("[getOtp] inject err " + ti); } } catch (Throwable ti) { System.out.println("[getOtp] inject err " + ti); }
// 调用 getOtp(AppLoginData&) @0x26916c // 调用 getOtp(AppLoginData&) @0x26916c
module.callFunction(emulator, 0x26916cL, thisPtr, UnidbgPointer.nativeValue(pv)); module.callFunction(emulator, 0x26916cL, thisPtr, UnidbgPointer.nativeValue(pv));
@@ -616,6 +631,11 @@ public class AesProbe {
p.callDecodeAes("d8042af68502099f0c812d6a8491c5a7", "KNSDNjfohweeromnmkladj3g"); p.callDecodeAes("d8042af68502099f0c812d6a8491c5a7", "KNSDNjfohweeromnmkladj3g");
p.callDecodeAes("e53bbc17664c15641fc5a55e89ddc7ae", "KNSDNjfohweeromnmkladj3g"); p.callDecodeAes("e53bbc17664c15641fc5a55e89ddc7ae", "KNSDNjfohweeromnmkladj3g");
p.callDecodeAes("d8042af68502099f0c812d6a8491c5a7", "xnkdDFIERRIPT5dfhfgiJ0FD"); p.callDecodeAes("d8042af68502099f0c812d6a8491c5a7", "xnkdDFIERRIPT5dfhfgiJ0FD");
// 空输入 OTP (s5 全零串族)
p.callOtpReal("0", 1L, "", "", "", 0L);
p.callOtpReal("0", 1L, "", "", "00000000000000000000000000000000", 0L);
p.callOtpReal("0", 1L, "hy_300023887", "772ed992b0e161276f44ec63671e60155c506294", "00000000000000000000000000000000", 0L);
p.callOtpReal("1724464550000", 0L, "", "", "", 0L);
// 基准: 已知 16B 明文 + 24B 钥 // 基准: 已知 16B 明文 + 24B 钥
// 64B 钥材料测试 (KeyExpansion 以 16B 步长读!!) // 64B 钥材料测试 (KeyExpansion 以 16B 步长读!!)
String k64_zmhav = "ZMHAVPRaxJ3MtXDjduUnXAKQ" + "\0".repeat(0); String k64_zmhav = "ZMHAVPRaxJ3MtXDjduUnXAKQ" + "\0".repeat(0);