feat(huya): turing JNI表解出+b87_@0x25c98 (R21)
- libturingmfa JNI 表: b87_(SparseArray,[B,Map,I)impl@0x25c98 + f87_ — 加密核心入口 - ELF 间隙洞察: LOAD-2 vaddr未4K对齐->unidbg映射崩因; mmap2补映射过导出 - TuringProbe.java: 装库+预注册类+gap补映射+直调框架(封送待办) - 路线: 直调b87_喂真实blob->SparseArray明文; ga侧JNI表同法
This commit is contained in:
@@ -0,0 +1,163 @@
|
||||
package hydev;
|
||||
|
||||
import com.github.unidbg.AndroidEmulator;
|
||||
import com.github.unidbg.Emulator;
|
||||
import com.github.unidbg.LibraryResolver;
|
||||
import com.github.unidbg.linux.android.AndroidEmulatorBuilder;
|
||||
import com.github.unidbg.linux.android.AndroidResolver;
|
||||
import com.github.unidbg.linux.android.dvm.*;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* TuringProbe: unidbg 装载 turing 双库 (libturingga/libturingmfa) + JNI_OnLoad,
|
||||
* 列出注册的原生方法 -> 定位加密入口偏移。
|
||||
*
|
||||
* 用法: java -cp $CP:out hydev.TuringProbe [ga|mfa|both]
|
||||
*/
|
||||
public class TuringProbe {
|
||||
|
||||
private final AndroidEmulator emulator;
|
||||
private final VM vm;
|
||||
|
||||
TuringProbe() {
|
||||
com.github.unidbg.arm.backend.BackendFactory backend = new com.github.unidbg.arm.backend.Unicorn2Factory(true);
|
||||
emulator = AndroidEmulatorBuilder.for64Bit()
|
||||
.setProcessName("com.duowan.kiwi")
|
||||
.addBackendFactory(backend)
|
||||
.build();
|
||||
vm = emulator.createDalvikVM();
|
||||
vm.setJni(new AbstractJni() {});
|
||||
vm.setVerbose(true);
|
||||
if (!new File("/Users/yml/codes/douyu_login_py/evidence/dfp_live/turingga.so").exists()) {
|
||||
System.out.println("[TuringProbe] missing libs in evidence/dfp_live/");
|
||||
}
|
||||
}
|
||||
|
||||
/** 预注册 turing 相关类 (JNI FindClass 需要) */
|
||||
void preResolveClasses() {
|
||||
String[] cls = {
|
||||
"com/tencent/turingfd/sdk/ams/ga/native",
|
||||
"com/tencent/turingfd/sdk/ams/ga/TNiT$aa",
|
||||
"com/tencent/turingfd/sdk/ams/ga/TNiT$if",
|
||||
"com/tencent/turingfd/sdk/ams/ga/Seedless",
|
||||
"com/tencent/turingfd/sdk/ams/ga/ITuringDID",
|
||||
"com/tencent/turingfd/sdk/ams/ga/TuringSDK",
|
||||
"com/tencent/turingfd/sdk/ams/ga/TNative$aa",
|
||||
"com/tencent/turingfd/sdk/ams/ga/TNative$if",
|
||||
"com/tencent/turingfd/sdk/ams/ga/Lemon",
|
||||
"com/tencent/turingfd/sdk/ams/ga/Pineapple",
|
||||
"android/util/SparseArray",
|
||||
};
|
||||
for (String c : cls) {
|
||||
try {
|
||||
vm.resolveClass(c);
|
||||
System.out.println("[TP] class ok " + c);
|
||||
} catch (Throwable t) {
|
||||
System.out.println("[TP] class '" + c + "' EXC " + t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void load(String which) {
|
||||
String base = "/Users/yml/codes/douyu_login_py/evidence/dfp_live/";
|
||||
try {
|
||||
switch (which) {
|
||||
case "ga": {
|
||||
DalvikModule dm = vm.loadLibrary(new File(base + "turingga.so"), false);
|
||||
dm.callJNI_OnLoad(emulator);
|
||||
System.out.println("[TP] libturingga JNI_OnLoad OK");
|
||||
break;
|
||||
}
|
||||
case "mfa": {
|
||||
DalvikModule dm = vm.loadLibrary(new File(base + "libturingmfa.so"), false);
|
||||
com.github.unidbg.Module m = dm.getModule();
|
||||
long gapBase = m.base + 0x45000;
|
||||
try {
|
||||
// mmap2(addr, len, PROT_READ|WRITE|EXEC=7, MAP_PRIVATE|ANON|FIXED=0x32, -1, 0)
|
||||
emulator.getMemory().mmap2(gapBase, 0x648, 7, 0x32, -1, 0);
|
||||
// 清零
|
||||
com.github.unidbg.pointer.UnidbgPointer.pointer(emulator, gapBase).setMemory(0, 0x648, (byte) 0);
|
||||
System.out.println("[TP] gap mapped @" + Long.toHexString(gapBase));
|
||||
} catch (Throwable t2) {
|
||||
System.out.println("[TP] gap map EXC " + t2);
|
||||
}
|
||||
try {
|
||||
dm.callJNI_OnLoad(emulator);
|
||||
System.out.println("[TP] libturingmfa JNI_OnLoad OK");
|
||||
} catch (Throwable t3) {
|
||||
System.out.println("[TP] onLoad EXC: " + t3);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
load("ga");
|
||||
load("mfa");
|
||||
}
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
System.out.println("[TP] load " + which + " EXC: " + t);
|
||||
try {
|
||||
com.github.unidbg.arm.ARM emu = (com.github.unidbg.arm.ARM) emulator;
|
||||
java.lang.reflect.Field f = emulator.getClass().getSuperclass().getDeclaredField("backend");
|
||||
f.setAccessible(true);
|
||||
Object be = f.get(emulator);
|
||||
java.lang.reflect.Method pc = be.getClass().getMethod("reg_read", int.class);
|
||||
System.out.println("[TP] PC=" + Long.toHexString(((Number) pc.invoke(be, com.github.unidbg.arm.backend.Unicorn2Factory.class.getField("UC_ARM64_REG_PC").getLong(null))).longValue()));
|
||||
} catch (Throwable t2) {
|
||||
System.out.println("[TP] pc-dump fail " + t2);
|
||||
}
|
||||
t.printStackTrace(System.out);
|
||||
}
|
||||
}
|
||||
|
||||
/** 直调 mfa 的 b87_ (impl@0x25c98) — JNI: (env, thiz, SparseArray, byte[], Map, int) -> SparseArray */
|
||||
void callEnc(String blobPath) {
|
||||
try {
|
||||
DalvikModule dm = vm.loadLibrary(new File("/Users/yml/codes/douyu_login_py/evidence/dfp_live/libturingmfa.so"), false);
|
||||
com.github.unidbg.Module m = dm.getModule();
|
||||
long gapBase = m.base + 0x45000;
|
||||
try { emulator.getMemory().mmap2(gapBase, 0x648, 7, 0x32, -1, 0); } catch (Throwable t2) {}
|
||||
byte[] blob = new java.io.FileInputStream(blobPath).readAllBytes();
|
||||
// SparseArray obj
|
||||
DvmObject<?> sa = vm.resolveClass("android/util/SparseArray").newObject(null);
|
||||
DvmObject<?> dba = vm.resolveClass("[B").newObject(blob);
|
||||
DvmObject<?> map = vm.resolveClass("java/util/HashMap").newObject(null);
|
||||
// 直调 impl: module.base + 0x25c98; 参数: env, null, sa, dba, map, 1
|
||||
long fn = m.base + 0x25c98;
|
||||
System.out.println("[TP] calling b87_ @ " + Long.toHexString(fn) + " blob=" + blob.length + "B");
|
||||
Number ret = m.callFunction(emulator, fn, vm.getJavaVM(), null, sa, dba, map, 1);
|
||||
System.out.println("[TP] b87_ ret=" + ret);
|
||||
} catch (Throwable t) {
|
||||
System.out.println("[TP] callEnc EXC " + t);
|
||||
t.printStackTrace(System.out);
|
||||
}
|
||||
}
|
||||
|
||||
void listNatives() {
|
||||
try {
|
||||
java.lang.reflect.Method m = BaseVM.class.getDeclaredMethod("listNativeMethods");
|
||||
// 尝试不同的内部访问; 失败则走 vm 自省
|
||||
System.out.println("[TP] vm class methods: ");
|
||||
for (java.lang.reflect.Method mm : vm.getClass().getDeclaredMethods()) {
|
||||
if (mm.getName().toLowerCase().contains("native") || mm.getName().toLowerCase().contains("register"))
|
||||
System.out.println(" " + mm.getName() + " " + java.util.Arrays.toString(mm.getParameterTypes()));
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
System.out.println("[TP] listNatives EXC " + t);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
TuringProbe p = new TuringProbe();
|
||||
String which = args.length > 0 ? args[0] : "both";
|
||||
p.preResolveClasses();
|
||||
if (which.equals("call")) {
|
||||
p.callEnc(args.length > 1 ? args[1] : "/tmp/dfp_str2.bin");
|
||||
} else {
|
||||
p.load(which);
|
||||
p.listNatives();
|
||||
}
|
||||
System.out.println("[TP] done");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user