diff --git a/docs/HUYA_HDID_ALGORITHM_GEN.md b/docs/HUYA_HDID_ALGORITHM_GEN.md index b4effe8..19a385d 100644 --- a/docs/HUYA_HDID_ALGORITHM_GEN.md +++ b/docs/HUYA_HDID_ALGORITHM_GEN.md @@ -615,3 +615,20 @@ UdbAESUtilC1 + encrypt ← AES 层 ### 工作台状态 (本轮新增) - tools/unidbg/hydev/src/hydev/AesProbe.java: encode_aes 差分源 (已验证) - 子代理: 静态复刻 KeyExpansion/Cipher → Python (验证目标 = 探针 3 向量) + +## §11.18 md5_char16 变体识别 + 探针全家桶 (2026-08-28 夜) + +### md5_char16@0x32e71c = "MD5-hex 中段 16 字符" (非 32hex 本体) +- md5_char16("") → 8f00b204e9800998 = md5("").hex[8:24] (d41d8cd9⁈**8f00b204e9800998**⁈ecf8427e) ✓ +- md5_char16("0123456789") → 5d69b566979b86e2 = md5.hex[8:24] ✓ +→ OTP 链的 32hex 形态 = 其它环节 (md5 全串 / AES 输出)。 + +### AesProbe 可调函数 (unidbg 权威差分) +- encode_aes@0x330218 (IN,KEY,OUT) ✓ +- md5_char16@0x32e71c (OUT,IN) ✓ +- xxtea_encrypt@0x32e83c (OUT,IN,KEY): xxtea("0123456789abcdef","ZMHAV…")→124105f9d7a549dfb6bc756cade6679ed412a6bd +- hyudb_otp_encrypt@0x32fa24 (string,h,h,string,string,string,h,m,string&): 参数语义待定 (现按序猜, 出空) + +### 在途 +- 子代理静态复刻 KeyExpansion/Cipher → huya_aes_replica.py (3 验证向量) +- 下步: OTP 参数语义 (读 32fa24 前半 arg 处理) + getkey 双 id 材料 diff --git a/tools/unidbg/hydev/src/hydev/AesProbe.java b/tools/unidbg/hydev/src/hydev/AesProbe.java index 50eb8ae..54b18ff 100644 --- a/tools/unidbg/hydev/src/hydev/AesProbe.java +++ b/tools/unidbg/hydev/src/hydev/AesProbe.java @@ -117,6 +117,45 @@ public class AesProbe { return out; } + String callMd5Char16(String in) { + UnidbgPointer pin = writeStdString(in); + UnidbgPointer pout = writeStdString(""); + Number r = module.callFunction(emulator, 0x32e71cL, UnidbgPointer.nativeValue(pout), UnidbgPointer.nativeValue(pin)); + String out = readStdString(pout); + System.out.println("[md5_char16] in=" + in + " -> " + out + " hex=" + toHex(out)); + return out; + } + + String callXxtea(String in, String key) { + UnidbgPointer pin = writeStdString(in); + UnidbgPointer pkey = writeStdString(key); + UnidbgPointer pout = writeStdString(""); + Number r = module.callFunction(emulator, 0x32e83cL, UnidbgPointer.nativeValue(pout), UnidbgPointer.nativeValue(pin), UnidbgPointer.nativeValue(pkey)); + String out = readStdString(pout); + System.out.println("[xxtea] in=" + in + " key=" + key + " -> hex=" + toHex(out)); + return out; + } + + String callOtp(String a, String b) { + UnidbgPointer pa = writeStdString(a); + UnidbgPointer pb = writeStdString(b); + UnidbgPointer pc = writeStdString("k"); + UnidbgPointer pd = writeStdString("ivx"); + UnidbgPointer pout = writeStdString(""); + // 尝试 4 位置: arg0=in, arg1=?, arg2=?, arg3=key, arg4=?, arg5=?, arg6=h, arg7=m, arg8=out + try { + Number r = module.callFunction(emulator, 0x32fa24L, + UnidbgPointer.nativeValue(pa), 1L, 2L, + UnidbgPointer.nativeValue(pb), UnidbgPointer.nativeValue(pc), UnidbgPointer.nativeValue(pd), + 3L, 4L, UnidbgPointer.nativeValue(pout)); + String out = readStdString(pout); + System.out.println("[otp] a=" + a + " b=" + b + " -> hex=" + toHex(out)); + } catch (Throwable t) { + System.out.println("[otp] err " + t); + } + return ""; + } + static String toHex(String s) { StringBuilder sb = new StringBuilder(); for (byte b : s.getBytes(java.nio.charset.StandardCharsets.ISO_8859_1)) sb.append(String.format("%02x", b)); @@ -135,8 +174,17 @@ public class AesProbe { p.callEncodeAes("0123456789abcdef", k64_zmhav); p.callEncodeAes("0123456789abcdef", k64_ow); p.callEncodeAes("0123456789abcdef", k64_cfg0); - p.callEncodeAes("1e8bdf7d4f7a01d3", k64_zmhav); - p.callEncodeAes("1e8bdf7d4f7a01d3", k64_cfg0); + // md5_char16@0x32e71c (out&, in&) -- 32hex 形态验证 + p.callMd5Char16("0123456789"); + p.callMd5Char16("ZMHAVPRaxJ3MtXDjduUnXAKQ"); + p.callMd5Char16("1e8bdf7d4f7a01d3"); + p.callMd5Char16(""); + // xxtea_encrypt@0x32e83c (out&, in&, key&) + p.callXxtea("0123456789abcdef", "ZMHAVPRaxJ3MtXDjduUnXAKQ"); + // hyudb_otp_encrypt@0x32fa24 (string, h,h, string,string,string, h,m, string&) + p.callOtp("abc", "ZMHAVPRaxJ3MtXDjduUnXAKQ"); + p.callOtp("1e8bdf7d4f7a01d3", "KFWAH2cbkkNgFAgQPzriFPcU"); + p.emulator.close(); p.emulator.close(); } } \ No newline at end of file