#include "unicorn_test.h" const uint64_t code_start = 0x1000; const uint64_t code_len = 0x4000; static void uc_common_setup(uc_engine **uc, uc_arch arch, uc_mode mode, const char *code, uint64_t size, uc_cpu_arm cpu) { OK(uc_open(arch, mode, uc)); OK(uc_ctl_set_cpu_model(*uc, cpu)); OK(uc_mem_map(*uc, code_start, code_len, UC_PROT_ALL)); OK(uc_mem_write(*uc, code_start, code, size)); } static void test_arm_nop() { uc_engine *uc; char code[] = "\x00\xf0\x20\xe3"; // nop int r_r0 = 0x1234; int r_r2 = 0x6789; uc_common_setup(&uc, UC_ARCH_ARM, UC_MODE_ARM, code, sizeof(code) - 1, UC_CPU_ARM_CORTEX_A15); OK(uc_reg_write(uc, UC_ARM_REG_R0, &r_r0)); OK(uc_reg_write(uc, UC_ARM_REG_R2, &r_r2)); OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0)); OK(uc_reg_read(uc, UC_ARM_REG_R0, &r_r0)); OK(uc_reg_read(uc, UC_ARM_REG_R2, &r_r2)); TEST_CHECK(r_r0 == 0x1234); TEST_CHECK(r_r2 == 0x6789); OK(uc_close(uc)); } static void test_arm_thumb_sub() { uc_engine *uc; char code[] = "\x83\xb0"; // sub sp, #0xc int r_sp = 0x1234; uc_common_setup(&uc, UC_ARCH_ARM, UC_MODE_THUMB, code, sizeof(code) - 1, UC_CPU_ARM_CORTEX_A15); OK(uc_reg_write(uc, UC_ARM_REG_SP, &r_sp)); OK(uc_emu_start(uc, code_start | 1, code_start + sizeof(code) - 1, 0, 0)); OK(uc_reg_read(uc, UC_ARM_REG_SP, &r_sp)); TEST_CHECK(r_sp == 0x1228); OK(uc_close(uc)); } static void test_armeb_sub() { uc_engine *uc; char code[] = "\xe3\xa0\x00\x37\xe0\x42\x10\x03"; // mov r0, #0x37; sub r1, r2, r3 int r_r0 = 0x1234; int r_r2 = 0x6789; int r_r3 = 0x3333; int r_r1; uc_common_setup(&uc, UC_ARCH_ARM, UC_MODE_ARM | UC_MODE_BIG_ENDIAN, code, sizeof(code) - 1, UC_CPU_ARM_1176); OK(uc_reg_write(uc, UC_ARM_REG_R0, &r_r0)); OK(uc_reg_write(uc, UC_ARM_REG_R2, &r_r2)); OK(uc_reg_write(uc, UC_ARM_REG_R3, &r_r3)); OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0)); OK(uc_reg_read(uc, UC_ARM_REG_R0, &r_r0)); OK(uc_reg_read(uc, UC_ARM_REG_R1, &r_r1)); OK(uc_reg_read(uc, UC_ARM_REG_R2, &r_r2)); OK(uc_reg_read(uc, UC_ARM_REG_R3, &r_r3)); TEST_CHECK(r_r0 == 0x37); TEST_CHECK(r_r2 == 0x6789); TEST_CHECK(r_r3 == 0x3333); TEST_CHECK(r_r1 == 0x3456); OK(uc_close(uc)); } static void test_armeb_be8_sub() { uc_engine *uc; char code[] = "\x37\x00\xa0\xe3\x03\x10\x42\xe0"; // mov r0, #0x37; sub r1, r2, r3 int r_r0 = 0x1234; int r_r2 = 0x6789; int r_r3 = 0x3333; int r_r1; uc_common_setup(&uc, UC_ARCH_ARM, UC_MODE_ARM | UC_MODE_ARMBE8, code, sizeof(code) - 1, UC_CPU_ARM_CORTEX_A15); OK(uc_reg_write(uc, UC_ARM_REG_R0, &r_r0)); OK(uc_reg_write(uc, UC_ARM_REG_R2, &r_r2)); OK(uc_reg_write(uc, UC_ARM_REG_R3, &r_r3)); OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0)); OK(uc_reg_read(uc, UC_ARM_REG_R0, &r_r0)); OK(uc_reg_read(uc, UC_ARM_REG_R1, &r_r1)); OK(uc_reg_read(uc, UC_ARM_REG_R2, &r_r2)); OK(uc_reg_read(uc, UC_ARM_REG_R3, &r_r3)); TEST_CHECK(r_r0 == 0x37); TEST_CHECK(r_r2 == 0x6789); TEST_CHECK(r_r3 == 0x3333); TEST_CHECK(r_r1 == 0x3456); OK(uc_close(uc)); } static void test_arm_thumbeb_sub() { uc_engine *uc; char code[] = "\xb0\x83"; // sub sp, #0xc int r_sp = 0x1234; uc_common_setup(&uc, UC_ARCH_ARM, UC_MODE_THUMB | UC_MODE_BIG_ENDIAN, code, sizeof(code) - 1, UC_CPU_ARM_1176); OK(uc_reg_write(uc, UC_ARM_REG_SP, &r_sp)); OK(uc_emu_start(uc, code_start | 1, code_start + sizeof(code) - 1, 0, 0)); OK(uc_reg_read(uc, UC_ARM_REG_SP, &r_sp)); TEST_CHECK(r_sp == 0x1228); OK(uc_close(uc)); } static void test_arm_thumb_ite_count_callback(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) { uint64_t *count = (uint64_t *)user_data; (*count) += 1; } static void test_arm_thumb_ite() { uc_engine *uc; uc_hook hook; char code[] = "\x9a\x42\x15\xbf\x00\x9a\x01\x9a\x78\x23\x15\x23"; // cmp r2, r3; itete // ne; ldrne r2, // [sp]; ldreq r2, // [sp,#4]; movne // r3, #0x78; moveq // r3, #0x15 int r_sp = 0x8000; int r_r2 = 0; int r_r3 = 1; int r_pc = 0; uint64_t count = 0; uc_common_setup(&uc, UC_ARCH_ARM, UC_MODE_THUMB, code, sizeof(code) - 1, UC_CPU_ARM_CORTEX_A15); OK(uc_reg_write(uc, UC_ARM_REG_SP, &r_sp)); OK(uc_reg_write(uc, UC_ARM_REG_R2, &r_r2)); OK(uc_reg_write(uc, UC_ARM_REG_R3, &r_r3)); OK(uc_mem_map(uc, r_sp, 0x1000, UC_PROT_ALL)); r_r2 = 0x68; OK(uc_mem_write(uc, r_sp, &r_r2, 4)); r_r2 = 0x4d; OK(uc_mem_write(uc, r_sp + 4, &r_r2, 4)); OK(uc_hook_add(uc, &hook, UC_HOOK_CODE, test_arm_thumb_ite_count_callback, &count, 1, 0)); // Execute four instructions at a time. OK(uc_emu_start(uc, code_start | 1, code_start + sizeof(code) - 1, 0, 0)); OK(uc_reg_read(uc, UC_ARM_REG_R2, &r_r2)); OK(uc_reg_read(uc, UC_ARM_REG_R3, &r_r3)); TEST_CHECK(r_r2 == 0x68); TEST_CHECK(count == 4); r_pc = code_start; r_r2 = 0; count = 0; OK(uc_reg_write(uc, UC_ARM_REG_R2, &r_r2)); OK(uc_reg_write(uc, UC_ARM_REG_R3, &r_r3)); for (int i = 0; i < 6 && r_pc < code_start + sizeof(code) - 1; i++) { // Execute one instruction at a time. OK(uc_emu_start(uc, r_pc | 1, code_start + sizeof(code) - 1, 0, 1)); OK(uc_reg_read(uc, UC_ARM_REG_PC, &r_pc)); } OK(uc_reg_read(uc, UC_ARM_REG_R2, &r_r2)); TEST_CHECK(r_r2 == 0x68); TEST_CHECK(r_r3 == 0x78); TEST_CHECK(count == 4); OK(uc_close(uc)); } static void test_arm_m_thumb_mrs() { uc_engine *uc; char code[] = "\xef\xf3\x14\x80\xef\xf3\x00\x81"; // mrs r0, control; mrs r1, apsr uint32_t r_control = 0b10; uint32_t r_apsr = (0b10101 << 27); uint32_t r_r0, r_r1; uc_common_setup(&uc, UC_ARCH_ARM, UC_MODE_THUMB | UC_MODE_MCLASS, code, sizeof(code) - 1, UC_CPU_ARM_CORTEX_A15); OK(uc_reg_write(uc, UC_ARM_REG_CONTROL, &r_control)); OK(uc_reg_write(uc, UC_ARM_REG_APSR_NZCVQ, &r_apsr)); OK(uc_emu_start(uc, code_start | 1, code_start + sizeof(code) - 1, 0, 0)); OK(uc_reg_read(uc, UC_ARM_REG_R0, &r_r0)); OK(uc_reg_read(uc, UC_ARM_REG_R1, &r_r1)); TEST_CHECK(r_r0 == 0b10); TEST_CHECK(r_r1 == (0b10101 << 27)); OK(uc_close(uc)); } static void test_arm_m_control() { uc_engine *uc; int r_control, r_msp, r_psp; OK(uc_open(UC_ARCH_ARM, UC_MODE_THUMB | UC_MODE_MCLASS, &uc)); r_control = 0; // Make sure we are using MSP. OK(uc_reg_write(uc, UC_ARM_REG_CONTROL, &r_control)); r_msp = 0x1000; OK(uc_reg_write(uc, UC_ARM_REG_R13, &r_msp)); r_control = 0b10; // Make the switch. OK(uc_reg_write(uc, UC_ARM_REG_CONTROL, &r_control)); OK(uc_reg_read(uc, UC_ARM_REG_R13, &r_psp)); TEST_CHECK(r_psp != r_msp); r_psp = 0x2000; OK(uc_reg_write(uc, UC_ARM_REG_R13, &r_psp)); r_control = 0; // Switch again OK(uc_reg_write(uc, UC_ARM_REG_CONTROL, &r_control)); OK(uc_reg_read(uc, UC_ARM_REG_R13, &r_msp)); TEST_CHECK(r_psp != r_msp); TEST_CHECK(r_msp == 0x1000); OK(uc_close(uc)); } // // Some notes: // Qemu raise a special exception EXCP_EXCEPTION_EXIT to handle the // EXC_RETURN. We can't help user handle EXC_RETURN since unicorn is designed // not to handle any CPU exception. // static void test_arm_m_exc_return_hook_interrupt(uc_engine *uc, int intno, void *data) { int r_pc; OK(uc_reg_read(uc, UC_ARM_REG_PC, &r_pc)); TEST_CHECK(intno == 8); // EXCP_EXCEPTION_EXIT: Return from v7M exception. TEST_CHECK((r_pc | 1) == 0xFFFFFFFD); OK(uc_emu_stop(uc)); } static void test_arm_m_exc_return() { uc_engine *uc; char code[] = "\x6f\xf0\x02\x00\x00\x47"; // mov r0, #0xFFFFFFFD; bx r0; int r_ipsr; int r_sp = 0x8000; uc_hook hook; uc_common_setup(&uc, UC_ARCH_ARM, UC_MODE_THUMB | UC_MODE_MCLASS, code, sizeof(code) - 1, UC_CPU_ARM_CORTEX_A15); OK(uc_mem_map(uc, r_sp - 0x1000, 0x1000, UC_PROT_ALL)); OK(uc_hook_add(uc, &hook, UC_HOOK_INTR, test_arm_m_exc_return_hook_interrupt, NULL, 0, 0)); r_sp -= 0x1c; OK(uc_reg_write(uc, UC_ARM_REG_SP, &r_sp)); r_ipsr = 16; // We are in whatever exception. OK(uc_reg_write(uc, UC_ARM_REG_IPSR, &r_ipsr)); OK(uc_emu_start(uc, code_start | 1, code_start + sizeof(code) - 1, 0, 2)); // Just execute 2 instructions. OK(uc_hook_del(uc, hook)); OK(uc_close(uc)); } // For details, see https://github.com/unicorn-engine/unicorn/issues/1494. static void test_arm_und32_to_svc32() { uc_engine *uc; // # MVN r0, #0 // # MOVS pc, lr // # MVN r0, #0 // # MVN r0, #0 char code[] = "\x00\x00\xe0\xe3\x0e\xf0\xb0\xe1\x00\x00\xe0\xe3\x00\x00\xe0\xe3"; int r_cpsr, r_sp, r_spsr, r_lr; OK(uc_open(UC_ARCH_ARM, UC_MODE_ARM, &uc)); OK(uc_ctl_set_cpu_model(uc, UC_CPU_ARM_CORTEX_A9)); OK(uc_mem_map(uc, code_start, code_len, UC_PROT_ALL)); OK(uc_mem_write(uc, code_start, code, sizeof(code) - 1)); // https://www.keil.com/pack/doc/CMSIS/Core_A/html/group__CMSIS__CPSR__M.html r_cpsr = 0x40000093; // SVC32 OK(uc_reg_write(uc, UC_ARM_REG_CPSR, &r_cpsr)); r_sp = 0x12345678; OK(uc_reg_write(uc, UC_ARM_REG_SP, &r_sp)); r_cpsr = 0x4000009b; // UND32 OK(uc_reg_write(uc, UC_ARM_REG_CPSR, &r_cpsr)); r_spsr = 0x40000093; // Save previous CPSR OK(uc_reg_write(uc, UC_ARM_REG_SPSR, &r_spsr)); r_sp = 0xDEAD0000; OK(uc_reg_write(uc, UC_ARM_REG_SP, &r_sp)); r_lr = code_start + 8; OK(uc_reg_write(uc, UC_ARM_REG_LR, &r_lr)); OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 3)); OK(uc_reg_read(uc, UC_ARM_REG_SP, &r_sp)); TEST_CHECK(r_sp == 0x12345678); OK(uc_close(uc)); } static void test_arm_usr32_to_svc32() { uc_engine *uc; int r_cpsr, r_sp, r_spsr, r_lr; OK(uc_open(UC_ARCH_ARM, UC_MODE_ARM, &uc)); OK(uc_ctl_set_cpu_model(uc, UC_CPU_ARM_CORTEX_A9)); // https://www.keil.com/pack/doc/CMSIS/Core_A/html/group__CMSIS__CPSR__M.html r_cpsr = 0x40000093; // SVC32 OK(uc_reg_write(uc, UC_ARM_REG_CPSR, &r_cpsr)); r_sp = 0x12345678; OK(uc_reg_write(uc, UC_ARM_REG_SP, &r_sp)); r_lr = 0x00102220; OK(uc_reg_write(uc, UC_ARM_REG_LR, &r_lr)); r_cpsr = 0x4000009b; // UND32 OK(uc_reg_write(uc, UC_ARM_REG_CPSR, &r_cpsr)); r_spsr = 0x40000093; // Save previous CPSR OK(uc_reg_write(uc, UC_ARM_REG_SPSR, &r_spsr)); r_sp = 0xDEAD0000; OK(uc_reg_write(uc, UC_ARM_REG_SP, &r_sp)); r_lr = 0x00509998; OK(uc_reg_write(uc, UC_ARM_REG_LR, &r_lr)); OK(uc_reg_read(uc, UC_ARM_REG_CPSR, &r_cpsr)); TEST_CHECK((r_cpsr & ((1 << 4) - 1)) == 0xb); // We are in UND32 r_cpsr = 0x40000090; // USR32 OK(uc_reg_write(uc, UC_ARM_REG_CPSR, &r_cpsr)); r_sp = 0x0010000; OK(uc_reg_write(uc, UC_ARM_REG_R13, &r_sp)); r_lr = 0x0001234; OK(uc_reg_write(uc, UC_ARM_REG_LR, &r_lr)); OK(uc_reg_read(uc, UC_ARM_REG_CPSR, &r_cpsr)); TEST_CHECK((r_cpsr & ((1 << 4) - 1)) == 0); // We are in USR32 r_cpsr = 0x40000093; // SVC32 OK(uc_reg_write(uc, UC_ARM_REG_CPSR, &r_cpsr)); OK(uc_reg_read(uc, UC_ARM_REG_CPSR, &r_cpsr)); OK(uc_reg_read(uc, UC_ARM_REG_SP, &r_sp)); TEST_CHECK((r_cpsr & ((1 << 4) - 1)) == 3); // We are in SVC32 TEST_CHECK(r_sp == 0x12345678); OK(uc_close(uc)); } static void test_arm_v8() { char code[] = "\xd0\xe8\xff\x17"; // LDAEXD.W R1, [R0] uc_engine *uc; uint32_t r_r1 = 0xdeadbeef; uint32_t r_r0; uc_common_setup(&uc, UC_ARCH_ARM, UC_MODE_THUMB, code, sizeof(code) - 1, UC_CPU_ARM_CORTEX_M33); r_r0 = 0x8000; OK(uc_mem_map(uc, r_r0, 0x1000, UC_PROT_ALL)); OK(uc_mem_write(uc, r_r0, (void *)&r_r1, 4)); OK(uc_reg_write(uc, UC_ARM_REG_R0, &r_r0)); OK(uc_emu_start(uc, code_start | 1, code_start + sizeof(code) - 1, 0, 0)); OK(uc_reg_read(uc, UC_ARM_REG_R1, &r_r1)); TEST_CHECK(r_r1 == 0xdeadbeef); OK(uc_close(uc)); } static void test_arm_thumb_smlabb() { char code[] = "\x13\xfb\x01\x23"; uint32_t r_r1, r_r2, r_r3; uc_engine *uc; uc_common_setup(&uc, UC_ARCH_ARM, UC_MODE_THUMB, code, sizeof(code) - 1, UC_CPU_ARM_CORTEX_M7); r_r3 = 5; r_r1 = 7; r_r2 = 9; OK(uc_reg_write(uc, UC_ARM_REG_R3, &r_r3)); OK(uc_reg_write(uc, UC_ARM_REG_R1, &r_r1)); OK(uc_reg_write(uc, UC_ARM_REG_R2, &r_r2)); OK(uc_emu_start(uc, code_start | 1, code_start + sizeof(code) - 1, 0, 0)); OK(uc_reg_read(uc, UC_ARM_REG_R3, &r_r3)); TEST_CHECK(r_r3 == 5 * 7 + 9); OK(uc_close(uc)); } static void test_arm_not_allow_privilege_escalation() { uc_engine *uc; int r_cpsr, r_sp, r_spsr, r_lr; // E3C6601F : BIC r6, r6, #&1F // E3866013 : ORR r6, r6, #&13 // E121F006 : MSR cpsr_c, r6 ; switch to SVC32 (should be ineffective // from USR32) // E1A00000 : MOV r0,r0 EF000011 : SWI OS_Exit char code[] = "\x1f\x60\xc6\xe3\x13\x60\x86\xe3\x06\xf0\x21\xe1\x00\x00\xa0" "\xe1\x11\x00\x00\xef"; uc_common_setup(&uc, UC_ARCH_ARM, UC_MODE_ARM, code, sizeof(code) - 1, UC_CPU_ARM_CORTEX_A15); // https://www.keil.com/pack/doc/CMSIS/Core_A/html/group__CMSIS__CPSR.html r_cpsr = 0x40000013; // SVC32 OK(uc_reg_write(uc, UC_ARM_REG_CPSR, &r_cpsr)); r_spsr = 0x40000013; OK(uc_reg_write(uc, UC_ARM_REG_SPSR, &r_spsr)); r_sp = 0x12345678; OK(uc_reg_write(uc, UC_ARM_REG_SP, &r_sp)); r_lr = 0x00102220; OK(uc_reg_write(uc, UC_ARM_REG_LR, &r_lr)); r_cpsr = 0x40000010; // USR32 OK(uc_reg_write(uc, UC_ARM_REG_CPSR, &r_cpsr)); r_sp = 0x0010000; OK(uc_reg_write(uc, UC_ARM_REG_SP, &r_sp)); r_lr = 0x0001234; OK(uc_reg_write(uc, UC_ARM_REG_LR, &r_lr)); uc_assert_err( UC_ERR_EXCEPTION, uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0)); OK(uc_reg_read(uc, UC_ARM_REG_SP, &r_sp)); OK(uc_reg_read(uc, UC_ARM_REG_LR, &r_lr)); OK(uc_reg_read(uc, UC_ARM_REG_CPSR, &r_cpsr)); TEST_CHECK((r_cpsr & ((1 << 4) - 1)) == 0); // Stay in USR32 TEST_CHECK(r_lr == 0x1234); TEST_CHECK(r_sp == 0x10000); OK(uc_close(uc)); } static void test_arm_mrc() { uc_engine *uc; // mrc p15, #0, r1, c13, c0, #3 char code[] = "\x1d\xee\x70\x1f"; uc_common_setup(&uc, UC_ARCH_ARM, UC_MODE_THUMB, code, sizeof(code) - 1, UC_CPU_ARM_MAX); OK(uc_emu_start(uc, code_start | 1, code_start + sizeof(code) - 1, 0, 0)); OK(uc_close(uc)); } static void test_arm_hflags_rebuilt() { // MRS r6, apsr // BIC r6, r6, #&1F // ORR r6, r6, #&10 // MSR cpsr_c, r6 // SWI OS_EnterOS // MSR cpsr_c, r6 char code[] = "\x00\x60\x0f\xe1\x1f\x60\xc6\xe3\x10\x60\x86\xe3\x06\xf0\x21" "\xe1\x16\x00\x02\xef\x06\xf0\x21\xe1"; uc_engine *uc; uint32_t r_cpsr, r_spsr, r_r13, r_r14, r_pc; uc_common_setup(&uc, UC_ARCH_ARM, UC_MODE_ARM, code, sizeof(code) - 1, UC_CPU_ARM_CORTEX_A9); r_cpsr = 0x40000013; // SVC32 OK(uc_reg_write(uc, UC_ARM_REG_CPSR, &r_cpsr)); r_spsr = 0x40000013; OK(uc_reg_write(uc, UC_ARM_REG_SPSR, &r_spsr)); r_r13 = 0x12345678; // SP OK(uc_reg_write(uc, UC_ARM_REG_R13, &r_r13)); r_r14 = 0x00102220; // LR OK(uc_reg_write(uc, UC_ARM_REG_R14, &r_r14)); r_cpsr = 0x40000010; // USR32 OK(uc_reg_write(uc, UC_ARM_REG_CPSR, &r_cpsr)); r_r13 = 0x0010000; // SP OK(uc_reg_write(uc, UC_ARM_REG_R13, &r_r13)); r_r14 = 0x0001234; // LR OK(uc_reg_write(uc, UC_ARM_REG_R14, &r_r14)); uc_assert_err( UC_ERR_EXCEPTION, uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0)); r_cpsr = 0x60000013; OK(uc_reg_write(uc, UC_ARM_REG_CPSR, &r_cpsr)); r_cpsr = 0x60000010; OK(uc_reg_write(uc, UC_ARM_REG_CPSR, &r_cpsr)); r_cpsr = 0x60000013; OK(uc_reg_write(uc, UC_ARM_REG_CPSR, &r_cpsr)); OK(uc_reg_read(uc, UC_ARM_REG_PC, &r_pc)); OK(uc_emu_start(uc, r_pc, code_start + sizeof(code) - 1, 0, 0)); OK(uc_reg_read(uc, UC_ARM_REG_CPSR, &r_cpsr)); OK(uc_reg_read(uc, UC_ARM_REG_R13, &r_r13)); OK(uc_reg_read(uc, UC_ARM_REG_R14, &r_r14)); TEST_CHECK(r_cpsr == 0x60000010); TEST_CHECK(r_r13 == 0x00010000); TEST_CHECK(r_r14 == 0x00001234); OK(uc_close(uc)); } static bool test_arm_mem_access_abort_hook_mem(uc_engine *uc, uc_mem_type type, uint64_t addr, int size, int64_t val, void *data) { OK(uc_reg_read(uc, UC_ARM_REG_PC, data)); return false; } static bool test_arm_mem_access_abort_hook_insn_invalid(uc_engine *uc, void *data) { OK(uc_reg_read(uc, UC_ARM_REG_PC, data)); return false; } static void test_arm_mem_access_abort() { // LDR r0, [r0] // Undefined instruction char code[] = "\x00\x00\x90\xe5\x00\xa0\xf0\xf7"; uc_engine *uc; uint32_t r_pc, r_r0, r_pc_in_hook; uc_hook hk, hkk; uc_common_setup(&uc, UC_ARCH_ARM, UC_MODE_ARM, code, sizeof(code) - 1, UC_CPU_ARM_CORTEX_A9); r_r0 = 0x990000; OK(uc_reg_write(uc, UC_ARM_REG_R0, &r_r0)); OK(uc_hook_add(uc, &hk, UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED | UC_HOOK_MEM_FETCH_UNMAPPED, test_arm_mem_access_abort_hook_mem, (void *)&r_pc_in_hook, 1, 0)); OK(uc_hook_add(uc, &hkk, UC_HOOK_INSN_INVALID, test_arm_mem_access_abort_hook_insn_invalid, (void *)&r_pc_in_hook, 1, 0)); uc_assert_err(UC_ERR_READ_UNMAPPED, uc_emu_start(uc, code_start, code_start + 4, 0, 0)); OK(uc_reg_read(uc, UC_ARM_REG_PC, &r_pc)); TEST_CHECK(r_pc == r_pc_in_hook); uc_assert_err(UC_ERR_INSN_INVALID, uc_emu_start(uc, code_start + 4, code_start + 8, 0, 0)); OK(uc_reg_read(uc, UC_ARM_REG_PC, &r_pc)); TEST_CHECK(r_pc == r_pc_in_hook); uc_assert_err(UC_ERR_FETCH_UNMAPPED, uc_emu_start(uc, 0x900000, 0x900000 + 8, 0, 0)); OK(uc_reg_read(uc, UC_ARM_REG_PC, &r_pc)); TEST_CHECK(r_pc == r_pc_in_hook); OK(uc_close(uc)); } static void test_arm_read_sctlr() { uc_engine *uc; uc_arm_cp_reg reg; OK(uc_open(UC_ARCH_ARM, UC_MODE_ARM, &uc)); // SCTLR. See arm reference. reg.cp = 15; reg.is64 = 0; reg.sec = 0; reg.crn = 1; reg.crm = 0; reg.opc1 = 0; reg.opc2 = 0; OK(uc_reg_read(uc, UC_ARM_REG_CP_REG, ®)); TEST_CHECK((uint32_t)((reg.val >> 31) & 1) == 0); OK(uc_close(uc)); } static void test_arm_be_cpsr_sctlr() { uc_engine *uc; uc_arm_cp_reg reg; uint32_t cpsr; OK(uc_open(UC_ARCH_ARM, UC_MODE_BIG_ENDIAN, &uc)); OK(uc_ctl_set_cpu_model( uc, UC_CPU_ARM_1176)); // big endian code, big endian data // SCTLR. See arm reference. reg.cp = 15; reg.is64 = 0; reg.sec = 0; reg.crn = 1; reg.crm = 0; reg.opc1 = 0; reg.opc2 = 0; OK(uc_reg_read(uc, UC_ARM_REG_CP_REG, ®)); OK(uc_reg_read(uc, UC_ARM_REG_CPSR, &cpsr)); TEST_CHECK((reg.val & (1 << 7)) != 0); TEST_CHECK((cpsr & (1 << 9)) != 0); OK(uc_close(uc)); OK(uc_open(UC_ARCH_ARM, UC_MODE_ARMBE8, &uc)); OK(uc_ctl_set_cpu_model(uc, UC_CPU_ARM_CORTEX_A15)); // SCTLR. See arm reference. reg.cp = 15; reg.is64 = 0; reg.sec = 0; reg.crn = 1; reg.crm = 0; reg.opc1 = 0; reg.opc2 = 0; OK(uc_reg_read(uc, UC_ARM_REG_CP_REG, ®)); OK(uc_reg_read(uc, UC_ARM_REG_CPSR, &cpsr)); // SCTLR.B == 0 TEST_CHECK((reg.val & (1 << 7)) == 0); TEST_CHECK((cpsr & (1 << 9)) != 0); OK(uc_close(uc)); } static void test_arm_switch_endian() { uc_engine *uc; char code[] = "\x00\x00\x91\xe5"; // ldr r0, [r1] uint32_t r_r1 = (uint32_t)code_start; uint32_t r_r0, r_cpsr; uc_common_setup(&uc, UC_ARCH_ARM, UC_MODE_ARM, code, sizeof(code) - 1, UC_CPU_ARM_CORTEX_A15); OK(uc_reg_write(uc, UC_ARM_REG_R1, &r_r1)); OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0)); OK(uc_reg_read(uc, UC_ARM_REG_R0, &r_r0)); // Little endian TEST_CHECK(r_r0 == 0xe5910000); OK(uc_reg_read(uc, UC_ARM_REG_CPSR, &r_cpsr)); r_cpsr |= (1 << 9); OK(uc_reg_write(uc, UC_ARM_REG_CPSR, &r_cpsr)); OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0)); OK(uc_reg_read(uc, UC_ARM_REG_R0, &r_r0)); // Big endian TEST_CHECK(r_r0 == 0x000091e5); OK(uc_close(uc)); } TEST_LIST = {{"test_arm_nop", test_arm_nop}, {"test_arm_thumb_sub", test_arm_thumb_sub}, {"test_armeb_sub", test_armeb_sub}, {"test_armeb_be8_sub", test_armeb_be8_sub}, {"test_arm_thumbeb_sub", test_arm_thumbeb_sub}, {"test_arm_thumb_ite", test_arm_thumb_ite}, {"test_arm_m_thumb_mrs", test_arm_m_thumb_mrs}, {"test_arm_m_control", test_arm_m_control}, {"test_arm_m_exc_return", test_arm_m_exc_return}, {"test_arm_und32_to_svc32", test_arm_und32_to_svc32}, {"test_arm_usr32_to_svc32", test_arm_usr32_to_svc32}, {"test_arm_v8", test_arm_v8}, {"test_arm_thumb_smlabb", test_arm_thumb_smlabb}, {"test_arm_not_allow_privilege_escalation", test_arm_not_allow_privilege_escalation}, {"test_arm_mrc", test_arm_mrc}, {"test_arm_hflags_rebuilt", test_arm_hflags_rebuilt}, {"test_arm_mem_access_abort", test_arm_mem_access_abort}, {"test_arm_read_sctlr", test_arm_read_sctlr}, {"test_arm_be_cpsr_sctlr", test_arm_be_cpsr_sctlr}, {"test_arm_switch_endian", test_arm_switch_endian}, {NULL, NULL}};