feat(huya): 里程碑 - UdbAESUtil纯Python复刻成功(A/B/D三向量逐字节) + 登录帧t1=ProtoInfo(appSign槽=HDID32)

- tools/huya_aes_replica.py 617行逐指令复刻, AES-128变异(64B钥材用[0:16]+列链式扩展+移位吸收)
- 结构定案: t1 = {0:appSign=ed0db8! 1:appVer 2:sdkVer 3:lcid 4:clientIp 5:channel 6:countryCode}
- APP_SIGN错误名=appSign字段校验失败; 下步InvCipher直解明文
This commit is contained in:
yml2213
2026-08-29 00:37:56 +08:00
parent 71e28f3406
commit fda956beca
4 changed files with 802 additions and 0 deletions
@@ -156,6 +156,27 @@ public class AesProbe {
return "";
}
void dumpKeyMgr() {
UnidbgPointer self = emulator.getMemory().malloc(0x80, false).getPointer();
self.write(0, new byte[0x80], 0, 0x80);
module.callFunction(emulator, 0x26fcc8L, UnidbgPointer.nativeValue(self));
System.out.println("[keymgr] C2 done. object 0x80B:");
byte[] buf = new byte[0x80];
self.read(0, buf, 0, 0x80);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 0x80; i++) {
byte b = buf[i];
if (b >= 0x20 && b < 0x7f) sb.append((char) b); else sb.append('.');
if ((i + 1) % 16 == 0) sb.append('\n');
}
System.out.println(sb.toString());
// 也尝试 getkey(1,0) 返回值 (x0)
try {
Number r = module.callFunction(emulator, 0x26871cL, UnidbgPointer.nativeValue(self), 1L, 0L);
System.out.println("[keymgr] getkey(1,0) ret-x0 = " + Long.toHexString(r == null ? -1 : r.longValue()));
} catch (Throwable t) { System.out.println("[keymgr] getkey err " + t); }
}
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));
@@ -192,6 +213,7 @@ public class AesProbe {
p.callOtp("abcd", "ZMHAVPRaxJ3MtXDjduUnXAKQ");
p.callXxtea("abc", "ZMHAVPRaxJ3MtXDjduUnXAKQ");
p.callMd5Char16("abc");
p.dumpKeyMgr();
p.emulator.close();
p.emulator.close();
}
+136
View File
@@ -0,0 +1,136 @@
package hydev;
import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.Module;
import com.github.unidbg.arm.backend.BackendFactory;
import com.github.unidbg.arm.backend.DynarmicFactory;
import com.github.unidbg.linux.android.AndroidEmulatorBuilder;
import com.github.unidbg.linux.android.AndroidResolver;
import com.github.unidbg.linux.android.dvm.DalvikModule;
import com.github.unidbg.linux.android.dvm.VM;
import com.github.unidbg.memory.Memory;
import com.github.unidbg.pointer.UnidbgPointer;
import java.io.File;
import java.util.Arrays;
/**
* 差分探针: 与 huya_aes_replica.py 对拍 encode_aes@0x330218
* 1) C-vector: in="1e8bdf7d4f7a01d3"(ASCII 16B) key=ZMHAV..+40NUL -> ?
* 2) 随机差分: 若干 16B 明文 x 64B 钥
*/
public class DiffProbe {
private final AndroidEmulator emulator;
private final Module module;
DiffProbe(String soPath) throws Exception {
BackendFactory backend = new DynarmicFactory(true);
emulator = AndroidEmulatorBuilder.for64Bit().setProcessName("com.duowan.kiwi")
.addBackendFactory(backend).build();
Memory memory = emulator.getMemory();
memory.setLibraryResolver(new AndroidResolver(23));
VM vm = emulator.createDalvikVM();
vm.setJni(new com.github.unidbg.linux.android.dvm.AbstractJni() {});
vm.setVerbose(false);
DalvikModule dm = vm.loadLibrary(new File(soPath), false);
dm.callJNI_OnLoad(emulator);
module = dm.getModule();
}
UnidbgPointer writeStdString(String s) {
Memory mem = emulator.getMemory();
byte[] data = s.getBytes(java.nio.charset.StandardCharsets.ISO_8859_1);
int len = data.length;
UnidbgPointer p;
if (len <= 22) {
p = mem.malloc(24, false).getPointer();
byte[] buf = new byte[24];
buf[0] = (byte) (len << 1);
System.arraycopy(data, 0, buf, 1, len);
p.write(0, buf, 0, buf.length);
} else {
UnidbgPointer heap = mem.malloc(len + 1, false).getPointer();
heap.write(0, data, 0, len);
heap.write(len, new byte[]{0}, 0, 1);
p = mem.malloc(24, false).getPointer();
byte[] cap = new byte[8]; Arrays.fill(cap, (byte) 0xff);
p.write(0, cap, 0, 8);
p.write(8, new byte[]{(byte) (len & 0xff), (byte) (len >> 8), 0, 0, 0, 0, 0, 0}, 0, 8);
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;
}
String readStdString(UnidbgPointer p) {
byte[] one = new byte[1];
p.read(0, one, 0, 1);
int first = one[0] & 0xff;
if ((first & 1) == 0) {
int len = first >> 1;
byte[] dat = new byte[len];
p.read(1, dat, 0, len);
return new String(dat, java.nio.charset.StandardCharsets.ISO_8859_1);
} else {
long size = 0;
byte[] szb = new byte[8];
p.read(8, szb, 0, 8);
for (int i = 0; i < 8; i++) size |= ((long) (szb[i] & 0xff)) << (8 * i);
byte[] ptrb = new byte[8];
p.read(16, ptrb, 0, 8);
long pv = 0;
for (int i = 0; i < 8; i++) pv |= ((long) (ptrb[i] & 0xff)) << (8 * i);
UnidbgPointer data = UnidbgPointer.pointer(this.emulator, pv);
byte[] dat2 = new byte[(int) size];
data.read(0, dat2, 0, (int) size);
return new String(dat2, java.nio.charset.StandardCharsets.ISO_8859_1);
}
}
String enc(String in, String key) {
UnidbgPointer pin = writeStdString(in);
UnidbgPointer pkey = writeStdString(key);
UnidbgPointer pout = writeStdString("");
module.callFunction(emulator, 0x330218L, UnidbgPointer.nativeValue(pin),
UnidbgPointer.nativeValue(pkey), UnidbgPointer.nativeValue(pout));
String out = readStdString(pout);
StringBuilder sb = new StringBuilder();
for (byte b : out.getBytes(java.nio.charset.StandardCharsets.ISO_8859_1))
sb.append(String.format("%02x", b));
return sb.toString();
}
static String hexBytes(int n, long seed) {
// deterministic "random" 16-byte hex string
StringBuilder sb = new StringBuilder();
java.util.Random r = new java.util.Random(seed);
for (int i = 0; i < n; i++) sb.append(String.format("%02x", r.nextInt(256)));
return sb.toString();
}
public static void main(String[] args) throws Exception {
String so = args.length > 0 ? args[0] : "so/libudbauthunify_merged.so";
DiffProbe p = new DiffProbe(so);
String kzm = "ZMHAVPRaxJ3MtXDjduUnXAKQ" + "\0".repeat(40);
String k00 = "0123456789abcdef".repeat(4);
System.out.println("[C1] ascii-16 in=1e8bdf7d4f7a01d3 keyB -> " + p.enc("1e8bdf7d4f7a01d3", kzm));
System.out.println("[C2] flag+15 in=\\u0020+0123456789abcde keyB -> " + p.enc("\u00200123456789abcde", kzm));
System.out.println("[C3] hexbytes8pad in=1e8bdf7d4f7a01d3+0000000000000000 keyB -> " + p.enc("1e8bdf7d4f7a01d3\0\0\0\0\0\0\0\0", kzm));
System.out.println("[X0] in=0123456789abcdef keyB -> " + p.enc("0123456789abcdef", kzm));
for (int i = 0; i < 8; i++) {
long seed = 1000 + i;
String in = hexBytes(16, seed);
String key = hexBytes(64, seed ^ 0x5a5a);
System.out.println("[R" + i + "] in=" + in + " key=" + key + " -> " + p.enc(in, key));
}
// 用 64 个 'A' 测试纯 64B ASCII 钥
System.out.println("[KAA] in=0123456789abcdef key='A'*64 -> " + p.enc("0123456789abcdef", "A".repeat(64)));
// 24B 短钥 (short string, flag 参与装载?)
System.out.println("[K24] in=0123456789abcdef key=0123456789abcdef(16B short) -> " + p.enc("0123456789abcdef", "0123456789abcdef"));
}
}