diff --git a/README.md b/README.md index c66509b62..cfe97d3f2 100644 --- a/README.md +++ b/README.md @@ -56,3 +56,77 @@ Simple tests under src/test directory - [kaitai_struct](https://github.com/kaitai-io/kaitai_struct) - [fishhook](https://github.com/facebook/fishhook) - [runtime_class-dump](https://github.com/Tyilo/runtime_class-dump) + +## 在大佬的基础上增加了trace +相关代码在unidbg-api/src/main/java/king.trace中 +使用方式如下 + +~~~java +//添加忽略trace的模块 +GlobalData.ignoreModuleList.add("libc.so"); +GlobalData.ignoreModuleList.add("libhookzz.so"); +//添加内存监控,每个指令执行时,都查询该内存是否值有变化。比较消耗性能。 +GlobalData.watch_address.put(0x401db840,""); +//dump ldr的数据。包括ldr赋值给寄存器的如果是指针,也会dump +GlobalData.is_dump_ldr=true; +//dump str的数据 +GlobalData.is_dump_str=true; +KingTrace trace=new KingTrace(emulator); +trace.initialize(1,0,null); +emulator.getBackend().hook_add_new(trace,1,0,emulator); +~~~ + +trace的效果大致如下 + +~~~ +>-----------------------------------------------------------------------------< +[23:25:53 634]watch_address:401db840 onchange, md5=526e01d14f11b9492f77e174187cccf2, hex=46f0c2bbd0b705006cfeffff70feffffb0fdffff2de9304806489c2406497844 +size: 32 +0000: 46 F0 C2 BB D0 B7 05 00 6C FE FF FF 70 FE FF FF F.......l...p... +0010: B0 FD FF FF 2D E9 30 48 06 48 9C 24 06 49 78 44 ....-.0H.H.$.IxD +^-----------------------------------------------------------------------------^ +[ libc++.so] [0x32820] [ 2d e9 30 48 ] 0x401db820: push.w {r4, r5, fp, lr}-----r4=0x0 r5=0x0 //r4=0x700000000 + +>-----------------------------------------------------------------------------< +[23:25:53 639]ldr_right_address:401db840 dump, md5=ef93abe822600c1f7853f7391442906b, hex=46f0c2bbd0b705006cfeffff70feffffb0fdffff2de9304806489c24064978440d182819fef740e80c3c14f10c0ff8d1 +size: 48 +0000: 46 F0 C2 BB D0 B7 05 00 6C FE FF FF 70 FE FF FF F.......l...p... +0010: B0 FD FF FF 2D E9 30 48 06 48 9C 24 06 49 78 44 ....-.0H.H.$.IxD +0020: 0D 18 28 19 FE F7 40 E8 0C 3C 14 F1 0C 0F F8 D1 ..(...@..<...... +^-----------------------------------------------------------------------------^ +[ libc++.so] [0x32824] [ 07 4d ] 0x401db824: ldr r5, [pc, #0x1c]-----r5=0x0 pc=0x401db824 //r5=0x70005b7d0 + +>-----------------------------------------------------------------------------< +[23:25:53 642]ldr_right_address:401db846 dump, md5=d31277769916b0ea11452a4a5fd365dc, hex=05006cfeffff70feffffb0fdffff2de9304806489c24064978440d182819fef740e80c3c14f10c0ff8d1bde830889ab7 +size: 48 +0000: 05 00 6C FE FF FF 70 FE FF FF B0 FD FF FF 2D E9 ..l...p.......-. +0010: 30 48 06 48 9C 24 06 49 78 44 0D 18 28 19 FE F7 0H.H.$.IxD..(... +0020: 40 E8 0C 3C 14 F1 0C 0F F8 D1 BD E8 30 88 9A B7 @..<........0... +^-----------------------------------------------------------------------------^ +[ libc++.so] [0x32826] [ 08 48 ] 0x401db826: ldr r0, [pc, #0x20]-----r0=0x0 pc=0x401db826 //r0=0x7fffffe6c +[ libc++.so] [0x32828] [ 7d 44 ] 0x401db828: add r5, pc-----r5=0x5b7d0 pc=0x401db828 //r5=0x740236ffc +[ libc++.so] [0x3282c] [ 20 46 ] 0x401db82c: mov r0, r4-----r0=0xfffffe6c r4=0x40239040 //r0=0x740239040 +[ libc++.so] [0x3282e] [ fe f7 3e e8 ] 0x401db82e: blx #0x401d98ac +[ libc++.so] [0x308ac] [ 00 c6 8f e2 ] 0x401d98ac: add ip, pc, #0, #12-----ip=0x40082908 pc=0x401d98ac //sp=0x7bffff778 +[ libc++.so] [0x308b0] [ 5d ca 8c e2 ] 0x401d98b0: add ip, ip, #0x5d000-----ip=0x401d98b4 //sp=0x1bffff778 + +>-----------------------------------------------------------------------------< +[23:25:53 660]ldr_right_address:40237584 dump, md5=7334f49b4d7a7548eb1c3356311f48eb, hex=f9fd1f40f5892140598a2140299d1f40d1142140d19f214031962140e5122040814a2040c1a02140d12b2040e18b2140 +size: 48 +0000: F9 FD 1F 40 F5 89 21 40 59 8A 21 40 29 9D 1F 40 ...@..!@Y.!@)..@ +0010: D1 14 21 40 D1 9F 21 40 31 96 21 40 E5 12 20 40 ..!@..!@1.!@.. @ +0020: 81 4A 20 40 C1 A0 21 40 D1 2B 20 40 E1 8B 21 40 .J @..!@.+ @..!@ +^-----------------------------------------------------------------------------^ +[ libc++.so] [0x308b4] [ d0 fc bc e5 ] 0x401d98b4: ldr pc, [ip, #0xcd0]!-----ip=0x402368b4 pc=0x401d98b4 //sp=0xbffff778 + +>-----------------------------------------------------------------------------< +[23:25:53 663]ldr_left_address:bffff778 dump, md5=f0f77a5db1c6c46c94ec8a0ea7e43f56, hex=0000000000000000000000000000ffff000000000000000000fcffbf0000000000000000000000000000000000000000 +size: 48 +0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FF FF ................ +0010: 00 00 00 00 00 00 00 00 00 FC FF BF 00 00 00 00 ................ +0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +^-----------------------------------------------------------------------------^ +[ libc++.so] [0x56df8] [ 2d e9 f0 4f ] 0x401ffdf8: push.w {r4, r5, r6, r7, r8, sb, sl, fp, lr}-----r4=0x40239040 r5=0x40236ffc r6=0x0 r7=0x0 r8=0x0 //r4=0x40239040 +[ libc++.so] [0x56dfc] [ 81 b0 ] 0x401ffdfc: sub sp, #4-----sp=0xbffff754 //sp=0xbffff750 +~~~ + diff --git a/unidbg-android/src/test/java/com/bytedance/frameworks/core/encrypt/TTEncrypt.java b/unidbg-android/src/test/java/com/bytedance/frameworks/core/encrypt/TTEncrypt.java index 7bbe52a68..d4f6df09f 100644 --- a/unidbg-android/src/test/java/com/bytedance/frameworks/core/encrypt/TTEncrypt.java +++ b/unidbg-android/src/test/java/com/bytedance/frameworks/core/encrypt/TTEncrypt.java @@ -22,6 +22,8 @@ import com.github.unidbg.memory.Memory; import com.github.unidbg.utils.Inspector; import com.sun.jna.Pointer; +import king.trace.GlobalData; +import king.trace.KingTrace; import java.io.File; import java.io.IOException; @@ -50,6 +52,15 @@ public class TTEncrypt { module = dm.getModule(); // 加载好的libttEncrypt.so对应为一个模块 TTEncryptUtils = vm.resolveClass("com/bytedance/frameworks/core/encrypt/TTEncryptUtils"); + + GlobalData.ignoreModuleList.add("libc.so"); + GlobalData.ignoreModuleList.add("libhookzz.so"); + GlobalData.watch_address.put(0x401db840,""); + GlobalData.is_dump_ldr=true; + GlobalData.is_dump_str=true; + KingTrace trace=new KingTrace(emulator); + trace.initialize(1,0,null); + emulator.getBackend().hook_add_new(trace,1,0,emulator); } void destroy() throws IOException { @@ -152,7 +163,7 @@ public HookStatus onCall(Emulator emulator, long originFunction) { } if (logging) { - emulator.attach(DebuggerType.ANDROID_SERVER_V7); // 附加IDA android_server,可输入c命令取消附加继续运行 +// emulator.attach(DebuggerType.ANDROID_SERVER_V7); // 附加IDA android_server,可输入c命令取消附加继续运行 } byte[] data = new byte[16]; ByteArray array = TTEncryptUtils.callStaticJniMethodObject(emulator, "ttEncrypt([BI)[B", new ByteArray(vm, data), data.length); // 执行Jni方法 diff --git a/unidbg-android/src/test/java/com/sun/jna/JniDispatch32.java b/unidbg-android/src/test/java/com/sun/jna/JniDispatch32.java index f0a9e3ea8..0e603fdf3 100644 --- a/unidbg-android/src/test/java/com/sun/jna/JniDispatch32.java +++ b/unidbg-android/src/test/java/com/sun/jna/JniDispatch32.java @@ -22,6 +22,8 @@ import com.github.unidbg.memory.MemoryBlock; import com.github.unidbg.pointer.UnidbgPointer; import com.github.unidbg.utils.Inspector; +import king.trace.GlobalData; +import king.trace.KingTrace; import java.io.File; import java.io.IOException; diff --git a/unidbg-api/src/main/java/com/github/unidbg/arm/ARM.java b/unidbg-api/src/main/java/com/github/unidbg/arm/ARM.java index ed4bf459f..ffa9eb956 100644 --- a/unidbg-api/src/main/java/com/github/unidbg/arm/ARM.java +++ b/unidbg-api/src/main/java/com/github/unidbg/arm/ARM.java @@ -849,7 +849,7 @@ public static String readCString(Backend backend, long address) { } } - static String assembleDetail(Emulator emulator, Capstone.CsInsn ins, long address, boolean thumb) { + public static String assembleDetail(Emulator emulator, Capstone.CsInsn ins, long address, boolean thumb) { return assembleDetail(emulator, ins, address, thumb, false); } diff --git a/unidbg-api/src/main/java/king/trace/GlobalData.java b/unidbg-api/src/main/java/king/trace/GlobalData.java new file mode 100644 index 000000000..c31572a90 --- /dev/null +++ b/unidbg-api/src/main/java/king/trace/GlobalData.java @@ -0,0 +1,193 @@ +package king.trace; + +import unicorn.Arm64Const; +import unicorn.ArmConst; + +import java.util.*; + +public class GlobalData { + //上一次汇编指令 + public static String pre_codestr; + //上一次汇编的第一个寄存器名称 + public static String pre_regname; + //是否有记录上一次的数据 + public static boolean has_pre; + //监控的地址 + public static Map watch_address=new HashMap(); + //监控地址打印的内存数据长度 + public static int watch_print_size=0x20; + //计算结果和汇编的分隔符 + public static String print_split="-----"; + //忽略的module + public static List ignoreModuleList=new ArrayList<>(); + //忽略打印计算数据的操作指令 + public static List ignoreOpList=new ArrayList<>(); + //是否要dump汇编的ldr指令的内存 + public static boolean is_dump_ldr=false; + //是否要dump汇编的str指令的内存 + public static boolean is_dump_str=false; + //dump汇编的ldr指令内存的大小 + public static int dump_ldr_size=0x30; + //dump汇编的str指令内存的大小 + public static int dump_str_size=0x30; + + //arm64的对应寄存器,需要打印的就追加 + public static Map arm64_reg_names ; + static { + Map aMap =new HashMap(); + aMap.put("X0", Arm64Const.UC_ARM64_REG_X0); + aMap.put("X1", Arm64Const.UC_ARM64_REG_X1); + aMap.put("X2", Arm64Const.UC_ARM64_REG_X2); + aMap.put("X3", Arm64Const.UC_ARM64_REG_X3); + aMap.put("X4", Arm64Const.UC_ARM64_REG_X4); + aMap.put("X5", Arm64Const.UC_ARM64_REG_X5); + aMap.put("X6", Arm64Const.UC_ARM64_REG_X6); + aMap.put("X7", Arm64Const.UC_ARM64_REG_X7); + aMap.put("X8", Arm64Const.UC_ARM64_REG_X8); + aMap.put("X9", Arm64Const.UC_ARM64_REG_X9); + aMap.put("X10", Arm64Const.UC_ARM64_REG_X10); + aMap.put("X11", Arm64Const.UC_ARM64_REG_X11); + aMap.put("X12", Arm64Const.UC_ARM64_REG_X12); + aMap.put("X13", Arm64Const.UC_ARM64_REG_X13); + aMap.put("X14", Arm64Const.UC_ARM64_REG_X14); + aMap.put("X15", Arm64Const.UC_ARM64_REG_X15); + aMap.put("X16", Arm64Const.UC_ARM64_REG_X16); + aMap.put("X17", Arm64Const.UC_ARM64_REG_X17); + aMap.put("X18", Arm64Const.UC_ARM64_REG_X18); + aMap.put("X19", Arm64Const.UC_ARM64_REG_X19); + aMap.put("X20", Arm64Const.UC_ARM64_REG_X20); + aMap.put("X21", Arm64Const.UC_ARM64_REG_X21); + aMap.put("X22", Arm64Const.UC_ARM64_REG_X22); + aMap.put("X23", Arm64Const.UC_ARM64_REG_X23); + aMap.put("X24", Arm64Const.UC_ARM64_REG_X24); + aMap.put("X25", Arm64Const.UC_ARM64_REG_X25); + aMap.put("X26", Arm64Const.UC_ARM64_REG_X26); + aMap.put("X27", Arm64Const.UC_ARM64_REG_X27); + aMap.put("X28", Arm64Const.UC_ARM64_REG_X28); + aMap.put("X29", Arm64Const.UC_ARM64_REG_X29); + aMap.put("X30", Arm64Const.UC_ARM64_REG_X30); + aMap.put("W0", Arm64Const.UC_ARM64_REG_W0); + aMap.put("W1", Arm64Const.UC_ARM64_REG_W1); + aMap.put("W2", Arm64Const.UC_ARM64_REG_W2); + aMap.put("W3", Arm64Const.UC_ARM64_REG_W3); + aMap.put("W4", Arm64Const.UC_ARM64_REG_W4); + aMap.put("W5", Arm64Const.UC_ARM64_REG_W5); + aMap.put("W6", Arm64Const.UC_ARM64_REG_W6); + aMap.put("W7", Arm64Const.UC_ARM64_REG_W7); + aMap.put("W8", Arm64Const.UC_ARM64_REG_W8); + aMap.put("W9", Arm64Const.UC_ARM64_REG_W9); + aMap.put("W10", Arm64Const.UC_ARM64_REG_W10); + aMap.put("W11", Arm64Const.UC_ARM64_REG_W11); + aMap.put("W12", Arm64Const.UC_ARM64_REG_W12); + aMap.put("W13", Arm64Const.UC_ARM64_REG_W13); + aMap.put("W14", Arm64Const.UC_ARM64_REG_W14); + aMap.put("W15", Arm64Const.UC_ARM64_REG_W15); + aMap.put("W16", Arm64Const.UC_ARM64_REG_W16); + aMap.put("W17", Arm64Const.UC_ARM64_REG_W17); + aMap.put("W18", Arm64Const.UC_ARM64_REG_W18); + aMap.put("W19", Arm64Const.UC_ARM64_REG_W19); + aMap.put("W20", Arm64Const.UC_ARM64_REG_W20); + aMap.put("W21", Arm64Const.UC_ARM64_REG_W21); + aMap.put("W22", Arm64Const.UC_ARM64_REG_W22); + aMap.put("W23", Arm64Const.UC_ARM64_REG_W23); + aMap.put("W24", Arm64Const.UC_ARM64_REG_W24); + aMap.put("W25", Arm64Const.UC_ARM64_REG_W25); + aMap.put("W26", Arm64Const.UC_ARM64_REG_W26); + aMap.put("W27", Arm64Const.UC_ARM64_REG_W27); + aMap.put("W28", Arm64Const.UC_ARM64_REG_W28); + aMap.put("W29", Arm64Const.UC_ARM64_REG_W29); + aMap.put("W30", Arm64Const.UC_ARM64_REG_W30); + aMap.put("SP", Arm64Const.UC_ARM64_REG_SP); + aMap.put("XZR", Arm64Const.UC_ARM64_REG_XZR); + aMap.put("WZR", Arm64Const.UC_ARM64_REG_WZR); + aMap.put("IP", Arm64Const.UC_ARM64_REG_IP0); + aMap.put("PC", Arm64Const.UC_ARM64_REG_PC); + arm64_reg_names = Collections.unmodifiableMap(aMap); + } + //arm的对应寄存器 + public static Map arm_reg_names ; + static { + Map aMap =new HashMap(); + aMap.put("R0", ArmConst.UC_ARM_REG_R0); + aMap.put("R1", ArmConst.UC_ARM_REG_R1); + aMap.put("R2", ArmConst.UC_ARM_REG_R2); + aMap.put("R3", ArmConst.UC_ARM_REG_R3); + aMap.put("R4", ArmConst.UC_ARM_REG_R4); + aMap.put("R5", ArmConst.UC_ARM_REG_R5); + aMap.put("R6", ArmConst.UC_ARM_REG_R6); + aMap.put("R7", ArmConst.UC_ARM_REG_R7); + aMap.put("R8", ArmConst.UC_ARM_REG_R8); + aMap.put("R9", ArmConst.UC_ARM_REG_R9); + aMap.put("R10", ArmConst.UC_ARM_REG_R10); + aMap.put("R11", ArmConst.UC_ARM_REG_R11); + aMap.put("R12", ArmConst.UC_ARM_REG_R12); + aMap.put("R13", ArmConst.UC_ARM_REG_R13); + aMap.put("R14", ArmConst.UC_ARM_REG_R14); + aMap.put("R15", ArmConst.UC_ARM_REG_R15); + aMap.put("SP", ArmConst.UC_ARM_REG_SP); + aMap.put("IP", ArmConst.UC_ARM_REG_IP); + aMap.put("PC", ArmConst.UC_ARM_REG_PC); + arm_reg_names = Collections.unmodifiableMap(aMap); + } +// { +// "X0": unicorn.arm64_const.UC_ARM64_REG_X0, +// "X1": unicorn.arm64_const.UC_ARM64_REG_X1, +// "X2": unicorn.arm64_const.UC_ARM64_REG_X2, +// "X3": unicorn.arm64_const.UC_ARM64_REG_X3, +// "X4": unicorn.arm64_const.UC_ARM64_REG_X4, +// "X5": unicorn.arm64_const.UC_ARM64_REG_X5, +// "X6": unicorn.arm64_const.UC_ARM64_REG_X6, +// "X7": unicorn.arm64_const.UC_ARM64_REG_X7, +// "X8": unicorn.arm64_const.UC_ARM64_REG_X8, +// "X9": unicorn.arm64_const.UC_ARM64_REG_X9, +// "X10": unicorn.arm64_const.UC_ARM64_REG_X10, +// "X11": unicorn.arm64_const.UC_ARM64_REG_X11, +// "X12": unicorn.arm64_const.UC_ARM64_REG_X12, +// "X13": unicorn.arm64_const.UC_ARM64_REG_X13, +// "X14": unicorn.arm64_const.UC_ARM64_REG_X14, +// "X15": unicorn.arm64_const.UC_ARM64_REG_X15, +// "X16": unicorn.arm64_const.UC_ARM64_REG_X16, +// "X17": unicorn.arm64_const.UC_ARM64_REG_X17, +// "X18": unicorn.arm64_const.UC_ARM64_REG_X18, +// "X19": unicorn.arm64_const.UC_ARM64_REG_X19, +// "X20": unicorn.arm64_const.UC_ARM64_REG_X20, +// "X21": unicorn.arm64_const.UC_ARM64_REG_X21, +// "X22": unicorn.arm64_const.UC_ARM64_REG_X22, +// "X23": unicorn.arm64_const.UC_ARM64_REG_X23, +// "X24": unicorn.arm64_const.UC_ARM64_REG_X24, +// "X25": unicorn.arm64_const.UC_ARM64_REG_X25, +// "X26": unicorn.arm64_const.UC_ARM64_REG_X26, +// "X27": unicorn.arm64_const.UC_ARM64_REG_X27, +// "X28": unicorn.arm64_const.UC_ARM64_REG_X28, +// "W0": unicorn.arm64_const.UC_ARM64_REG_W0, +// "W1": unicorn.arm64_const.UC_ARM64_REG_W1, +// "W2": unicorn.arm64_const.UC_ARM64_REG_W2, +// "W3": unicorn.arm64_const.UC_ARM64_REG_W3, +// "W4": unicorn.arm64_const.UC_ARM64_REG_W4, +// "W5": unicorn.arm64_const.UC_ARM64_REG_W5, +// "W6": unicorn.arm64_const.UC_ARM64_REG_W6, +// "W7": unicorn.arm64_const.UC_ARM64_REG_W7, +// "W8": unicorn.arm64_const.UC_ARM64_REG_W8, +// "W9": unicorn.arm64_const.UC_ARM64_REG_W9, +// "W10": unicorn.arm64_const.UC_ARM64_REG_W10, +// "W11": unicorn.arm64_const.UC_ARM64_REG_W11, +// "W12": unicorn.arm64_const.UC_ARM64_REG_W12, +// "W13": unicorn.arm64_const.UC_ARM64_REG_W13, +// "W14": unicorn.arm64_const.UC_ARM64_REG_W14, +// "W15": unicorn.arm64_const.UC_ARM64_REG_W15, +// "W16": unicorn.arm64_const.UC_ARM64_REG_W16, +// "W17": unicorn.arm64_const.UC_ARM64_REG_W17, +// "W18": unicorn.arm64_const.UC_ARM64_REG_W18, +// "W19": unicorn.arm64_const.UC_ARM64_REG_W19, +// "W20": unicorn.arm64_const.UC_ARM64_REG_W20, +// "W21": unicorn.arm64_const.UC_ARM64_REG_W21, +// "W22": unicorn.arm64_const.UC_ARM64_REG_W22, +// "W23": unicorn.arm64_const.UC_ARM64_REG_W23, +// "W24": unicorn.arm64_const.UC_ARM64_REG_W24, +// "W25": unicorn.arm64_const.UC_ARM64_REG_W25, +// "W26": unicorn.arm64_const.UC_ARM64_REG_W26, +// "W27": unicorn.arm64_const.UC_ARM64_REG_W27, +// "W28": unicorn.arm64_const.UC_ARM64_REG_W28, +// "SP": unicorn.arm64_const.UC_ARM64_REG_SP, +// } +} diff --git a/unidbg-api/src/main/java/king/trace/KingTrace.java b/unidbg-api/src/main/java/king/trace/KingTrace.java new file mode 100644 index 000000000..20d21a447 --- /dev/null +++ b/unidbg-api/src/main/java/king/trace/KingTrace.java @@ -0,0 +1,285 @@ +package king.trace; + +import capstone.Capstone; +import com.github.unidbg.Emulator; +import com.github.unidbg.Module; +import com.github.unidbg.arm.ARM; +import com.github.unidbg.arm.backend.Backend; +import com.github.unidbg.arm.backend.BackendException; +import com.github.unidbg.arm.backend.CodeHook; +import com.github.unidbg.arm.backend.WriteHook; +import com.github.unidbg.listener.TraceCodeListener; +import com.github.unidbg.memory.Memory; +import com.github.unidbg.utils.Inspector; + +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class KingTrace implements CodeHook { + + private final Emulator emulator; + + public KingTrace(Emulator emulator) { + super(); + this.emulator = emulator; + if(this.emulator.is64Bit()){ + reg_names=GlobalData.arm64_reg_names; + }else{ + reg_names=GlobalData.arm_reg_names; + } + MemTrace memtrace=new MemTrace(false); + //将所有监控的内存监控地址都trace下 + for(Integer key:GlobalData.watch_address.keySet()){ + long start=key; + long end=GlobalData.watch_address.get(key); + emulator.getBackend().hook_add_new((WriteHook) memtrace,start,end,emulator); + } + } + + private boolean traceInstruction; + private long traceBegin, traceEnd; + private TraceCodeListener listener; + private Map reg_names; + + public void initialize(long begin, long end, TraceCodeListener listener) { + this.traceInstruction = true; + this.traceBegin = begin; + this.traceEnd = end; + this.listener = listener; + } + + private boolean canTrace(long address) { + return traceInstruction && (traceBegin > traceEnd || (address >= traceBegin && address <= traceEnd)); + } + + PrintStream redirect; + + public void setRedirect(PrintStream redirect) { + this.redirect = redirect; + } + + @Override + public void hook(Backend backend, long address, int size, Object user) { + if (canTrace(address)) { + try { + PrintStream out = System.out; + if (redirect != null) { + out = redirect; + } + Memory memory = this.emulator.getMemory(); + Module module = memory.findModuleByAddress(address); + if(GlobalData.ignoreModuleList.contains(module.name)){ + return; + } +// Capstone.CsInsn[] insns = emulator.printAssemble(out, address, size); + Capstone.CsInsn[] insns = this.emulator.disassemble(address, size,0); + if (insns == null || insns.length != 1) { + throw new IllegalStateException("insns=" + Arrays.toString(insns)); + } + printTrace(backend,insns,address); + + //printMsg(this.emulator, address, size, result); + if (listener != null) { + if (insns == null || insns.length != 1) { + throw new IllegalStateException("insns=" + Arrays.toString(insns)); + } + listener.onInstruction(emulator, address, insns[0]); + } + } catch (BackendException e) { + throw new IllegalStateException(e); + } + } + } + + private void printMsg(String msg){ + PrintStream out = System.out; + out.print(msg+"\n"); + } + + private void dump_ldr(Backend backend, String Opstr){ + if(!GlobalData.is_dump_ldr){ + return; + } + //然后直接根据打印读取位置的数据 + String pattern = "\\[(.+?)\\]"; + Pattern r = Pattern.compile(pattern); + Matcher m = r.matcher(Opstr); + if(m.find()){ + String ldrRight=m.group(1); + String[] rights=ldrRight.split(","); + String regRight=rights[0]; + String valueRight=rights[1]; + Integer regIndex=reg_names.get(regRight.toUpperCase()); + if(regIndex==0){ + throw new IllegalStateException("not found regname:"+regRight); + } + Number regRightValue= backend.reg_read(regIndex); + long right; + if(reg_names.containsKey(valueRight.toUpperCase())){ + Integer regIndex2=reg_names.get(valueRight.toUpperCase()); + Number regRightValue2= backend.reg_read(regIndex2); + if(emulator.is64Bit()){ + right=regRightValue.longValue()+regRightValue2.longValue(); + }else{ + right=regRightValue.intValue()+regRightValue2.intValue(); + } + + }else{ + valueRight=valueRight.replace("#","").trim(); + long valueRightInt; + if(valueRight.startsWith("0x")){ + valueRight=valueRight.replace("0x",""); + valueRightInt=Integer.parseInt(valueRight,16); + }else{ + valueRightInt=Integer.parseInt(valueRight); + } + if(emulator.is64Bit()){ + right=regRightValue.longValue()+valueRightInt; + }else{ + right=regRightValue.intValue()+valueRightInt; + } + + } + try{ + long unsignedValue=OtherTools.toUnsignedLong(right); + byte[] dump_buff= backend.mem_read(unsignedValue,GlobalData.dump_str_size); + Inspector.inspect(dump_buff, String.format("ldr_right_address:%x dump",unsignedValue)); + }catch(Exception ex){ + + } + } + } + + private void printTrace(Backend backend, Capstone.CsInsn[] insns , long address) { + for (Capstone.CsInsn ins : insns) { + //查询上否有上一条缓存的指令,有的话,则查询上次的改动寄存器的数值。然后再打印 + if (GlobalData.has_pre && !GlobalData.pre_regname.equals("")){ + Integer regindex = reg_names.get(GlobalData.pre_regname.toUpperCase()); + Number regvalue = backend.reg_read(regindex); + if(emulator.is32Bit() || GlobalData.pre_regname.toUpperCase().startsWith("W")){ + GlobalData.pre_codestr+=String.format("\t//%s=0x%x" , GlobalData.pre_regname,OtherTools.toUnsignedInt(regvalue.intValue())); + }else{ + GlobalData.pre_codestr+=String.format("\t//%s=0x%x" , GlobalData.pre_regname,OtherTools.toUnsignedLong(regvalue.longValue())); + } + + printMsg(GlobalData.pre_codestr); + //是否要dump汇编str + if(GlobalData.is_dump_str){ + if(GlobalData.pre_codestr.contains(" str") ){ + if(regvalue.longValue()>0xffff){ + try{ + byte[] dump_buff= backend.mem_read(regvalue.longValue(),GlobalData.dump_str_size); + Inspector.inspect(dump_buff, String.format("str_address:%x dump",regvalue.longValue())); + }catch(Exception ex){ + + } + + } + } + } + //是否要dump汇编的ldr指令 + if(GlobalData.is_dump_ldr){ + if(GlobalData.pre_codestr.contains(" ldr")){ + //先尝试把ldr的结果当成指针去尝试读取 + if(regvalue.longValue()>0xffff){ + try{ + byte[] dump_buff= backend.mem_read(regvalue.longValue(),GlobalData.dump_str_size); + Inspector.inspect(dump_buff, String.format("ldr_left_address:%x dump",regvalue.longValue())); + }catch(Exception ex){ + + } + } + } + } + + GlobalData.pre_codestr=""; + GlobalData.pre_regname=""; + GlobalData.has_pre=false; + } + //内存监控,发生变化就打印 +// if (GlobalData.watch_address.size()>0){ +// for (Integer watch:GlobalData.watch_address.keySet()) { +// byte[] idata= backend.mem_read(watch,GlobalData.watch_print_size); +// String hexstr= OtherTools.byteToString(idata); +// if(GlobalData.watch_address.get(watch).equals(hexstr)){ +// continue; +// } +// GlobalData.watch_address.put(watch,hexstr); +// Inspector.inspect(idata, String.format("watch_address:%x onchange",watch)); +// } +// } + + + //拼接当前行的汇编指令 + String opstr= ARM.assembleDetail(emulator, ins, address, false); + //从当前行指令中匹配出所有的寄存器 + String pattern = ""; + if(emulator.is64Bit()){ + pattern="[^0]([wx][0-9]+)"; + }else if(emulator.is32Bit()){ + pattern="[^0]([r][0-9]+)"; + } + Pattern r = Pattern.compile(pattern); + Matcher m = r.matcher(" "+opstr); + ArrayList regs=new ArrayList(); + if(m.find()){ + GlobalData.pre_regname=m.group(1); + regs.add(m.group(1)); + } + while(m.find()){ + regs.add(m.group(1)); + } + if (ins.opStr.contains("sp")){ + regs.add("sp"); + if(GlobalData.pre_regname.equals("")){ + GlobalData.pre_regname="sp"; + } + } + if (ins.opStr.contains("ip")){ + regs.add("ip"); + if(GlobalData.pre_regname.equals("")){ + GlobalData.pre_regname="sp"; + } + } + if (ins.opStr.contains("pc")){ + regs.add("pc"); + if(GlobalData.pre_regname.equals("")){ + GlobalData.pre_regname="sp"; + } + } + //如果当前指令没有寄存器。则直接打印。下次无需再打印上次的结果 + if (regs.size()<=0){ + GlobalData.has_pre=false; + GlobalData.pre_codestr=""; + GlobalData.pre_regname=""; + printMsg(opstr); + continue; + } + String curRegs=""; + for(String reg:regs){ + Integer regindex=reg_names.get(reg.toUpperCase()); + Number regvalue=backend.reg_read(regindex); + if(emulator.is32Bit()||reg.toUpperCase().startsWith("W")){ + curRegs+=String.format("%s=0x%x\t" , reg,OtherTools.toUnsignedInt(regvalue.intValue())); + }else{ + curRegs+=String.format("%s=0x%x\t" , reg,OtherTools.toUnsignedLong(regvalue.longValue())); + } + } +// if(opstr.contains(" ldr")){ +// String ldrstr=opstr.split("ldr")[1]; +// dump_ldr(backend,ldrstr); +// } + + + + GlobalData.pre_codestr=opstr +GlobalData.print_split+ curRegs; + GlobalData.has_pre=true; + address += ins.size; + } + } + +} diff --git a/unidbg-api/src/main/java/king/trace/MemTrace.java b/unidbg-api/src/main/java/king/trace/MemTrace.java new file mode 100644 index 000000000..8bbb85340 --- /dev/null +++ b/unidbg-api/src/main/java/king/trace/MemTrace.java @@ -0,0 +1,92 @@ +package king.trace; + + +import com.github.unidbg.Emulator; +import com.github.unidbg.arm.backend.Backend; +import com.github.unidbg.arm.backend.BackendException; +import com.github.unidbg.arm.backend.ReadHook; +import com.github.unidbg.arm.backend.WriteHook; +import com.github.unidbg.arm.context.RegisterContext; +import com.github.unidbg.listener.TraceReadListener; +import com.github.unidbg.listener.TraceWriteListener; +import com.github.unidbg.pointer.UnidbgPointer; +import com.github.unidbg.utils.Inspector; +import org.apache.commons.codec.binary.Hex; + +import java.io.PrintStream; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * trace memory read + * Created by zhkl0228 on 2017/5/2. + */ + +public class MemTrace implements ReadHook, WriteHook { + + private final boolean read; + + public MemTrace(boolean read) { + this.read = read; + } + + PrintStream redirect; + TraceReadListener traceReadListener; + TraceWriteListener traceWriteListener; + + @Override + public void hook(Backend backend, long address, int size, Object user) { + if (!read) { + return; + } + + try { + byte[] data = backend.mem_read(address, size); + String value; + if (data.length == 4) { + value = "0x" + Long.toHexString(ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN).getInt() & 0xffffffffL); + } else { + value = Hex.encodeHexString(data); + } + Emulator emulator = (Emulator) user; + if (traceReadListener == null || traceReadListener.onRead(emulator, address, data, value)) { + printMsg("### Memory READ at 0x", emulator, address, size, value); + } + } catch (BackendException e) { + throw new IllegalStateException(e); + } + } + + private void printMsg(String type, Emulator emulator, long address, int size, String value) { + RegisterContext context = emulator.getContext(); + UnidbgPointer pc = context.getPCPointer(); + UnidbgPointer lr = context.getLRPointer(); + PrintStream out = System.out; + if (redirect != null) { + out = redirect; + } + String sb = type + Long.toHexString(address) + ", data size = " + size + ", data value = " + value + + " pc=" + pc + + " lr=" + lr; + out.println(sb); + } + + @Override + public void hook(Backend backend, long address, int size, long value, Object user) { + if (read) { + return; + } + + try { + Emulator emulator = (Emulator) user; + if (traceWriteListener == null || traceWriteListener.onWrite(emulator, address, size, value)) { + printMsg("### Memory WRITE at 0x", emulator, address, size, "0x" + Long.toHexString(value)); + byte[] idata= backend.mem_read(address,GlobalData.watch_print_size); + Inspector.inspect(idata, String.format("watch_address:%x onchange",address)); + } + } catch (BackendException e) { + throw new IllegalStateException(e); + } + } + +} diff --git a/unidbg-api/src/main/java/king/trace/OtherTools.java b/unidbg-api/src/main/java/king/trace/OtherTools.java new file mode 100644 index 000000000..bd486d38d --- /dev/null +++ b/unidbg-api/src/main/java/king/trace/OtherTools.java @@ -0,0 +1,20 @@ +package king.trace; + +public class OtherTools { + public static String byteToString(byte[] b) { + char[] _16 = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; + StringBuilder sb = new StringBuilder(); + for(int i = 0 ; i>4&0xf]) + .append(_16[b[i]&0xf]); + } + return sb.toString(); + } + + public static int toUnsignedInt(int data){ + return data&0xffffffff; + } + public static long toUnsignedLong(long data){ + return data&0xffffffffffffffffl; + } +}