From c6db9febe70b78ffe2b83b9116e424ba4035b3e5 Mon Sep 17 00:00:00 2001 From: jndok Date: Wed, 15 Jun 2016 19:18:51 +0200 Subject: [PATCH 1/3] added ARM64 hang test --- tests/unit/Makefile | 4 ++- tests/unit/test_hang.c | 58 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 tests/unit/test_hang.c diff --git a/tests/unit/Makefile b/tests/unit/Makefile index fd4f3eef..55f38be5 100644 --- a/tests/unit/Makefile +++ b/tests/unit/Makefile @@ -13,7 +13,7 @@ endif ALL_TESTS = test_sanity test_x86 test_mem_map test_mem_high test_mem_map_ptr \ test_tb_x86 test_multihook test_pc_change test_x86_soft_paging \ - test_hookcounts + test_hookcounts test_hang .PHONY: all all: ${ALL_TESTS} @@ -35,6 +35,7 @@ test: ${ALL_TESTS} ./test_pc_change ./test_x86_soft_paging ./test_hookcounts + ./test_hang test_sanity: test_sanity.c test_x86: test_x86.c @@ -46,6 +47,7 @@ test_multihook: test_multihook.c test_pc_change: test_pc_change.c test_x86_soft_paging: test_x86_soft_paging.c test_hookcounts: test_hookcounts.c +test_hang: test_hang.c ${ALL_TESTS}: ${CC} ${CFLAGS} -o $@ $^ diff --git a/tests/unit/test_hang.c b/tests/unit/test_hang.c new file mode 100644 index 00000000..4513a016 --- /dev/null +++ b/tests/unit/test_hang.c @@ -0,0 +1,58 @@ +/* + refer to issue #575. + to run correctly unicorn needs to be compiled for AArch64. +*/ + +#include "unicorn_test.h" +#include + +uint64_t trunc_page(uint64_t addr) +{ + return (addr & ~(4095)); +} + +int main(void) +{ + uint32_t code[] = { + 0xd503201f, /* NOP */ + 0xd503201f, /* NOP */ + 0xd503201f, /* NOP */ + 0xaa0103e0 /* MOV X0, X1 */ + }; + + uc_engine *uc; + + uint64_t x0 = 0; + uint64_t x1 = 1; + + if (uc_open(UC_ARCH_ARM64, UC_MODE_ARM, &uc) != UC_ERR_OK) { + printf("Error on open. Be sure that your unicorn library supports AArch64.\n"); + return -1; + } + + uint64_t addr = 0x13f0; + uint64_t trunc_addr = trunc_page(addr); // round down to nearest page + + uc_mem_map(uc, trunc_addr, 2 * 1024 * 1024, UC_PROT_ALL); + + if (uc_mem_write(uc, addr, &code, sizeof(code))) { + printf("error on write\n"); + return -2; + } + + uc_reg_write(uc, UC_ARM64_REG_X0, &x0); + uc_reg_write(uc, UC_ARM64_REG_X1, &x1); + + if (uc_emu_start(uc, addr, addr + sizeof(code), 0, 0)) { + printf("error on start\n"); + return -3; + } + + uc_reg_read(uc, UC_ARM64_REG_X0, &x0); + uc_reg_read(uc, UC_ARM64_REG_X1, &x1); + + printf("x0: %#llx\n", x0); + printf("x1: %#llx\n", x1); + + return 0; +} From 3bec4b2cf15b2f232c5938da1ddb4c961f3a6c0e Mon Sep 17 00:00:00 2001 From: nuko32 Date: Wed, 15 Jun 2016 20:44:22 +0200 Subject: [PATCH 2/3] refactored test_hang and fixed indentations --- tests/unit/test_hang.c | 108 ++++++++++++++++++++++++++--------------- 1 file changed, 69 insertions(+), 39 deletions(-) diff --git a/tests/unit/test_hang.c b/tests/unit/test_hang.c index 4513a016..c1812745 100644 --- a/tests/unit/test_hang.c +++ b/tests/unit/test_hang.c @@ -11,48 +11,78 @@ uint64_t trunc_page(uint64_t addr) return (addr & ~(4095)); } -int main(void) +/* Called before every test to set up a new instance */ +static int init(void **state) { - uint32_t code[] = { - 0xd503201f, /* NOP */ - 0xd503201f, /* NOP */ - 0xd503201f, /* NOP */ - 0xaa0103e0 /* MOV X0, X1 */ - }; + printf("[+] Initializing Unicorn...\n"); + uc_engine *uc; - uc_engine *uc; + if (uc_open(UC_ARCH_ARM64, UC_MODE_ARM, &uc) != UC_ERR_OK) { + printf("Error on open. Be sure that your unicorn library supports AArch64.\n"); + return -1; + } - uint64_t x0 = 0; - uint64_t x1 = 1; - - if (uc_open(UC_ARCH_ARM64, UC_MODE_ARM, &uc) != UC_ERR_OK) { - printf("Error on open. Be sure that your unicorn library supports AArch64.\n"); - return -1; - } - - uint64_t addr = 0x13f0; - uint64_t trunc_addr = trunc_page(addr); // round down to nearest page - - uc_mem_map(uc, trunc_addr, 2 * 1024 * 1024, UC_PROT_ALL); - - if (uc_mem_write(uc, addr, &code, sizeof(code))) { - printf("error on write\n"); - return -2; - } - - uc_reg_write(uc, UC_ARM64_REG_X0, &x0); - uc_reg_write(uc, UC_ARM64_REG_X1, &x1); - - if (uc_emu_start(uc, addr, addr + sizeof(code), 0, 0)) { - printf("error on start\n"); - return -3; - } - - uc_reg_read(uc, UC_ARM64_REG_X0, &x0); - uc_reg_read(uc, UC_ARM64_REG_X1, &x1); - - printf("x0: %#llx\n", x0); - printf("x1: %#llx\n", x1); + *state = uc; return 0; } + +/* Called after every test to clean up */ +static int teardown(void **state) +{ + printf("[+] Exiting...\n"); + uc_engine *uc = *state; + + uc_close(uc); + + *state = NULL; + return 0; +} + +void ayy(void **state) +{ + uint32_t code[] = { + 0xd503201f, /* NOP */ + 0xd503201f, /* NOP */ + 0xd503201f, /* NOP */ + 0xaa0103e0 /* MOV X0, X1 */ + }; + + uc_engine *uc = *state; + + uint64_t x0 = 0; + uint64_t x1 = 1; + + uint64_t addr = 0x13f0; + uint64_t trunc_addr = trunc_page(addr); // round down to nearest page + + uc_mem_map(uc, trunc_addr, 2 * 1024 * 1024, UC_PROT_ALL); + + if (uc_mem_write(uc, addr, &code, sizeof(code))) { + printf("error on write\n"); + return; + } + + uc_reg_write(uc, UC_ARM64_REG_X0, &x0); + uc_reg_write(uc, UC_ARM64_REG_X1, &x1); + + if (uc_emu_start(uc, addr, addr + sizeof(code), 0, 0)) { + printf("error on start\n"); + return; + } + + uc_reg_read(uc, UC_ARM64_REG_X0, &x0); + uc_reg_read(uc, UC_ARM64_REG_X1, &x1); + + printf("x0: %#llx\n", x0); + printf("x1: %#llx\n", x1); +} + +int main(int argc, const char * argv[]) { + + const struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown(ayy, init, teardown), + }; + + return cmocka_run_group_tests(tests, NULL, NULL);; +} From 9b46a22cd52aaf61bf17fd3904f912f5a5123d5a Mon Sep 17 00:00:00 2001 From: nuko32 Date: Wed, 15 Jun 2016 20:52:28 +0200 Subject: [PATCH 3/3] final refactoring for test_hang --- tests/unit/test_hang.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/tests/unit/test_hang.c b/tests/unit/test_hang.c index c1812745..4f7a8fef 100644 --- a/tests/unit/test_hang.c +++ b/tests/unit/test_hang.c @@ -39,7 +39,7 @@ static int teardown(void **state) return 0; } -void ayy(void **state) +void test_hang(void **state) { uint32_t code[] = { 0xd503201f, /* NOP */ @@ -53,7 +53,20 @@ void ayy(void **state) uint64_t x0 = 0; uint64_t x1 = 1; - uint64_t addr = 0x13f0; + /* + * emulation will hang if some instruction hits every quarter of a page, + * i.e. these offsets: + * 0x1400, 0x1800, 0x1c00, 0x2000 + * + * in this test, the code to be emulated is mapped just before the 0x1400 + * offset, so that the final instruction emulated (MOV X0, X1) hits the offset, + * causing the hang. + * If you try to write the code just four bytes behind, the hang doesn't occur. + * + * So far, this strange behaviour has only been observed with AArch64 Unicorn APIs. + */ + + uint64_t addr = 0x13f0; // try to map at (0x13f0 - 0x4) and the hang doesn't occur uint64_t trunc_addr = trunc_page(addr); // round down to nearest page uc_mem_map(uc, trunc_addr, 2 * 1024 * 1024, UC_PROT_ALL); @@ -81,7 +94,7 @@ void ayy(void **state) int main(int argc, const char * argv[]) { const struct CMUnitTest tests[] = { - cmocka_unit_test_setup_teardown(ayy, init, teardown), + cmocka_unit_test_setup_teardown(test_hang, init, teardown), }; return cmocka_run_group_tests(tests, NULL, NULL);;