From 4f563490e2c26e49c0d5e98ebde8adebddc5d476 Mon Sep 17 00:00:00 2001 From: Robert Xiao Date: Sun, 14 May 2023 16:23:49 -0700 Subject: [PATCH] Update Java samples to match C samples. Also add all of the samples as Java tests, referencing the output of the C samples. --- .../java/samples/SampleNetworkAuditing.java | 26 +- bindings/java/samples/Sample_arm.java | 305 ++++- bindings/java/samples/Sample_arm64.java | 274 +++- bindings/java/samples/Sample_ctl.java | 159 +++ bindings/java/samples/Sample_m68k.java | 157 +-- bindings/java/samples/Sample_mips.java | 70 +- bindings/java/samples/Sample_mmu.java | 224 +++ bindings/java/samples/Sample_ppc.java | 91 ++ bindings/java/samples/Sample_riscv.java | 477 +++++++ bindings/java/samples/Sample_s390x.java | 88 ++ bindings/java/samples/Sample_sparc.java | 77 +- bindings/java/samples/Sample_tricore.java | 84 ++ bindings/java/samples/Sample_x86.java | 1212 +++++++++++------ bindings/java/samples/Sample_x86_mmr.java | 27 +- bindings/java/samples/Shellcode.java | 170 +-- bindings/java/samples/Utils.java | 49 + bindings/java/tests/FunctionalityTests.java | 5 - bindings/java/tests/HookTests.java | 5 - bindings/java/tests/MemTests.java | 7 - bindings/java/tests/RegTests.java | 8 - bindings/java/tests/RegressionTests.java | 1 - bindings/java/tests/TestSamples.java | 1140 +++++++++++++++- samples/sample_arm64.c | 88 ++ samples/sample_tricore.c | 6 +- samples/sample_x86.c | 40 +- 25 files changed, 3884 insertions(+), 906 deletions(-) create mode 100644 bindings/java/samples/Sample_ctl.java create mode 100644 bindings/java/samples/Sample_mmu.java create mode 100644 bindings/java/samples/Sample_ppc.java create mode 100644 bindings/java/samples/Sample_riscv.java create mode 100644 bindings/java/samples/Sample_s390x.java create mode 100644 bindings/java/samples/Sample_tricore.java create mode 100644 bindings/java/samples/Utils.java diff --git a/bindings/java/samples/SampleNetworkAuditing.java b/bindings/java/samples/SampleNetworkAuditing.java index 95e567fd..7b689a5d 100644 --- a/bindings/java/samples/SampleNetworkAuditing.java +++ b/bindings/java/samples/SampleNetworkAuditing.java @@ -29,7 +29,7 @@ package samples; import unicorn.*; import java.util.*; -public class SampleNetworkAuditing { +public class SampleNetworkAuditing implements UnicornConst, X86Const { public static long next_id = 3; public static final int SIZE_REG = 4; @@ -67,11 +67,11 @@ public class SampleNetworkAuditing { if (intno != 0x80) { return; } - long eax = uc.reg_read(Unicorn.UC_X86_REG_EAX); - long ebx = uc.reg_read(Unicorn.UC_X86_REG_EBX); - long ecx = uc.reg_read(Unicorn.UC_X86_REG_ECX); - long edx = uc.reg_read(Unicorn.UC_X86_REG_EDX); - long eip = uc.reg_read(Unicorn.UC_X86_REG_EIP); + long eax = uc.reg_read(UC_X86_REG_EAX); + long ebx = uc.reg_read(UC_X86_REG_EBX); + long ecx = uc.reg_read(UC_X86_REG_ECX); + long edx = uc.reg_read(UC_X86_REG_EDX); + long eip = uc.reg_read(UC_X86_REG_EIP); // System.out.printf(">>> INTERRUPT %d\n", toInt(eax)); @@ -114,7 +114,7 @@ public class SampleNetworkAuditing { String filename = read_string(uc, filename_addr); long dummy_fd = get_id(); - uc.reg_write(Unicorn.UC_X86_REG_EAX, dummy_fd); + uc.reg_write(UC_X86_REG_EAX, dummy_fd); String msg = String.format( "open file (filename=%s flags=%d mode=%d) with fd(%d)", @@ -133,8 +133,8 @@ public class SampleNetworkAuditing { System.out.printf(">>> SYS_DUP2 oldfd=%d newfd=%d\n", ebx, ecx); } else if (eax == 102) { // sys_socketcall // ref: http://www.skyfree.org/linux/kernel_network/socket.html - long call = uc.reg_read(Unicorn.UC_X86_REG_EBX); - long args = uc.reg_read(Unicorn.UC_X86_REG_ECX); + long call = uc.reg_read(UC_X86_REG_EBX); + long args = uc.reg_read(UC_X86_REG_ECX); // int sys_socketcall(int call, unsigned long *args) if (call == 1) { // sys_socket @@ -147,7 +147,7 @@ public class SampleNetworkAuditing { toInt(uc.mem_read(args + SIZE_REG * 2, SIZE_REG)); long dummy_fd = get_id(); - uc.reg_write(Unicorn.UC_X86_REG_EAX, dummy_fd); + uc.reg_write(UC_X86_REG_EAX, dummy_fd); if (family == 2) { // AF_INET String msg = @@ -437,16 +437,16 @@ public class SampleNetworkAuditing { System.out.printf("Emulate i386 code\n"); try { // Initialize emulator in X86-32bit mode - Unicorn mu = new Unicorn(Unicorn.UC_ARCH_X86, Unicorn.UC_MODE_32); + Unicorn mu = new Unicorn(UC_ARCH_X86, UC_MODE_32); // map 2MB memory for this emulation - mu.mem_map(ADDRESS, 2 * 1024 * 1024, Unicorn.UC_PROT_ALL); + mu.mem_map(ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory mu.mem_write(ADDRESS, code); // initialize stack - mu.reg_write(Unicorn.UC_X86_REG_ESP, ADDRESS + 0x200000L); + mu.reg_write(UC_X86_REG_ESP, ADDRESS + 0x200000L); // handle interrupt ourself mu.hook_add(new MyInterruptHook(), null); diff --git a/bindings/java/samples/Sample_arm.java b/bindings/java/samples/Sample_arm.java index fc5b7dd1..77ba0d39 100644 --- a/bindings/java/samples/Sample_arm.java +++ b/bindings/java/samples/Sample_arm.java @@ -5,111 +5,117 @@ package samples; +import java.util.Arrays; + import unicorn.*; -public class Sample_arm { +public class Sample_arm implements UnicornConst, ArmConst { - // code to be emulated - public static final byte[] ARM_CODE = - { 55, 0, (byte) 0xa0, (byte) 0xe3, 3, 16, 66, (byte) 0xe0 }; // mov r0, #0x37; sub r1, r2, r3 - public static final byte[] THUMB_CODE = { (byte) 0x83, (byte) 0xb0 }; // sub sp, #0xc + /** code to be emulated {@code mov r0, #0x37; sub r1, r2, r3} */ + // private static final byte[] ARM_CODE = Utils.hexToBytes("3700a0e3031042e0"); + /** code to be emulated {@code nop} */ + private static final byte[] ARM_CODE = Utils.hexToBytes("00f020e3"); - // memory address where emulation starts - public static final int ADDRESS = 0x10000; + /** code to be emulated {@code sub sp, #0xc} */ + private static final byte[] THUMB_CODE = Utils.hexToBytes("83b0"); - public static final long toInt(byte val[]) { - long res = 0; - for (int i = 0; i < val.length; i++) { - long v = val[i] & 0xff; - res = res + (v << (i * 8)); - } - return res; - } + /** code to be emulated + *
+     * cmp r2, r3
+     * it ne
+     * mov r2, #0x68
+     * mov r2, #0x4d
+     * 
+ */ + private static final byte[] ARM_THUMB_COND_CODE = + Utils.hexToBytes("9a4214bf68224d22"); - private static class MyBlockHook implements BlockHook { - public void hook(Unicorn u, long address, int size, Object user_data) { - System.out.print(String.format( - ">>> Tracing basic block at 0x%x, block size = 0x%x\n", address, - size)); - } - } + /** code to be emulated {@code mov r0, #0x37; sub r1, r2, r3} */ + private static final byte[] ARM_CODE_EB = + Utils.hexToBytes("e3a00037e0421003"); + /** code to be emulated {@code sub sp, #0xc} */ + private static final byte[] THUMB_CODE_EB = Utils.hexToBytes("b083"); - // callback for tracing instruction - private static class MyCodeHook implements CodeHook { - public void hook(Unicorn u, long address, int size, Object user_data) { - System.out.print(String.format( + /** {@code 0xf3ef8014 - mrs r0, control} */ + private static final byte[] THUMB_CODE_MRS = Utils.hexToBytes("eff31480"); + + /** memory address where emulation starts */ + private static final long ADDRESS = 0x10000; + + private static final BlockHook hook_block = + (uc, address, size, user_data) -> { + System.out.format( + ">>> Tracing basic block at 0x%x, block size = 0x%x\n", + address, size); + }; + + private static final CodeHook hook_code = + (uc, address, size, user_data) -> { + System.out.format( ">>> Tracing instruction at 0x%x, instruction size = 0x%x\n", - address, size)); - } - } + address, size); + }; public static void test_arm() { - long r0 = 0x1234L; // R0 register long r2 = 0x6789L; // R1 register long r3 = 0x3333L; // R2 register - long r1; // R1 register - System.out.print("Emulate ARM code\n"); + System.out.println("Emulate ARM code"); // Initialize emulator in ARM mode - Unicorn u = new Unicorn(Unicorn.UC_ARCH_ARM, Unicorn.UC_MODE_ARM); + Unicorn u = new Unicorn(UC_ARCH_ARM, UC_MODE_ARM); // map 2MB memory for this emulation - u.mem_map(ADDRESS, 2 * 1024 * 1024, Unicorn.UC_PROT_ALL); + u.mem_map(ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory u.mem_write(ADDRESS, ARM_CODE); // initialize machine registers - u.reg_write(Unicorn.UC_ARM_REG_R0, r0); - u.reg_write(Unicorn.UC_ARM_REG_R2, r2); - u.reg_write(Unicorn.UC_ARM_REG_R3, r3); + u.reg_write(UC_ARM_REG_R0, r0); + u.reg_write(UC_ARM_REG_R2, r2); + u.reg_write(UC_ARM_REG_R3, r3); // tracing all basic blocks with customized callback - u.hook_add(new MyBlockHook(), 1, 0, null); + u.hook_add(hook_block, 1, 0, null); // tracing one instruction at ADDRESS with customized callback - u.hook_add(new MyCodeHook(), ADDRESS, ADDRESS, null); + u.hook_add(hook_code, ADDRESS, ADDRESS, null); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. u.emu_start(ADDRESS, ADDRESS + ARM_CODE.length, 0, 0); // now print out some registers - System.out.print(">>> Emulation done. Below is the CPU context\n"); + System.out.println(">>> Emulation done. Below is the CPU context"); - r0 = u.reg_read(Unicorn.UC_ARM_REG_R0); - r1 = u.reg_read(Unicorn.UC_ARM_REG_R1); - System.out.print(String.format(">>> R0 = 0x%x\n", r0)); - System.out.print(String.format(">>> R1 = 0x%x\n", r1)); - - u.close(); + System.out.format(">>> R0 = 0x%x\n", u.reg_read(UC_ARM_REG_R0)); + System.out.format(">>> R1 = 0x%x\n", u.reg_read(UC_ARM_REG_R1)); } public static void test_thumb() { - long sp = 0x1234L; // R0 register - System.out.print("Emulate THUMB code\n"); + System.out.println("Emulate THUMB code"); // Initialize emulator in ARM mode - Unicorn u = new Unicorn(Unicorn.UC_ARCH_ARM, Unicorn.UC_MODE_THUMB); + Unicorn u = new Unicorn(UC_ARCH_ARM, UC_MODE_THUMB); // map 2MB memory for this emulation - u.mem_map(ADDRESS, 2 * 1024 * 1024, Unicorn.UC_PROT_ALL); + u.mem_map(ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory u.mem_write(ADDRESS, THUMB_CODE); // initialize machine registers - u.reg_write(Unicorn.UC_ARM_REG_SP, sp); + u.reg_write(UC_ARM_REG_SP, sp); // tracing all basic blocks with customized callback - u.hook_add(new MyBlockHook(), 1, 0, null); + u.hook_add(hook_block, 1, 0, null); // tracing one instruction at ADDRESS with customized callback - u.hook_add(new MyCodeHook(), ADDRESS, ADDRESS, null); + u.hook_add(hook_code, ADDRESS, ADDRESS, null); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. @@ -117,17 +123,204 @@ public class Sample_arm { // now print out some registers System.out.print(">>> Emulation done. Below is the CPU context\n"); + System.out.format(">>> SP = 0x%x\n", u.reg_read(UC_ARM_REG_SP)); + } - sp = u.reg_read(Unicorn.UC_ARM_REG_SP); - System.out.print(String.format(">>> SP = 0x%x\n", sp)); + public static void test_armeb() { + long r0 = 0x1234L; // R0 register + long r2 = 0x6789L; // R1 register + long r3 = 0x3333L; // R2 register - u.close(); + System.out.println("Emulate ARM Big-Endian code"); + + // Initialize emulator in ARM mode + Unicorn uc = new Unicorn(UC_ARCH_ARM, UC_MODE_ARM | UC_MODE_BIG_ENDIAN); + + // map 2MB memory for this emulation + uc.mem_map(ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + + // write machine code to be emulated to memory + uc.mem_write(ADDRESS, ARM_CODE_EB); + + // initialize machine registers + uc.reg_write(UC_ARM_REG_R0, r0); + uc.reg_write(UC_ARM_REG_R2, r2); + uc.reg_write(UC_ARM_REG_R3, r3); + + // tracing all basic blocks with customized callback + uc.hook_add(hook_block, 1, 0, null); + + // tracing one instruction at ADDRESS with customized callback + uc.hook_add(hook_code, ADDRESS, ADDRESS, null); + + // emulate machine code in infinite time (last param = 0), or when + // finishing all the code. + uc.emu_start(ADDRESS, ADDRESS + ARM_CODE_EB.length, 0, 0); + + // now print out some registers + System.out.println(">>> Emulation done. Below is the CPU context"); + System.out.format(">>> R0 = 0x%x\n", uc.reg_read(UC_ARM_REG_R0)); + System.out.format(">>> R1 = 0x%x\n", uc.reg_read(UC_ARM_REG_R1)); + } + + public static void test_thumbeb() { + long sp = 0x1234L; + + System.out.println("Emulate THUMB Big-Endian code"); + + // Initialize emulator in ARM mode + Unicorn uc = + new Unicorn(UC_ARCH_ARM, UC_MODE_THUMB + UC_MODE_BIG_ENDIAN); + + // map 2MB memory for this emulation + uc.mem_map(ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + + // write machine code to be emulated to memory + uc.mem_write(ADDRESS, THUMB_CODE_EB); + + // initialize machine registers + uc.reg_write(UC_ARM_REG_SP, sp); + + // tracing all basic blocks with customized callback + uc.hook_add(hook_block, 1, 0, null); + + // tracing one instruction at ADDRESS with customized callback + uc.hook_add(hook_code, ADDRESS, ADDRESS, null); + + // emulate machine code in infinite time (last param = 0), or when + // finishing all the code. + // Note we start at ADDRESS | 1 to indicate THUMB mode. + uc.emu_start(ADDRESS | 1, ADDRESS + THUMB_CODE_EB.length, 0, 0); + + // now print out some registers + System.out.println(">>> Emulation done. Below is the CPU context"); + System.out.format(">>> SP = 0x%x\n", uc.reg_read(UC_ARM_REG_SP)); + } + + public static void test_thumb_mrs() { + System.out.println("Emulate THUMB MRS instruction"); + // 0xf3ef8014 - mrs r0, control + + // Initialize emulator in ARM mode + Unicorn uc = new Unicorn(UC_ARCH_ARM, UC_MODE_THUMB); + + // Setup the cpu model. + uc.ctl_set_cpu_model(UC_CPU_ARM_CORTEX_M33); + + // map 2MB memory for this emulation + uc.mem_map(ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + + // write machine code to be emulated to memory + uc.mem_write(ADDRESS, THUMB_CODE_MRS); + + // tracing all basic blocks with customized callback + uc.hook_add(hook_block, 1, 0, null); + + // tracing one instruction at ADDRESS with customized callback + uc.hook_add(hook_code, ADDRESS, ADDRESS, null); + + // emulate machine code in infinite time (last param = 0), or when + // finishing all the code. + + // Note we start at ADDRESS | 1 to indicate THUMB mode. + uc.emu_start(ADDRESS | 1, ADDRESS + THUMB_CODE_MRS.length, 0, 1); + + // now print out some registers + System.out.println(">>> Emulation done. Below is the CPU context"); + + long pc = uc.reg_read(UC_ARM_REG_PC); + System.out.format(">>> PC = 0x%x\n", pc); + if (pc != ADDRESS + 4) { + System.out.format("Error, PC was 0x%x, expected was 0x%x.\n", pc, + ADDRESS + 4); + } + } + + private static void test_thumb_ite_internal(boolean step, long[] r2r3) { + Unicorn uc = new Unicorn(UC_ARCH_ARM, UC_MODE_THUMB); + + uc.mem_map(ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + + uc.mem_write(ADDRESS, ARM_THUMB_COND_CODE); + + uc.reg_write(UC_ARM_REG_SP, 0x1234L); + + uc.reg_write(UC_ARM_REG_R2, 0); + uc.reg_write(UC_ARM_REG_R3, 1); + + if (!step) { + uc.emu_start(ADDRESS | 1, ADDRESS + ARM_THUMB_COND_CODE.length, 0, + 0); + } else { + long addr = ADDRESS; + for (int i = 0; i < ARM_THUMB_COND_CODE.length / 2; i++) { + uc.emu_start(addr | 1, ADDRESS + ARM_THUMB_COND_CODE.length, 0, + 1); + addr = uc.reg_read(UC_ARM_REG_PC); + } + } + + r2r3[0] = uc.reg_read(UC_ARM_REG_R2); + r2r3[1] = uc.reg_read(UC_ARM_REG_R3); + } + + public static void test_thumb_ite() { + long[] r2r3 = new long[2]; + long[] step_r2r3 = new long[2]; + + System.out.println( + "Emulate a THUMB ITE block as a whole or per instruction."); + + // Run once. + System.out.println("Running the entire binary."); + test_thumb_ite_internal(false, r2r3); + System.out.format(">>> R2: %d\n", r2r3[0]); + System.out.format(">>> R3: %d\n\n", r2r3[1]); + + // Step each instruction. + System.out.println("Running the binary one instruction at a time."); + test_thumb_ite_internal(true, step_r2r3); + System.out.format(">>> R2: %d\n", step_r2r3[0]); + System.out.format(">>> R3: %d\n\n", step_r2r3[1]); + + if (!Arrays.equals(r2r3, step_r2r3)) { + System.out.println("Failed with ARM ITE blocks stepping!"); + } + } + + public static void test_read_sctlr() { + System.out.println("Read the SCTLR register."); + + Unicorn uc = new Unicorn(UC_ARCH_ARM, UC_MODE_ARM); + + // SCTLR. See arm reference. + Arm_CP reg = new Arm_CP(15, 0, 0, 1, 0, 0, 0); + long val = (Long) uc.reg_read(UC_ARM_REG_CP_REG, reg); + + System.out.format(">>> SCTLR = 0x%x\n", val & 0xffffffffL); + System.out.format(">>> SCTLR.IE = %d\n", (val >> 31) & 1); + System.out.format(">>> SCTLR.B = %d\n", (val >> 7) & 1); } public static void main(String args[]) { test_arm(); System.out.print("==========================\n"); test_thumb(); + + System.out.print("==========================\n"); + test_armeb(); + + System.out.print("==========================\n"); + test_thumbeb(); + + System.out.print("==========================\n"); + test_thumb_mrs(); + + System.out.print("==========================\n"); + test_thumb_ite(); + + System.out.print("==========================\n"); + test_read_sctlr(); } } diff --git a/bindings/java/samples/Sample_arm64.java b/bindings/java/samples/Sample_arm64.java index 151bf58b..e8b4a4a7 100644 --- a/bindings/java/samples/Sample_arm64.java +++ b/bindings/java/samples/Sample_arm64.java @@ -26,94 +26,262 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. package samples; +import java.util.Arrays; + import unicorn.*; -public class Sample_arm64 { +public class Sample_arm64 implements UnicornConst, Arm64Const { - // code to be emulated - public static final byte[] ARM_CODE = { -85, 1, 15, -117 }; // add x11, x13, x15 + /** code to be emulated {@code str w11, [x13], #0; ldrb w15, [x13], #0} */ + private static final byte[] ARM64_CODE = + Utils.hexToBytes("ab0500b8af054038"); + + /** code to be emulated {@code str w11, [x13]; ldrb w15, [x13]} */ + //private static final byte[] ARM64_CODE_EB = Utils.hexToBytes("b80005ab384005af"); // str w11, [x13]; + + private static final byte[] ARM64_CODE_EB = ARM64_CODE; + + /** code to be emulated {@code mrs x2, tpidrro_el0} */ + private static final byte[] ARM64_MRS_CODE = Utils.hexToBytes("62d03bd5"); + + /** code to be emulated {@code paciza x1} */ + private static final byte[] ARM64_PAC_CODE = Utils.hexToBytes("e123c1da"); // memory address where emulation starts public static final int ADDRESS = 0x10000; - public static final long toInt(byte val[]) { - long res = 0; - for (int i = 0; i < val.length; i++) { - long v = val[i] & 0xff; - res = res + (v << (i * 8)); - } - return res; - } + private static final BlockHook hook_block = + (uc, address, size, user_data) -> { + System.out.format( + ">>> Tracing basic block at 0x%x, block size = 0x%x\n", + address, size); + }; - public static final byte[] toBytes(long val) { - byte[] res = new byte[8]; - for (int i = 0; i < 8; i++) { - res[i] = (byte) (val & 0xff); - val >>>= 8; - } - return res; - } - - // callback for tracing basic blocks - private static class MyBlockHook implements BlockHook { - public void hook(Unicorn u, long address, int size, Object user_data) { - System.out.print(String.format( - ">>> Tracing basic block at 0x%x, block size = 0x%x\n", address, - size)); - } - } - - // callback for tracing instruction - private static class MyCodeHook implements CodeHook { - public void hook(Unicorn u, long address, int size, Object user_data) { - System.out.print(String.format( + private static final CodeHook hook_code = + (uc, address, size, user_data) -> { + System.out.format( ">>> Tracing instruction at 0x%x, instruction size = 0x%x\n", - address, size)); - } + address, size); + }; + + public static void test_arm64_mem_fetch() { + // msr x0, CurrentEL + byte[] shellcode0 = { 64, 66, 56, (byte) 213 }; + // .text:00000000004002C0 LDR X1, [SP,#arg_0] + byte[] shellcode = { (byte) 0xE1, 0x03, 0x40, (byte) 0xF9 }; + long shellcode_address = 0x4002C0L; + long data_address = 0x10000000000000L; + + System.out.format( + ">>> Emulate ARM64 fetching stack data from high address %x\n", + data_address); + + // Initialize emulator in ARM mode + Unicorn uc = new Unicorn(UC_ARCH_ARM64, UC_MODE_ARM); + + uc.mem_map(data_address, 0x30000, UC_PROT_ALL); + uc.mem_map(0x400000, 0x1000, UC_PROT_ALL); + + uc.reg_write(UC_ARM64_REG_SP, data_address); + byte[] data = new byte[8]; + Arrays.fill(data, (byte) 0xc8); + uc.mem_write(data_address, data); + uc.mem_write(shellcode_address, shellcode0); + uc.mem_write(shellcode_address + 4, shellcode); + + uc.emu_start(shellcode_address, shellcode_address + 4, 0, 0); + + long x0 = uc.reg_read(UC_ARM64_REG_X0); + System.out.format(">>> x0(Exception Level)=%x\n", x0 >> 2); + + uc.emu_start(shellcode_address + 4, shellcode_address + 8, 0, 0); + + long x1 = uc.reg_read(UC_ARM64_REG_X1); + + System.out.format(">>> X1 = 0x%x\n", x1); } public static void test_arm64() { + long x11 = 0x12345678; // X11 register + long x13 = 0x10000 + 0x8; // X13 register + long x15 = 0x33; // X15 register - long x11 = 0x1234L; // X11 register - long x13 = 0x6789L; // X13 register - long x15 = 0x3333L; // X15 register - - System.out.print("Emulate ARM64 code\n"); + System.out.println("Emulate ARM64 code"); // Initialize emulator in ARM mode - Unicorn u = new Unicorn(Unicorn.UC_ARCH_ARM64, Unicorn.UC_MODE_ARM); + Unicorn uc = new Unicorn(UC_ARCH_ARM64, UC_MODE_ARM); // map 2MB memory for this emulation - u.mem_map(ADDRESS, 2 * 1024 * 1024, Unicorn.UC_PROT_ALL); + uc.mem_map(ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory - u.mem_write(ADDRESS, ARM_CODE); + uc.mem_write(ADDRESS, ARM64_CODE); // initialize machine registers - u.reg_write(Unicorn.UC_ARM64_REG_X11, x11); - u.reg_write(Unicorn.UC_ARM64_REG_X13, x13); - u.reg_write(Unicorn.UC_ARM64_REG_X15, x15); + uc.reg_write(UC_ARM64_REG_X11, x11); + uc.reg_write(UC_ARM64_REG_X13, x13); + uc.reg_write(UC_ARM64_REG_X15, x15); // tracing all basic blocks with customized callback - u.hook_add(new MyBlockHook(), 1, 0, null); + uc.hook_add(hook_block, 1, 0, null); // tracing one instruction at ADDRESS with customized callback - u.hook_add(new MyCodeHook(), ADDRESS, ADDRESS, null); + uc.hook_add(hook_code, ADDRESS, ADDRESS, null); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. - u.emu_start(ADDRESS, ADDRESS + ARM_CODE.length, 0, 0); + uc.emu_start(ADDRESS, ADDRESS + ARM64_CODE.length, 0, 0); // now print out some registers - System.out.print(">>> Emulation done. Below is the CPU context\n"); + System.out.println(">>> Emulation done. Below is the CPU context"); + System.out.println(">>> As little endian, X15 should be 0x78:"); + System.out.format(">>> X15 = 0x%x\n", uc.reg_read(UC_ARM64_REG_X15)); + } - x11 = u.reg_read(Unicorn.UC_ARM64_REG_X11); - System.out.print(String.format(">>> X11 = 0x%x\n", x11)); + public static void test_arm64eb() { + long x11 = 0x12345678; // X11 register + long x13 = 0x10000 + 0x8; // X13 register + long x15 = 0x33; // X15 register - u.close(); + System.out.println("Emulate ARM64 Big-Endian code"); + + // Initialize emulator in ARM mode + Unicorn uc = + new Unicorn(UC_ARCH_ARM64, UC_MODE_ARM + UC_MODE_BIG_ENDIAN); + + // map 2MB memory for this emulation + uc.mem_map(ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + + // write machine code to be emulated to memory + uc.mem_write(ADDRESS, ARM64_CODE_EB); + + // initialize machine registers + uc.reg_write(UC_ARM64_REG_X11, x11); + uc.reg_write(UC_ARM64_REG_X13, x13); + uc.reg_write(UC_ARM64_REG_X15, x15); + + // tracing all basic blocks with customized callback + uc.hook_add(hook_block, 1, 0, null); + + // tracing one instruction at ADDRESS with customized callback + uc.hook_add(hook_code, ADDRESS, ADDRESS, null); + + // emulate machine code in infinite time (last param = 0), or when + // finishing all the code. + uc.emu_start(ADDRESS, ADDRESS + ARM64_CODE_EB.length, 0, 0); + + // now print out some registers + System.out.println(">>> Emulation done. Below is the CPU context"); + System.out.println(">>> As big endian, X15 should be 0x78:"); + System.out.format(">>> X15 = 0x%x\n", uc.reg_read(UC_ARM64_REG_X15)); + } + + public static void test_arm64_sctlr() { + long val; + System.out.println("Read the SCTLR register."); + + Unicorn uc = + new Unicorn(UC_ARCH_ARM64, UC_MODE_LITTLE_ENDIAN | UC_MODE_ARM); + + // SCTLR_EL1. See arm reference. + Arm64_CP reg = new Arm64_CP(1, 0, 3, 0, 0); + + val = (long) uc.reg_read(UC_ARM64_REG_CP_REG, reg); + System.out.format(">>> SCTLR_EL1 = 0x%x\n", val); + + reg.op1 = 0b100; + val = (long) uc.reg_read(UC_ARM64_REG_CP_REG, reg); + System.out.format(">>> SCTLR_EL2 = 0x%x\n", val); + } + + private static final Arm64SysHook hook_mrs = + (uc, reg, cp_reg, user_data) -> { + System.out + .println(">>> Hook MSR instruction. Write 0x114514 to X2."); + + uc.reg_write(reg, 0x114514L); + + // Skip + return 1; + }; + + public static void test_arm64_hook_mrs() { + System.out.println("Hook MRS instruction."); + + Unicorn uc = + new Unicorn(UC_ARCH_ARM64, UC_MODE_LITTLE_ENDIAN | UC_MODE_ARM); + uc.mem_map(0x1000, 0x1000, UC_PROT_ALL); + uc.mem_write(0x1000, ARM64_MRS_CODE); + uc.hook_add(hook_mrs, UC_ARM64_INS_MRS, 1, 0, null); + uc.emu_start(0x1000, 0x1000 + ARM64_MRS_CODE.length, 0, 0); + System.out.format(">>> X2 = 0x%x\n", uc.reg_read(UC_ARM64_REG_X2)); + } + + public static void test_arm64_pac() { + long x1 = 0x0000aaaabbbbccccL; + + System.out.println("Try ARM64 PAC"); + + // Initialize emulator in ARM mode + Unicorn uc = new Unicorn(UC_ARCH_ARM64, UC_MODE_ARM); + uc.ctl_set_cpu_model(UC_CPU_ARM64_MAX); + uc.mem_map(ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + uc.mem_write(ADDRESS, ARM64_PAC_CODE); + uc.reg_write(UC_ARM64_REG_X1, x1); + + /** Initialize PAC support **/ + Arm64_CP reg; + + // SCR_EL3 + reg = new Arm64_CP(1, 1, 3, 6, 0); + reg.val = (Long) uc.reg_read(UC_ARM64_REG_CP_REG, reg); + // NS && RW && API + reg.val |= (1 | (1L << 10) | (1L << 17)); + uc.reg_write(UC_ARM64_REG_CP_REG, reg); + + // SCTLR_EL1 + reg = new Arm64_CP(1, 0, 3, 0, 0); + reg.val = (Long) uc.reg_read(UC_ARM64_REG_CP_REG, reg); + // EnIA && EnIB + reg.val |= (1L << 31) | (1L << 30); + uc.reg_write(UC_ARM64_REG_CP_REG, reg); + + // HCR_EL2 + reg = new Arm64_CP(1, 1, 3, 4, 0); + reg.val = (Long) uc.reg_read(UC_ARM64_REG_CP_REG, reg); + // HCR.API + reg.val |= (1L << 41); + uc.reg_write(UC_ARM64_REG_CP_REG, reg); + + /** Check that PAC worked **/ + uc.emu_start(ADDRESS, ADDRESS + ARM64_PAC_CODE.length, 0, 0); + long new_x1 = uc.reg_read(UC_ARM64_REG_X1); + + System.out.format("X1 = 0x%x\n", new_x1); + if (new_x1 == x1) { + System.out.println("FAIL: No PAC tag added!"); + } else { + // Expect 0x1401aaaabbbbccccULL with the default key + System.out.println("SUCCESS: PAC tag found."); + } } public static void main(String args[]) { + test_arm64_mem_fetch(); + + System.out.println("-------------------------"); test_arm64(); + + System.out.println("-------------------------"); + test_arm64eb(); + + System.out.println("-------------------------"); + test_arm64_sctlr(); + + System.out.println("-------------------------"); + test_arm64_hook_mrs(); + + System.out.println("-------------------------"); + test_arm64_pac(); } } diff --git a/bindings/java/samples/Sample_ctl.java b/bindings/java/samples/Sample_ctl.java new file mode 100644 index 00000000..29fddac0 --- /dev/null +++ b/bindings/java/samples/Sample_ctl.java @@ -0,0 +1,159 @@ +package samples; + +import java.util.Arrays; + +import unicorn.*; + +public class Sample_ctl implements UnicornConst, X86Const { + /** Code to be emulated + *
+     *   cmp eax, 0;
+     *   jg lb;
+     *   inc eax;
+     *   nop;
+     * lb:
+     *   inc ebx;
+     *   nop;
+     * 
+ */ + private static final byte[] X86_JUMP_CODE = + Utils.hexToBytes("83f8007f0240904390"); + + /** memory address where emulation starts */ + private static final long ADDRESS = 0x10000; + + public static void test_uc_ctl_read() { + System.out.println("Reading some properties by uc_ctl."); + + // Initialize emulator in X86-32bit mode + Unicorn uc = new Unicorn(UC_ARCH_X86, UC_MODE_32); + + // Let's query some properties by uc_ctl. + int mode = uc.ctl_get_mode(); + int arch = uc.ctl_get_arch(); + long timeout = uc.ctl_get_timeout(); + int pagesize = uc.ctl_get_page_size(); + + System.out.format(">>> mode = %d, arch = %d, timeout=%d, pagesize=%d\n", + mode, arch, timeout, pagesize); + } + + private static final EdgeGeneratedHook trace_new_edge = + (uc, cur, prev, data) -> { + System.out.format(">>> Getting a new edge from 0x%x to 0x%x.\n", + prev.pc + prev.size - 1, cur.pc); + }; + + public static void test_uc_ctl_exits() { + long r_eax, r_ebx; + long exits[] = { ADDRESS + 6, ADDRESS + 8 }; + + System.out.println("Using multiple exits by uc_ctl."); + + // Initialize emulator in X86-32bit mode + Unicorn uc = new Unicorn(UC_ARCH_X86, UC_MODE_32); + + uc.mem_map(ADDRESS, 0x1000, UC_PROT_ALL); + + // Write our code to the memory. + uc.mem_write(ADDRESS, X86_JUMP_CODE); + + // We trace if any new edge is generated. + uc.hook_add(trace_new_edge, 1, 0, null); + + // Enable multiple exits. + uc.ctl_exits_enabled(true); + uc.ctl_set_exits(exits); + + // This should stop at ADDRESS + 6 and increase eax, even thouhg we don't + // provide an exit. + uc.emu_start(ADDRESS, 0, 0, 0); + + r_eax = uc.reg_read(UC_X86_REG_EAX); + r_ebx = uc.reg_read(UC_X86_REG_EBX); + System.out.format( + ">>> eax = %d and ebx = %d after the first emulation\n", + r_eax, r_ebx); + + // This should stop at ADDRESS + 8, even though we don't provide an exit. + uc.emu_start(ADDRESS, 0, 0, 0); + + r_eax = uc.reg_read(UC_X86_REG_EAX); + r_ebx = uc.reg_read(UC_X86_REG_EBX); + System.out.format( + ">>> eax = %d and ebx = %d after the second emulation\n", + r_eax, r_ebx); + } + + private static final int TB_COUNT = 8; + private static final int TCG_MAX_INSNS = 512; // from tcg.h + private static final int CODE_LEN = TB_COUNT * TCG_MAX_INSNS; + + private static double time_emulation(Unicorn uc, long start, long end) { + long t1 = System.nanoTime(); + uc.emu_start(start, end, 0, 0); + long t2 = System.nanoTime(); + return (t2 - t1) / 1000000.0; + } + + public static void test_uc_ctl_tb_cache() { + byte[] code = new byte[CODE_LEN]; + double standard, cached, evicted; + + System.out.println( + "Controlling the TB cache in a finer granularity by uc_ctl."); + + // Fill the code buffer with NOP. + Arrays.fill(code, (byte) 0x90); + + // Initialize emulator in X86-32bit mode + Unicorn uc = new Unicorn(UC_ARCH_X86, UC_MODE_32); + + uc.mem_map(ADDRESS, 0x10000, UC_PROT_ALL); + + // Write our code to the memory. + uc.mem_write(ADDRESS, code); + + // We trace if any new edge is generated. + // Note: In this sample, there is only **one** basic block while muliple + // translation blocks is generated due to QEMU tcg buffer limit. In this + // case, we don't consider it as a new edge. + uc.hook_add(trace_new_edge, 1, 0, null); + + // Do emulation without any cache. + standard = time_emulation(uc, ADDRESS, ADDRESS + CODE_LEN); + + // Now we request cache for all TBs. + for (int i = 0; i < TB_COUNT; i++) { + TranslationBlock tb = + uc.ctl_request_cache(ADDRESS + i * TCG_MAX_INSNS); + System.out.format( + ">>> TB is cached at 0x%x which has %d instructions with %d bytes.\n", + tb.pc, tb.icount, tb.size); + } + + // Do emulation with all TB cached. + cached = time_emulation(uc, ADDRESS, ADDRESS + CODE_LEN); + + // Now we clear cache for all TBs. + for (int i = 0; i < TB_COUNT; i++) { + uc.ctl_remove_cache(ADDRESS + i * TCG_MAX_INSNS, + ADDRESS + i * TCG_MAX_INSNS + 1); + } + + // Do emulation with all TB cache evicted. + evicted = time_emulation(uc, ADDRESS, ADDRESS + CODE_LEN); + + System.out.format( + ">>> Run time: First time: %fms, Cached: %fms, Cache evicted: %fms\n", + standard, cached, evicted); + } + + public static final void main(String[] args) { + test_uc_ctl_read(); + System.out.println("===================="); + test_uc_ctl_exits(); + System.out.println("===================="); + test_uc_ctl_tb_cache(); + } +} diff --git a/bindings/java/samples/Sample_m68k.java b/bindings/java/samples/Sample_m68k.java index 772b5fcd..80ea4a6b 100644 --- a/bindings/java/samples/Sample_m68k.java +++ b/bindings/java/samples/Sample_m68k.java @@ -28,7 +28,7 @@ package samples; import unicorn.*; -public class Sample_m68k { +public class Sample_m68k implements UnicornConst, M68kConst { // code to be emulated public static final byte[] M68K_CODE = { 118, -19 }; // movq #-19, %d3 @@ -36,41 +36,21 @@ public class Sample_m68k { // memory address where emulation starts public static final int ADDRESS = 0x10000; - public static final long toInt(byte val[]) { - long res = 0; - for (int i = 0; i < val.length; i++) { - long v = val[i] & 0xff; - res = res + (v << (i * 8)); - } - return res; - } - - public static final byte[] toBytes(long val) { - byte[] res = new byte[8]; - for (int i = 0; i < 8; i++) { - res[i] = (byte) (val & 0xff); - val >>>= 8; - } - return res; - } - // callback for tracing basic blocks - private static class MyBlockHook implements BlockHook { - public void hook(Unicorn u, long address, int size, Object user_data) { - System.out.print(String.format( - ">>> Tracing basic block at 0x%x, block size = 0x%x\n", address, - size)); - } - } + private static final BlockHook hook_block = + (uc, address, size, user_data) -> { + System.out.format( + ">>> Tracing basic block at 0x%x, block size = 0x%x\n", + address, size); + }; - // callback for tracing instruction - private static class MyCodeHook implements CodeHook { - public void hook(Unicorn u, long address, int size, Object user_data) { - System.out.print(String.format( + // callback for tracing instructions + private static final CodeHook hook_code = + (uc, address, size, user_data) -> { + System.out.format( ">>> Tracing instruction at 0x%x, instruction size = 0x%x\n", - address, size)); - } - } + address, size); + }; public static void test_m68k() { long d0 = 0x0000L; // d0 data register @@ -97,42 +77,41 @@ public class Sample_m68k { System.out.print("Emulate M68K code\n"); // Initialize emulator in M68K mode - Unicorn u = - new Unicorn(Unicorn.UC_ARCH_M68K, Unicorn.UC_MODE_BIG_ENDIAN); + Unicorn u = new Unicorn(UC_ARCH_M68K, UC_MODE_BIG_ENDIAN); // map 2MB memory for this emulation - u.mem_map(ADDRESS, 2 * 1024 * 1024, Unicorn.UC_PROT_ALL); + u.mem_map(ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory u.mem_write(ADDRESS, M68K_CODE); // initialize machine registers - u.reg_write(Unicorn.UC_M68K_REG_D0, d0); - u.reg_write(Unicorn.UC_M68K_REG_D1, d1); - u.reg_write(Unicorn.UC_M68K_REG_D2, d2); - u.reg_write(Unicorn.UC_M68K_REG_D3, d3); - u.reg_write(Unicorn.UC_M68K_REG_D4, d4); - u.reg_write(Unicorn.UC_M68K_REG_D5, d5); - u.reg_write(Unicorn.UC_M68K_REG_D6, d6); - u.reg_write(Unicorn.UC_M68K_REG_D7, d7); + u.reg_write(UC_M68K_REG_D0, d0); + u.reg_write(UC_M68K_REG_D1, d1); + u.reg_write(UC_M68K_REG_D2, d2); + u.reg_write(UC_M68K_REG_D3, d3); + u.reg_write(UC_M68K_REG_D4, d4); + u.reg_write(UC_M68K_REG_D5, d5); + u.reg_write(UC_M68K_REG_D6, d6); + u.reg_write(UC_M68K_REG_D7, d7); - u.reg_write(Unicorn.UC_M68K_REG_A0, a0); - u.reg_write(Unicorn.UC_M68K_REG_A1, a1); - u.reg_write(Unicorn.UC_M68K_REG_A2, a2); - u.reg_write(Unicorn.UC_M68K_REG_A3, a3); - u.reg_write(Unicorn.UC_M68K_REG_A4, a4); - u.reg_write(Unicorn.UC_M68K_REG_A5, a5); - u.reg_write(Unicorn.UC_M68K_REG_A6, a6); - u.reg_write(Unicorn.UC_M68K_REG_A7, a7); + u.reg_write(UC_M68K_REG_A0, a0); + u.reg_write(UC_M68K_REG_A1, a1); + u.reg_write(UC_M68K_REG_A2, a2); + u.reg_write(UC_M68K_REG_A3, a3); + u.reg_write(UC_M68K_REG_A4, a4); + u.reg_write(UC_M68K_REG_A5, a5); + u.reg_write(UC_M68K_REG_A6, a6); + u.reg_write(UC_M68K_REG_A7, a7); - u.reg_write(Unicorn.UC_M68K_REG_PC, pc); - u.reg_write(Unicorn.UC_M68K_REG_SR, sr); + u.reg_write(UC_M68K_REG_PC, pc); + u.reg_write(UC_M68K_REG_SR, sr); // tracing all basic blocks with customized callback - u.hook_add(new MyBlockHook(), 1, 0, null); + u.hook_add(hook_block, 1, 0, null); // tracing all instruction - u.hook_add(new MyCodeHook(), 1, 0, null); + u.hook_add(hook_code, 1, 0, null); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. @@ -141,47 +120,37 @@ public class Sample_m68k { // now print out some registers System.out.print(">>> Emulation done. Below is the CPU context\n"); - d0 = u.reg_read(Unicorn.UC_M68K_REG_D0); - d1 = u.reg_read(Unicorn.UC_M68K_REG_D1); - d2 = u.reg_read(Unicorn.UC_M68K_REG_D2); - d3 = u.reg_read(Unicorn.UC_M68K_REG_D3); - d4 = u.reg_read(Unicorn.UC_M68K_REG_D4); - d5 = u.reg_read(Unicorn.UC_M68K_REG_D5); - d6 = u.reg_read(Unicorn.UC_M68K_REG_D6); - d7 = u.reg_read(Unicorn.UC_M68K_REG_D7); + d0 = u.reg_read(UC_M68K_REG_D0); + d1 = u.reg_read(UC_M68K_REG_D1); + d2 = u.reg_read(UC_M68K_REG_D2); + d3 = u.reg_read(UC_M68K_REG_D3); + d4 = u.reg_read(UC_M68K_REG_D4); + d5 = u.reg_read(UC_M68K_REG_D5); + d6 = u.reg_read(UC_M68K_REG_D6); + d7 = u.reg_read(UC_M68K_REG_D7); - a0 = u.reg_read(Unicorn.UC_M68K_REG_A0); - a1 = u.reg_read(Unicorn.UC_M68K_REG_A1); - a2 = u.reg_read(Unicorn.UC_M68K_REG_A2); - a3 = u.reg_read(Unicorn.UC_M68K_REG_A3); - a4 = u.reg_read(Unicorn.UC_M68K_REG_A4); - a5 = u.reg_read(Unicorn.UC_M68K_REG_A5); - a6 = u.reg_read(Unicorn.UC_M68K_REG_A6); - a7 = u.reg_read(Unicorn.UC_M68K_REG_A7); + a0 = u.reg_read(UC_M68K_REG_A0); + a1 = u.reg_read(UC_M68K_REG_A1); + a2 = u.reg_read(UC_M68K_REG_A2); + a3 = u.reg_read(UC_M68K_REG_A3); + a4 = u.reg_read(UC_M68K_REG_A4); + a5 = u.reg_read(UC_M68K_REG_A5); + a6 = u.reg_read(UC_M68K_REG_A6); + a7 = u.reg_read(UC_M68K_REG_A7); - pc = u.reg_read(Unicorn.UC_M68K_REG_PC); - sr = u.reg_read(Unicorn.UC_M68K_REG_SR); + pc = u.reg_read(UC_M68K_REG_PC); + sr = u.reg_read(UC_M68K_REG_SR); - System.out.print(String.format(">>> A0 = 0x%x\t\t>>> D0 = 0x%x\n", - a0, d0)); - System.out.print(String.format(">>> A1 = 0x%x\t\t>>> D1 = 0x%x\n", - a1, d1)); - System.out.print(String.format(">>> A2 = 0x%x\t\t>>> D2 = 0x%x\n", - a2, d2)); - System.out.print(String.format(">>> A3 = 0x%x\t\t>>> D3 = 0x%x\n", - a3, d3)); - System.out.print(String.format(">>> A4 = 0x%x\t\t>>> D4 = 0x%x\n", - a4, d4)); - System.out.print(String.format(">>> A5 = 0x%x\t\t>>> D5 = 0x%x\n", - a5, d5)); - System.out.print(String.format(">>> A6 = 0x%x\t\t>>> D6 = 0x%x\n", - a6, d6)); - System.out.print(String.format(">>> A7 = 0x%x\t\t>>> D7 = 0x%x\n", - a7, d7)); - System.out.print(String.format(">>> PC = 0x%x\n", pc)); - System.out.print(String.format(">>> SR = 0x%x\n", sr)); - - u.close(); + System.out.format(">>> A0 = 0x%x\t\t>>> D0 = 0x%x\n", a0, d0); + System.out.format(">>> A1 = 0x%x\t\t>>> D1 = 0x%x\n", a1, d1); + System.out.format(">>> A2 = 0x%x\t\t>>> D2 = 0x%x\n", a2, d2); + System.out.format(">>> A3 = 0x%x\t\t>>> D3 = 0x%x\n", a3, d3); + System.out.format(">>> A4 = 0x%x\t\t>>> D4 = 0x%x\n", a4, d4); + System.out.format(">>> A5 = 0x%x\t\t>>> D5 = 0x%x\n", a5, d5); + System.out.format(">>> A6 = 0x%x\t\t>>> D6 = 0x%x\n", a6, d6); + System.out.format(">>> A7 = 0x%x\t\t>>> D7 = 0x%x\n", a7, d7); + System.out.format(">>> PC = 0x%x\n", pc); + System.out.format(">>> SR = 0x%x\n", sr); } public static void main(String args[]) { diff --git a/bindings/java/samples/Sample_mips.java b/bindings/java/samples/Sample_mips.java index 03697f3e..d238b604 100644 --- a/bindings/java/samples/Sample_mips.java +++ b/bindings/java/samples/Sample_mips.java @@ -28,48 +28,30 @@ package samples; import unicorn.*; -public class Sample_mips { +public class Sample_mips implements UnicornConst, MipsConst { // code to be emulated - public static final byte[] MIPS_CODE_EB = { 52, 33, 52, 86 }; - public static final byte[] MIPS_CODE_EL = { 86, 52, 33, 52 }; + public static final byte[] MIPS_CODE_EB = { 52, 33, 52, 86 }; // ori $at, $at, 0x3456 + public static final byte[] MIPS_CODE_EL = { 86, 52, 33, 52 }; // ori $at, $at, 0x3456 // memory address where emulation starts public static final int ADDRESS = 0x10000; - public static final long toInt(byte val[]) { - long res = 0; - for (int i = 0; i < val.length; i++) { - long v = val[i] & 0xff; - res = res + (v << (i * 8)); - } - return res; - } - - public static final byte[] toBytes(long val) { - byte[] res = new byte[8]; - for (int i = 0; i < 8; i++) { - res[i] = (byte) (val & 0xff); - val >>>= 8; - } - return res; - } - // callback for tracing basic blocks private static class MyBlockHook implements BlockHook { public void hook(Unicorn u, long address, int size, Object user_data) { - System.out.print(String.format( + System.out.format( ">>> Tracing basic block at 0x%x, block size = 0x%x\n", address, - size)); + size); } } // callback for tracing instruction private static class MyCodeHook implements CodeHook { public void hook(Unicorn u, long address, int size, Object user_data) { - System.out.print(String.format( + System.out.format( ">>> Tracing instruction at 0x%x, instruction size = 0x%x\n", - address, size)); + address, size); } } @@ -77,20 +59,20 @@ public class Sample_mips { long r1 = 0x6789L; // R1 register - System.out.print("Emulate MIPS code (big-endian)\n"); + System.out.println("Emulate MIPS code (big-endian)"); // Initialize emulator in MIPS mode - Unicorn u = new Unicorn(Unicorn.UC_ARCH_MIPS, - Unicorn.UC_MODE_MIPS32 + Unicorn.UC_MODE_BIG_ENDIAN); + Unicorn u = + new Unicorn(UC_ARCH_MIPS, UC_MODE_MIPS32 + UC_MODE_BIG_ENDIAN); // map 2MB memory for this emulation - u.mem_map(ADDRESS, 2 * 1024 * 1024, Unicorn.UC_PROT_ALL); + u.mem_map(ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory u.mem_write(ADDRESS, MIPS_CODE_EB); // initialize machine registers - u.reg_write(Unicorn.UC_MIPS_REG_1, r1); + u.reg_write(UC_MIPS_REG_1, r1); // tracing all basic blocks with customized callback u.hook_add(new MyBlockHook(), 1, 0, null); @@ -103,32 +85,29 @@ public class Sample_mips { u.emu_start(ADDRESS, ADDRESS + MIPS_CODE_EB.length, 0, 0); // now print out some registers - System.out.print(">>> Emulation done. Below is the CPU context\n"); + System.out.println(">>> Emulation done. Below is the CPU context"); - r1 = u.reg_read(Unicorn.UC_MIPS_REG_1); - System.out.print(String.format(">>> R1 = 0x%x\n", r1)); - - u.close(); + r1 = u.reg_read(UC_MIPS_REG_1); + System.out.format(">>> R1 = 0x%x\n", r1); } public static void test_mips_el() { long r1 = 0x6789L; // R1 register - System.out.print("===========================\n"); - System.out.print("Emulate MIPS code (little-endian)\n"); + System.out.println("Emulate MIPS code (little-endian)"); // Initialize emulator in MIPS mode - Unicorn u = new Unicorn(Unicorn.UC_ARCH_MIPS, - Unicorn.UC_MODE_MIPS32 + Unicorn.UC_MODE_LITTLE_ENDIAN); + Unicorn u = new Unicorn(UC_ARCH_MIPS, + UC_MODE_MIPS32 + UC_MODE_LITTLE_ENDIAN); // map 2MB memory for this emulation - u.mem_map(ADDRESS, 2 * 1024 * 1024, Unicorn.UC_PROT_ALL); + u.mem_map(ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory u.mem_write(ADDRESS, MIPS_CODE_EL); // initialize machine registers - u.reg_write(Unicorn.UC_MIPS_REG_1, r1); + u.reg_write(UC_MIPS_REG_1, r1); // tracing all basic blocks with customized callback u.hook_add(new MyBlockHook(), 1, 0, null); @@ -141,16 +120,15 @@ public class Sample_mips { u.emu_start(ADDRESS, ADDRESS + MIPS_CODE_EL.length, 0, 0); // now print out some registers - System.out.print(">>> Emulation done. Below is the CPU context\n"); + System.out.println(">>> Emulation done. Below is the CPU context"); - r1 = u.reg_read(Unicorn.UC_MIPS_REG_1); - System.out.print(String.format(">>> R1 = 0x%x\n", r1)); - - u.close(); + r1 = u.reg_read(UC_MIPS_REG_1); + System.out.format(">>> R1 = 0x%x\n", r1); } public static void main(String args[]) { test_mips_eb(); + System.out.println("==========================="); test_mips_el(); } } diff --git a/bindings/java/samples/Sample_mmu.java b/bindings/java/samples/Sample_mmu.java new file mode 100644 index 00000000..f5fe680f --- /dev/null +++ b/bindings/java/samples/Sample_mmu.java @@ -0,0 +1,224 @@ +package samples; + +import unicorn.*; + +public class Sample_mmu implements UnicornConst, X86Const { + /** Code: + *
+     * mov rax, 57
+     * syscall
+     * test rax, rax
+     * jz child
+     * xor rax, rax
+     * mov rax, 60
+     * mov [0x4000], rax
+     * syscall
+     *
+     * child:
+     * xor rcx, rcx
+     * mov rcx, 42
+     * mov [0x4000], rcx
+     * mov rax, 60
+     * syscall
+     * 
+ */ + private static final byte[] CODE = Utils.hexToBytes( + "B8390000000F054885C0740FB83C00000048890425004000000F05B92A00000048890C2500400000B83C0000000F05"); + + private static final MemHook mmu_write_callback = + (uc, type, address, size, value, user_data) -> { + System.out.format("write at 0x%x: 0x%x\n", address, value); + }; + + private static void x86_mmu_prepare_tlb(Unicorn uc, long vaddr, + long tlb_base) { + long cr0; + long cr4; + X86_MSR msr = new X86_MSR(0xC0000080); + long pml4o = ((vaddr & 0x00ff8000000000L) >> 39) * 8; + long pdpo = ((vaddr & 0x00007fc0000000L) >> 30) * 8; + long pdo = ((vaddr & 0x0000003fe00000L) >> 21) * 8; + long pml4e = (tlb_base + 0x1000L) | 1 | (1 << 2); + long pdpe = (tlb_base + 0x2000L) | 1 | (1 << 2); + long pde = (tlb_base + 0x3000L) | 1 | (1 << 2); + uc.mem_write(tlb_base + pml4o, Utils.toBytes(pml4e)); + uc.mem_write(tlb_base + 0x1000 + pdpo, Utils.toBytes(pdpe)); + uc.mem_write(tlb_base + 0x2000 + pdo, Utils.toBytes(pde)); + uc.reg_write(UC_X86_REG_CR3, tlb_base); + cr0 = uc.reg_read(UC_X86_REG_CR0); + cr4 = uc.reg_read(UC_X86_REG_CR4); + msr.value = (Long) uc.reg_read(UC_X86_REG_MSR, msr); + + cr0 |= 1; //enable protected mode + cr0 |= 1l << 31; //enable paging + cr4 |= 1l << 5; //enable physical address extension + msr.value |= 1l << 8; //enable long mode + + uc.reg_write(UC_X86_REG_CR0, cr0); + uc.reg_write(UC_X86_REG_CR4, cr4); + uc.reg_write(UC_X86_REG_MSR, msr); + } + + private static void x86_mmu_pt_set(Unicorn uc, long vaddr, long paddr, + long tlb_base) { + long pto = ((vaddr & 0x000000001ff000L) >> 12) * 8; + long pte = (paddr) | 1 | (1 << 2); + uc.mem_write(tlb_base + 0x3000 + pto, Utils.toBytes((int) pte)); + } + + private static SyscallHook x86_mmu_syscall_callback = (uc, userdata) -> { + boolean[] parent_done = (boolean[]) userdata; + long rax = uc.reg_read(UC_X86_REG_RAX); + switch ((int) rax) { + case 57: + /* fork */ + break; + case 60: + /* exit */ + parent_done[0] = true; + uc.emu_stop(); + return; + default: + System.out.println("unknown syscall"); + System.exit(1); + } + + if (!parent_done[0]) { + rax = 27; + uc.reg_write(UC_X86_REG_RAX, rax); + uc.emu_stop(); + } + }; + + public static void cpu_tlb() { + long tlb_base = 0x3000; + long rip; + boolean[] parent_done = { false }; + + System.out.println( + "Emulate x86 amd64 code with mmu enabled and switch mappings"); + + Unicorn uc = new Unicorn(UC_ARCH_X86, UC_MODE_64); + uc.ctl_tlb_mode(UC_TLB_CPU); + Unicorn.Context context = uc.context_save(); + + uc.hook_add(x86_mmu_syscall_callback, UC_X86_INS_SYSCALL, 1, 0, + parent_done); + + // Memory hooks are called after the mmu translation, so hook the physicall addresses + uc.hook_add(mmu_write_callback, UC_HOOK_MEM_WRITE, 0x1000, 0x3000, + null); + + System.out.println("map code"); + uc.mem_map(0x0, 0x1000, UC_PROT_ALL); // Code + uc.mem_write(0x0, CODE); + System.out.println("map parent memory"); + uc.mem_map(0x1000, 0x1000, UC_PROT_ALL); // Parrent + System.out.println("map child memory"); + uc.mem_map(0x2000, 0x1000, UC_PROT_ALL); // Child + System.out.println("map tlb memory"); + uc.mem_map(tlb_base, 0x4000, UC_PROT_ALL); // TLB + + System.out.println("set up the tlb"); + x86_mmu_prepare_tlb(uc, 0x0, tlb_base); + x86_mmu_pt_set(uc, 0x2000, 0x0, tlb_base); + x86_mmu_pt_set(uc, 0x4000, 0x1000, tlb_base); + + uc.ctl_flush_tlb(); + System.out.println("run the parent"); + uc.emu_start(0x2000, 0x0, 0, 0); + + System.out.println("save the context for the child"); + uc.context_update(context); + System.out.println("finish the parent"); + rip = uc.reg_read(UC_X86_REG_RIP); + + uc.emu_start(rip, 0x0, 0, 0); + + System.out.println("restore the context for the child"); + uc.context_restore(context); + x86_mmu_prepare_tlb(uc, 0x0, tlb_base); + x86_mmu_pt_set(uc, 0x4000, 0x2000, tlb_base); + uc.reg_write(UC_X86_REG_RAX, 0L); + uc.ctl_flush_tlb(); + + uc.emu_start(rip, 0x0, 0, 0); + long parent = Utils.toLong(uc.mem_read(0x1000, Long.BYTES)); + long child = Utils.toLong(uc.mem_read(0x2000, Long.BYTES)); + System.out.format("parent result == %d\n", parent); + System.out.format("child result == %d\n", child); + } + + private static final TlbFillHook virtual_tlb_callback = + (uc, addr, type, user_data) -> { + boolean[] parent_done = (boolean[]) user_data; + System.out.format("tlb lookup for address: 0x%X\n", addr); + switch ((int) (addr & ~(0xfffL))) { + case 0x2000: + return 0x0L | UC_PROT_EXEC; + case 0x4000: + if (parent_done[0]) { + return (0x2000L) | UC_PROT_READ | UC_PROT_WRITE; + } else { + return (0x1000L) | UC_PROT_READ | UC_PROT_WRITE; + } + default: + return -1L; + } + }; + + public static void virtual_tlb() { + long rip; + boolean[] parent_done = { false }; + + System.out.println("Emulate x86 amd64 code with virtual mmu"); + Unicorn uc = new Unicorn(UC_ARCH_X86, UC_MODE_64); + uc.ctl_tlb_mode(UC_TLB_VIRTUAL); + Unicorn.Context context = uc.context_save(); + + uc.hook_add(x86_mmu_syscall_callback, UC_X86_INS_SYSCALL, 1, 0, + parent_done); + + // Memory hooks are called after the mmu translation, so hook the physicall addresses + uc.hook_add(mmu_write_callback, UC_HOOK_MEM_WRITE, 0x1000, 0x3000, + null); + + System.out.println("map code"); + uc.mem_map(0x0, 0x1000, UC_PROT_ALL); // Code + uc.mem_write(0x0, CODE); + System.out.println("map parent memory"); + uc.mem_map(0x1000, 0x1000, UC_PROT_ALL); // Parrent + System.out.println("map child memory"); + uc.mem_map(0x2000, 0x1000, UC_PROT_ALL); // Child + + uc.hook_add(virtual_tlb_callback, 1, 0, parent_done); + + System.out.println("run the parent"); + uc.emu_start(0x2000, 0x0, 0, 0); + + System.out.println("save the context for the child"); + uc.context_update(context); + System.out.println("finish the parent"); + rip = uc.reg_read(UC_X86_REG_RIP); + + uc.emu_start(rip, 0x0, 0, 0); + + System.out.println("restore the context for the child"); + uc.context_restore(context); + parent_done[0] = true; + uc.reg_write(UC_X86_REG_RAX, 0); + uc.ctl_flush_tlb(); + + uc.emu_start(rip, 0x0, 0, 0); + long parent = Utils.toLong(uc.mem_read(0x1000, Long.BYTES)); + long child = Utils.toLong(uc.mem_read(0x2000, Long.BYTES)); + System.out.format("parent result == %d\n", parent); + System.out.format("child result == %d\n", child); + } + + public static final void main(String[] args) { + cpu_tlb(); + System.out.println("------------------"); + virtual_tlb(); + } +} diff --git a/bindings/java/samples/Sample_ppc.java b/bindings/java/samples/Sample_ppc.java new file mode 100644 index 00000000..ed7aea26 --- /dev/null +++ b/bindings/java/samples/Sample_ppc.java @@ -0,0 +1,91 @@ +/* + +Java bindings for the Unicorn Emulator Engine + +Copyright(c) 2023 Robert Xiao + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +version 2 as published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ + +/* Sample code to demonstrate how to emulate S390X code */ + +package samples; + +import unicorn.*; + +public class Sample_ppc implements UnicornConst, PpcConst { + /** code to be emulated: + * {@code add r26, r6, r3} + */ + private static final byte[] CODE = Utils.hexToBytes("7F461A14"); + + // memory address where emulation starts + private static final long ADDRESS = 0x10000; + + private static final BlockHook hook_block = + (uc, address, size, user_data) -> { + System.out.format( + ">>> Tracing basic block at 0x%x, block size = 0x%x\n", + address, size); + }; + + private static final CodeHook hook_code = + (uc, address, size, user_data) -> { + System.out.format( + ">>> Tracing instruction at 0x%x, instruction size = 0x%x\n", + address, size); + }; + + public static void test_ppc() { + long r3 = 0x1234; // R3 register + long r6 = 0x6789; // R6 register + long r26 = 0x8877; // R26 register (result) + + System.out.println("Emulate PPC code"); + + Unicorn uc = + new Unicorn(UC_ARCH_PPC, UC_MODE_PPC32 | UC_MODE_BIG_ENDIAN); + + // map 2MB memory for this emulation + uc.mem_map(ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + + // write machine code to be emulated to memory + uc.mem_write(ADDRESS, CODE); + + // initialize machine registers + uc.reg_write(UC_PPC_REG_3, r3); + uc.reg_write(UC_PPC_REG_6, r6); + uc.reg_write(UC_PPC_REG_26, r26); + + // tracing all basic blocks with customized callback + uc.hook_add(hook_block, 1, 0, null); + + // tracing one instruction at ADDRESS with customized callback + uc.hook_add(hook_code, ADDRESS, ADDRESS + CODE.length, null); + + // emulate machine code in infinite time (last param = 0), or when + // finishing all the code. + uc.emu_start(ADDRESS, ADDRESS + CODE.length, 0, 0); + + // now print out some registers + System.out.println(">>> Emulation done. Below is the CPU context"); + + System.out.format(">>> r26 = 0x%x\n", uc.reg_read(UC_PPC_REG_26)); + } + + public static final void main(String[] args) { + test_ppc(); + } +} diff --git a/bindings/java/samples/Sample_riscv.java b/bindings/java/samples/Sample_riscv.java new file mode 100644 index 00000000..97e3b486 --- /dev/null +++ b/bindings/java/samples/Sample_riscv.java @@ -0,0 +1,477 @@ +/* + +Java bindings for the Unicorn Emulator Engine + +Copyright(c) 2023 Robert Xiao + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +version 2 as published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ + +/* Sample code to demonstrate how to emulate S390X code */ + +package samples; + +import unicorn.*; + +public class Sample_riscv implements UnicornConst, RiscvConst { + /** code to be emulated: + *
+     * $ cstool riscv64 1305100093850502
+     *  0  13 05 10 00  addi   a0, zero, 1
+     *  4  93 85 05 02  addi   a1, a1, 0x20
+     * 
+ */ + private static final byte[] CODE = Utils.hexToBytes("1305100093850502"); + + // memory address where emulation starts + private static final long ADDRESS = 0x10000; + + private static final BlockHook hook_block = + (uc, address, size, user_data) -> { + System.out.format( + ">>> Tracing basic block at 0x%x, block size = 0x%x\n", + address, size); + }; + + private static final CodeHook hook_code = + (uc, address, size, user_data) -> { + System.out.format( + ">>> Tracing instruction at 0x%x, instruction size = 0x%x\n", + address, size); + }; + + private static final CodeHook hook_code3 = + (uc, address, size, user_data) -> { + System.out.format( + ">>> Tracing instruction at 0x%x, instruction size = 0x%x\n", + address, size); + if (address == ADDRESS) { + System.out.println("stop emulation"); + uc.emu_stop(); + } + }; + + /* + 00813823 sd s0,16(sp) + 00000013 nop + */ + private static final byte[] CODE64 = Utils.hexToBytes("2338810013000000"); + + // 10000: 00008067 ret + // 10004: 8082 c.ret + // 10006: 0001 nop + // 10008: 0001 nop + + private static final byte[] FUNC_CODE = + Utils.hexToBytes("67800000828001000100"); + + public static void test_riscv() { + long a0 = 0x1234L; + long a1 = 0x7890L; + + System.out.println("Emulate RISCV code"); + + // Initialize emulator in RISCV64 mode + Unicorn uc = new Unicorn(UC_ARCH_RISCV, UC_MODE_RISCV32); + + // map 2MB memory for this emulation + uc.mem_map(ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + + // write machine code to be emulated to memory + uc.mem_write(ADDRESS, CODE); + + // initialize machine registers + uc.reg_write(UC_RISCV_REG_A0, a0); + uc.reg_write(UC_RISCV_REG_A1, a1); + + // tracing all basic blocks with customized callback + uc.hook_add(hook_block, 1, 0, null); + + // tracing all instruction + uc.hook_add(hook_code, 1, 0, null); + + // emulate machine code in infinite time (last param = 0), or when + // finishing all the code. + uc.emu_start(ADDRESS, ADDRESS + CODE.length, 0, 0); + + // now print out some registers + System.out.println(">>> Emulation done. Below is the CPU context"); + + System.out.format(">>> A0 = 0x%x\n", uc.reg_read(UC_RISCV_REG_A0)); + System.out.format(">>> A1 = 0x%x\n", uc.reg_read(UC_RISCV_REG_A1)); + } + + public static void test_riscv2() { + long a0 = 0x1234L; + long a1 = 0x7890L; + + System.out.println("Emulate RISCV code: split emulation"); + + // Initialize emulator in RISCV64 mode + Unicorn uc = new Unicorn(UC_ARCH_RISCV, UC_MODE_RISCV32); + + // map 2MB memory for this emulation + uc.mem_map(ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + + // write machine code to be emulated to memory + uc.mem_write(ADDRESS, CODE); + + // initialize machine registers + uc.reg_write(UC_RISCV_REG_A0, a0); + uc.reg_write(UC_RISCV_REG_A1, a1); + + // tracing all basic blocks with customized callback + uc.hook_add(hook_block, 1, 0, null); + + // tracing all instruction + uc.hook_add(hook_code, 1, 0, null); + + // emulate 1 instruction + uc.emu_start(ADDRESS, ADDRESS + 4, 0, 0); + + System.out.format(">>> A0 = 0x%x\n", uc.reg_read(UC_RISCV_REG_A0)); + System.out.format(">>> A1 = 0x%x\n", uc.reg_read(UC_RISCV_REG_A1)); + + // emulate one more instruction + uc.emu_start(ADDRESS + 4, ADDRESS + 8, 0, 0); + + // now print out some registers + System.out.println(">>> Emulation done. Below is the CPU context"); + + System.out.format(">>> A0 = 0x%x\n", uc.reg_read(UC_RISCV_REG_A0)); + System.out.format(">>> A1 = 0x%x\n", uc.reg_read(UC_RISCV_REG_A1)); + } + + public static void test_riscv3() { + long a0 = 0x1234L; + long a1 = 0x7890L; + + System.out.println("Emulate RISCV code: early stop"); + + // Initialize emulator in RISCV64 mode + Unicorn uc = new Unicorn(UC_ARCH_RISCV, UC_MODE_RISCV32); + + // map 2MB memory for this emulation + uc.mem_map(ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + + // write machine code to be emulated to memory + uc.mem_write(ADDRESS, CODE); + + // initialize machine registers + uc.reg_write(UC_RISCV_REG_A0, a0); + uc.reg_write(UC_RISCV_REG_A1, a1); + + // tracing all basic blocks with customized callback + uc.hook_add(hook_block, 1, 0, null); + + // tracing all instruction + uc.hook_add(hook_code3, 1, 0, null); + + // emulate machine code in infinite time (last param = 0), or when + // finishing all the code. + uc.emu_start(ADDRESS, ADDRESS + CODE.length, 0, 0); + + // now print out some registers + System.out.println(">>> Emulation done. Below is the CPU context"); + + System.out.format(">>> A0 = 0x%x\n", uc.reg_read(UC_RISCV_REG_A0)); + System.out.format(">>> A1 = 0x%x\n", uc.reg_read(UC_RISCV_REG_A1)); + } + + public static void test_riscv_step() { + long a0 = 0x1234L; + long a1 = 0x7890L; + long pc = 0x0000L; + + System.out.println("Emulate RISCV code: step"); + + // Initialize emulator in RISCV64 mode + Unicorn uc = new Unicorn(UC_ARCH_RISCV, UC_MODE_RISCV32); + + // map 2MB memory for this emulation + uc.mem_map(ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + + // write machine code to be emulated to memory + uc.mem_write(ADDRESS, CODE); + + // initialize machine registers + uc.reg_write(UC_RISCV_REG_A0, a0); + uc.reg_write(UC_RISCV_REG_A1, a1); + + // tracing all basic blocks with customized callback + uc.hook_add(hook_block, 1, 0, null); + + // tracing all instruction + uc.hook_add(hook_code, 1, 0, null); + + // emulate 1 instruction + uc.emu_start(ADDRESS, ADDRESS + CODE.length, 0, 1); + + pc = uc.reg_read(UC_RISCV_REG_PC); + + System.out.format(">>> A0 = 0x%x\n", uc.reg_read(UC_RISCV_REG_A0)); + System.out.format(">>> A1 = 0x%x\n", uc.reg_read(UC_RISCV_REG_A1)); + + if (pc != 0x10004) { + System.out.format( + "Error after step: PC is: 0x%x, expected was 0x10004\n", pc); + } + + // emulate one more instruction + uc.emu_start(ADDRESS + 4, ADDRESS + 8, 0, 0); + + // now print out some registers + System.out.println(">>> Emulation done. Below is the CPU context"); + + System.out.format(">>> A0 = 0x%x\n", uc.reg_read(UC_RISCV_REG_A0)); + System.out.format(">>> A1 = 0x%x\n", uc.reg_read(UC_RISCV_REG_A1)); + } + + public static void test_riscv_timeout() { + long a0 = 0x1234L; + long a1 = 0x7890L; + long pc = 0x0000L; + + System.out.println("Emulate RISCV code: timeout"); + + // Initialize emulator in RISCV64 mode + Unicorn uc = new Unicorn(UC_ARCH_RISCV, UC_MODE_RISCV32); + + // map 2MB memory for this emulation + uc.mem_map(ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + + // write machine code to be emulated to memory + // TODO(nneonneo): what code was meant to go here? sample_riscv.c + // has all zeros, but that just crashes without running into the + // timeout... + uc.mem_write(ADDRESS, new byte[8]); + + // initialize machine registers + uc.reg_write(UC_RISCV_REG_A0, a0); + uc.reg_write(UC_RISCV_REG_A1, a1); + + // tracing all basic blocks with customized callback + uc.hook_add(hook_block, 1, 0, null); + + // tracing all instruction + uc.hook_add(hook_code, 1, 0, null); + + // emulate 1 instruction with timeout + uc.emu_start(ADDRESS, ADDRESS + 4, 1000, 1); + pc = uc.reg_read(UC_RISCV_REG_PC); + + if (pc != 0x10000) { + System.out.format( + "Error after step: PC is: 0x%x, expected was 0x10004\n", pc); + } + + // emulate 1 instruction with timeout + uc.emu_start(ADDRESS, ADDRESS + 4, 1000, 1); + pc = uc.reg_read(UC_RISCV_REG_PC); + + if (pc != 0x10000) { + System.out.format( + "Error after step: PC is: 0x%x, expected was 0x10004\n", pc); + } + + // now print out some registers + System.out.println(">>> Emulation done"); + } + + public static void test_riscv_sd64() { + long reg; + + System.out.println("Emulate RISCV code: sd64 instruction"); + + // Initialize emulator in RISCV64 mode + Unicorn uc = new Unicorn(UC_ARCH_RISCV, UC_MODE_RISCV64); + + // map 2MB memory for this emulation + uc.mem_map(ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + + // write machine code to be emulated to memory + uc.mem_write(ADDRESS, CODE64); + + // tracing all basic blocks with customized callback + uc.hook_add(hook_block, 1, 0, null); + + // tracing all instruction + uc.hook_add(hook_code, 1, 0, null); + + reg = ADDRESS + 0x100; + uc.reg_write(UC_RISCV_REG_SP, reg); + + reg = 0x11223344; + uc.reg_write(UC_RISCV_REG_S0, reg); + + // execute instruction + uc.emu_start(0x10000, -1, 0, 1); + + // now print out some registers + System.out.println(">>> Emulation done."); + } + + private static final EventMemHook hook_memalloc = + (uc, type, address, size, value, user_data) -> { + long aligned_address = address & ~0xFFFL; + int aligned_size = ((int) (size / 0x1000) + 1) * 0x1000; + + System.out.format( + ">>> Allocating block at 0x%x (0x%x), block size = 0x%x (0x%x)\n", + address, aligned_address, size, aligned_size); + + uc.mem_map(aligned_address, aligned_size, UC_PROT_ALL); + + // this recovers from missing memory, so we return true + return true; + }; + + public static void test_recover_from_illegal() { + long a0 = 0x1234L; + long a1 = 0x7890L; + + System.out.println("Emulate RISCV code: recover_from_illegal"); + + // Initialize emulator in RISCV64 mode + Unicorn uc = new Unicorn(UC_ARCH_RISCV, UC_MODE_RISCV64); + + uc.reg_write(UC_RISCV_REG_A0, a0); + uc.reg_write(UC_RISCV_REG_A1, a1); + + // map 2MB memory for this emulation + uc.mem_map(ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + + // auto-allocate memory on access + uc.hook_add(hook_memalloc, UC_HOOK_MEM_UNMAPPED, 1, 0, null); + + // tracing all basic blocks with customized callback + uc.hook_add(hook_block, 1, 0, null); + + // tracing all instruction + uc.hook_add(hook_code, 1, 0, null); + + // write machine code to be emulated to memory + uc.mem_write(ADDRESS, CODE); + + // emulate 1 instruction, wrong address, illegal code + try { + uc.emu_start(0x1000, -1, 0, 1); + throw new RuntimeException("emu_start should have failed!"); + } catch (UnicornException e) { + System.out.println("Expected Illegal Instruction error, got: " + e); + } + + // emulate 1 instruction, correct address, valid code + uc.emu_start(ADDRESS, -1, 0, 1); + + // now print out some registers + System.out.println(">>> Emulation done. Below is the CPU context"); + + System.out.format(">>> A0 = 0x%x\n", uc.reg_read(UC_RISCV_REG_A0)); + System.out.format(">>> A1 = 0x%x\n", uc.reg_read(UC_RISCV_REG_A1)); + } + + public static void test_riscv_func_return() { + long pc = 0, ra = 0; + + System.out.println("Emulate RISCV code: return from func"); + + // Initialize emulator in RISCV64 mode + Unicorn uc = new Unicorn(UC_ARCH_RISCV, UC_MODE_RISCV64); + + // map 2MB memory for this emulation + uc.mem_map(ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + + // write machine code to be emulated to memory + uc.mem_write(ADDRESS, FUNC_CODE); + + // tracing all basic blocks with customized callback + uc.hook_add(hook_block, 1, 0, null); + + // tracing all instruction + uc.hook_add(hook_code, 1, 0, null); + + // set return address register + // RET instruction will return to address in RA + // so after RET, PC == RA + ra = 0x10006; + uc.reg_write(UC_RISCV_REG_RA, ra); + + // execute ret instruction + uc.emu_start(0x10000, -1, 0, 1); + + pc = uc.reg_read(UC_RISCV_REG_PC); + if (pc != ra) { + System.out.format( + "Error after execution: PC is: 0x%x, expected was 0x%x\n", + pc, ra); + if (pc == 0x10000) { + System.out.println(" PC did not change during execution"); + } + } else { + System.out.println("Good, PC == RA"); + } + + // set return address register + // C.RET instruction will return to address in RA + // so after C.RET, PC == RA + ra = 0x10006; + uc.reg_write(UC_RISCV_REG_RA, ra); + + System.out.println("========"); + // execute c.ret instruction + uc.emu_start(0x10004, -1, 0, 1); + + pc = uc.reg_read(UC_RISCV_REG_PC); + if (pc != ra) { + System.out.format( + "Error after execution: PC is: 0x%x, expected was 0x%x\n", + pc, ra); + if (pc == 0x10004) { + System.out.println(" PC did not change during execution"); + } + } else { + System.out.println("Good, PC == RA"); + } + + // now print out some registers + System.out.println(">>> Emulation done."); + } + + public static final void main(String[] args) { + test_recover_from_illegal(); + + System.out.println("------------------"); + test_riscv(); + + System.out.println("------------------"); + test_riscv2(); + + System.out.println("------------------"); + test_riscv3(); + + System.out.println("------------------"); + test_riscv_step(); + + // System.out.println("------------------"); + // test_riscv_timeout(); + + System.out.println("------------------"); + test_riscv_sd64(); + + System.out.println("------------------"); + test_riscv_func_return(); + } +} diff --git a/bindings/java/samples/Sample_s390x.java b/bindings/java/samples/Sample_s390x.java new file mode 100644 index 00000000..66c9dd17 --- /dev/null +++ b/bindings/java/samples/Sample_s390x.java @@ -0,0 +1,88 @@ +/* + +Java bindings for the Unicorn Emulator Engine + +Copyright(c) 2023 Robert Xiao + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +version 2 as published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ + +/* Sample code to demonstrate how to emulate S390X code */ + +package samples; + +import unicorn.*; + +public class Sample_s390x implements UnicornConst, S390xConst { + /** code to be emulated: + * {@code lr %r2, %r3} + */ + private static final byte[] CODE = Utils.hexToBytes("1823"); + + // memory address where emulation starts + private static final long ADDRESS = 0x10000; + + private static final BlockHook hook_block = + (uc, address, size, user_data) -> { + System.out.format( + ">>> Tracing basic block at 0x%x, block size = 0x%x\n", + address, size); + }; + + private static final CodeHook hook_code = + (uc, address, size, user_data) -> { + System.out.format( + ">>> Tracing instruction at 0x%x, instruction size = 0x%x\n", + address, size); + }; + + public static void test_s390x() { + long r2 = 2, r3 = 3; + + System.out.println("Emulate S390X code"); + + Unicorn uc = new Unicorn(UC_ARCH_S390X, UC_MODE_BIG_ENDIAN); + + // map 2MB memory for this emulation + uc.mem_map(ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + + // write machine code to be emulated to memory + uc.mem_write(ADDRESS, CODE); + + // initialize machine registers + uc.reg_write(UC_S390X_REG_R2, r2); + uc.reg_write(UC_S390X_REG_R3, r3); + + // tracing all basic blocks with customized callback + uc.hook_add(hook_block, 1, 0, null); + + // tracing one instruction at ADDRESS with customized callback + uc.hook_add(hook_code, ADDRESS, ADDRESS + CODE.length, null); + + // emulate machine code in infinite time (last param = 0), or when + // finishing all the code. + uc.emu_start(ADDRESS, ADDRESS + CODE.length, 0, 0); + + // now print out some registers + System.out.println(">>> Emulation done. Below is the CPU context"); + + System.out.format(">>> R2 = 0x%x\t\t>>> R3 = 0x%x\n", + uc.reg_read(UC_S390X_REG_R2), uc.reg_read(UC_S390X_REG_R3)); + } + + public static final void main(String[] args) { + test_s390x(); + } +} diff --git a/bindings/java/samples/Sample_sparc.java b/bindings/java/samples/Sample_sparc.java index 90058d2e..43f01af7 100644 --- a/bindings/java/samples/Sample_sparc.java +++ b/bindings/java/samples/Sample_sparc.java @@ -28,50 +28,30 @@ package samples; import unicorn.*; -public class Sample_sparc { +public class Sample_sparc implements UnicornConst, SparcConst { - // code to be emulated - public static final byte[] SPARC_CODE = { -122, 0, 64, 2 }; - //public static final byte[] SPARC_CODE = {-69,112,0,0}; //illegal code + /** code to be emulated: + * {@code add %g1, %g2, %g3} + */ + private static final byte[] SPARC_CODE = Utils.hexToBytes("86004002"); + //public static final byte[] SPARC_CODE = Utils.hexToBytes("bb700000"); //illegal code // memory address where emulation starts - public static final int ADDRESS = 0x10000; + private static final int ADDRESS = 0x10000; - public static final long toInt(byte val[]) { - long res = 0; - for (int i = 0; i < val.length; i++) { - long v = val[i] & 0xff; - res = res + (v << (i * 8)); - } - return res; - } + private static final BlockHook hook_block = + (uc, address, size, user_data) -> { + System.out.format( + ">>> Tracing basic block at 0x%x, block size = 0x%x\n", + address, size); + }; - public static final byte[] toBytes(long val) { - byte[] res = new byte[8]; - for (int i = 0; i < 8; i++) { - res[i] = (byte) (val & 0xff); - val >>>= 8; - } - return res; - } - - // callback for tracing basic blocks - private static class MyBlockHook implements BlockHook { - public void hook(Unicorn u, long address, int size, Object user_data) { - System.out.print(String.format( - ">>> Tracing basic block at 0x%x, block size = 0x%x\n", address, - size)); - } - } - - // callback for tracing instruction - private static class MyCodeHook implements CodeHook { - public void hook(Unicorn u, long address, int size, Object user_data) { - System.out.print(String.format( + private static final CodeHook hook_code = + (uc, address, size, user_data) -> { + System.out.format( ">>> Tracing instruction at 0x%x, instruction size = 0x%x\n", - address, size)); - } - } + address, size); + }; public static void test_sparc() { long g1 = 0x1230L; // G1 register @@ -81,25 +61,24 @@ public class Sample_sparc { System.out.print("Emulate SPARC code\n"); // Initialize emulator in Sparc mode - Unicorn u = new Unicorn(Unicorn.UC_ARCH_SPARC, - Unicorn.UC_MODE_32 + Unicorn.UC_MODE_BIG_ENDIAN); + Unicorn u = new Unicorn(UC_ARCH_SPARC, UC_MODE_32 | UC_MODE_BIG_ENDIAN); // map 2MB memory for this emulation - u.mem_map(ADDRESS, 2 * 1024 * 1024, Unicorn.UC_PROT_ALL); + u.mem_map(ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory u.mem_write(ADDRESS, SPARC_CODE); // initialize machine registers - u.reg_write(Unicorn.UC_SPARC_REG_G1, g1); - u.reg_write(Unicorn.UC_SPARC_REG_G2, g2); - u.reg_write(Unicorn.UC_SPARC_REG_G3, g3); + u.reg_write(UC_SPARC_REG_G1, g1); + u.reg_write(UC_SPARC_REG_G2, g2); + u.reg_write(UC_SPARC_REG_G3, g3); // tracing all basic blocks with customized callback - u.hook_add(new MyBlockHook(), 1, 0, null); + u.hook_add(hook_block, 1, 0, null); // tracing one instruction at ADDRESS with customized callback - u.hook_add(new MyCodeHook(), ADDRESS, ADDRESS, null); + u.hook_add(hook_code, ADDRESS, ADDRESS, null); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. @@ -107,11 +86,7 @@ public class Sample_sparc { // now print out some registers System.out.print(">>> Emulation done. Below is the CPU context\n"); - - g3 = u.reg_read(Unicorn.UC_SPARC_REG_G3); - System.out.print(String.format(">>> G3 = 0x%x\n", g3)); - - u.close(); + System.out.format(">>> G3 = 0x%x\n", u.reg_read(UC_SPARC_REG_G3)); } public static void main(String args[]) { diff --git a/bindings/java/samples/Sample_tricore.java b/bindings/java/samples/Sample_tricore.java new file mode 100644 index 00000000..6a67a8da --- /dev/null +++ b/bindings/java/samples/Sample_tricore.java @@ -0,0 +1,84 @@ +/* + +Java bindings for the Unicorn Emulator Engine + +Copyright(c) 2023 Robert Xiao + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +version 2 as published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ + +/* Sample code to demonstrate how to emulate TriCore code + * Ported from the C version originally by Eric Poole , 2022 + */ + +package samples; + +import unicorn.*; + +public class Sample_tricore implements UnicornConst, TriCoreConst { + /** code to be emulated: + * {@code mov d1, #0x1; mov.u d0, #0x8000} + */ + private static final byte[] CODE = Utils.hexToBytes("8211bb000008"); + + // memory address where emulation starts + private static final long ADDRESS = 0x10000; + + private static final BlockHook hook_block = + (uc, address, size, user_data) -> { + System.out.format( + ">>> Tracing basic block at 0x%x, block size = 0x%x\n", + address, size); + }; + + private static final CodeHook hook_code = + (uc, address, size, user_data) -> { + System.out.format( + ">>> Tracing instruction at 0x%x, instruction size = 0x%x\n", + address, size); + }; + + public static void test_tricore() { + System.out.println("Emulate TriCore code"); + + Unicorn uc = new Unicorn(UC_ARCH_TRICORE, UC_MODE_LITTLE_ENDIAN); + + // map 2MB memory for this emulation + uc.mem_map(ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + + // write machine code to be emulated to memory + uc.mem_write(ADDRESS, CODE); + + // tracing all basic blocks with customized callback + uc.hook_add(hook_block, 1, 0, null); + + // tracing one instruction at ADDRESS with customized callback + uc.hook_add(hook_code, ADDRESS, ADDRESS + CODE.length, null); + + // emulate machine code in infinite time (last param = 0), or when + // finishing all the code. + uc.emu_start(ADDRESS, ADDRESS + CODE.length, 0, 0); + + // now print out some registers + System.out.println(">>> Emulation done. Below is the CPU context"); + + System.out.format(">>> d0 = 0x%x\n", uc.reg_read(UC_TRICORE_REG_D0)); + System.out.format(">>> d1 = 0x%x\n", uc.reg_read(UC_TRICORE_REG_D1)); + } + + public static final void main(String[] args) { + test_tricore(); + } +} diff --git a/bindings/java/samples/Sample_x86.java b/bindings/java/samples/Sample_x86.java index 75e6a3fc..5870a66d 100644 --- a/bindings/java/samples/Sample_x86.java +++ b/bindings/java/samples/Sample_x86.java @@ -26,519 +26,653 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. package samples; +import java.math.BigInteger; +import java.nio.ByteBuffer; + import unicorn.*; -public class Sample_x86 { +public class Sample_x86 implements UnicornConst, X86Const { - // code to be emulated - public static final byte[] X86_CODE32 = { 65, 74 }; - public static final byte[] X86_CODE32_JUMP = - { -21, 2, -112, -112, -112, -112, -112, -112 }; - public static final byte[] X86_CODE32_SELF = { -21, 28, 90, -119, -42, -117, - 2, 102, 61, -54, 125, 117, 6, 102, 5, 3, 3, -119, 2, -2, -62, 61, 65, - 65, 65, 65, 117, -23, -1, -26, -24, -33, -1, -1, -1, 49, -46, 106, 11, - 88, -103, 82, 104, 47, 47, 115, 104, 104, 47, 98, 105, 110, -119, -29, - 82, 83, -119, -31, -54, 125, 65, 65, 65, 65 }; - public static final byte[] X86_CODE32_LOOP = { 65, 74, -21, -2 }; - public static final byte[] X86_CODE32_MEM_WRITE = - { -119, 13, -86, -86, -86, -86, 65, 74 }; - public static final byte[] X86_CODE32_MEM_READ = - { -117, 13, -86, -86, -86, -86, 65, 74 }; - public static final byte[] X86_CODE32_JMP_INVALID = - { -23, -23, -18, -18, -18, 65, 74 }; - public static final byte[] X86_CODE32_INOUT = - { 65, -28, 63, 74, -26, 70, 67 }; - public static final byte[] X86_CODE64 = { 65, -68, 59, -80, 40, 42, 73, 15, - -55, -112, 77, 15, -83, -49, 73, -121, -3, -112, 72, -127, -46, -118, - -50, 119, 53, 72, -9, -39, 77, 41, -12, 73, -127, -55, -10, -118, -58, - 83, 77, -121, -19, 72, 15, -83, -46, 73, -9, -44, 72, -9, -31, 77, 25, - -59, 77, -119, -59, 72, -9, -42, 65, -72, 79, -115, 107, 89, 77, -121, - -48, 104, 106, 30, 9, 60, 89 }; - public static final byte[] X86_CODE16 = { 0, 0 }; // add byte ptr [bx + si], al + /** code to be emulated + * {@code INC ecx; DEC edx; PXOR xmm0, xmm1} + */ + private static final byte[] X86_CODE32 = Utils.hexToBytes("414a660fefc1"); + /** code to be emulated + * {@code jmp 4; nop; nop; nop; nop; nop; nop} + */ + private static final byte[] X86_CODE32_JUMP = + Utils.hexToBytes("eb02909090909090"); + // private static final byte[] X86_CODE32_SELF = Utils.hexToBytes("eb1c5a89d68b02663dca7d7506660503038902fec23d4141414175e9ffe6e8dfffffff31d26a0b589952682f2f7368682f62696e89e3525389e1ca7d41414141"); - // memory address where emulation starts + /** code to be emulated + * {@code PUSH ecx; PUSH ecx; PUSH ecx; PUSH ecx} + */ + // private static final byte[] X86_CODE32 = Utils.hexToBytes("51515151"); + + /** code to be emulated + * {@code INC ecx; DEC edx; self_loop: JMP self_loop} + */ + private static final byte[] X86_CODE32_LOOP = Utils.hexToBytes("414aebfe"); + + /** code to be emulated + * {@code mov [0xaaaaaaaa], ecx; INC ecx; DEC edx} + */ + private static final byte[] X86_CODE32_MEM_WRITE = + Utils.hexToBytes("890DAAAAAAAA414a"); + + /** code to be emulated + * {@code mov ecx, [0xaaaaaaaa]; INC ecx; DEC edx} + */ + private static final byte[] X86_CODE32_MEM_READ = + Utils.hexToBytes("8B0DAAAAAAAA414a"); + + /** code to be emulated + * {@code inc eax; mov ebx, [0x100000]; inc edx} + */ + private static final byte[] X86_CODE32_MEM_READ_IN_TB = + Utils.hexToBytes("408b1d0000100042"); + + /** code to be emulated + * {@code JMP outside; INC ecx; DEC edx} + */ + private static final byte[] X86_CODE32_JMP_INVALID = + Utils.hexToBytes("e9e9eeeeee414a"); + + /** code to be emulated + * {@code INC ecx; IN AL, 0x3f; DEC edx; OUT 0x46, AL; INC ebx} + */ + private static final byte[] X86_CODE32_INOUT = + Utils.hexToBytes("41E43F4aE64643"); + + /** code to be emulated + * {@code INC eax} + */ + private static final byte[] X86_CODE32_INC = Utils.hexToBytes("40"); + + //private static final byte[] X86_CODE64 = Utils.hexToBytes("41BC3BB0282A490FC9904D0FADCF4987FD904881D28ACE773548F7D9"); // <== still crash + /** code to be emulated */ + private static final byte[] X86_CODE64 = + Utils.hexToBytes("41BC3BB0282A490FC9904D0FADCF4987FD90" + + "4881D28ACE773548F7D94D29F44981C9F68A" + + "C6534D87ED480FADD249F7D448F7E14D19C5" + + "4D89C548F7D641B84F8D6B594D87D0686A1E" + + "093C59"); + /** code to be emulated + * {@code add byte ptr [bx + si], al} + */ + private static final byte[] X86_CODE16 = Utils.hexToBytes("0000"); + /** code to be emulated + * {@code syscall} + */ + private static final byte[] X86_CODE64_SYSCALL = Utils.hexToBytes("0f05"); + /** code to be emulated + * {@code mov [0x20004], ecx; mov ecx, [0x20004]} + */ + private static final byte[] X86_MMIO_CODE = + Utils.hexToBytes("890d040002008b0d04000200"); + /** code to be emulated + *
+     * 0x1000 xor dword ptr [edi+0x3], eax ; edi=0x1000, eax=0xbc4177e6
+     * 0x1003 dw 0x3ea98b13
+     * 
+ */ + private static final byte[] X86_CODE32_SMC = + Utils.hexToBytes("314703138ba93e"); + + /** memory address where emulation starts */ public static final int ADDRESS = 0x1000000; - public static final long toInt(byte val[]) { - long res = 0; - for (int i = 0; i < val.length; i++) { - long v = val[i] & 0xff; - res = res + (v << (i * 8)); - } - return res; - } + private static final BlockHook hook_block = + (uc, address, size, user_data) -> { + System.out.format( + ">>> Tracing basic block at 0x%x, block size = 0x%x\n", + address, size); + }; - public static final byte[] toBytes(long val) { - byte[] res = new byte[8]; - for (int i = 0; i < 8; i++) { - res[i] = (byte) (val & 0xff); - val >>>= 8; - } - return res; - } - - // callback for tracing basic blocks - // callback for tracing instruction - private static class MyBlockHook implements BlockHook { - public void hook(Unicorn u, long address, int size, Object user_data) { - System.out.printf( - ">>> Tracing basic block at 0x%x, block size = 0x%x\n", address, - size); - } - } - - // callback for tracing instruction - private static class MyCodeHook implements CodeHook { - public void hook(Unicorn u, long address, int size, Object user_data) { - System.out.printf( + private static final CodeHook hook_code = + (uc, address, size, user_data) -> { + System.out.format( ">>> Tracing instruction at 0x%x, instruction size = 0x%x\n", address, size); - long eflags = u.reg_read(Unicorn.UC_X86_REG_EFLAGS); - System.out.printf(">>> --- EFLAGS is 0x%x\n", eflags); + long eflags = uc.reg_read(UC_X86_REG_EFLAGS); + System.out.format(">>> --- EFLAGS is 0x%x\n", eflags); // Uncomment below code to stop the emulation using uc_emu_stop() // if (address == 0x1000009) - // u.emu_stop(); - } - } + // uc.emu_stop(); + }; - private static class MyWriteInvalidHook implements EventMemHook { - public boolean hook(Unicorn u, int type, long address, int size, - long value, - Object user) { - System.out.printf( - ">>> Missing memory is being WRITE at 0x%x, data size = %d, data value = 0x%x\n", - address, size, value); - // map this memory in with 2MB in size - u.mem_map(0xaaaa0000, 2 * 1024 * 1024, Unicorn.UC_PROT_ALL); - // return true to indicate we want to continue - return true; - } - } - - // callback for tracing instruction - private static class MyCode64Hook implements CodeHook { - public void hook(Unicorn u, long address, int size, Object user_data) { - long r_rip = u.reg_read(Unicorn.UC_X86_REG_RIP); - System.out.printf( + private static final CodeHook hook_code64 = + (uc, address, size, user_data) -> { + long rip = uc.reg_read(UC_X86_REG_RIP); + System.out.format( ">>> Tracing instruction at 0x%x, instruction size = 0x%x\n", address, size); - System.out.printf(">>> RIP is 0x%x\n", r_rip); + System.out.format(">>> RIP is 0x%x\n", rip); + }; - // Uncomment below code to stop the emulation using uc_emu_stop() - // if (address == 0x1000009) - // uc_emu_stop(handle); - } - } + private static final EventMemHook hook_mem_invalid = + (uc, type, address, size, value, user) -> { + switch (type) { + default: + // return false to indicate we want to stop emulation + return false; + case UC_MEM_WRITE_UNMAPPED: + System.out.printf( + ">>> Missing memory is being WRITE at 0x%x, data size = %d, data value = 0x%x\n", + address, size, value); + // map this memory in with 2MB in size + uc.mem_map(0xaaaa0000L, 2 * 1024 * 1024, UC_PROT_ALL); + // return true to indicate we want to continue + return true; + } + }; - private static class MyRead64Hook implements MemHook { - public void hook(Unicorn u, int type, long address, int size, - long value, Object user) { - System.out.printf( - ">>> Memory is being READ at 0x%x, data size = %d\n", address, - size); - } - } - - private static class MyWrite64Hook implements MemHook { - public void hook(Unicorn u, int type, long address, int size, - long value, - Object user) { - System.out.printf( - ">>> Memory is being WRITE at 0x%x, data size = %d, data value = 0x%x\n", - address, size, value); - } - } + private static final MemHook hook_mem64 = + (uc, type, address, size, value, user_data) -> { + switch (type) { + default: + break; + case UC_MEM_READ: + System.out.format( + ">>> Memory is being READ at 0x%x, data size = %d\n", + address, size); + break; + case UC_MEM_WRITE: + System.out.format( + ">>> Memory is being WRITE at 0x%x, data size = %d, data value = 0x%x\n", + address, size, value); + break; + } + }; // callback for IN instruction (X86). // this returns the data read from the port - private static class MyInHook implements InHook { - public int hook(Unicorn u, int port, int size, Object user_data) { - long r_eip = u.reg_read(Unicorn.UC_X86_REG_EIP); + private static final InHook hook_in = (uc, port, size, user) -> { + long r_eip = uc.reg_read(UC_X86_REG_EIP); - System.out.printf( - "--- reading from port 0x%x, size: %d, address: 0x%x\n", port, - size, r_eip); + System.out.printf( + "--- reading from port 0x%x, size: %d, address: 0x%x\n", port, + size, r_eip); - switch (size) { - case 1: - // read 1 byte to AL - return 0xf1; - case 2: - // read 2 byte to AX - return 0xf2; - case 4: - // read 4 byte to EAX - return 0xf4; - } - return 0; + switch (size) { + case 1: + // read 1 byte to AL + return 0xf1; + case 2: + // read 2 byte to AX + return 0xf2; + case 4: + // read 4 byte to EAX + return 0xf4; } - } + return 0; + }; // callback for OUT instruction (X86). - private static class MyOutHook implements OutHook { - public void hook(Unicorn u, int port, int size, int value, - Object user) { - long eip = u.reg_read(Unicorn.UC_X86_REG_EIP); - long tmp = 0; - System.out.printf( - "--- writing to port 0x%x, size: %d, value: 0x%x, address: 0x%x\n", - port, size, value, eip); + private static final OutHook hook_out = (uc, port, size, value, user) -> { + long eip = uc.reg_read(UC_X86_REG_EIP); + long tmp = 0; + System.out.printf( + "--- writing to port 0x%x, size: %d, value: 0x%x, address: 0x%x\n", + port, size, value, eip); - // confirm that value is indeed the value of AL/AX/EAX - switch (size) { - default: - return; // should never reach this - case 1: - tmp = u.reg_read(Unicorn.UC_X86_REG_AL); - break; - case 2: - tmp = u.reg_read(Unicorn.UC_X86_REG_AX); - break; - case 4: - tmp = u.reg_read(Unicorn.UC_X86_REG_EAX); - break; - } - - System.out.printf("--- register value = 0x%x\n", tmp); + // confirm that value is indeed the value of AL/AX/EAX + switch (size) { + default: + return; // should never reach this + case 1: + tmp = uc.reg_read(UC_X86_REG_AL); + break; + case 2: + tmp = uc.reg_read(UC_X86_REG_AX); + break; + case 4: + tmp = uc.reg_read(UC_X86_REG_EAX); + break; } + + System.out.printf("--- register value = 0x%x\n", tmp); + }; + + // callback for SYSCALL instruction (X86). + private static final SyscallHook hook_syscall = (uc, user_data) -> { + long rax = uc.reg_read(UC_X86_REG_RAX); + if (rax == 0x100) { + rax = 0x200; + uc.reg_write(UC_X86_REG_RAX, rax); + } else { + System.out.format("ERROR: was not expecting rax=0x%x in syscall\n", + rax); + } + }; + + private static final EventMemHook hook_memalloc = + (uc, type, address, size, value, user_data) -> { + long aligned_address = address & ~(0xFFFL); + int aligned_size = ((int) (size / 0x1000) + 1) * 0x1000; + + System.out.format( + ">>> Allocating block at 0x%x (0x%x), block size = 0x%x (0x%x)\n", + address, aligned_address, size, aligned_size); + + uc.mem_map(aligned_address, aligned_size, UC_PROT_ALL); + + // write machine code to be emulated to memory + uc.mem_write(aligned_address, X86_CODE32); + + // this recovers from missing memory, so we return true + return true; + }; + + public static void test_miss_code() { + int r_ecx = 0x1234; // ECX register + int r_edx = 0x7890; // EDX register + + System.out.println("Emulate i386 code - missing code"); + + // Initialize emulator in X86-32bit mode + Unicorn uc = new Unicorn(UC_ARCH_X86, UC_MODE_32); + + // initialize machine registers + uc.reg_write(UC_X86_REG_ECX, r_ecx); + uc.reg_write(UC_X86_REG_EDX, r_edx); + + // tracing all instruction by having @begin > @end + uc.hook_add(hook_code, 1, 0, null); + + // auto-allocate memory on access + uc.hook_add(hook_memalloc, UC_HOOK_MEM_UNMAPPED, 1, 0, null); + + // emulate machine code, without having the code in yet + uc.emu_start(ADDRESS, ADDRESS + X86_CODE32.length, 0, 0); + + // now print out some registers + System.out.println(">>> Emulation done. Below is the CPU context"); + + System.out.format(">>> ECX = 0x%x\n", uc.reg_read(UC_X86_REG_ECX)); + System.out.format(">>> EDX = 0x%x\n", uc.reg_read(UC_X86_REG_EDX)); } public static void test_i386() { - long r_ecx = 0x1234L; // ECX register - long r_edx = 0x7890L; // EDX register + int tmp; + long r_ecx = 0x1234; // ECX register + long r_edx = 0x7890; // EDX register + // XMM0 and XMM1 registers, low qword then high qword + BigInteger r_xmm0 = + new BigInteger("000102030405060708090a0b0c0d0e0f", 16); + BigInteger r_xmm1 = + new BigInteger("00102030405060708090a0b0c0d0e0f0", 16); - System.out.print("Emulate i386 code\n"); + System.out.println("Emulate i386 code"); // Initialize emulator in X86-32bit mode - Unicorn uc; - try { - uc = new Unicorn(Unicorn.UC_ARCH_X86, Unicorn.UC_MODE_32); - } catch (UnicornException uex) { - System.out - .println("Failed on uc_open() with error returned: " + uex); - return; - } + Unicorn uc = new Unicorn(UC_ARCH_X86, UC_MODE_32); // map 2MB memory for this emulation - uc.mem_map(ADDRESS, 2 * 1024 * 1024, Unicorn.UC_PROT_ALL); + uc.mem_map(ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory - try { - uc.mem_write(ADDRESS, X86_CODE32); - } catch (UnicornException uex) { - System.out.println( - "Failed to write emulation code to memory, quit!\n"); - return; - } + uc.mem_write(ADDRESS, X86_CODE32); // initialize machine registers - uc.reg_write(Unicorn.UC_X86_REG_ECX, r_ecx); - uc.reg_write(Unicorn.UC_X86_REG_EDX, r_edx); + uc.reg_write(UC_X86_REG_ECX, r_ecx); + uc.reg_write(UC_X86_REG_EDX, r_edx); + uc.reg_write(UC_X86_REG_XMM0, r_xmm0); + uc.reg_write(UC_X86_REG_XMM1, r_xmm1); // tracing all basic blocks with customized callback - uc.hook_add(new MyBlockHook(), 1, 0, null); + uc.hook_add(hook_block, 1, 0, null); // tracing all instruction by having @begin > @end - uc.hook_add(new MyCodeHook(), 1, 0, null); + uc.hook_add(hook_code, 1, 0, null); // emulate machine code in infinite time - try { - uc.emu_start(ADDRESS, ADDRESS + X86_CODE32.length, 0, 0); - } catch (UnicornException uex) { - System.out.printf("Failed on uc_emu_start() with error : %s\n", - uex.getMessage()); - } + uc.emu_start(ADDRESS, ADDRESS + X86_CODE32.length, 0, 0); // now print out some registers - System.out.print(">>> Emulation done. Below is the CPU context\n"); + System.out.println(">>> Emulation done. Below is the CPU context"); - r_ecx = uc.reg_read(Unicorn.UC_X86_REG_ECX); - r_edx = uc.reg_read(Unicorn.UC_X86_REG_EDX); - System.out.printf(">>> ECX = 0x%x\n", r_ecx); - System.out.printf(">>> EDX = 0x%x\n", r_edx); + r_ecx = uc.reg_read(UC_X86_REG_ECX); + r_edx = uc.reg_read(UC_X86_REG_EDX); + r_xmm0 = (BigInteger) uc.reg_read(UC_X86_REG_XMM0, null); + System.out.format(">>> ECX = 0x%x\n", r_ecx); + System.out.format(">>> EDX = 0x%x\n", r_edx); + String xmm0_string = + String.format("%32s", r_xmm0.toString(16)).replace(' ', '0'); + System.out.format(">>> XMM0 = 0x%s\n", xmm0_string); // read from memory - try { - byte[] tmp = uc.mem_read(ADDRESS, 4); - System.out.printf(">>> Read 4 bytes from [0x%x] = 0x%x\n", ADDRESS, - toInt(tmp)); - } catch (UnicornException ex) { - System.out.printf(">>> Failed to read 4 bytes from [0x%x]\n", - ADDRESS); - } - uc.close(); + tmp = Utils.toInt(uc.mem_read(ADDRESS, 4)); + System.out.format(">>> Read 4 bytes from [0x%x] = 0x%x\n", ADDRESS, + tmp); } - public static void test_i386_inout() { - long r_eax = 0x1234L; // ECX register - long r_ecx = 0x6789L; // EDX register + public static void test_i386_map_ptr() { + int tmp; + int r_ecx = 0x1234; // ECX register + int r_edx = 0x7890; // EDX register - System.out.print("===================================\n"); - System.out.print("Emulate i386 code with IN/OUT instructions\n"); + System.out.println("Emulate i386 code - use uc_mem_map_ptr()"); // Initialize emulator in X86-32bit mode - Unicorn u = new Unicorn(Unicorn.UC_ARCH_X86, Unicorn.UC_MODE_32); + Unicorn uc = new Unicorn(UC_ARCH_X86, UC_MODE_32); - // map 2MB memory for this emulation - u.mem_map(ADDRESS, 2 * 1024 * 1024, Unicorn.UC_PROT_ALL); - - // write machine code to be emulated to memory - u.mem_write(ADDRESS, X86_CODE32_INOUT); + // malloc 2MB memory for this emulation + ByteBuffer mem = ByteBuffer.allocateDirect(2 * 1024 * 1024); + uc.mem_map_ptr(ADDRESS, mem, UC_PROT_ALL); + mem.put(X86_CODE32); // initialize machine registers - u.reg_write(Unicorn.UC_X86_REG_EAX, r_eax); - u.reg_write(Unicorn.UC_X86_REG_ECX, r_ecx); + uc.reg_write(UC_X86_REG_ECX, r_ecx); + uc.reg_write(UC_X86_REG_EDX, r_edx); // tracing all basic blocks with customized callback - u.hook_add(new MyBlockHook(), 1, 0, null); + uc.hook_add(hook_block, 1, 0, null); - // tracing all instructions - u.hook_add(new MyCodeHook(), 1, 0, null); - - // handle IN instruction - u.hook_add(new MyInHook(), Unicorn.UC_X86_INS_IN, 1, 0, null); - // handle OUT instruction - u.hook_add(new MyOutHook(), Unicorn.UC_X86_INS_OUT, 1, 0, null); + // tracing all instruction by having @begin > @end + uc.hook_add(hook_code, 1, 0, null); // emulate machine code in infinite time - u.emu_start(ADDRESS, ADDRESS + X86_CODE32_INOUT.length, 0, 0); + uc.emu_start(ADDRESS, ADDRESS + X86_CODE32.length, 0, 0); // now print out some registers - System.out.print(">>> Emulation done. Below is the CPU context\n"); + System.out.println(">>> Emulation done. Below is the CPU context"); + System.out.format(">>> ECX = 0x%x\n", uc.reg_read(UC_X86_REG_ECX)); + System.out.format(">>> EDX = 0x%x\n", uc.reg_read(UC_X86_REG_EDX)); - r_eax = u.reg_read(Unicorn.UC_X86_REG_EAX); - r_ecx = u.reg_read(Unicorn.UC_X86_REG_ECX); - System.out.printf(">>> EAX = 0x%x\n", r_eax); - System.out.printf(">>> ECX = 0x%x\n", r_ecx); - - u.close(); + // read from memory + tmp = Utils.toInt(uc.mem_read(ADDRESS, 4)); + System.out.format(">>> Read 4 bytes from [0x%x] = 0x%x\n", ADDRESS, + tmp); } public static void test_i386_jump() { - System.out.print("===================================\n"); - System.out.print("Emulate i386 code with jump\n"); + System.out.println("Emulate i386 code with jump"); // Initialize emulator in X86-32bit mode - Unicorn u = new Unicorn(Unicorn.UC_ARCH_X86, Unicorn.UC_MODE_32); + Unicorn uc = new Unicorn(UC_ARCH_X86, UC_MODE_32); // map 2MB memory for this emulation - u.mem_map(ADDRESS, 2 * 1024 * 1024, Unicorn.UC_PROT_ALL); + uc.mem_map(ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory - u.mem_write(ADDRESS, X86_CODE32_JUMP); + uc.mem_write(ADDRESS, X86_CODE32_JUMP); // tracing 1 basic block with customized callback - u.hook_add(new MyBlockHook(), ADDRESS, ADDRESS, null); + uc.hook_add(hook_block, ADDRESS, ADDRESS, null); // tracing 1 instruction at ADDRESS - u.hook_add(new MyCodeHook(), ADDRESS, ADDRESS, null); + uc.hook_add(hook_code, ADDRESS, ADDRESS, null); // emulate machine code in infinite time - u.emu_start(ADDRESS, ADDRESS + X86_CODE32_JUMP.length, 0, 0); + uc.emu_start(ADDRESS, ADDRESS + X86_CODE32_JUMP.length, 0, 0); - System.out.print(">>> Emulation done. Below is the CPU context\n"); - - u.close(); + System.out.println(">>> Emulation done. Below is the CPU context"); } // emulate code that loop forever public static void test_i386_loop() { - long r_ecx = 0x1234L; // ECX register - long r_edx = 0x7890L; // EDX register + int r_ecx = 0x1234; // ECX register + int r_edx = 0x7890; // EDX register - System.out.print("===================================\n"); - System.out.print("Emulate i386 code that loop forever\n"); + System.out.println("Emulate i386 code that loop forever"); // Initialize emulator in X86-32bit mode - Unicorn u = new Unicorn(Unicorn.UC_ARCH_X86, Unicorn.UC_MODE_32); + Unicorn uc = new Unicorn(UC_ARCH_X86, UC_MODE_32); // map 2MB memory for this emulation - u.mem_map(ADDRESS, 2 * 1024 * 1024, Unicorn.UC_PROT_ALL); + uc.mem_map(ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory - u.mem_write(ADDRESS, X86_CODE32_LOOP); + uc.mem_write(ADDRESS, X86_CODE32_LOOP); // initialize machine registers - u.reg_write(Unicorn.UC_X86_REG_ECX, r_ecx); - u.reg_write(Unicorn.UC_X86_REG_EDX, r_edx); + uc.reg_write(UC_X86_REG_ECX, r_ecx); + uc.reg_write(UC_X86_REG_EDX, r_edx); // emulate machine code in 2 seconds, so we can quit even // if the code loops - u.emu_start(ADDRESS, ADDRESS + X86_CODE32_LOOP.length, - 2 * Unicorn.UC_SECOND_SCALE, 0); + uc.emu_start(ADDRESS, ADDRESS + X86_CODE32_LOOP.length, + 2 * UC_SECOND_SCALE, 0); // now print out some registers - System.out.print(">>> Emulation done. Below is the CPU context\n"); - - r_ecx = u.reg_read(Unicorn.UC_X86_REG_ECX); - r_edx = u.reg_read(Unicorn.UC_X86_REG_EDX); - System.out.printf(">>> ECX = 0x%x\n", r_ecx); - System.out.printf(">>> EDX = 0x%x\n", r_edx); - - u.close(); + System.out.println(">>> Emulation done. Below is the CPU context"); + System.out.format(">>> ECX = 0x%x\n", uc.reg_read(UC_X86_REG_ECX)); + System.out.format(">>> EDX = 0x%x\n", uc.reg_read(UC_X86_REG_EDX)); } // emulate code that read invalid memory public static void test_i386_invalid_mem_read() { - long r_ecx = 0x1234L; // ECX register - long r_edx = 0x7890L; // EDX register + int r_ecx = 0x1234; // ECX register + int r_edx = 0x7890; // EDX register - System.out.print("===================================\n"); - System.out.print("Emulate i386 code that read from invalid memory\n"); + System.out.println("Emulate i386 code that read from invalid memory"); // Initialize emulator in X86-32bit mode - Unicorn u = new Unicorn(Unicorn.UC_ARCH_X86, Unicorn.UC_MODE_32); + Unicorn uc = new Unicorn(UC_ARCH_X86, UC_MODE_32); // map 2MB memory for this emulation - u.mem_map(ADDRESS, 2 * 1024 * 1024, Unicorn.UC_PROT_ALL); + uc.mem_map(ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory - u.mem_write(ADDRESS, X86_CODE32_MEM_READ); + uc.mem_write(ADDRESS, X86_CODE32_MEM_READ); // initialize machine registers - u.reg_write(Unicorn.UC_X86_REG_ECX, r_ecx); - u.reg_write(Unicorn.UC_X86_REG_EDX, r_edx); + uc.reg_write(UC_X86_REG_ECX, r_ecx); + uc.reg_write(UC_X86_REG_EDX, r_edx); // tracing all basic blocks with customized callback - u.hook_add(new MyBlockHook(), 1, 0, null); + uc.hook_add(hook_block, 1, 0, null); // tracing all instruction by having @begin > @end - u.hook_add(new MyCodeHook(), 1, 0, null); + uc.hook_add(hook_code, 1, 0, null); // emulate machine code in infinite time try { - u.emu_start(ADDRESS, ADDRESS + X86_CODE32_MEM_READ.length, 0, 0); - } catch (UnicornException uex) { - int err = u.errno(); - System.out.printf( - "Failed on u.emu_start() with error returned: %s\n", - uex.getMessage()); + uc.emu_start(ADDRESS, ADDRESS + X86_CODE32_MEM_READ.length, 0, 0); + throw new RuntimeException("Expected a crash!"); + } catch (UnicornException e) { + System.out.println("uc.emu_start failed as expected: " + e); } // now print out some registers - System.out.print(">>> Emulation done. Below is the CPU context\n"); - - r_ecx = u.reg_read(Unicorn.UC_X86_REG_ECX); - r_edx = u.reg_read(Unicorn.UC_X86_REG_EDX); - System.out.printf(">>> ECX = 0x%x\n", r_ecx); - System.out.printf(">>> EDX = 0x%x\n", r_edx); - - u.close(); + System.out.println(">>> Emulation done. Below is the CPU context"); + System.out.format(">>> ECX = 0x%x\n", uc.reg_read(UC_X86_REG_ECX)); + System.out.format(">>> EDX = 0x%x\n", uc.reg_read(UC_X86_REG_EDX)); } - // emulate code that read invalid memory + // emulate code that write invalid memory public static void test_i386_invalid_mem_write() { - long r_ecx = 0x1234L; // ECX register - long r_edx = 0x7890L; // EDX register + int r_ecx = 0x1234; // ECX register + int r_edx = 0x7890; // EDX register + int tmp; - System.out.print("===================================\n"); - System.out.print("Emulate i386 code that write to invalid memory\n"); + System.out.println("Emulate i386 code that write to invalid memory"); // Initialize emulator in X86-32bit mode - Unicorn u = new Unicorn(Unicorn.UC_ARCH_X86, Unicorn.UC_MODE_32); + Unicorn uc = new Unicorn(UC_ARCH_X86, UC_MODE_32); // map 2MB memory for this emulation - u.mem_map(ADDRESS, 2 * 1024 * 1024, Unicorn.UC_PROT_ALL); + uc.mem_map(ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory - u.mem_write(ADDRESS, X86_CODE32_MEM_WRITE); + uc.mem_write(ADDRESS, X86_CODE32_MEM_WRITE); // initialize machine registers - u.reg_write(Unicorn.UC_X86_REG_ECX, r_ecx); - u.reg_write(Unicorn.UC_X86_REG_EDX, r_edx); + uc.reg_write(UC_X86_REG_ECX, r_ecx); + uc.reg_write(UC_X86_REG_EDX, r_edx); // tracing all basic blocks with customized callback - u.hook_add(new MyBlockHook(), 1, 0, null); + uc.hook_add(hook_block, 1, 0, null); // tracing all instruction by having @begin > @end - u.hook_add(new MyCodeHook(), 1, 0, null); + uc.hook_add(hook_code, 1, 0, null); // intercept invalid memory events - u.hook_add(new MyWriteInvalidHook(), Unicorn.UC_HOOK_MEM_WRITE_UNMAPPED, - 1, 0, - null); + uc.hook_add(hook_mem_invalid, + UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED, + 1, 0, null); // emulate machine code in infinite time - try { - u.emu_start(ADDRESS, ADDRESS + X86_CODE32_MEM_WRITE.length, 0, 0); - } catch (UnicornException uex) { - System.out.printf( - "Failed on uc_emu_start() with error returned: %s\n", - uex.getMessage()); - } + uc.emu_start(ADDRESS, ADDRESS + X86_CODE32_MEM_WRITE.length, 0, 0); // now print out some registers - System.out.print(">>> Emulation done. Below is the CPU context\n"); - - r_ecx = u.reg_read(Unicorn.UC_X86_REG_ECX); - r_edx = u.reg_read(Unicorn.UC_X86_REG_EDX); - System.out.printf(">>> ECX = 0x%x\n", r_ecx); - System.out.printf(">>> EDX = 0x%x\n", r_edx); + System.out.println(">>> Emulation done. Below is the CPU context"); + System.out.format(">>> ECX = 0x%x\n", uc.reg_read(UC_X86_REG_ECX)); + System.out.format(">>> EDX = 0x%x\n", uc.reg_read(UC_X86_REG_EDX)); // read from memory - byte tmp[] = u.mem_read(0xaaaaaaaa, 4); - System.out.printf(">>> Read 4 bytes from [0x%x] = 0x%x\n", 0xaaaaaaaa, - toInt(tmp)); + tmp = Utils.toInt(uc.mem_read(0xaaaaaaaaL, 4)); + System.out.format(">>> Read 4 bytes from [0x%x] = 0x%x\n", 0xaaaaaaaa, + tmp); try { - u.mem_read(0xffffffaa, 4); - System.out.printf(">>> Read 4 bytes from [0x%x] = 0x%x\n", - 0xffffffaa, toInt(tmp)); - } catch (UnicornException uex) { - System.out.printf(">>> Failed to read 4 bytes from [0x%x]\n", + tmp = Utils.toInt(uc.mem_read(0xffffffaaL, 4)); + throw new RuntimeException("Expected mem_read to fail"); + } catch (UnicornException e) { + System.out.format(">>> Failed to read 4 bytes from [0x%x]\n", 0xffffffaa); } - - u.close(); } // emulate code that jump to invalid memory public static void test_i386_jump_invalid() { - long r_ecx = 0x1234L; // ECX register - long r_edx = 0x7890L; // EDX register + int r_ecx = 0x1234; // ECX register + int r_edx = 0x7890; // EDX register - System.out.print("===================================\n"); - System.out.print("Emulate i386 code that jumps to invalid memory\n"); + System.out.println("Emulate i386 code that jumps to invalid memory"); // Initialize emulator in X86-32bit mode - Unicorn u = new Unicorn(Unicorn.UC_ARCH_X86, Unicorn.UC_MODE_32); + Unicorn uc = new Unicorn(UC_ARCH_X86, UC_MODE_32); // map 2MB memory for this emulation - u.mem_map(ADDRESS, 2 * 1024 * 1024, Unicorn.UC_PROT_ALL); + uc.mem_map(ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory - u.mem_write(ADDRESS, X86_CODE32_JMP_INVALID); + uc.mem_write(ADDRESS, X86_CODE32_JMP_INVALID); // initialize machine registers - u.reg_write(Unicorn.UC_X86_REG_ECX, r_ecx); - u.reg_write(Unicorn.UC_X86_REG_EDX, r_edx); + uc.reg_write(UC_X86_REG_ECX, r_ecx); + uc.reg_write(UC_X86_REG_EDX, r_edx); // tracing all basic blocks with customized callback - u.hook_add(new MyBlockHook(), 1, 0, null); + uc.hook_add(hook_block, 1, 0, null); // tracing all instructions by having @begin > @end - u.hook_add(new MyCodeHook(), 1, 0, null); + uc.hook_add(hook_code, 1, 0, null); // emulate machine code in infinite time try { - u.emu_start(ADDRESS, ADDRESS + X86_CODE32_JMP_INVALID.length, 0, 0); - } catch (UnicornException uex) { - System.out.printf( - "Failed on uc_emu_start() with error returned: %s\n", - uex.getMessage()); + uc.emu_start(ADDRESS, ADDRESS + X86_CODE32_JMP_INVALID.length, 0, + 0); + throw new RuntimeException("Expected a crash!"); + } catch (UnicornException e) { + System.out.println("uc.emu_start failed as expected: " + e); } // now print out some registers - System.out.print(">>> Emulation done. Below is the CPU context\n"); + System.out.println(">>> Emulation done. Below is the CPU context"); + System.out.format(">>> ECX = 0x%x\n", uc.reg_read(UC_X86_REG_ECX)); + System.out.format(">>> EDX = 0x%x\n", uc.reg_read(UC_X86_REG_EDX)); + } - r_ecx = u.reg_read(Unicorn.UC_X86_REG_ECX); - r_edx = u.reg_read(Unicorn.UC_X86_REG_EDX); - System.out.printf(">>> ECX = 0x%x\n", r_ecx); - System.out.printf(">>> EDX = 0x%x\n", r_edx); + public static void test_i386_inout() { + int r_eax = 0x1234; // EAX register + int r_ecx = 0x6789; // ECX register - u.close(); + System.out.println("Emulate i386 code with IN/OUT instructions"); + + // Initialize emulator in X86-32bit mode + Unicorn uc = new Unicorn(UC_ARCH_X86, UC_MODE_32); + + // map 2MB memory for this emulation + uc.mem_map(ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + + // write machine code to be emulated to memory + uc.mem_write(ADDRESS, X86_CODE32_INOUT); + + // initialize machine registers + uc.reg_write(UC_X86_REG_EAX, r_eax); + uc.reg_write(UC_X86_REG_ECX, r_ecx); + + // tracing all basic blocks with customized callback + uc.hook_add(hook_block, 1, 0, null); + + // tracing all instructions + uc.hook_add(hook_code, 1, 0, null); + + // uc IN instruction + uc.hook_add(hook_in, null); + // uc OUT instruction + uc.hook_add(hook_out, null); + + // emulate machine code in infinite time + uc.emu_start(ADDRESS, ADDRESS + X86_CODE32_INOUT.length, 0, 0); + + // now print out some registers + System.out.println(">>> Emulation done. Below is the CPU context"); + System.out.format(">>> EAX = 0x%x\n", uc.reg_read(UC_X86_REG_EAX)); + System.out.format(">>> ECX = 0x%x\n", uc.reg_read(UC_X86_REG_ECX)); + } + + // emulate code and save/restore the CPU context + public static void test_i386_context_save() { + int r_eax = 0x1; // EAX register + + System.out.println("Save/restore CPU context in opaque blob"); + + // initialize emulator in X86-32bit mode + Unicorn uc = new Unicorn(UC_ARCH_X86, UC_MODE_32); + + // map 8KB memory for this emulation + uc.mem_map(ADDRESS, 8 * 1024, UC_PROT_ALL); + + // write machine code to be emulated to memory + uc.mem_write(ADDRESS, X86_CODE32_INC); + + // initialize machine registers + uc.reg_write(UC_X86_REG_EAX, r_eax); + + // emulate machine code in infinite time + System.out.println(">>> Running emulation for the first time"); + uc.emu_start(ADDRESS, ADDRESS + X86_CODE32_INC.length, 0, 0); + + // now print out some registers + System.out.println(">>> Emulation done. Below is the CPU context"); + System.out.format(">>> EAX = 0x%x\n", uc.reg_read(UC_X86_REG_EAX)); + + // allocate and save the CPU context + System.out.println(">>> Saving CPU context"); + Unicorn.Context context = uc.context_save(); + + // emulate machine code again + System.out.println(">>> Running emulation for the second time"); + uc.emu_start(ADDRESS, ADDRESS + X86_CODE32_INC.length, 0, 0); + + // now print out some registers + System.out.println(">>> Emulation done. Below is the CPU context"); + System.out.format(">>> EAX = 0x%x\n", uc.reg_read(UC_X86_REG_EAX)); + + // restore CPU context + uc.context_restore(context); + + // now print out some registers + System.out + .println(">>> CPU context restored. Below is the CPU context"); + System.out.format(">>> EAX = 0x%x\n", uc.reg_read(UC_X86_REG_EAX)); + + // modify some registers of the context + context.reg_write(UC_X86_REG_EAX, 0xc8); + + // and restore CPU context again + uc.context_restore(context); + + // now print out some registers + System.out.format( + ">>> CPU context restored with modification. Below is the CPU context\n"); + System.out.format(">>> EAX = 0x%x\n", uc.reg_read(UC_X86_REG_EAX)); } public static void test_x86_64() { @@ -557,156 +691,370 @@ public class Sample_x86 { long r14 = 0x595f72f6e4017f6eL; long r15 = 0x1efd97aea331ccccL; - long rsp = ADDRESS + 0x200000; + long rsp = ADDRESS + 0x200000L; - System.out.print("Emulate x86_64 code\n"); + System.out.println("Emulate x86_64 code"); // Initialize emulator in X86-64bit mode - Unicorn u = new Unicorn(Unicorn.UC_ARCH_X86, Unicorn.UC_MODE_64); + Unicorn uc = new Unicorn(UC_ARCH_X86, UC_MODE_64); // map 2MB memory for this emulation - u.mem_map(ADDRESS, 2 * 1024 * 1024, Unicorn.UC_PROT_ALL); + uc.mem_map(ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory - u.mem_write(ADDRESS, X86_CODE64); + uc.mem_write(ADDRESS, X86_CODE64); // initialize machine registers - u.reg_write(Unicorn.UC_X86_REG_RSP, rsp); + uc.reg_write(UC_X86_REG_RSP, rsp); - u.reg_write(Unicorn.UC_X86_REG_RAX, rax); - u.reg_write(Unicorn.UC_X86_REG_RBX, rbx); - u.reg_write(Unicorn.UC_X86_REG_RCX, rcx); - u.reg_write(Unicorn.UC_X86_REG_RDX, rdx); - u.reg_write(Unicorn.UC_X86_REG_RSI, rsi); - u.reg_write(Unicorn.UC_X86_REG_RDI, rdi); - u.reg_write(Unicorn.UC_X86_REG_R8, r8); - u.reg_write(Unicorn.UC_X86_REG_R9, r9); - u.reg_write(Unicorn.UC_X86_REG_R10, r10); - u.reg_write(Unicorn.UC_X86_REG_R11, r11); - u.reg_write(Unicorn.UC_X86_REG_R12, r12); - u.reg_write(Unicorn.UC_X86_REG_R13, r13); - u.reg_write(Unicorn.UC_X86_REG_R14, r14); - u.reg_write(Unicorn.UC_X86_REG_R15, r15); + uc.reg_write(UC_X86_REG_RAX, rax); + uc.reg_write(UC_X86_REG_RBX, rbx); + uc.reg_write(UC_X86_REG_RCX, rcx); + uc.reg_write(UC_X86_REG_RDX, rdx); + uc.reg_write(UC_X86_REG_RSI, rsi); + uc.reg_write(UC_X86_REG_RDI, rdi); + uc.reg_write(UC_X86_REG_R8, r8); + uc.reg_write(UC_X86_REG_R9, r9); + uc.reg_write(UC_X86_REG_R10, r10); + uc.reg_write(UC_X86_REG_R11, r11); + uc.reg_write(UC_X86_REG_R12, r12); + uc.reg_write(UC_X86_REG_R13, r13); + uc.reg_write(UC_X86_REG_R14, r14); + uc.reg_write(UC_X86_REG_R15, r15); // tracing all basic blocks with customized callback - u.hook_add(new MyBlockHook(), 1, 0, null); + uc.hook_add(hook_block, 1, 0, null); // tracing all instructions in the range [ADDRESS, ADDRESS+20] - u.hook_add(new MyCode64Hook(), ADDRESS, ADDRESS + 20, null); + uc.hook_add(hook_code64, ADDRESS, ADDRESS + 20, null); // tracing all memory WRITE access (with @begin > @end) - u.hook_add(new MyWrite64Hook(), Unicorn.UC_HOOK_MEM_WRITE, 1, 0, null); + uc.hook_add(hook_mem64, UC_HOOK_MEM_WRITE, 1, 0, null); // tracing all memory READ access (with @begin > @end) - u.hook_add(new MyRead64Hook(), Unicorn.UC_HOOK_MEM_READ, 1, 0, null); + uc.hook_add(hook_mem64, UC_HOOK_MEM_READ, 1, 0, null); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. - u.emu_start(ADDRESS, ADDRESS + X86_CODE64.length, 0, 0); + uc.emu_start(ADDRESS, ADDRESS + X86_CODE64.length, 0, 0); // now print out some registers - System.out.print(">>> Emulation done. Below is the CPU context\n"); + System.out.println(">>> Emulation done. Below is the CPU context"); - long r_rax = u.reg_read(Unicorn.UC_X86_REG_RAX); - long r_rbx = u.reg_read(Unicorn.UC_X86_REG_RBX); - long r_rcx = u.reg_read(Unicorn.UC_X86_REG_RCX); - long r_rdx = u.reg_read(Unicorn.UC_X86_REG_RDX); - long r_rsi = u.reg_read(Unicorn.UC_X86_REG_RSI); - long r_rdi = u.reg_read(Unicorn.UC_X86_REG_RDI); - long r_r8 = u.reg_read(Unicorn.UC_X86_REG_R8); - long r_r9 = u.reg_read(Unicorn.UC_X86_REG_R9); - long r_r10 = u.reg_read(Unicorn.UC_X86_REG_R10); - long r_r11 = u.reg_read(Unicorn.UC_X86_REG_R11); - long r_r12 = u.reg_read(Unicorn.UC_X86_REG_R12); - long r_r13 = u.reg_read(Unicorn.UC_X86_REG_R13); - long r_r14 = u.reg_read(Unicorn.UC_X86_REG_R14); - long r_r15 = u.reg_read(Unicorn.UC_X86_REG_R15); + System.out.format(">>> RAX = 0x%x\n", uc.reg_read(UC_X86_REG_RAX)); + System.out.format(">>> RBX = 0x%x\n", uc.reg_read(UC_X86_REG_RBX)); + System.out.format(">>> RCX = 0x%x\n", uc.reg_read(UC_X86_REG_RCX)); + System.out.format(">>> RDX = 0x%x\n", uc.reg_read(UC_X86_REG_RDX)); + System.out.format(">>> RSI = 0x%x\n", uc.reg_read(UC_X86_REG_RSI)); + System.out.format(">>> RDI = 0x%x\n", uc.reg_read(UC_X86_REG_RDI)); + System.out.format(">>> R8 = 0x%x\n", uc.reg_read(UC_X86_REG_R8)); + System.out.format(">>> R9 = 0x%x\n", uc.reg_read(UC_X86_REG_R9)); + System.out.format(">>> R10 = 0x%x\n", uc.reg_read(UC_X86_REG_R10)); + System.out.format(">>> R11 = 0x%x\n", uc.reg_read(UC_X86_REG_R11)); + System.out.format(">>> R12 = 0x%x\n", uc.reg_read(UC_X86_REG_R12)); + System.out.format(">>> R13 = 0x%x\n", uc.reg_read(UC_X86_REG_R13)); + System.out.format(">>> R14 = 0x%x\n", uc.reg_read(UC_X86_REG_R14)); + System.out.format(">>> R15 = 0x%x\n", uc.reg_read(UC_X86_REG_R15)); + } - System.out.printf(">>> RAX = 0x%x\n", r_rax); - System.out.printf(">>> RBX = 0x%x\n", r_rbx); - System.out.printf(">>> RCX = 0x%x\n", r_rcx); - System.out.printf(">>> RDX = 0x%x\n", r_rdx); - System.out.printf(">>> RSI = 0x%x\n", r_rsi); - System.out.printf(">>> RDI = 0x%x\n", r_rdi); - System.out.printf(">>> R8 = 0x%x\n", r_r8); - System.out.printf(">>> R9 = 0x%x\n", r_r9); - System.out.printf(">>> R10 = 0x%x\n", r_r10); - System.out.printf(">>> R11 = 0x%x\n", r_r11); - System.out.printf(">>> R12 = 0x%x\n", r_r12); - System.out.printf(">>> R13 = 0x%x\n", r_r13); - System.out.printf(">>> R14 = 0x%x\n", r_r14); - System.out.printf(">>> R15 = 0x%x\n", r_r15); + public static void test_x86_64_syscall() { + long rax = 0x100; - u.close(); + System.out.println("Emulate x86_64 code with 'syscall' instruction"); + + // Initialize emulator in X86-64bit mode + Unicorn uc = new Unicorn(UC_ARCH_X86, UC_MODE_64); + + // map 2MB memory for this emulation + uc.mem_map(ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + + // write machine code to be emulated to memory + uc.mem_write(ADDRESS, X86_CODE64_SYSCALL); + + // hook interrupts for syscall + uc.hook_add(hook_syscall, UC_X86_INS_SYSCALL, 1, 0, null); + + // initialize machine registers + uc.reg_write(UC_X86_REG_RAX, rax); + + // emulate machine code in infinite time (last param = 0), or when + // finishing all the code. + uc.emu_start(ADDRESS, ADDRESS + X86_CODE64_SYSCALL.length, 0, 0); + + // now print out some registers + System.out.println(">>> Emulation done. Below is the CPU context"); + System.out.format(">>> RAX = 0x%x\n", uc.reg_read(UC_X86_REG_RAX)); } public static void test_x86_16() { - long eax = 7L; - long ebx = 5L; - long esi = 6L; + int eax = 7; + int ebx = 5; + int esi = 6; - System.out.print("Emulate x86 16-bit code\n"); + System.out.println("Emulate x86 16-bit code"); // Initialize emulator in X86-16bit mode - Unicorn u = new Unicorn(Unicorn.UC_ARCH_X86, Unicorn.UC_MODE_16); + Unicorn uc = new Unicorn(UC_ARCH_X86, UC_MODE_16); // map 8KB memory for this emulation - u.mem_map(0, 8 * 1024, Unicorn.UC_PROT_ALL); + uc.mem_map(0, 8 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory - u.mem_write(0, X86_CODE16); + uc.mem_write(0, X86_CODE16); // initialize machine registers - u.reg_write(Unicorn.UC_X86_REG_EAX, eax); - u.reg_write(Unicorn.UC_X86_REG_EBX, ebx); - u.reg_write(Unicorn.UC_X86_REG_ESI, esi); + uc.reg_write(UC_X86_REG_EAX, eax); + uc.reg_write(UC_X86_REG_EBX, ebx); + uc.reg_write(UC_X86_REG_ESI, esi); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. - u.emu_start(0, X86_CODE16.length, 0, 0); + uc.emu_start(0, X86_CODE16.length, 0, 0); // now print out some registers - System.out.print(">>> Emulation done. Below is the CPU context\n"); + System.out.println(">>> Emulation done. Below is the CPU context"); // read from memory - byte[] tmp = u.mem_read(11, 1); - System.out.printf(">>> Read 1 bytes from [0x%x] = 0x%x\n", 11, - toInt(tmp)); + byte[] result = uc.mem_read(11, 1); + System.out.format(">>> Read 1 bytes from [0x%x] = 0x%x\n", 11, + result[0] & 0xff); + } - u.close(); + public static void test_i386_invalid_mem_read_in_tb() { + int r_eax = 0x1234; // EAX register + int r_edx = 0x7890; // EDX register + + System.out.format( + "Emulate i386 code that read invalid memory in the middle of a TB\n"); + + // Initialize emulator in X86-32bit mode + Unicorn uc = new Unicorn(UC_ARCH_X86, UC_MODE_32); + + // map 2MB memory for this emulation + uc.mem_map(ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + + // write machine code to be emulated to memory + uc.mem_write(ADDRESS, X86_CODE32_MEM_READ_IN_TB); + + // initialize machine registers + uc.reg_write(UC_X86_REG_EAX, r_eax); + uc.reg_write(UC_X86_REG_EDX, r_edx); + + // Add a dummy callback. + // Note: if this callback is not added, the EIP will not be updated, + // and EIP will read as ADDRESS after emu_start fails. + uc.hook_add((MemHook) (u, type, address, size, value, user) -> { + }, UC_HOOK_MEM_READ, 1, 0, null); + + // Let it crash by design. + try { + uc.emu_start(ADDRESS, ADDRESS + X86_CODE32_MEM_READ_IN_TB.length, 0, + 0); + throw new RuntimeException("Expected uc.emu_start to fail"); + } catch (UnicornException e) { + System.out.println( + "uc.emu_start() failed BY DESIGN with error returned: " + e); + } + + System.out.println(">>> Emulation done. Below is the CPU context"); + + long r_eip = uc.reg_read(UC_X86_REG_EIP); + System.out.format(">>> EIP = 0x%x\n", r_eip); + + if (r_eip != ADDRESS + 1) { + System.out.format( + ">>> ERROR: Wrong PC 0x%x when reading unmapped memory in the middle of TB!\n", + r_eip); + } else { + System.out.format( + ">>> The PC is correct after reading unmapped memory in the middle of TB.\n"); + } + } + + public static void test_i386_smc_xor() { + long r_edi = ADDRESS; // ECX register + long r_eax = 0xbc4177e6L; // EDX register + + System.out.println("Emulate i386 code that modfies itself"); + + // Initialize emulator in X86-32bit mode + Unicorn uc = new Unicorn(UC_ARCH_X86, UC_MODE_32); + + // map 1KB memory for this emulation + uc.mem_map(ADDRESS, 0x1000, UC_PROT_ALL); + + // write machine code to be emulated to memory + uc.mem_write(ADDRESS, X86_CODE32_SMC); + + // initialize machine registers + uc.reg_write(UC_X86_REG_EDI, r_edi); + uc.reg_write(UC_X86_REG_EAX, r_eax); + + // **Important Note** + // + // Since SMC code will cause TB regeneration, the XOR in fact would executed + // twice (the first execution won't take effect.). Thus, if you would like + // to use count to control the emulation, the count should be set to 2. + // + // uc.emu_start(ADDRESS, ADDRESS + 3, 0, 0); + uc.emu_start(ADDRESS, 0, 0, 2); + + System.out.println(">>> Emulation done. Below is the result."); + + int result = Utils.toInt(uc.mem_read(ADDRESS + 3, 4)); + + if (result == (0x3ea98b13 ^ 0xbc4177e6)) { + System.out.format( + ">>> SMC emulation is correct. 0x3ea98b13 ^ 0xbc4177e6 = 0x%x\n", + result); + } else { + System.out.format( + ">>> SMC emulation is wrong. 0x3ea98b13 ^ 0xbc4177e6 = 0x%x\n", + result); + } + } + + private static final MmioReadHandler mmio_read_callback = + (uc, offset, size, user_data) -> { + System.out.format( + ">>> Read IO memory at offset 0x%d with 0x%d bytes and return 0x19260817\n", + offset, size); + // The value returned here would be written to ecx. + return 0x19260817; + }; + + private static final MmioWriteHandler mmio_write_callback = + (uc, offset, size, value, user_data) -> { + System.out.format( + ">>> Write value 0x%d to IO memory at offset 0x%d with 0x%d bytes\n", + value, offset, size); + }; + + public static void test_i386_mmio() { + long r_ecx = 0xdeadbeefL; + + System.out.println("Emulate i386 code that uses MMIO"); + + // Initialize emulator in X86-32bit mode + Unicorn uc = new Unicorn(UC_ARCH_X86, UC_MODE_32); + + // map 1KB memory for this emulation + uc.mem_map(ADDRESS, 0x1000, UC_PROT_ALL); + + // write machine code to be emulated to memory + uc.mem_write(ADDRESS, X86_MMIO_CODE); + uc.mmio_map(0x20000, 0x4000, mmio_read_callback, null, + mmio_write_callback, null); + + // prepare ecx + uc.reg_write(UC_X86_REG_ECX, r_ecx); + + uc.emu_start(ADDRESS, ADDRESS + X86_MMIO_CODE.length, 0, 0); + System.out.format(">>> Emulation done. ECX=0x%x\n", + uc.reg_read(UC_X86_REG_ECX)); + } + + private static final EventMemHook test_i386_hook_mem_invalid_cb = + (uc, type, address, size, value, user_data) -> { + if (type == UC_MEM_READ_UNMAPPED || type == UC_MEM_WRITE_UNMAPPED) { + System.out.format( + ">>> We have to add a map at 0x%x before continue execution!\n", + address); + uc.mem_map(address, 0x1000, UC_PROT_ALL); + } + + // If you really would like to continue the execution, make sure the memory + // is already mapped properly! + return true; + }; + + public static void test_i386_hook_mem_invalid() { + // mov eax, 0xdeadbeef; + // mov [0x8000], eax; + // mov eax, [0x10000]; + byte[] code = Utils.hexToBytes("b8efbeaddea300800000a100000100"); + + System.out.println( + "Emulate i386 code that triggers invalid memory read/write."); + + Unicorn uc = new Unicorn(UC_ARCH_X86, UC_MODE_32); + uc.mem_map(ADDRESS, 0x1000, UC_PROT_ALL); + uc.mem_write(ADDRESS, code); + long hook = uc.hook_add(test_i386_hook_mem_invalid_cb, + UC_HOOK_MEM_INVALID, 1, 0, null); + uc.emu_start(ADDRESS, ADDRESS + code.length, 0, 0); + + uc.hook_del(hook); } public static void main(String args[]) { if (args.length == 1) { - if (args[0].equals("-32")) { - test_i386(); - test_i386_inout(); - test_i386_jump(); - test_i386_loop(); - test_i386_invalid_mem_read(); - test_i386_invalid_mem_write(); - test_i386_jump_invalid(); - } - - if (args[0].equals("-64")) { - test_x86_64(); - } - if (args[0].equals("-16")) { test_x86_16(); - } - - // test memleak - if (args[0].equals("-0")) { - while (true) { - test_i386(); - // test_x86_64(); - } + } else if (args[0].equals("-32")) { + test_miss_code(); + System.out.println("==================================="); + test_i386(); + System.out.println("==================================="); + test_i386_map_ptr(); + System.out.println("==================================="); + test_i386_inout(); + System.out.println("==================================="); + test_i386_context_save(); + System.out.println("==================================="); + test_i386_jump(); + System.out.println("==================================="); + test_i386_loop(); + System.out.println("==================================="); + test_i386_invalid_mem_read(); + System.out.println("==================================="); + test_i386_invalid_mem_write(); + System.out.println("==================================="); + test_i386_jump_invalid(); + // test_i386_invalid_c6c7(); + } else if (args[0].equals("-64")) { + test_x86_64(); + System.out.println("==================================="); + test_x86_64_syscall(); + } else if (args[0].equals("-h")) { + System.out.println( + "Syntax: java samples.Sample_x86 <-16|-32|-64>"); } } else { - System.out.print("Syntax: java Sample_x86 <-16|-32|-64>\n"); + test_x86_16(); + System.out.println("==================================="); + test_miss_code(); + System.out.println("==================================="); + test_i386(); + System.out.println("==================================="); + test_i386_map_ptr(); + System.out.println("==================================="); + test_i386_inout(); + System.out.println("==================================="); + test_i386_context_save(); + System.out.println("==================================="); + test_i386_jump(); + System.out.println("==================================="); + test_i386_loop(); + System.out.println("==================================="); + test_i386_invalid_mem_read(); + System.out.println("==================================="); + test_i386_invalid_mem_write(); + System.out.println("==================================="); + test_i386_jump_invalid(); + // test_i386_invalid_c6c7(); + System.out.println("==================================="); + test_x86_64(); + System.out.println("==================================="); + test_x86_64_syscall(); + System.out.println("==================================="); + test_i386_invalid_mem_read_in_tb(); + System.out.println("==================================="); + test_i386_smc_xor(); + System.out.println("==================================="); + test_i386_mmio(); + System.out.println("==================================="); + test_i386_hook_mem_invalid(); } - } - } diff --git a/bindings/java/samples/Sample_x86_mmr.java b/bindings/java/samples/Sample_x86_mmr.java index 65cd4b76..eaadf878 100644 --- a/bindings/java/samples/Sample_x86_mmr.java +++ b/bindings/java/samples/Sample_x86_mmr.java @@ -25,21 +25,14 @@ package samples; import unicorn.*; -public class Sample_x86_mmr { +public class Sample_x86_mmr implements UnicornConst, X86Const { public static void test_x86_mmr() { // Initialize emulator in X86-32bit mode - Unicorn uc; - try { - uc = new Unicorn(Unicorn.UC_ARCH_X86, Unicorn.UC_MODE_32); - } catch (UnicornException uex) { - System.out - .println("Failed on uc_open() with error returned: " + uex); - return; - } + Unicorn uc = new Unicorn(UC_ARCH_X86, UC_MODE_32); // map 4k - uc.mem_map(0x400000, 0x1000, Unicorn.UC_PROT_ALL); + uc.mem_map(0x400000, 0x1000, UC_PROT_ALL); X86_MMR ldtr1 = new X86_MMR(0x1111111122222222L, 0x33333333, 0x44444444, (short) 0x5555); @@ -52,14 +45,14 @@ public class Sample_x86_mmr { // initialize machine registers - uc.reg_write(Unicorn.UC_X86_REG_LDTR, ldtr1); - uc.reg_write(Unicorn.UC_X86_REG_GDTR, gdtr1); - uc.reg_write(Unicorn.UC_X86_REG_EAX, 0xddddddddL); + uc.reg_write(UC_X86_REG_LDTR, ldtr1); + uc.reg_write(UC_X86_REG_GDTR, gdtr1); + uc.reg_write(UC_X86_REG_EAX, 0xddddddddL); // read the registers back out - eax = (int) uc.reg_read(Unicorn.UC_X86_REG_EAX); - ldtr2 = (X86_MMR) uc.reg_read(Unicorn.UC_X86_REG_LDTR, null); - gdtr2 = (X86_MMR) uc.reg_read(Unicorn.UC_X86_REG_GDTR, null); + eax = (int) uc.reg_read(UC_X86_REG_EAX); + ldtr2 = (X86_MMR) uc.reg_read(UC_X86_REG_LDTR, null); + gdtr2 = (X86_MMR) uc.reg_read(UC_X86_REG_GDTR, null); System.out.printf(">>> EAX = 0x%x\n", eax); @@ -70,8 +63,6 @@ public class Sample_x86_mmr { System.out.printf(">>> GDTR.base = 0x%x\n", gdtr2.base); System.out.printf(">>> GDTR.limit = 0x%x\n", gdtr2.limit); - - uc.close(); } public static void main(String args[]) { diff --git a/bindings/java/samples/Shellcode.java b/bindings/java/samples/Shellcode.java index e31dc3a2..6ed1d45f 100644 --- a/bindings/java/samples/Shellcode.java +++ b/bindings/java/samples/Shellcode.java @@ -28,137 +28,107 @@ package samples; import unicorn.*; -public class Shellcode { +public class Shellcode implements UnicornConst, X86Const { - public static final byte[] X86_CODE32 = { -21, 25, 49, -64, 49, -37, 49, - -46, 49, -55, -80, 4, -77, 1, 89, -78, 5, -51, -128, 49, -64, -80, 1, - 49, -37, -51, -128, -24, -30, -1, -1, -1, 104, 101, 108, 108, 111 }; - public static final byte[] X86_CODE32_SELF = { -21, 28, 90, -119, -42, -117, - 2, 102, 61, -54, 125, 117, 6, 102, 5, 3, 3, -119, 2, -2, -62, 61, 65, - 65, 65, 65, 117, -23, -1, -26, -24, -33, -1, -1, -1, 49, -46, 106, 11, - 88, -103, 82, 104, 47, 47, 115, 104, 104, 47, 98, 105, 110, -119, -29, - 82, 83, -119, -31, -54, 125, 65, 65, 65, 65, 65, 65, 65, 65 }; + public static final byte[] X86_CODE32_SELF = Utils.hexToBytes( + "eb1c5a89d68b02663dca7d75066605030389" + + "02fec23d4141414175e9ffe6e8dfffffff31" + + "d26a0b589952682f2f7368682f62696e89e3" + + "525389e1ca7d4141414141414141"); // memory address where emulation starts public static final int ADDRESS = 0x1000000; - public static final long toInt(byte val[]) { - long res = 0; - for (int i = 0; i < val.length; i++) { - long v = val[i] & 0xff; - res = res + (v << (i * 8)); - } - return res; - } - - public static final byte[] toBytes(long val) { - byte[] res = new byte[8]; - for (int i = 0; i < 8; i++) { - res[i] = (byte) (val & 0xff); - val >>>= 8; - } - return res; - } - - public static class MyCodeHook implements CodeHook { - public void hook(Unicorn u, long address, int size, Object user) { - - System.out.print(String.format( - "Tracing instruction at 0x%x, instruction size = 0x%x\n", - address, size)); - - long r_eip = u.reg_read(Unicorn.UC_X86_REG_EIP); - System.out.print( - String.format("*** EIP = %x ***: ", r_eip)); - - size = Math.min(16, size); - - byte[] tmp = u.mem_read(address, size); - for (int i = 0; i < tmp.length; i++) { - System.out.print(String.format("%x ", 0xff & tmp[i])); - } - System.out.print("\n"); + public static CodeHook hook_code = (u, address, size, user) -> { + System.out.format( + "Tracing instruction at 0x%x, instruction size = 0x%x\n", + address, size); + + long r_eip = u.reg_read(UC_X86_REG_EIP); + System.out.format("*** EIP = %x ***: ", r_eip); + + byte[] tmp = u.mem_read(address, size); + for (int i = 0; i < tmp.length; i++) { + System.out.format("%x ", 0xff & tmp[i]); } + System.out.println(); }; - public static class MyInterruptHook implements InterruptHook { - public void hook(Unicorn u, int intno, Object user) { - long r_ecx; - long r_edx; - int size; - - // only handle Linux syscall - if (intno != 0x80) { - return; - } - - long r_eax = u.reg_read(Unicorn.UC_X86_REG_EAX); - long r_eip = u.reg_read(Unicorn.UC_X86_REG_EIP); - - switch ((int) r_eax) { - default: - System.out.print( - String.format(">>> 0x%x: interrupt 0x%x, EAX = 0x%x\n", - r_eip, intno, r_eax)); - break; - case 1: // sys_exit - System.out.print(String.format( - ">>> 0x%x: interrupt 0x%x, SYS_EXIT. quit!\n\n", - r_eip, intno)); - u.emu_stop(); - break; - case 4: // sys_write - // ECX = buffer address - r_ecx = u.reg_read(Unicorn.UC_X86_REG_ECX); - - // EDX = buffer size - r_edx = u.reg_read(Unicorn.UC_X86_REG_EDX); - - // read the buffer in - size = (int) Math.min(256, r_edx); - - byte[] buffer = u.mem_read(r_ecx, size); - System.out.print(String.format( - ">>> 0x%x: interrupt 0x%x, SYS_WRITE. buffer = 0x%x, size = %u, content = '%s'\n", - r_eip, intno, r_ecx, - r_edx, new String(buffer))); - break; - } + public static InterruptHook hook_intr = (u, intno, user) -> { + // only handle Linux syscall + if (intno != 0x80) { + return; } - } + + long r_eax = u.reg_read(UC_X86_REG_EAX); + long r_eip = u.reg_read(UC_X86_REG_EIP); + + switch ((int) r_eax) { + default: + System.out.format(">>> 0x%x: interrupt 0x%x, EAX = 0x%x\n", + r_eip, intno, r_eax); + break; + case 1: // sys_exit + System.out.format( + ">>> 0x%x: interrupt 0x%x, SYS_EXIT. quit!\n\n", + r_eip, intno); + u.emu_stop(); + break; + case 4: { // sys_write + // ECX = buffer address + long r_ecx = u.reg_read(UC_X86_REG_ECX); + + // EDX = buffer size + long r_edx = u.reg_read(UC_X86_REG_EDX); + + // read the buffer in + int size = (int) Math.min(256, r_edx); + + try { + byte[] buffer = u.mem_read(r_ecx, size); + System.out.format( + ">>> 0x%x: interrupt 0x%x, SYS_WRITE. buffer = 0x%x, size = %u, content = '%s'\n", + r_eip, intno, r_ecx, r_edx, new String(buffer)); + } catch (UnicornException e) { + System.out.format( + ">>> 0x%x: interrupt 0x%x, SYS_WRITE. buffer = 0x%x, size = %u (cannot get content)\n", + r_eip, intno, r_ecx, r_edx); + } + break; + } + } + }; public static void test_i386() { long r_esp = ADDRESS + 0x200000L; // ESP register - System.out.print("Emulate i386 code\n"); + System.out.println("Emulate i386 code"); // Initialize emulator in X86-32bit mode - Unicorn u = new Unicorn(Unicorn.UC_ARCH_X86, Unicorn.UC_MODE_32); + Unicorn u = new Unicorn(UC_ARCH_X86, UC_MODE_32); // map 2MB memory for this emulation - u.mem_map(ADDRESS, 2 * 1024 * 1024, Unicorn.UC_PROT_ALL); + u.mem_map(ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory u.mem_write(ADDRESS, X86_CODE32_SELF); // initialize machine registers - u.reg_write(Unicorn.UC_X86_REG_ESP, r_esp); + u.reg_write(UC_X86_REG_ESP, r_esp); // tracing all instructions by having @begin > @end - u.hook_add(new MyCodeHook(), 1, 0, null); + u.hook_add(hook_code, 1, 0, null); // handle interrupt ourself - u.hook_add(new MyInterruptHook(), null); + u.hook_add(hook_intr, null); - System.out.print("\n>>> Start tracing this Linux code\n"); + System.out.println("\n>>> Start tracing this Linux code"); // emulate machine code in infinite time // u.emu_start(ADDRESS, ADDRESS + X86_CODE32_SELF.length, 0, 12); <--- emulate only 12 instructions u.emu_start(ADDRESS, ADDRESS + X86_CODE32_SELF.length, 0, 0); - System.out.print("\n>>> Emulation done.\n"); - - u.close(); + System.out.println("\n>>> Emulation done."); } public static void main(String args[]) { @@ -167,7 +137,7 @@ public class Shellcode { test_i386(); } } else { - System.out.print("Syntax: java Shellcode <-32|-64>\n"); + System.out.println("Syntax: java Shellcode <-32|-64>"); } } diff --git a/bindings/java/samples/Utils.java b/bindings/java/samples/Utils.java new file mode 100644 index 00000000..260fed70 --- /dev/null +++ b/bindings/java/samples/Utils.java @@ -0,0 +1,49 @@ +package samples; + +public class Utils { + public static byte[] hexToBytes(String s) { + int len = s.length(); + byte[] data = new byte[len / 2]; + for (int i = 0; i < len; i += 2) { + data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + + Character.digit(s.charAt(i + 1), 16)); + } + return data; + } + + public static final int toInt(byte val[]) { + int res = 0; + for (int i = 0; i < val.length; i++) { + int v = val[i] & 0xff; + res = res + (v << (i * 8)); + } + return res; + } + + public static final long toLong(byte val[]) { + long res = 0; + for (int i = 0; i < val.length; i++) { + long v = val[i] & 0xff; + res = res + (v << (i * 8)); + } + return res; + } + + public static final byte[] toBytes(int val) { + byte[] res = new byte[4]; + for (int i = 0; i < 4; i++) { + res[i] = (byte) (val & 0xff); + val >>>= 8; + } + return res; + } + + public static final byte[] toBytes(long val) { + byte[] res = new byte[8]; + for (int i = 0; i < 8; i++) { + res[i] = (byte) (val & 0xff); + val >>>= 8; + } + return res; + } +} diff --git a/bindings/java/tests/FunctionalityTests.java b/bindings/java/tests/FunctionalityTests.java index 38e7908d..d40d0218 100644 --- a/bindings/java/tests/FunctionalityTests.java +++ b/bindings/java/tests/FunctionalityTests.java @@ -122,8 +122,6 @@ public class FunctionalityTests { u.emu_stop(); }).start(); u.emu_start(ADDRESS, ADDRESS + X86_CODE.length, 0, 0); - - u.close(); } @Test @@ -157,8 +155,6 @@ public class FunctionalityTests { uc.context_restore(ctx); assertEquals(0xfee1deadL, uc.reg_read(Unicorn.UC_ARM64_REG_X0)); assertEquals(0xfee1deadL, ctx.reg_read(Unicorn.UC_ARM64_REG_X0)); - - uc.close(); } @Test @@ -188,6 +184,5 @@ public class FunctionalityTests { assertEquals(0xfee1deadL, uc.reg_read(Unicorn.UC_ARM64_REG_X0)); uc.free(ctx); - uc.close(); } } diff --git a/bindings/java/tests/HookTests.java b/bindings/java/tests/HookTests.java index 7b0500fc..330e4e52 100644 --- a/bindings/java/tests/HookTests.java +++ b/bindings/java/tests/HookTests.java @@ -59,7 +59,6 @@ public class HookTests { // TODO(nneonneo): I don't totally understand this output! Why 8 bytes at address 5? assertTranslationBlock(new TranslationBlock(ADDRESS + 5, 3, 8), u.ctl_request_cache(ADDRESS + 5)); - u.close(); } @Test @@ -84,8 +83,6 @@ public class HookTests { u.ctl_tlb_mode(Unicorn.UC_TLB_VIRTUAL); u.emu_start(ADDRESS, ADDRESS + X86_CODE32_MEM_READ.length, 0, 0); assertEquals("ecx", u.reg_read(Unicorn.UC_X86_REG_ECX), 0x04030201); - - u.close(); } @Test @@ -124,7 +121,5 @@ public class HookTests { assertThrows(UnicornException.class, () -> u.hook_del(h1)); assertThrows(UnicornException.class, () -> u.hook_del(h3)); assertThrows(UnicornException.class, () -> u.hook_del(h4)); - - u.close(); } } diff --git a/bindings/java/tests/MemTests.java b/bindings/java/tests/MemTests.java index 976f5d7f..0c553d3a 100644 --- a/bindings/java/tests/MemTests.java +++ b/bindings/java/tests/MemTests.java @@ -29,7 +29,6 @@ public class MemTests { assertEquals("two memory regions", 2, arr.length); assertMemRegion(ADDR1, 2 * 1024 * 1024, Unicorn.UC_PROT_ALL, arr[0]); assertMemRegion(ADDR2, 4096, Unicorn.UC_PROT_READ, arr[1]); - uc.close(); } @Test @@ -71,8 +70,6 @@ public class MemTests { assertMemRegion(0x230000, 0x10000, Unicorn.UC_PROT_READ, mrs[7]); assertMemRegion(0x250000, 0x10000, Unicorn.UC_PROT_WRITE, mrs[8]); assertMemRegion(0x270000, 0x10000, Unicorn.UC_PROT_NONE, mrs[9]); - - u.close(); } @Test @@ -111,8 +108,6 @@ public class MemTests { assertEquals("ecx", 0x44556679, u.reg_read(Unicorn.UC_X86_REG_ECX)); assertEquals("edx", 0x22334453, u.reg_read(Unicorn.UC_X86_REG_EDX)); - - u.close(); } @Test @@ -132,7 +127,5 @@ public class MemTests { u.emu_start(ADDRESS, ADDRESS + X86_CODE32_MEM_WRITE.length, 0, 0); assertEquals("buffer contents", 0x12345678, buffer.getInt(0xaaa)); - - u.close(); } } diff --git a/bindings/java/tests/RegTests.java b/bindings/java/tests/RegTests.java index f9f0183c..356dd69f 100644 --- a/bindings/java/tests/RegTests.java +++ b/bindings/java/tests/RegTests.java @@ -33,7 +33,6 @@ public class RegTests { assertEquals(Math.sin(Math.log(Math.E) / Math.log(2)), reg1.toDouble(), 1e-12); assertEquals(reg1.toDouble(), reg2.toDouble(), 1e-12); - u.close(); } @Test @@ -51,7 +50,6 @@ public class RegTests { u.emu_start(ADDRESS, ADDRESS + X86_CODE.length, 0, 0); reg = (X86_Float80) u.reg_read(Unicorn.UC_X86_REG_ST0, null); assertEquals(Math.sin(-1.1), reg.toDouble(), 1e-12); - u.close(); } @Test @@ -104,8 +102,6 @@ public class RegTests { b[0x70] = -0x80; uc.reg_write(reg, new BigInteger(b)); assertEquals("write untrimmed value", b127, uc.reg_read(reg, null)); - - uc.close(); } @Test @@ -144,8 +140,6 @@ public class RegTests { assertEquals("v0.8h = v1.8h + v2.8h", new BigInteger("4860570d497678b4a5728c3e34a5f85c", 16), uc.reg_read(Unicorn.UC_ARM64_REG_V0, null)); - - uc.close(); } @Test @@ -200,7 +194,5 @@ public class RegTests { uc.reg_read(Unicorn.UC_ARM64_REG_X1)); assertEquals("X1 low bits should be unchanged", 0x0000bbbbccccddddL, uc.reg_read(Unicorn.UC_ARM64_REG_X1) & 0xffffffffffffL); - - uc.close(); } } diff --git a/bindings/java/tests/RegressionTests.java b/bindings/java/tests/RegressionTests.java index af5cdb05..a94090ad 100644 --- a/bindings/java/tests/RegressionTests.java +++ b/bindings/java/tests/RegressionTests.java @@ -24,7 +24,6 @@ public class RegressionTests { uc.reg_read(Unicorn.UC_ARM64_REG_B0)); assertEquals("V0 low halfword", 0x1234, uc.reg_read(Unicorn.UC_ARM64_REG_H0)); - uc.close(); } /** Test for GH #1164: Java binding use CodeHook on Windows, will invoke callback before every instruction */ diff --git a/bindings/java/tests/TestSamples.java b/bindings/java/tests/TestSamples.java index d6e97b08..6c970035 100644 --- a/bindings/java/tests/TestSamples.java +++ b/bindings/java/tests/TestSamples.java @@ -1,14 +1,19 @@ package tests; import static org.junit.Assert.assertEquals; +import static org.junit.Assume.assumeTrue; import java.io.ByteArrayOutputStream; import java.io.PrintStream; import org.junit.Before; +import org.junit.Ignore; import org.junit.After; import org.junit.Test; -public class TestSamples { +import unicorn.Unicorn; +import unicorn.UnicornConst; + +public class TestSamples implements UnicornConst { private final ByteArrayOutputStream outContent = new ByteArrayOutputStream(); private final PrintStream originalOut = System.out; @@ -26,9 +31,37 @@ public class TestSamples { @Test public void testArm() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_ARM)); samples.Sample_arm.test_arm(); - assertEquals("testArm", + assertEquals( "Emulate ARM code\n" + + ">>> Tracing basic block at 0x10000, block size = 0x4\n" + + ">>> Tracing instruction at 0x10000, instruction size = 0x4\n" + + ">>> Emulation done. Below is the CPU context\n" + + ">>> R0 = 0x1234\n" + + ">>> R1 = 0x0\n", + outContent.toString()); + } + + @Test + public void testArmThumb() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_ARM)); + samples.Sample_arm.test_thumb(); + assertEquals( + "Emulate THUMB code\n" + + ">>> Tracing basic block at 0x10000, block size = 0x2\n" + + ">>> Tracing instruction at 0x10000, instruction size = 0x2\n" + + ">>> Emulation done. Below is the CPU context\n" + + ">>> SP = 0x1228\n", + outContent.toString()); + } + + @Test + public void testArmEb() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_ARM)); + samples.Sample_arm.test_armeb(); + assertEquals( + "Emulate ARM Big-Endian code\n" + ">>> Tracing basic block at 0x10000, block size = 0x8\n" + ">>> Tracing instruction at 0x10000, instruction size = 0x4\n" + ">>> Emulation done. Below is the CPU context\n" + @@ -36,4 +69,1107 @@ public class TestSamples { ">>> R1 = 0x3456\n", outContent.toString()); } + + @Test + public void testArmThumbEb() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_ARM)); + samples.Sample_arm.test_thumbeb(); + assertEquals( + "Emulate THUMB Big-Endian code\n" + + ">>> Tracing basic block at 0x10000, block size = 0x2\n" + + ">>> Tracing instruction at 0x10000, instruction size = 0x2\n" + + ">>> Emulation done. Below is the CPU context\n" + + ">>> SP = 0x1228\n", + outContent.toString()); + } + + @Test + public void testArmThumbMrs() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_ARM)); + samples.Sample_arm.test_thumb_mrs(); + assertEquals( + "Emulate THUMB MRS instruction\n" + + ">>> Tracing basic block at 0x10000, block size = 0x4\n" + + ">>> Tracing instruction at 0x10000, instruction size = 0x4\n" + + ">>> Emulation done. Below is the CPU context\n" + + ">>> PC = 0x10004\n", + outContent.toString()); + } + + @Test + public void testArmThumbIte() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_ARM)); + samples.Sample_arm.test_thumb_ite(); + assertEquals( + "Emulate a THUMB ITE block as a whole or per instruction.\n" + + "Running the entire binary.\n" + + ">>> R2: 104\n" + + ">>> R3: 1\n" + + "\n" + + "Running the binary one instruction at a time.\n" + + ">>> R2: 104\n" + + ">>> R3: 1\n" + + "\n", + outContent.toString()); + } + + @Test + public void testArmReadSctlr() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_ARM)); + samples.Sample_arm.test_read_sctlr(); + assertEquals( + "Read the SCTLR register.\n" + + ">>> SCTLR = 0xc50078\n" + + ">>> SCTLR.IE = 0\n" + + ">>> SCTLR.B = 0\n", + outContent.toString()); + } + + @Test + public void testArm64MemFetch() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_ARM64)); + samples.Sample_arm64.test_arm64_mem_fetch(); + assertEquals( + ">>> Emulate ARM64 fetching stack data from high address 10000000000000\n" + + ">>> x0(Exception Level)=1\n" + + ">>> X1 = 0xc8c8c8c8c8c8c8c8\n", + outContent.toString()); + } + + @Test + public void testArm64() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_ARM64)); + samples.Sample_arm64.test_arm64(); + assertEquals( + "Emulate ARM64 code\n" + + ">>> Tracing basic block at 0x10000, block size = 0x8\n" + + ">>> Tracing instruction at 0x10000, instruction size = 0x4\n" + + ">>> Emulation done. Below is the CPU context\n" + + ">>> As little endian, X15 should be 0x78:\n" + + ">>> X15 = 0x78\n", + outContent.toString()); + } + + @Test + public void testArm64Eb() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_ARM64)); + samples.Sample_arm64.test_arm64eb(); + assertEquals( + "Emulate ARM64 Big-Endian code\n" + + ">>> Tracing basic block at 0x10000, block size = 0x8\n" + + ">>> Tracing instruction at 0x10000, instruction size = 0x4\n" + + ">>> Emulation done. Below is the CPU context\n" + + ">>> As big endian, X15 should be 0x78:\n" + + ">>> X15 = 0x12\n", + outContent.toString()); + } + + @Test + public void testArm64Sctlr() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_ARM64)); + samples.Sample_arm64.test_arm64_sctlr(); + assertEquals( + "Read the SCTLR register.\n" + + ">>> SCTLR_EL1 = 0xc50838\n" + + ">>> SCTLR_EL2 = 0x0\n", + outContent.toString()); + } + + @Test + public void testArm64HookMrs() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_ARM64)); + samples.Sample_arm64.test_arm64_hook_mrs(); + assertEquals( + "Hook MRS instruction.\n" + + ">>> Hook MSR instruction. Write 0x114514 to X2.\n" + + ">>> X2 = 0x114514\n", + outContent.toString()); + } + + @Test + public void testArm64Pac() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_ARM64)); + samples.Sample_arm64.test_arm64_pac(); + assertEquals( + "Try ARM64 PAC\n" + + "X1 = 0x1401aaaabbbbcccc\n" + + "SUCCESS: PAC tag found.\n", + outContent.toString()); + } + + @Test + public void testCtlRead() { + samples.Sample_ctl.test_uc_ctl_read(); + assertEquals( + "Reading some properties by uc_ctl.\n" + + ">>> mode = 4, arch = 4, timeout=0, pagesize=4096\n", + outContent.toString()); + } + + @Test + public void testCtlExits() { + samples.Sample_ctl.test_uc_ctl_exits(); + assertEquals( + "Using multiple exits by uc_ctl.\n" + + ">>> Getting a new edge from 0x10004 to 0x10005.\n" + + ">>> eax = 1 and ebx = 0 after the first emulation\n" + + ">>> Getting a new edge from 0x10004 to 0x10007.\n" + + ">>> eax = 1 and ebx = 1 after the second emulation\n", + outContent.toString()); + } + + @Test + public void testM68k() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_M68K)); + samples.Sample_m68k.test_m68k(); + assertEquals( + "Emulate M68K code\n" + + ">>> Tracing basic block at 0x10000, block size = 0x2\n" + + ">>> Tracing instruction at 0x10000, instruction size = 0x2\n" + + ">>> Emulation done. Below is the CPU context\n" + + ">>> A0 = 0x0 >>> D0 = 0x0\n" + + ">>> A1 = 0x0 >>> D1 = 0x0\n" + + ">>> A2 = 0x0 >>> D2 = 0x0\n" + + ">>> A3 = 0x0 >>> D3 = 0xffffffed\n" + + ">>> A4 = 0x0 >>> D4 = 0x0\n" + + ">>> A5 = 0x0 >>> D5 = 0x0\n" + + ">>> A6 = 0x0 >>> D6 = 0x0\n" + + ">>> A7 = 0x0 >>> D7 = 0x0\n" + + ">>> PC = 0x10002\n" + + ">>> SR = 0x0\n", + outContent.toString()); + } + + @Test + public void testMipsEl() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_MIPS)); + samples.Sample_mips.test_mips_el(); + assertEquals( + "Emulate MIPS code (little-endian)\n" + + ">>> Tracing basic block at 0x10000, block size = 0x4\n" + + ">>> Tracing instruction at 0x10000, instruction size = 0x4\n" + + ">>> Emulation done. Below is the CPU context\n" + + ">>> R1 = 0x77df\n", + outContent.toString()); + } + + @Test + public void testMipsEb() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_MIPS)); + samples.Sample_mips.test_mips_eb(); + assertEquals( + "Emulate MIPS code (big-endian)\n" + + ">>> Tracing basic block at 0x10000, block size = 0x4\n" + + ">>> Tracing instruction at 0x10000, instruction size = 0x4\n" + + ">>> Emulation done. Below is the CPU context\n" + + ">>> R1 = 0x77df\n", + outContent.toString()); + } + + @Test + public void testMmuCpuTlb() { + samples.Sample_mmu.cpu_tlb(); + assertEquals( + "Emulate x86 amd64 code with mmu enabled and switch mappings\n" + + "map code\n" + + "map parent memory\n" + + "map child memory\n" + + "map tlb memory\n" + + "set up the tlb\n" + + "run the parent\n" + + "save the context for the child\n" + + "finish the parent\n" + + "write at 0x1000: 0x3c\n" + + "restore the context for the child\n" + + "write at 0x2000: 0x2a\n" + + "parent result == 60\n" + + "child result == 42\n", + outContent.toString()); + } + + @Test + public void testMmuVirtualTlb() { + samples.Sample_mmu.virtual_tlb(); + assertEquals( + "Emulate x86 amd64 code with virtual mmu\n" + + "map code\n" + + "map parent memory\n" + + "map child memory\n" + + "run the parent\n" + + "tlb lookup for address: 0x2000\n" + + "save the context for the child\n" + + "finish the parent\n" + + "tlb lookup for address: 0x4000\n" + + "write at 0x1000: 0x3c\n" + + "restore the context for the child\n" + + "tlb lookup for address: 0x2000\n" + + "tlb lookup for address: 0x4000\n" + + "write at 0x2000: 0x2a\n" + + "parent result == 60\n" + + "child result == 42\n", + outContent.toString()); + } + + @Test + public void testPpc() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_PPC)); + samples.Sample_ppc.test_ppc(); + assertEquals( + "Emulate PPC code\n" + + ">>> Tracing basic block at 0x10000, block size = 0x4\n" + + ">>> Tracing instruction at 0x10000, instruction size = 0x4\n" + + ">>> Emulation done. Below is the CPU context\n" + + ">>> r26 = 0x79bd\n", + outContent.toString()); + } + + @Test + public void testRiscvRecoverFromIllegal() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_RISCV)); + samples.Sample_riscv.test_recover_from_illegal(); + assertEquals( + "Emulate RISCV code: recover_from_illegal\n" + + ">>> Allocating block at 0x1000 (0x1000), block size = 0x2 (0x1000)\n" + + ">>> Tracing basic block at 0x1000, block size = 0x0\n" + + "Expected Illegal Instruction error, got: " + + "unicorn.UnicornException: Unhandled CPU exception (UC_ERR_EXCEPTION)\n" + + ">>> Tracing basic block at 0x10000, block size = 0x8\n" + + ">>> Tracing instruction at 0x10000, instruction size = 0x4\n" + + ">>> Emulation done. Below is the CPU context\n" + + ">>> A0 = 0x1\n" + + ">>> A1 = 0x7890\n", + outContent.toString()); + } + + @Test + public void testRiscv1() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_RISCV)); + samples.Sample_riscv.test_riscv(); + assertEquals( + "Emulate RISCV code\n" + + ">>> Tracing basic block at 0x10000, block size = 0x8\n" + + ">>> Tracing instruction at 0x10000, instruction size = 0x4\n" + + ">>> Tracing instruction at 0x10004, instruction size = 0x4\n" + + ">>> Emulation done. Below is the CPU context\n" + + ">>> A0 = 0x1\n" + + ">>> A1 = 0x78b0\n", + outContent.toString()); + } + + @Test + public void testRiscv2() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_RISCV)); + samples.Sample_riscv.test_riscv2(); + assertEquals( + "Emulate RISCV code: split emulation\n" + + ">>> Tracing basic block at 0x10000, block size = 0x4\n" + + ">>> Tracing instruction at 0x10000, instruction size = 0x4\n" + + ">>> A0 = 0x1\n" + + ">>> A1 = 0x7890\n" + + ">>> Tracing basic block at 0x10004, block size = 0x4\n" + + ">>> Tracing instruction at 0x10004, instruction size = 0x4\n" + + ">>> Emulation done. Below is the CPU context\n" + + ">>> A0 = 0x1\n" + + ">>> A1 = 0x78b0\n", + outContent.toString()); + } + + @Test + public void testRiscv3() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_RISCV)); + samples.Sample_riscv.test_riscv3(); + assertEquals( + "Emulate RISCV code: early stop\n" + + ">>> Tracing basic block at 0x10000, block size = 0x8\n" + + ">>> Tracing instruction at 0x10000, instruction size = 0x4\n" + + "stop emulation\n" + + ">>> Emulation done. Below is the CPU context\n" + + ">>> A0 = 0x1234\n" + + ">>> A1 = 0x7890\n", + outContent.toString()); + } + + @Test + public void testRiscvStep() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_RISCV)); + samples.Sample_riscv.test_riscv_step(); + assertEquals( + "Emulate RISCV code: step\n" + + ">>> Tracing basic block at 0x10000, block size = 0x8\n" + + ">>> Tracing instruction at 0x10000, instruction size = 0x4\n" + + ">>> A0 = 0x1\n" + + ">>> A1 = 0x7890\n" + + ">>> Tracing basic block at 0x10004, block size = 0x4\n" + + ">>> Tracing instruction at 0x10004, instruction size = 0x4\n" + + ">>> Emulation done. Below is the CPU context\n" + + ">>> A0 = 0x1\n" + + ">>> A1 = 0x78b0\n", + outContent.toString()); + } + + @Ignore("timeout test is currently broken") + @Test + public void testRiscvTimeout() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_RISCV)); + samples.Sample_riscv.test_riscv_timeout(); + assertEquals( + "Emulate RISCV code: timeout\n" + + ">>> Tracing basic block at 0x10000, block size = 0x0\n" + + "Failed on uc_emu_start() with error returned: 21\n" + + "Error after step: PC is: 0x10004, expected was 0x10004\n" + + ">>> Tracing basic block at 0x10000, block size = 0x0\n" + + "Failed on uc_emu_start() with error returned: 21\n" + + "Error after step: PC is: 0x10004, expected was 0x10004\n" + + ">>> Emulation done\n", + outContent.toString()); + } + + @Test + public void testRiscvSd64() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_RISCV)); + samples.Sample_riscv.test_riscv_sd64(); + assertEquals( + "Emulate RISCV code: sd64 instruction\n" + + ">>> Tracing basic block at 0x10000, block size = 0x8\n" + + ">>> Tracing instruction at 0x10000, instruction size = 0x4\n" + + ">>> Emulation done.\n", + outContent.toString()); + } + + @Test + public void testRiscvFuncReturn() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_RISCV)); + samples.Sample_riscv.test_riscv_func_return(); + assertEquals( + "Emulate RISCV code: return from func\n" + + ">>> Tracing basic block at 0x10000, block size = 0x4\n" + + ">>> Tracing instruction at 0x10000, instruction size = 0x4\n" + + ">>> Tracing basic block at 0x10006, block size = 0x4\n" + + "Good, PC == RA\n" + + "========\n" + + ">>> Tracing basic block at 0x10004, block size = 0x2\n" + + ">>> Tracing instruction at 0x10004, instruction size = 0x2\n" + + ">>> Tracing basic block at 0x10006, block size = 0x4\n" + + "Good, PC == RA\n" + + ">>> Emulation done.\n", + outContent.toString()); + } + + @Test + public void testS390x() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_S390X)); + samples.Sample_s390x.test_s390x(); + assertEquals( + "Emulate S390X code\n" + + ">>> Tracing basic block at 0x10000, block size = 0x2\n" + + ">>> Tracing instruction at 0x10000, instruction size = 0x2\n" + + ">>> Emulation done. Below is the CPU context\n" + + ">>> R2 = 0x3 >>> R3 = 0x3\n", + outContent.toString()); + } + + @Test + public void testShellcode() { + samples.Shellcode.test_i386(); + assertEquals( + "Emulate i386 code\n" + + "\n" + + ">>> Start tracing this Linux code\n" + + "Tracing instruction at 0x1000000, instruction size = 0x2\n" + + "*** EIP = 1000000 ***: eb 1c \n" + + "Tracing instruction at 0x100001e, instruction size = 0x5\n" + + "*** EIP = 100001e ***: e8 df ff ff ff \n" + + "Tracing instruction at 0x1000002, instruction size = 0x1\n" + + "*** EIP = 1000002 ***: 5a \n" + + "Tracing instruction at 0x1000003, instruction size = 0x2\n" + + "*** EIP = 1000003 ***: 89 d6 \n" + + "Tracing instruction at 0x1000005, instruction size = 0x2\n" + + "*** EIP = 1000005 ***: 8b 2 \n" + + "Tracing instruction at 0x1000007, instruction size = 0x4\n" + + "*** EIP = 1000007 ***: 66 3d ca 7d \n" + + "Tracing instruction at 0x100000b, instruction size = 0x2\n" + + "*** EIP = 100000b ***: 75 6 \n" + + "Tracing instruction at 0x1000013, instruction size = 0x2\n" + + "*** EIP = 1000013 ***: fe c2 \n" + + "Tracing instruction at 0x1000015, instruction size = 0x5\n" + + "*** EIP = 1000015 ***: 3d 41 41 41 41 \n" + + "Tracing instruction at 0x100001a, instruction size = 0x2\n" + + "*** EIP = 100001a ***: 75 e9 \n" + + "Tracing instruction at 0x1000005, instruction size = 0x2\n" + + "*** EIP = 1000005 ***: 8b 2 \n" + + "Tracing instruction at 0x1000007, instruction size = 0x4\n" + + "*** EIP = 1000007 ***: 66 3d ca 7d \n" + + "Tracing instruction at 0x100000b, instruction size = 0x2\n" + + "*** EIP = 100000b ***: 75 6 \n" + + "Tracing instruction at 0x1000013, instruction size = 0x2\n" + + "*** EIP = 1000013 ***: fe c2 \n" + + "Tracing instruction at 0x1000015, instruction size = 0x5\n" + + "*** EIP = 1000015 ***: 3d 41 41 41 41 \n" + + "Tracing instruction at 0x100001a, instruction size = 0x2\n" + + "*** EIP = 100001a ***: 75 e9 \n" + + "Tracing instruction at 0x1000005, instruction size = 0x2\n" + + "*** EIP = 1000005 ***: 8b 2 \n" + + "Tracing instruction at 0x1000007, instruction size = 0x4\n" + + "*** EIP = 1000007 ***: 66 3d ca 7d \n" + + "Tracing instruction at 0x100000b, instruction size = 0x2\n" + + "*** EIP = 100000b ***: 75 6 \n" + + "Tracing instruction at 0x1000013, instruction size = 0x2\n" + + "*** EIP = 1000013 ***: fe c2 \n" + + "Tracing instruction at 0x1000015, instruction size = 0x5\n" + + "*** EIP = 1000015 ***: 3d 41 41 41 41 \n" + + "Tracing instruction at 0x100001a, instruction size = 0x2\n" + + "*** EIP = 100001a ***: 75 e9 \n" + + "Tracing instruction at 0x1000005, instruction size = 0x2\n" + + "*** EIP = 1000005 ***: 8b 2 \n" + + "Tracing instruction at 0x1000007, instruction size = 0x4\n" + + "*** EIP = 1000007 ***: 66 3d ca 7d \n" + + "Tracing instruction at 0x100000b, instruction size = 0x2\n" + + "*** EIP = 100000b ***: 75 6 \n" + + "Tracing instruction at 0x1000013, instruction size = 0x2\n" + + "*** EIP = 1000013 ***: fe c2 \n" + + "Tracing instruction at 0x1000015, instruction size = 0x5\n" + + "*** EIP = 1000015 ***: 3d 41 41 41 41 \n" + + "Tracing instruction at 0x100001a, instruction size = 0x2\n" + + "*** EIP = 100001a ***: 75 e9 \n" + + "Tracing instruction at 0x1000005, instruction size = 0x2\n" + + "*** EIP = 1000005 ***: 8b 2 \n" + + "Tracing instruction at 0x1000007, instruction size = 0x4\n" + + "*** EIP = 1000007 ***: 66 3d ca 7d \n" + + "Tracing instruction at 0x100000b, instruction size = 0x2\n" + + "*** EIP = 100000b ***: 75 6 \n" + + "Tracing instruction at 0x1000013, instruction size = 0x2\n" + + "*** EIP = 1000013 ***: fe c2 \n" + + "Tracing instruction at 0x1000015, instruction size = 0x5\n" + + "*** EIP = 1000015 ***: 3d 41 41 41 41 \n" + + "Tracing instruction at 0x100001a, instruction size = 0x2\n" + + "*** EIP = 100001a ***: 75 e9 \n" + + "Tracing instruction at 0x1000005, instruction size = 0x2\n" + + "*** EIP = 1000005 ***: 8b 2 \n" + + "Tracing instruction at 0x1000007, instruction size = 0x4\n" + + "*** EIP = 1000007 ***: 66 3d ca 7d \n" + + "Tracing instruction at 0x100000b, instruction size = 0x2\n" + + "*** EIP = 100000b ***: 75 6 \n" + + "Tracing instruction at 0x1000013, instruction size = 0x2\n" + + "*** EIP = 1000013 ***: fe c2 \n" + + "Tracing instruction at 0x1000015, instruction size = 0x5\n" + + "*** EIP = 1000015 ***: 3d 41 41 41 41 \n" + + "Tracing instruction at 0x100001a, instruction size = 0x2\n" + + "*** EIP = 100001a ***: 75 e9 \n" + + "Tracing instruction at 0x1000005, instruction size = 0x2\n" + + "*** EIP = 1000005 ***: 8b 2 \n" + + "Tracing instruction at 0x1000007, instruction size = 0x4\n" + + "*** EIP = 1000007 ***: 66 3d ca 7d \n" + + "Tracing instruction at 0x100000b, instruction size = 0x2\n" + + "*** EIP = 100000b ***: 75 6 \n" + + "Tracing instruction at 0x1000013, instruction size = 0x2\n" + + "*** EIP = 1000013 ***: fe c2 \n" + + "Tracing instruction at 0x1000015, instruction size = 0x5\n" + + "*** EIP = 1000015 ***: 3d 41 41 41 41 \n" + + "Tracing instruction at 0x100001a, instruction size = 0x2\n" + + "*** EIP = 100001a ***: 75 e9 \n" + + "Tracing instruction at 0x1000005, instruction size = 0x2\n" + + "*** EIP = 1000005 ***: 8b 2 \n" + + "Tracing instruction at 0x1000007, instruction size = 0x4\n" + + "*** EIP = 1000007 ***: 66 3d ca 7d \n" + + "Tracing instruction at 0x100000b, instruction size = 0x2\n" + + "*** EIP = 100000b ***: 75 6 \n" + + "Tracing instruction at 0x1000013, instruction size = 0x2\n" + + "*** EIP = 1000013 ***: fe c2 \n" + + "Tracing instruction at 0x1000015, instruction size = 0x5\n" + + "*** EIP = 1000015 ***: 3d 41 41 41 41 \n" + + "Tracing instruction at 0x100001a, instruction size = 0x2\n" + + "*** EIP = 100001a ***: 75 e9 \n" + + "Tracing instruction at 0x1000005, instruction size = 0x2\n" + + "*** EIP = 1000005 ***: 8b 2 \n" + + "Tracing instruction at 0x1000007, instruction size = 0x4\n" + + "*** EIP = 1000007 ***: 66 3d ca 7d \n" + + "Tracing instruction at 0x100000b, instruction size = 0x2\n" + + "*** EIP = 100000b ***: 75 6 \n" + + "Tracing instruction at 0x1000013, instruction size = 0x2\n" + + "*** EIP = 1000013 ***: fe c2 \n" + + "Tracing instruction at 0x1000015, instruction size = 0x5\n" + + "*** EIP = 1000015 ***: 3d 41 41 41 41 \n" + + "Tracing instruction at 0x100001a, instruction size = 0x2\n" + + "*** EIP = 100001a ***: 75 e9 \n" + + "Tracing instruction at 0x1000005, instruction size = 0x2\n" + + "*** EIP = 1000005 ***: 8b 2 \n" + + "Tracing instruction at 0x1000007, instruction size = 0x4\n" + + "*** EIP = 1000007 ***: 66 3d ca 7d \n" + + "Tracing instruction at 0x100000b, instruction size = 0x2\n" + + "*** EIP = 100000b ***: 75 6 \n" + + "Tracing instruction at 0x1000013, instruction size = 0x2\n" + + "*** EIP = 1000013 ***: fe c2 \n" + + "Tracing instruction at 0x1000015, instruction size = 0x5\n" + + "*** EIP = 1000015 ***: 3d 41 41 41 41 \n" + + "Tracing instruction at 0x100001a, instruction size = 0x2\n" + + "*** EIP = 100001a ***: 75 e9 \n" + + "Tracing instruction at 0x1000005, instruction size = 0x2\n" + + "*** EIP = 1000005 ***: 8b 2 \n" + + "Tracing instruction at 0x1000007, instruction size = 0x4\n" + + "*** EIP = 1000007 ***: 66 3d ca 7d \n" + + "Tracing instruction at 0x100000b, instruction size = 0x2\n" + + "*** EIP = 100000b ***: 75 6 \n" + + "Tracing instruction at 0x1000013, instruction size = 0x2\n" + + "*** EIP = 1000013 ***: fe c2 \n" + + "Tracing instruction at 0x1000015, instruction size = 0x5\n" + + "*** EIP = 1000015 ***: 3d 41 41 41 41 \n" + + "Tracing instruction at 0x100001a, instruction size = 0x2\n" + + "*** EIP = 100001a ***: 75 e9 \n" + + "Tracing instruction at 0x1000005, instruction size = 0x2\n" + + "*** EIP = 1000005 ***: 8b 2 \n" + + "Tracing instruction at 0x1000007, instruction size = 0x4\n" + + "*** EIP = 1000007 ***: 66 3d ca 7d \n" + + "Tracing instruction at 0x100000b, instruction size = 0x2\n" + + "*** EIP = 100000b ***: 75 6 \n" + + "Tracing instruction at 0x1000013, instruction size = 0x2\n" + + "*** EIP = 1000013 ***: fe c2 \n" + + "Tracing instruction at 0x1000015, instruction size = 0x5\n" + + "*** EIP = 1000015 ***: 3d 41 41 41 41 \n" + + "Tracing instruction at 0x100001a, instruction size = 0x2\n" + + "*** EIP = 100001a ***: 75 e9 \n" + + "Tracing instruction at 0x1000005, instruction size = 0x2\n" + + "*** EIP = 1000005 ***: 8b 2 \n" + + "Tracing instruction at 0x1000007, instruction size = 0x4\n" + + "*** EIP = 1000007 ***: 66 3d ca 7d \n" + + "Tracing instruction at 0x100000b, instruction size = 0x2\n" + + "*** EIP = 100000b ***: 75 6 \n" + + "Tracing instruction at 0x1000013, instruction size = 0x2\n" + + "*** EIP = 1000013 ***: fe c2 \n" + + "Tracing instruction at 0x1000015, instruction size = 0x5\n" + + "*** EIP = 1000015 ***: 3d 41 41 41 41 \n" + + "Tracing instruction at 0x100001a, instruction size = 0x2\n" + + "*** EIP = 100001a ***: 75 e9 \n" + + "Tracing instruction at 0x1000005, instruction size = 0x2\n" + + "*** EIP = 1000005 ***: 8b 2 \n" + + "Tracing instruction at 0x1000007, instruction size = 0x4\n" + + "*** EIP = 1000007 ***: 66 3d ca 7d \n" + + "Tracing instruction at 0x100000b, instruction size = 0x2\n" + + "*** EIP = 100000b ***: 75 6 \n" + + "Tracing instruction at 0x1000013, instruction size = 0x2\n" + + "*** EIP = 1000013 ***: fe c2 \n" + + "Tracing instruction at 0x1000015, instruction size = 0x5\n" + + "*** EIP = 1000015 ***: 3d 41 41 41 41 \n" + + "Tracing instruction at 0x100001a, instruction size = 0x2\n" + + "*** EIP = 100001a ***: 75 e9 \n" + + "Tracing instruction at 0x1000005, instruction size = 0x2\n" + + "*** EIP = 1000005 ***: 8b 2 \n" + + "Tracing instruction at 0x1000007, instruction size = 0x4\n" + + "*** EIP = 1000007 ***: 66 3d ca 7d \n" + + "Tracing instruction at 0x100000b, instruction size = 0x2\n" + + "*** EIP = 100000b ***: 75 6 \n" + + "Tracing instruction at 0x1000013, instruction size = 0x2\n" + + "*** EIP = 1000013 ***: fe c2 \n" + + "Tracing instruction at 0x1000015, instruction size = 0x5\n" + + "*** EIP = 1000015 ***: 3d 41 41 41 41 \n" + + "Tracing instruction at 0x100001a, instruction size = 0x2\n" + + "*** EIP = 100001a ***: 75 e9 \n" + + "Tracing instruction at 0x1000005, instruction size = 0x2\n" + + "*** EIP = 1000005 ***: 8b 2 \n" + + "Tracing instruction at 0x1000007, instruction size = 0x4\n" + + "*** EIP = 1000007 ***: 66 3d ca 7d \n" + + "Tracing instruction at 0x100000b, instruction size = 0x2\n" + + "*** EIP = 100000b ***: 75 6 \n" + + "Tracing instruction at 0x1000013, instruction size = 0x2\n" + + "*** EIP = 1000013 ***: fe c2 \n" + + "Tracing instruction at 0x1000015, instruction size = 0x5\n" + + "*** EIP = 1000015 ***: 3d 41 41 41 41 \n" + + "Tracing instruction at 0x100001a, instruction size = 0x2\n" + + "*** EIP = 100001a ***: 75 e9 \n" + + "Tracing instruction at 0x1000005, instruction size = 0x2\n" + + "*** EIP = 1000005 ***: 8b 2 \n" + + "Tracing instruction at 0x1000007, instruction size = 0x4\n" + + "*** EIP = 1000007 ***: 66 3d ca 7d \n" + + "Tracing instruction at 0x100000b, instruction size = 0x2\n" + + "*** EIP = 100000b ***: 75 6 \n" + + "Tracing instruction at 0x1000013, instruction size = 0x2\n" + + "*** EIP = 1000013 ***: fe c2 \n" + + "Tracing instruction at 0x1000015, instruction size = 0x5\n" + + "*** EIP = 1000015 ***: 3d 41 41 41 41 \n" + + "Tracing instruction at 0x100001a, instruction size = 0x2\n" + + "*** EIP = 100001a ***: 75 e9 \n" + + "Tracing instruction at 0x1000005, instruction size = 0x2\n" + + "*** EIP = 1000005 ***: 8b 2 \n" + + "Tracing instruction at 0x1000007, instruction size = 0x4\n" + + "*** EIP = 1000007 ***: 66 3d ca 7d \n" + + "Tracing instruction at 0x100000b, instruction size = 0x2\n" + + "*** EIP = 100000b ***: 75 6 \n" + + "Tracing instruction at 0x1000013, instruction size = 0x2\n" + + "*** EIP = 1000013 ***: fe c2 \n" + + "Tracing instruction at 0x1000015, instruction size = 0x5\n" + + "*** EIP = 1000015 ***: 3d 41 41 41 41 \n" + + "Tracing instruction at 0x100001a, instruction size = 0x2\n" + + "*** EIP = 100001a ***: 75 e9 \n" + + "Tracing instruction at 0x1000005, instruction size = 0x2\n" + + "*** EIP = 1000005 ***: 8b 2 \n" + + "Tracing instruction at 0x1000007, instruction size = 0x4\n" + + "*** EIP = 1000007 ***: 66 3d ca 7d \n" + + "Tracing instruction at 0x100000b, instruction size = 0x2\n" + + "*** EIP = 100000b ***: 75 6 \n" + + "Tracing instruction at 0x1000013, instruction size = 0x2\n" + + "*** EIP = 1000013 ***: fe c2 \n" + + "Tracing instruction at 0x1000015, instruction size = 0x5\n" + + "*** EIP = 1000015 ***: 3d 41 41 41 41 \n" + + "Tracing instruction at 0x100001a, instruction size = 0x2\n" + + "*** EIP = 100001a ***: 75 e9 \n" + + "Tracing instruction at 0x1000005, instruction size = 0x2\n" + + "*** EIP = 1000005 ***: 8b 2 \n" + + "Tracing instruction at 0x1000007, instruction size = 0x4\n" + + "*** EIP = 1000007 ***: 66 3d ca 7d \n" + + "Tracing instruction at 0x100000b, instruction size = 0x2\n" + + "*** EIP = 100000b ***: 75 6 \n" + + "Tracing instruction at 0x1000013, instruction size = 0x2\n" + + "*** EIP = 1000013 ***: fe c2 \n" + + "Tracing instruction at 0x1000015, instruction size = 0x5\n" + + "*** EIP = 1000015 ***: 3d 41 41 41 41 \n" + + "Tracing instruction at 0x100001a, instruction size = 0x2\n" + + "*** EIP = 100001a ***: 75 e9 \n" + + "Tracing instruction at 0x1000005, instruction size = 0x2\n" + + "*** EIP = 1000005 ***: 8b 2 \n" + + "Tracing instruction at 0x1000007, instruction size = 0x4\n" + + "*** EIP = 1000007 ***: 66 3d ca 7d \n" + + "Tracing instruction at 0x100000b, instruction size = 0x2\n" + + "*** EIP = 100000b ***: 75 6 \n" + + "Tracing instruction at 0x1000013, instruction size = 0x2\n" + + "*** EIP = 1000013 ***: fe c2 \n" + + "Tracing instruction at 0x1000015, instruction size = 0x5\n" + + "*** EIP = 1000015 ***: 3d 41 41 41 41 \n" + + "Tracing instruction at 0x100001a, instruction size = 0x2\n" + + "*** EIP = 100001a ***: 75 e9 \n" + + "Tracing instruction at 0x1000005, instruction size = 0x2\n" + + "*** EIP = 1000005 ***: 8b 2 \n" + + "Tracing instruction at 0x1000007, instruction size = 0x4\n" + + "*** EIP = 1000007 ***: 66 3d ca 7d \n" + + "Tracing instruction at 0x100000b, instruction size = 0x2\n" + + "*** EIP = 100000b ***: 75 6 \n" + + "Tracing instruction at 0x1000013, instruction size = 0x2\n" + + "*** EIP = 1000013 ***: fe c2 \n" + + "Tracing instruction at 0x1000015, instruction size = 0x5\n" + + "*** EIP = 1000015 ***: 3d 41 41 41 41 \n" + + "Tracing instruction at 0x100001a, instruction size = 0x2\n" + + "*** EIP = 100001a ***: 75 e9 \n" + + "Tracing instruction at 0x1000005, instruction size = 0x2\n" + + "*** EIP = 1000005 ***: 8b 2 \n" + + "Tracing instruction at 0x1000007, instruction size = 0x4\n" + + "*** EIP = 1000007 ***: 66 3d ca 7d \n" + + "Tracing instruction at 0x100000b, instruction size = 0x2\n" + + "*** EIP = 100000b ***: 75 6 \n" + + "Tracing instruction at 0x1000013, instruction size = 0x2\n" + + "*** EIP = 1000013 ***: fe c2 \n" + + "Tracing instruction at 0x1000015, instruction size = 0x5\n" + + "*** EIP = 1000015 ***: 3d 41 41 41 41 \n" + + "Tracing instruction at 0x100001a, instruction size = 0x2\n" + + "*** EIP = 100001a ***: 75 e9 \n" + + "Tracing instruction at 0x1000005, instruction size = 0x2\n" + + "*** EIP = 1000005 ***: 8b 2 \n" + + "Tracing instruction at 0x1000007, instruction size = 0x4\n" + + "*** EIP = 1000007 ***: 66 3d ca 7d \n" + + "Tracing instruction at 0x100000b, instruction size = 0x2\n" + + "*** EIP = 100000b ***: 75 6 \n" + + "Tracing instruction at 0x100000d, instruction size = 0x4\n" + + "*** EIP = 100000d ***: 66 5 3 3 \n" + + "Tracing instruction at 0x1000011, instruction size = 0x2\n" + + "*** EIP = 1000011 ***: 89 2 \n" + + "Tracing instruction at 0x1000013, instruction size = 0x2\n" + + "*** EIP = 1000013 ***: fe c2 \n" + + "Tracing instruction at 0x1000015, instruction size = 0x5\n" + + "*** EIP = 1000015 ***: 3d 41 41 41 41 \n" + + "Tracing instruction at 0x100001a, instruction size = 0x2\n" + + "*** EIP = 100001a ***: 75 e9 \n" + + "Tracing instruction at 0x1000005, instruction size = 0x2\n" + + "*** EIP = 1000005 ***: 8b 2 \n" + + "Tracing instruction at 0x1000007, instruction size = 0x4\n" + + "*** EIP = 1000007 ***: 66 3d ca 7d \n" + + "Tracing instruction at 0x100000b, instruction size = 0x2\n" + + "*** EIP = 100000b ***: 75 6 \n" + + "Tracing instruction at 0x1000013, instruction size = 0x2\n" + + "*** EIP = 1000013 ***: fe c2 \n" + + "Tracing instruction at 0x1000015, instruction size = 0x5\n" + + "*** EIP = 1000015 ***: 3d 41 41 41 41 \n" + + "Tracing instruction at 0x100001a, instruction size = 0x2\n" + + "*** EIP = 100001a ***: 75 e9 \n" + + "Tracing instruction at 0x1000005, instruction size = 0x2\n" + + "*** EIP = 1000005 ***: 8b 2 \n" + + "Tracing instruction at 0x1000007, instruction size = 0x4\n" + + "*** EIP = 1000007 ***: 66 3d ca 7d \n" + + "Tracing instruction at 0x100000b, instruction size = 0x2\n" + + "*** EIP = 100000b ***: 75 6 \n" + + "Tracing instruction at 0x1000013, instruction size = 0x2\n" + + "*** EIP = 1000013 ***: fe c2 \n" + + "Tracing instruction at 0x1000015, instruction size = 0x5\n" + + "*** EIP = 1000015 ***: 3d 41 41 41 41 \n" + + "Tracing instruction at 0x100001a, instruction size = 0x2\n" + + "*** EIP = 100001a ***: 75 e9 \n" + + "Tracing instruction at 0x100001c, instruction size = 0x2\n" + + "*** EIP = 100001c ***: ff e6 \n" + + "Tracing instruction at 0x1000023, instruction size = 0x2\n" + + "*** EIP = 1000023 ***: 31 d2 \n" + + "Tracing instruction at 0x1000025, instruction size = 0x2\n" + + "*** EIP = 1000025 ***: 6a b \n" + + "Tracing instruction at 0x1000027, instruction size = 0x1\n" + + "*** EIP = 1000027 ***: 58 \n" + + "Tracing instruction at 0x1000028, instruction size = 0x1\n" + + "*** EIP = 1000028 ***: 99 \n" + + "Tracing instruction at 0x1000029, instruction size = 0x1\n" + + "*** EIP = 1000029 ***: 52 \n" + + "Tracing instruction at 0x100002a, instruction size = 0x5\n" + + "*** EIP = 100002a ***: 68 2f 2f 73 68 \n" + + "Tracing instruction at 0x100002f, instruction size = 0x5\n" + + "*** EIP = 100002f ***: 68 2f 62 69 6e \n" + + "Tracing instruction at 0x1000034, instruction size = 0x2\n" + + "*** EIP = 1000034 ***: 89 e3 \n" + + "Tracing instruction at 0x1000036, instruction size = 0x1\n" + + "*** EIP = 1000036 ***: 52 \n" + + "Tracing instruction at 0x1000037, instruction size = 0x1\n" + + "*** EIP = 1000037 ***: 53 \n" + + "Tracing instruction at 0x1000038, instruction size = 0x2\n" + + "*** EIP = 1000038 ***: 89 e1 \n" + + "Tracing instruction at 0x100003a, instruction size = 0x2\n" + + "*** EIP = 100003a ***: cd 80 \n" + + ">>> 0x100003c: interrupt 0x80, EAX = 0xb\n" + + "Tracing instruction at 0x100003c, instruction size = 0x1\n" + + "*** EIP = 100003c ***: 41 \n" + + "Tracing instruction at 0x100003d, instruction size = 0x1\n" + + "*** EIP = 100003d ***: 41 \n" + + "Tracing instruction at 0x100003e, instruction size = 0x1\n" + + "*** EIP = 100003e ***: 41 \n" + + "Tracing instruction at 0x100003f, instruction size = 0x1\n" + + "*** EIP = 100003f ***: 41 \n" + + "Tracing instruction at 0x1000040, instruction size = 0x1\n" + + "*** EIP = 1000040 ***: 41 \n" + + "Tracing instruction at 0x1000041, instruction size = 0x1\n" + + "*** EIP = 1000041 ***: 41 \n" + + "Tracing instruction at 0x1000042, instruction size = 0x1\n" + + "*** EIP = 1000042 ***: 41 \n" + + "Tracing instruction at 0x1000043, instruction size = 0x1\n" + + "*** EIP = 1000043 ***: 41 \n" + + "\n" + + ">>> Emulation done.\n", + outContent.toString()); + } + + @Test + public void testSparc() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_SPARC)); + samples.Sample_sparc.test_sparc(); + assertEquals( + "Emulate SPARC code\n" + + ">>> Tracing basic block at 0x10000, block size = 0x4\n" + + ">>> Tracing instruction at 0x10000, instruction size = 0x4\n" + + ">>> Emulation done. Below is the CPU context\n" + + ">>> G3 = 0x79b9\n", + outContent.toString()); + } + + @Test + public void testTricore() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_TRICORE)); + samples.Sample_tricore.test_tricore(); + assertEquals( + "Emulate TriCore code\n" + + ">>> Tracing basic block at 0x10000, block size = 0x6\n" + + ">>> Tracing instruction at 0x10000, instruction size = 0x2\n" + + ">>> Tracing instruction at 0x10002, instruction size = 0x4\n" + + ">>> Emulation done. Below is the CPU context\n" + + ">>> d0 = 0x8000\n" + + ">>> d1 = 0x1\n", + outContent.toString()); + } + + @Test + public void testX86_16() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_X86)); + samples.Sample_x86.test_x86_16(); + assertEquals( + "Emulate x86 16-bit code\n" + + ">>> Emulation done. Below is the CPU context\n" + + ">>> Read 1 bytes from [0xb] = 0x7\n", + outContent.toString()); + } + + @Test + public void testX86MissCode() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_X86)); + samples.Sample_x86.test_miss_code(); + assertEquals( + "Emulate i386 code - missing code\n" + + ">>> Allocating block at 0x1000000 (0x1000000), block size = 0x1 (0x1000)\n" + + ">>> Tracing instruction at 0x1000000, instruction size = 0x1\n" + + ">>> --- EFLAGS is 0x2\n" + + ">>> Tracing instruction at 0x1000001, instruction size = 0x1\n" + + ">>> --- EFLAGS is 0x6\n" + + ">>> Tracing instruction at 0x1000002, instruction size = 0x4\n" + + ">>> --- EFLAGS is 0x12\n" + + ">>> Emulation done. Below is the CPU context\n" + + ">>> ECX = 0x1235\n" + + ">>> EDX = 0x788f\n", + outContent.toString()); + } + + @Test + public void testX86() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_X86)); + samples.Sample_x86.test_i386(); + assertEquals( + "Emulate i386 code\n" + + ">>> Tracing basic block at 0x1000000, block size = 0x6\n" + + ">>> Tracing instruction at 0x1000000, instruction size = 0x1\n" + + ">>> --- EFLAGS is 0x2\n" + + ">>> Tracing instruction at 0x1000001, instruction size = 0x1\n" + + ">>> --- EFLAGS is 0x6\n" + + ">>> Tracing instruction at 0x1000002, instruction size = 0x4\n" + + ">>> --- EFLAGS is 0x12\n" + + ">>> Emulation done. Below is the CPU context\n" + + ">>> ECX = 0x1235\n" + + ">>> EDX = 0x788f\n" + + ">>> XMM0 = 0x00112233445566778899aabbccddeeff\n" + + ">>> Read 4 bytes from [0x1000000] = 0xf664a41\n", + outContent.toString()); + } + + @Test + public void testX86MapPtr() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_X86)); + samples.Sample_x86.test_i386_map_ptr(); + assertEquals( + "Emulate i386 code - use uc_mem_map_ptr()\n" + + ">>> Tracing basic block at 0x1000000, block size = 0x6\n" + + ">>> Tracing instruction at 0x1000000, instruction size = 0x1\n" + + ">>> --- EFLAGS is 0x2\n" + + ">>> Tracing instruction at 0x1000001, instruction size = 0x1\n" + + ">>> --- EFLAGS is 0x6\n" + + ">>> Tracing instruction at 0x1000002, instruction size = 0x4\n" + + ">>> --- EFLAGS is 0x12\n" + + ">>> Emulation done. Below is the CPU context\n" + + ">>> ECX = 0x1235\n" + + ">>> EDX = 0x788f\n" + + ">>> Read 4 bytes from [0x1000000] = 0xf664a41\n", + outContent.toString()); + } + + @Test + public void testX86InOut() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_X86)); + samples.Sample_x86.test_i386_inout(); + assertEquals( + "Emulate i386 code with IN/OUT instructions\n" + + ">>> Tracing basic block at 0x1000000, block size = 0x7\n" + + ">>> Tracing instruction at 0x1000000, instruction size = 0x1\n" + + ">>> --- EFLAGS is 0x2\n" + + ">>> Tracing instruction at 0x1000001, instruction size = 0x2\n" + + ">>> --- EFLAGS is 0x2\n" + + "--- reading from port 0x3f, size: 1, address: 0x1000001\n" + + ">>> Tracing instruction at 0x1000003, instruction size = 0x1\n" + + ">>> --- EFLAGS is 0x2\n" + + ">>> Tracing instruction at 0x1000004, instruction size = 0x2\n" + + ">>> --- EFLAGS is 0x96\n" + + "--- writing to port 0x46, size: 1, value: 0xf1, address: 0x1000004\n" + + "--- register value = 0xf1\n" + + ">>> Tracing instruction at 0x1000006, instruction size = 0x1\n" + + ">>> --- EFLAGS is 0x96\n" + + ">>> Emulation done. Below is the CPU context\n" + + ">>> EAX = 0x12f1\n" + + ">>> ECX = 0x678a\n", + outContent.toString()); + } + + @Test + public void testX86ContextSave() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_X86)); + samples.Sample_x86.test_i386_context_save(); + assertEquals( + "Save/restore CPU context in opaque blob\n" + + ">>> Running emulation for the first time\n" + + ">>> Emulation done. Below is the CPU context\n" + + ">>> EAX = 0x2\n" + + ">>> Saving CPU context\n" + + ">>> Running emulation for the second time\n" + + ">>> Emulation done. Below is the CPU context\n" + + ">>> EAX = 0x3\n" + + ">>> CPU context restored. Below is the CPU context\n" + + ">>> EAX = 0x2\n" + + ">>> CPU context restored with modification. Below is the CPU context\n" + + ">>> EAX = 0xc8\n", + outContent.toString()); + } + + @Test + public void testX86Jump() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_X86)); + samples.Sample_x86.test_i386_jump(); + assertEquals( + "Emulate i386 code with jump\n" + + ">>> Tracing basic block at 0x1000000, block size = 0x2\n" + + ">>> Tracing instruction at 0x1000000, instruction size = 0x2\n" + + ">>> --- EFLAGS is 0x2\n" + + ">>> Emulation done. Below is the CPU context\n", + outContent.toString()); + } + + @Test + public void testX86Loop() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_X86)); + samples.Sample_x86.test_i386_loop(); + assertEquals( + "Emulate i386 code that loop forever\n" + + ">>> Emulation done. Below is the CPU context\n" + + ">>> ECX = 0x1235\n" + + ">>> EDX = 0x788f\n", + outContent.toString()); + } + + @Test + public void testX86InvalidMemRead() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_X86)); + samples.Sample_x86.test_i386_invalid_mem_read(); + assertEquals( + "Emulate i386 code that read from invalid memory\n" + + ">>> Tracing basic block at 0x1000000, block size = 0x8\n" + + ">>> Tracing instruction at 0x1000000, instruction size = 0x6\n" + + ">>> --- EFLAGS is 0x2\n" + + "uc.emu_start failed as expected: " + + "unicorn.UnicornException: Invalid memory read (UC_ERR_READ_UNMAPPED)\n" + + ">>> Emulation done. Below is the CPU context\n" + + ">>> ECX = 0x1234\n" + + ">>> EDX = 0x7890\n", + outContent.toString()); + } + + @Test + public void testX86InvalidMemWrite() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_X86)); + samples.Sample_x86.test_i386_invalid_mem_write(); + assertEquals( + "Emulate i386 code that write to invalid memory\n" + + ">>> Tracing basic block at 0x1000000, block size = 0x8\n" + + ">>> Tracing instruction at 0x1000000, instruction size = 0x6\n" + + ">>> --- EFLAGS is 0x2\n" + + ">>> Missing memory is being WRITE at 0xaaaaaaaa, data size = 4, data value = 0x1234\n" + + ">>> Tracing instruction at 0x1000006, instruction size = 0x1\n" + + ">>> --- EFLAGS is 0x2\n" + + ">>> Tracing instruction at 0x1000007, instruction size = 0x1\n" + + ">>> --- EFLAGS is 0x6\n" + + ">>> Emulation done. Below is the CPU context\n" + + ">>> ECX = 0x1235\n" + + ">>> EDX = 0x788f\n" + + ">>> Read 4 bytes from [0xaaaaaaaa] = 0x1234\n" + + ">>> Failed to read 4 bytes from [0xffffffaa]\n", + outContent.toString()); + } + + @Test + public void testX86JumpInvalid() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_X86)); + samples.Sample_x86.test_i386_jump_invalid(); + assertEquals( + "Emulate i386 code that jumps to invalid memory\n" + + ">>> Tracing basic block at 0x1000000, block size = 0x5\n" + + ">>> Tracing instruction at 0x1000000, instruction size = 0x5\n" + + ">>> --- EFLAGS is 0x2\n" + + "uc.emu_start failed as expected: " + + "unicorn.UnicornException: Invalid memory fetch (UC_ERR_FETCH_UNMAPPED)\n" + + ">>> Emulation done. Below is the CPU context\n" + + ">>> ECX = 0x1234\n" + + ">>> EDX = 0x7890\n", + outContent.toString()); + } + + @Test + public void testX86_64() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_X86)); + samples.Sample_x86.test_x86_64(); + assertEquals( + "Emulate x86_64 code\n" + + ">>> Tracing basic block at 0x1000000, block size = 0x4b\n" + + ">>> Tracing instruction at 0x1000000, instruction size = 0x6\n" + + ">>> RIP is 0x1000000\n" + + ">>> Tracing instruction at 0x1000006, instruction size = 0x3\n" + + ">>> RIP is 0x1000006\n" + + ">>> Tracing instruction at 0x1000009, instruction size = 0x1\n" + + ">>> RIP is 0x1000009\n" + + ">>> Tracing instruction at 0x100000a, instruction size = 0x4\n" + + ">>> RIP is 0x100000a\n" + + ">>> Tracing instruction at 0x100000e, instruction size = 0x3\n" + + ">>> RIP is 0x100000e\n" + + ">>> Tracing instruction at 0x1000011, instruction size = 0x1\n" + + ">>> RIP is 0x1000011\n" + + ">>> Tracing instruction at 0x1000012, instruction size = 0x7\n" + + ">>> RIP is 0x1000012\n" + + ">>> Memory is being WRITE at 0x11ffff8, data size = 8, data value = 0x3c091e6a\n" + + ">>> Memory is being READ at 0x11ffff8, data size = 8\n" + + ">>> Emulation done. Below is the CPU context\n" + + ">>> RAX = 0xdb8ee18208cd6d03\n" + + ">>> RBX = 0xd87b45277f133ddb\n" + + ">>> RCX = 0x3c091e6a\n" + + ">>> RDX = 0x25b8d5a4dbb38112\n" + + ">>> RSI = 0xb3db18ac5e815ca7\n" + + ">>> RDI = 0x48288ca5671c5492\n" + + ">>> R8 = 0xec45774f00c5f682\n" + + ">>> R9 = 0xc118b68e7fcfeeff\n" + + ">>> R10 = 0x596b8d4f\n" + + ">>> R11 = 0xe17e9dbec8c074aa\n" + + ">>> R12 = 0x595f72f6b9d8cf32\n" + + ">>> R13 = 0xea5b108cc2b9ab1f\n" + + ">>> R14 = 0x595f72f6e4017f6e\n" + + ">>> R15 = 0x3e04f60c8f7ecbd7\n", + outContent.toString()); + } + + @Test + public void testX86_64Syscall() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_X86)); + samples.Sample_x86.test_x86_64_syscall(); + assertEquals( + "Emulate x86_64 code with 'syscall' instruction\n" + + ">>> Emulation done. Below is the CPU context\n" + + ">>> RAX = 0x200\n", + outContent.toString()); + } + + @Test + public void testX86InvalidMemReadInTb() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_X86)); + samples.Sample_x86.test_i386_invalid_mem_read_in_tb(); + assertEquals( + "Emulate i386 code that read invalid memory in the middle of a TB\n" + + "uc.emu_start() failed BY DESIGN with error returned: " + + "unicorn.UnicornException: Invalid memory read (UC_ERR_READ_UNMAPPED)\n" + + ">>> Emulation done. Below is the CPU context\n" + + ">>> EIP = 0x1000001\n" + + ">>> The PC is correct after reading unmapped memory in the middle of TB.\n", + outContent.toString()); + } + + @Test + public void testX86SmcXor() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_X86)); + samples.Sample_x86.test_i386_smc_xor(); + assertEquals( + "Emulate i386 code that modfies itself\n" + + ">>> Emulation done. Below is the result.\n" + + ">>> SMC emulation is correct. 0x3ea98b13 ^ 0xbc4177e6 = 0x82e8fcf5\n", + outContent.toString()); + } + + @Test + public void testX86Mmio() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_X86)); + samples.Sample_x86.test_i386_mmio(); + assertEquals( + "Emulate i386 code that uses MMIO\n" + + ">>> Write value 0x3735928559 to IO memory at offset 0x4 with 0x4 bytes\n" + + ">>> Read IO memory at offset 0x4 with 0x4 bytes and return 0x19260817\n" + + ">>> Emulation done. ECX=0x19260817\n", + outContent.toString()); + } + + @Test + public void testX86HookMemInvalid() { + assumeTrue(Unicorn.arch_supported(UC_ARCH_X86)); + samples.Sample_x86.test_i386_hook_mem_invalid(); + assertEquals( + "Emulate i386 code that triggers invalid memory read/write.\n" + + ">>> We have to add a map at 0x8000 before continue execution!\n" + + ">>> We have to add a map at 0x10000 before continue execution!\n", + outContent.toString()); + } } diff --git a/samples/sample_arm64.c b/samples/sample_arm64.c index 84f32c29..1d11592a 100644 --- a/samples/sample_arm64.c +++ b/samples/sample_arm64.c @@ -293,9 +293,94 @@ static void test_arm64_hook_mrs() uc_close(uc); } + +#define CHECK(x) do { \ + if((x) != UC_ERR_OK) { \ + fprintf(stderr, "FAIL at %s:%d: %s\n", __FILE__, __LINE__, #x); \ + exit(1); \ + } \ +} while(0) + +static void test_arm64_pac(void) +{ + uc_engine *uc; + uint64_t x1 = 0x0000aaaabbbbccccULL; + + // paciza x1 + #define ARM64_PAC_CODE "\xe1\x23\xc1\xda" + + printf("Try ARM64 PAC\n"); + + // Initialize emulator in ARM mode + CHECK(uc_open(UC_ARCH_ARM64, UC_MODE_ARM, &uc)); + CHECK(uc_ctl_set_cpu_model(uc, UC_CPU_ARM64_MAX)); + CHECK(uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL)); + CHECK(uc_mem_write(uc, ADDRESS, ARM64_PAC_CODE, sizeof(ARM64_PAC_CODE) - 1)); + CHECK(uc_reg_write(uc, UC_ARM64_REG_X1, &x1)); + + /** Initialize PAC support **/ + uc_arm64_cp_reg reg; + + // SCR_EL3 + reg.op0 = 0b11; + reg.op1 = 0b110; + reg.crn = 0b0001; + reg.crm = 0b0001; + reg.op2 = 0b000; + + CHECK(uc_reg_read(uc, UC_ARM64_REG_CP_REG, ®)); + + // NS && RW && API + reg.val |= (1 | (1<<10) | (1<<17)); + + CHECK(uc_reg_write(uc, UC_ARM64_REG_CP_REG, ®)); + + // SCTLR_EL1 + reg.op0 = 0b11; + reg.op1 = 0b000; + reg.crn = 0b0001; + reg.crm = 0b0000; + reg.op2 = 0b000; + + CHECK(uc_reg_read(uc, UC_ARM64_REG_CP_REG, ®)); + + // EnIA && EnIB + reg.val |= (1<<31) | (1<<30); + + CHECK(uc_reg_write(uc, UC_ARM64_REG_CP_REG, ®)); + + // HCR_EL2 + reg.op0 = 0b11; + reg.op1 = 0b100; + reg.crn = 0b0001; + reg.crm = 0b0001; + reg.op2 = 0b000; + + // HCR.API + reg.val |= (1ULL<<41); + + CHECK(uc_reg_write(uc, UC_ARM64_REG_CP_REG, ®)); + + /** Check that PAC worked **/ + CHECK(uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(ARM64_PAC_CODE) - 1, 0, 0)); + CHECK(uc_reg_read(uc, UC_ARM64_REG_X1, &x1)); + + printf("X1 = 0x%" PRIx64 "\n", x1); + if (x1 == 0x0000aaaabbbbccccULL) { + printf("FAIL: No PAC tag added!\n"); + } else { + // Expect 0x1401aaaabbbbccccULL with the default key + printf("SUCCESS: PAC tag found.\n"); + } + + uc_close(uc); +} + int main(int argc, char **argv, char **envp) { test_arm64_mem_fetch(); + + printf("-------------------------\n"); test_arm64(); printf("-------------------------\n"); @@ -307,5 +392,8 @@ int main(int argc, char **argv, char **envp) printf("-------------------------\n"); test_arm64_hook_mrs(); + printf("-------------------------\n"); + test_arm64_pac(); + return 0; } diff --git a/samples/sample_tricore.c b/samples/sample_tricore.c index 1b7a5551..c3e20655 100644 --- a/samples/sample_tricore.c +++ b/samples/sample_tricore.c @@ -9,7 +9,7 @@ #include // code to be emulated -#define CODE "\x82\x11\xbb\x00\x00\x08" // mov d0, #0x1; mov.u d0, #0x8000 +#define CODE "\x82\x11\xbb\x00\x00\x08" // mov d1, #0x1; mov.u d0, #0x8000 // memory address where emulation starts #define ADDRESS 0x10000 @@ -36,6 +36,7 @@ static void test_tricore(void) uc_hook trace1, trace2; uint32_t d0 = 0x0; // d0 register + uint32_t d1 = 0x0; // d1 register printf("Emulate TriCore code\n"); @@ -73,6 +74,9 @@ static void test_tricore(void) uc_reg_read(uc, UC_TRICORE_REG_D0, &d0); printf(">>> d0 = 0x%x\n", d0); + uc_reg_read(uc, UC_TRICORE_REG_D1, &d1); + printf(">>> d1 = 0x%x\n", d1); + uc_close(uc); } diff --git a/samples/sample_x86.c b/samples/sample_x86.c index 735a9985..9aca8550 100644 --- a/samples/sample_x86.c +++ b/samples/sample_x86.c @@ -360,7 +360,6 @@ static void test_i386_map_ptr(void) int r_ecx = 0x1234; // ECX register int r_edx = 0x7890; // EDX register - printf("===================================\n"); printf("Emulate i386 code - use uc_mem_map_ptr()\n"); // Initialize emulator in X86-32bit mode @@ -426,7 +425,6 @@ static void test_i386_jump(void) uc_err err; uc_hook trace1, trace2; - printf("===================================\n"); printf("Emulate i386 code with jump\n"); // Initialize emulator in X86-32bit mode @@ -474,7 +472,6 @@ static void test_i386_loop(void) int r_ecx = 0x1234; // ECX register int r_edx = 0x7890; // EDX register - printf("===================================\n"); printf("Emulate i386 code that loop forever\n"); // Initialize emulator in X86-32bit mode @@ -528,7 +525,6 @@ static void test_i386_invalid_mem_read(void) int r_ecx = 0x1234; // ECX register int r_edx = 0x7890; // EDX register - printf("===================================\n"); printf("Emulate i386 code that read from invalid memory\n"); // Initialize emulator in X86-32bit mode @@ -588,7 +584,6 @@ static void test_i386_invalid_mem_write(void) int r_ecx = 0x1234; // ECX register int r_edx = 0x7890; // EDX register - printf("===================================\n"); printf("Emulate i386 code that write to invalid memory\n"); // Initialize emulator in X86-32bit mode @@ -663,7 +658,6 @@ static void test_i386_jump_invalid(void) int r_ecx = 0x1234; // ECX register int r_edx = 0x7890; // EDX register - printf("===================================\n"); printf("Emulate i386 code that jumps to invalid memory\n"); // Initialize emulator in X86-32bit mode @@ -721,7 +715,6 @@ static void test_i386_inout(void) int r_eax = 0x1234; // EAX register int r_ecx = 0x6789; // ECX register - printf("===================================\n"); printf("Emulate i386 code with IN/OUT instructions\n"); // Initialize emulator in X86-32bit mode @@ -785,7 +778,6 @@ static void test_i386_context_save(void) int r_eax = 0x1; // EAX register - printf("===================================\n"); printf("Save/restore CPU context in opaque blob\n"); // initialize emulator in X86-32bit mode @@ -908,7 +900,6 @@ static void test_i386_invalid_c6c7(void) }; int i, j, k; - printf("===================================\n"); printf("Emulate i386 C6/C7 opcodes\n"); // Initialize emulator in X86-32bit mode @@ -1077,7 +1068,6 @@ static void test_x86_64_syscall(void) int64_t rax = 0x100; - printf("===================================\n"); printf("Emulate x86_64 code with 'syscall' instruction\n"); // Initialize emulator in X86-64bit mode @@ -1186,7 +1176,6 @@ static void test_i386_invalid_mem_read_in_tb(void) int r_edx = 0x7890; // EDX register int r_eip = 0; - printf("===================================\n"); printf( "Emulate i386 code that read invalid memory in the middle of a TB\n"); @@ -1249,7 +1238,6 @@ static void test_i386_smc_xor() uint32_t r_eax = 0xbc4177e6; // EDX register uint32_t result; - printf("===================================\n"); printf("Emulate i386 code that modfies itself\n"); // Initialize emulator in X86-32bit mode @@ -1325,7 +1313,6 @@ static void test_i386_mmio() int r_ecx = 0xdeadbeef; uc_err err; - printf("===================================\n"); printf("Emulate i386 code that uses MMIO\n"); // Initialize emulator in X86-32bit mode @@ -1403,7 +1390,6 @@ static void test_i386_hook_mem_invalid() "\xb8\xef\xbe\xad\xde\xa3\x00\x80\x00\x00\xa1\x00\x00\x01\x00"; uc_err err; - printf("===================================\n"); printf("Emulate i386 code that triggers invalid memory read/write.\n"); err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); @@ -1448,40 +1434,66 @@ int main(int argc, char **argv, char **envp) test_x86_16(); } else if (!strcmp(argv[1], "-32")) { test_miss_code(); + printf("===================================\n"); test_i386(); + printf("===================================\n"); test_i386_map_ptr(); + printf("===================================\n"); test_i386_inout(); + printf("===================================\n"); test_i386_context_save(); + printf("===================================\n"); test_i386_jump(); + printf("===================================\n"); test_i386_loop(); + printf("===================================\n"); test_i386_invalid_mem_read(); + printf("===================================\n"); test_i386_invalid_mem_write(); + printf("===================================\n"); test_i386_jump_invalid(); // test_i386_invalid_c6c7(); } else if (!strcmp(argv[1], "-64")) { test_x86_64(); + printf("===================================\n"); test_x86_64_syscall(); } else if (!strcmp(argv[1], "-h")) { printf("Syntax: %s <-16|-32|-64>\n", argv[0]); } } else { test_x86_16(); + printf("===================================\n"); test_miss_code(); + printf("===================================\n"); test_i386(); + printf("===================================\n"); test_i386_map_ptr(); + printf("===================================\n"); test_i386_inout(); + printf("===================================\n"); test_i386_context_save(); + printf("===================================\n"); test_i386_jump(); + printf("===================================\n"); test_i386_loop(); + printf("===================================\n"); test_i386_invalid_mem_read(); + printf("===================================\n"); test_i386_invalid_mem_write(); + printf("===================================\n"); test_i386_jump_invalid(); // test_i386_invalid_c6c7(); + printf("===================================\n"); test_x86_64(); + printf("===================================\n"); test_x86_64_syscall(); + printf("===================================\n"); test_i386_invalid_mem_read_in_tb(); + printf("===================================\n"); test_i386_smc_xor(); + printf("===================================\n"); test_i386_mmio(); + printf("===================================\n"); test_i386_hook_mem_invalid(); }