feat(huya): getOtp全流程执行成功!OTP调用实弹+参数读取 - 根因=BusinessCfg实例配置字段空

This commit is contained in:
yml2213
2026-08-29 02:42:18 +08:00
parent 76de9c3e39
commit d46654438f
2 changed files with 69 additions and 5 deletions
+62 -5
View File
@@ -248,6 +248,8 @@ public class AesProbe {
// hook: getOtp 入口 + 内部 OTP 调用点
final long ENTRY = module.base + 0x26916cL;
final long OTPC = module.base + 0x269324L;
final boolean[] f1 = {false};
final long[] outSlot = {0};
com.github.unidbg.arm.backend.CodeHook th = new com.github.unidbg.arm.backend.CodeHook() {
public void hook(com.github.unidbg.arm.backend.Backend backend, long address, int size, Object user) {
System.out.println("[hook] hit @0x" + Long.toHexString(address));
@@ -264,10 +266,47 @@ public class AesProbe {
long x23 = backend.reg_read(Arm64Const.UC_ARM64_REG_X23).longValue();
long x20 = backend.reg_read(Arm64Const.UC_ARM64_REG_X20).longValue();
long sp = backend.reg_read(Arm64Const.UC_ARM64_REG_SP).longValue();
long x29r = backend.reg_read(Arm64Const.UC_ARM64_REG_X29).longValue();
if (address == module.base + 0x269278L && !f1[0]) {
f1[0] = true;
UnidbgPointer inslot = UnidbgPointer.pointer(emulator, x29r - 0x58L);
if (inslot != null) {
byte[] sso = new byte[24];
sso[0] = 0x02; // len1<<1
sso[1] = (byte) '0';
inslot.write(0, sso, 0, 24);
System.out.println("[hook] in-slot pre-written @0x" + Long.toHexString(x29r - 0x58));
}
}
long outPtr = 0, x19r = 0;
if (address == module.base + 0x269324L) {
UnidbgPointer spP = UnidbgPointer.pointer(emulator, sp);
if (spP != null) { outPtr = spP.getLong(0); x19r = backend.reg_read(Arm64Const.UC_ARM64_REG_X19).longValue(); }
if (spP != null) { outPtr = spP.getLong(0); outSlot[0] = outPtr; x19r = backend.reg_read(Arm64Const.UC_ARM64_REG_X19).longValue(); }
// 读 x0/x3/x4/x5 槽内容 (各 24B)
for (long rr : new long[]{a0, a3, a4, a5}) {
UnidbgPointer strp = UnidbgPointer.pointer(emulator, rr);
if (strp != null && rr != 0) {
byte[] hh = new byte[24];
try { strp.read(0, hh, 0, 24); } catch (Throwable tx) { continue; }
StringBuilder sbx = new StringBuilder();
for (byte bb2 : hh) sbx.append(String.format("%02x", bb2 & 0xff));
System.out.println("[otp-arg] @" + Long.toHexString(rr) + " = " + sbx);
}
}
}
if ((address == module.base + 0x269328L || address == module.base + 0x2693a8L || address == module.base + 0x2693b0L) && outSlot[0] != 0) {
// 后调: 读 OUT 串内容
UnidbgPointer oP = UnidbgPointer.pointer(emulator, outSlot[0]);
if (oP != null) {
byte[] head = new byte[24];
oP.read(0, head, 0, 24);
StringBuilder hx = new StringBuilder();
for (byte bb2 : head) hx.append(String.format("%02x", bb2 & 0xff));
StringBuilder asc = new StringBuilder();
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);
outSlot[0] = 0;
}
}
System.out.println("[hook-args] @0x" + Long.toHexString(address) + " x0=" + Long.toHexString(a0) + " x1=" + Long.toHexString(a1)
+ " x2=" + Long.toHexString(a2) + " x3=" + Long.toHexString(a3) + " x4=" + Long.toHexString(a4) + " x5=" + Long.toHexString(a5)
@@ -280,10 +319,14 @@ public class AesProbe {
public void detach() {}
};
emulator.getBackend().hook_add_new(th, ENTRY, ENTRY, null);
emulator.getBackend().hook_add_new(th, module.base + 0x2691a4L, module.base + 0x2691d8L, null);
emulator.getBackend().hook_add_new(th, module.base + 0x26921cL, module.base + 0x269330L, null);
emulator.getBackend().hook_add_new(th, module.base + 0x4543a0L, module.base + 0x4543a4L, null);
System.out.println("[hook] installed full-flow 0x2691a4->0x269330");
emulator.getBackend().hook_add_new(th, module.base + 0x26916cL, module.base + 0x2695dcL, null);
emulator.getBackend().hook_add_new(th, module.base + 0x4542c0L, module.base + 0x4542c4L, null);
emulator.getBackend().hook_add_new(th, module.base + 0x4543a0L, module.base + 0x4543c4L, null);
// to_string@0x4543c0 符号缺失(UC_ERR_READ_UNMAPPED) -> 269278 bl 换 NOP
byte[] nop = new byte[]{(byte)0x1f, (byte)0x20, (byte)0x03, (byte)0xd5};
try { emulator.getBackend().mem_write(module.base + 0x269278L, nop); System.out.println("[hook] NOP-patched 0x269278"); }
catch (Throwable tn) { System.out.println("[hook] NOP-patch failed: " + tn); }
System.out.println("[hook] MEGA + to_string bypass");
scanHeapWindow("[getOtp-pre]");
// BusinessCfg::getInstance @0x281270
Number inst = module.callFunction(emulator, 0x281270L);
@@ -310,6 +353,20 @@ public class AesProbe {
for (byte bb : rb) sb2.append(String.format("%02x", bb));
System.out.println("[getOtp] call ok, struct: " + sb2);
scanHeapWindow("[getOtp-post]");
System.out.println("[getOtp] instance dump 0x0-0xc0:");
{
byte[] ib = new byte[0xc0];
UnidbgPointer iptr = UnidbgPointer.pointer(emulator, thisPtr);
if (iptr != null) {
try { iptr.read(0, ib, 0, ib.length); } catch (Throwable te) {}
StringBuilder hx = new StringBuilder();
for (int i = 0; i < ib.length; i++) { hx.append(String.format("%02x", ib[i] & 0xff)); if (i % 2 == 1) hx.append(' '); }
System.out.println("[inst] " + hx);
StringBuilder asc = new StringBuilder();
for (int i = 0; i < ib.length; i++) asc.append((ib[i] >= 0x20 && ib[i] < 0x7f) ? (char) ib[i] : '.');
System.out.println("[inst] " + asc);
} else System.out.println("[inst] null iptr");
}
System.out.println("[getOtp] heap-scan done");
} catch (Throwable t) {
System.out.println("[getOtp] err: " + t);