From 8ec8c85e0bb3d7c49696f12e8ebdf4723668683f Mon Sep 17 00:00:00 2001 From: samothtronicien Date: Thu, 28 Jul 2016 22:35:58 +0200 Subject: [PATCH 01/11] added regress test for X86 Test a bug with the SHL instruction. --- test_x86_shl.cpp | 115 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 test_x86_shl.cpp diff --git a/test_x86_shl.cpp b/test_x86_shl.cpp new file mode 100644 index 00000000..52642f8b --- /dev/null +++ b/test_x86_shl.cpp @@ -0,0 +1,115 @@ +#include +#include +#include + + +void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + uint32_t eax = 0, eflags = 0; + uc_reg_read(uc, UC_X86_REG_EAX, &eax); + uc_reg_read(uc, UC_X86_REG_EFLAGS, &eflags); + printf("eip=%08x - eax=%08x - eflags=%08X\n", (uint32_t)address, eax, eflags); +} + +const char code32_prob[] = { + 0xB8, 0x3C, 0x00, 0x00, 0x00, //0x100000: mov eax, 3Ch + 0xB1, 0x02, //0x100005: mov cl, 2 + 0xD3, 0xE0, //0x100007: shl eax, cl <- do not set PF + 0x33, 0xC0 //0x100009: xor eax, eax +}; + +const char code32_ok[] = { + 0xB8, 0x3C, 0x00, 0x00, 0x00, //0x100000: mov eax, 3Ch + 0xC1, 0xE0, 0x02, //0x100005: shl eax, 2 <- set PF correctly + 0x33, 0xC0 //0x100007: xor eax, eax +}; + +const char code16_prob[] = { + 0x66, 0xB8, 0x3C, 0x00, //0x100000: mov ax, 3Ch + 0xB1, 0x02, //0x100004: mov cl, 2 + 0x66, 0xD3, 0xE0, //0x100006: shl ax, cl + 0x33, 0xC0 //0x100009: xor eax, eax +}; + +const char code16_ok[] = { + 0x66, 0xB8, 0x3C, 0x00, //0x100000: mov ax, 3Ch + 0x66, 0xC1, 0xE0, 0x02, //0x100004: shl ax, 2 + 0x33, 0xC0 //0x100008: xor eax, eax +}; + +const char code8_prob[] = { + 0xB0, 0x3C, //0x100000: mov al, 3Ch + 0xB1, 0x02, //0x100002: mov cl, 2 + 0xD2, 0xE0, //0x100004: shl al, 2 + 0x33, 0xC0 //0x100006: xor eax, eax +}; + +const char code8_ok[] = { + 0xB0, 0x3C, //0x100000: mov al, 3Ch + 0xC0, 0xE0, 0x02, //0x100002: shl al, 2 + 0x33, 0xC0 //0x100005: xor eax, eax +}; + +#define ADDR_START 0x100000 + +#define TEST(X) if((X) != UC_ERR_OK) { \ + printf("error: '" #X "' failed\n"); \ + return 1; \ + } + +int main() +{ + uc_engine * uc = NULL; + + TEST(uc_open(UC_ARCH_X86, UC_MODE_32, &uc)); + + uc_hook trace_hook_code; + TEST(uc_hook_add(uc, &trace_hook_code, UC_HOOK_CODE, hook_code, NULL, 1, 0)); + TEST(uc_mem_map(uc, ADDR_START, 0x1000, UC_PROT_READ | UC_PROT_EXEC)); + + //32 bits + TEST(uc_mem_write(uc, ADDR_START, code32_prob, sizeof(code32_prob))); + printf("running code_prob\n"); + TEST(uc_emu_start(uc, ADDR_START, ADDR_START + sizeof(code32_prob) - 1, 0, 4)); + + uint32_t eflags = 0; + uc_reg_write(uc, UC_X86_REG_EFLAGS, &eflags); + + TEST(uc_mem_write(uc, ADDR_START, code32_ok, sizeof(code32_ok))); + printf("running code_ok\n"); + TEST(uc_emu_start(uc, ADDR_START, ADDR_START + sizeof(code32_ok) - 1, 0, 3)); + + //16 bits + eflags = 0; + uc_reg_write(uc, UC_X86_REG_EFLAGS, &eflags); + + TEST(uc_mem_write(uc, ADDR_START, code16_prob, sizeof(code16_prob))); + printf("running code16_prob\n"); + TEST(uc_emu_start(uc, ADDR_START, ADDR_START + sizeof(code16_prob) - 1, 0, 4)); + + eflags = 0; + uc_reg_write(uc, UC_X86_REG_EFLAGS, &eflags); + + TEST(uc_mem_write(uc, ADDR_START, code16_ok, sizeof(code16_ok))); + printf("running code16_ok\n"); + TEST(uc_emu_start(uc, ADDR_START, ADDR_START + sizeof(code16_ok) - 1, 0, 3)); + + //8 bits + eflags = 0; + uc_reg_write(uc, UC_X86_REG_EFLAGS, &eflags); + + TEST(uc_mem_write(uc, ADDR_START, code8_prob, sizeof(code8_prob))); + printf("running code8_prob\n"); + TEST(uc_emu_start(uc, ADDR_START, ADDR_START + sizeof(code8_prob) - 1, 0, 4)); + + eflags = 0; + uc_reg_write(uc, UC_X86_REG_EFLAGS, &eflags); + + TEST(uc_mem_write(uc, ADDR_START, code8_ok, sizeof(code8_ok))); + printf("running code8_ok\n"); + TEST(uc_emu_start(uc, ADDR_START, ADDR_START + sizeof(code8_ok) - 1, 0, 3)); + + TEST(uc_close(uc)); + + return 0; +} From 2ba32922e41e579f91d9f4a256c67cdf9eea2fe0 Mon Sep 17 00:00:00 2001 From: samothtronicien Date: Fri, 29 Jul 2016 12:00:48 +0200 Subject: [PATCH 02/11] Moved test_x86_shl.cpp to tests/regress --- test_x86_shl.cpp => tests/regress/test_x86_shl.cpp | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test_x86_shl.cpp => tests/regress/test_x86_shl.cpp (100%) diff --git a/test_x86_shl.cpp b/tests/regress/test_x86_shl.cpp similarity index 100% rename from test_x86_shl.cpp rename to tests/regress/test_x86_shl.cpp From 6fc1f274920165edb7f89c91848076b100b9e58e Mon Sep 17 00:00:00 2001 From: samothtronicien Date: Fri, 29 Jul 2016 18:52:53 +0200 Subject: [PATCH 03/11] completed the test The issue noticed before only occurs while we are in the hook_code (eflags is not correctly updated after the execution of the SHL instruction using CL). Once the emulation has finished executing the code the value of eflags is correct. --- tests/regress/test_x86_shl.cpp | 148 ++++++++++++++++++++++----------- 1 file changed, 99 insertions(+), 49 deletions(-) diff --git a/tests/regress/test_x86_shl.cpp b/tests/regress/test_x86_shl.cpp index 52642f8b..41955b61 100644 --- a/tests/regress/test_x86_shl.cpp +++ b/tests/regress/test_x86_shl.cpp @@ -1,55 +1,96 @@ #include #include +#include #include +#ifdef _WIN32 +# include +# define printf OutputDebugStringA +#endif + +char buffer[256]; void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) { - uint32_t eax = 0, eflags = 0; + uint32_t eax = 0, ebx = 0, eflags = 0; uc_reg_read(uc, UC_X86_REG_EAX, &eax); + uc_reg_read(uc, UC_X86_REG_EBX, &ebx); uc_reg_read(uc, UC_X86_REG_EFLAGS, &eflags); - printf("eip=%08x - eax=%08x - eflags=%08X\n", (uint32_t)address, eax, eflags); + sprintf(buffer, "eip=%08x - eax=%08x - ebx=%08x - eflags=%08X\n", (uint32_t)address, eax, ebx, eflags); + printf(buffer); } const char code32_prob[] = { - 0xB8, 0x3C, 0x00, 0x00, 0x00, //0x100000: mov eax, 3Ch + 0xBB, 0x3C, 0x00, 0x00, 0x00, //0x100000: mov ebx, 3Ch 0xB1, 0x02, //0x100005: mov cl, 2 - 0xD3, 0xE0, //0x100007: shl eax, cl <- do not set PF - 0x33, 0xC0 //0x100009: xor eax, eax + 0xD3, 0xE3, //0x100007: shl ebx, cl + 0x9F, //0x100009: lahf + 0xCC //0x10000A: int3 }; const char code32_ok[] = { - 0xB8, 0x3C, 0x00, 0x00, 0x00, //0x100000: mov eax, 3Ch - 0xC1, 0xE0, 0x02, //0x100005: shl eax, 2 <- set PF correctly - 0x33, 0xC0 //0x100007: xor eax, eax + 0xBB, 0x3C, 0x00, 0x00, 0x00, //0x100000: mov ebx, 3Ch + 0xC1, 0xE3, 0x02, //0x100005: shl ebx, 2 + 0x9F, //0x100008: lahf + 0xCC //0x100009: int3 }; const char code16_prob[] = { - 0x66, 0xB8, 0x3C, 0x00, //0x100000: mov ax, 3Ch + 0x66, 0xBB, 0x3C, 0x00, //0x100000: mov bx, 3Ch 0xB1, 0x02, //0x100004: mov cl, 2 - 0x66, 0xD3, 0xE0, //0x100006: shl ax, cl - 0x33, 0xC0 //0x100009: xor eax, eax + 0x66, 0xD3, 0xE3, //0x100006: shl bx, cl + 0x9F, //0x100009: lahf + 0xCC //0x10000A: int3 }; const char code16_ok[] = { - 0x66, 0xB8, 0x3C, 0x00, //0x100000: mov ax, 3Ch - 0x66, 0xC1, 0xE0, 0x02, //0x100004: shl ax, 2 - 0x33, 0xC0 //0x100008: xor eax, eax + 0x66, 0xBB, 0x3C, 0x00, //0x100000: mov bx, 3Ch + 0x66, 0xC1, 0xE3, 0x02, //0x100004: shl bx, 2 + 0x9F, //0x100008: lahf + 0xCC //0x10000A: int3 }; const char code8_prob[] = { - 0xB0, 0x3C, //0x100000: mov al, 3Ch + 0xB3, 0x3C, //0x100000: mov bl, 3Ch 0xB1, 0x02, //0x100002: mov cl, 2 - 0xD2, 0xE0, //0x100004: shl al, 2 - 0x33, 0xC0 //0x100006: xor eax, eax + 0xD2, 0xE3, //0x100004: shl bl, 2 + 0x9F, //0x100006: lahf + 0xCC //0x100007: int3 }; const char code8_ok[] = { - 0xB0, 0x3C, //0x100000: mov al, 3Ch - 0xC0, 0xE0, 0x02, //0x100002: shl al, 2 - 0x33, 0xC0 //0x100005: xor eax, eax + 0xB3, 0x3C, //0x100000: mov bl, 3Ch + 0xC0, 0xE3, 0x02, //0x100002: shl bl, 2 + 0x9F, //0x100005: lahf + 0xCC //0x100006: int3 }; +const char code_SHL_JP_CL[] = { + 0xB4, 0x00, //0x100000: mov ah, 0 + 0x9E, //0x100002: sahf + 0xB8, 0x3C, 0x00, 0x00, 0x00, //0x100003: mov eax, 3Ch + 0xB1, 0x02, //0x100008: mov cl, 2 + 0xD3, 0xE0, //0x10000A: shl eax, cl + 0x7A, 0x07, //0x10000C: jp +7 + 0xB8, 0x00, 0x00, 0x00, 0x00, //0x10000E: mov eax, 0 + 0xEB, 0x05, //0x100014: jmp +5 + 0xB8, 0x01, 0x00, 0x00, 0x00, //0x100016: mov eax, 1 + 0xCC //0x10001B: int3 +}; + +const char code_SHL_JP_NOCL[] = { + 0xB4, 0x00, //0x100000: mov ah, 0 + 0x9E, //0x100002: sahf + 0xB8, 0x3C, 0x00, 0x00, 0x00, //0x100003: mov eax, 3Ch + 0xC1, 0xE0, 0x02, //0x100008: shl eax, 2 + 0x7A, 0x07, //0x10000B: jp +7 + 0xB8, 0x00, 0x00, 0x00, 0x00, //0x10000D: mov eax, 0 + 0xEB, 0x05, //0x100014: + 0xB8, 0x01, 0x00, 0x00, 0x00, //0x100016: mov eax, 1 + 0xCC //0x100017: int3 +}; + + #define ADDR_START 0x100000 #define TEST(X) if((X) != UC_ERR_OK) { \ @@ -59,6 +100,7 @@ const char code8_ok[] = { int main() { + uint32_t eflags = 0, eax = 0; uc_engine * uc = NULL; TEST(uc_open(UC_ARCH_X86, UC_MODE_32, &uc)); @@ -67,47 +109,55 @@ int main() TEST(uc_hook_add(uc, &trace_hook_code, UC_HOOK_CODE, hook_code, NULL, 1, 0)); TEST(uc_mem_map(uc, ADDR_START, 0x1000, UC_PROT_READ | UC_PROT_EXEC)); +#define RUN_CODE(CODE) { \ + TEST(uc_mem_write(uc, ADDR_START, CODE, sizeof(CODE))); \ + printf("running " #CODE "...\n"); \ + eflags = 0; \ + uc_reg_write(uc, UC_X86_REG_EFLAGS, &eflags); \ + TEST(uc_emu_start(uc, ADDR_START, ADDR_START + sizeof(CODE) - 1, 0, 0)); \ + uc_reg_read(uc, UC_X86_REG_EFLAGS, &eflags); \ + uc_reg_read(uc, UC_X86_REG_EAX, &eax); \ + sprintf(buffer, "after uc_emu_start: eflags=%08X - ah=%08X - %s\n", eflags, (eax>>8) & 0xFF, eflags & 4 ? "success" : "failed"); \ + printf(buffer); \ +} + //32 bits - TEST(uc_mem_write(uc, ADDR_START, code32_prob, sizeof(code32_prob))); - printf("running code_prob\n"); - TEST(uc_emu_start(uc, ADDR_START, ADDR_START + sizeof(code32_prob) - 1, 0, 4)); - - uint32_t eflags = 0; - uc_reg_write(uc, UC_X86_REG_EFLAGS, &eflags); - - TEST(uc_mem_write(uc, ADDR_START, code32_ok, sizeof(code32_ok))); - printf("running code_ok\n"); - TEST(uc_emu_start(uc, ADDR_START, ADDR_START + sizeof(code32_ok) - 1, 0, 3)); + RUN_CODE(code32_prob); + RUN_CODE(code32_ok); //16 bits - eflags = 0; - uc_reg_write(uc, UC_X86_REG_EFLAGS, &eflags); - - TEST(uc_mem_write(uc, ADDR_START, code16_prob, sizeof(code16_prob))); - printf("running code16_prob\n"); - TEST(uc_emu_start(uc, ADDR_START, ADDR_START + sizeof(code16_prob) - 1, 0, 4)); - - eflags = 0; - uc_reg_write(uc, UC_X86_REG_EFLAGS, &eflags); - - TEST(uc_mem_write(uc, ADDR_START, code16_ok, sizeof(code16_ok))); - printf("running code16_ok\n"); - TEST(uc_emu_start(uc, ADDR_START, ADDR_START + sizeof(code16_ok) - 1, 0, 3)); + RUN_CODE(code16_prob); + RUN_CODE(code16_ok); //8 bits + RUN_CODE(code8_prob); + RUN_CODE(code8_ok); + + //test with JP-CL eflags = 0; uc_reg_write(uc, UC_X86_REG_EFLAGS, &eflags); - TEST(uc_mem_write(uc, ADDR_START, code8_prob, sizeof(code8_prob))); - printf("running code8_prob\n"); - TEST(uc_emu_start(uc, ADDR_START, ADDR_START + sizeof(code8_prob) - 1, 0, 4)); + TEST(uc_mem_write(uc, ADDR_START, code_SHL_JP_CL, sizeof(code_SHL_JP_CL))); + printf("running code_SHL_JP_CL ...\n"); + TEST(uc_emu_start(uc, ADDR_START, ADDR_START + sizeof(code_SHL_JP_CL) - 1, 0, 0)); + eax = 0; + uc_reg_read(uc, UC_X86_REG_EAX, &eax); + if (eax == 1) printf("success\n"); + else printf("failed\n"); + + //test with JP-NOCL eflags = 0; uc_reg_write(uc, UC_X86_REG_EFLAGS, &eflags); - TEST(uc_mem_write(uc, ADDR_START, code8_ok, sizeof(code8_ok))); - printf("running code8_ok\n"); - TEST(uc_emu_start(uc, ADDR_START, ADDR_START + sizeof(code8_ok) - 1, 0, 3)); + TEST(uc_mem_write(uc, ADDR_START, code_SHL_JP_NOCL, sizeof(code_SHL_JP_NOCL))); + printf("running code_SHL_JP_NOCL ...\n"); + TEST(uc_emu_start(uc, ADDR_START, ADDR_START + sizeof(code_SHL_JP_NOCL) - 1, 0, 0)); + + eax = 0; + uc_reg_read(uc, UC_X86_REG_EAX, &eax); + if (eax == 1) printf("success\n"); + else printf("failed\n"); TEST(uc_close(uc)); From 6c3eecb2a36d202d583687199d01846537646785 Mon Sep 17 00:00:00 2001 From: samothtronicien Date: Sat, 30 Jul 2016 04:18:12 +0200 Subject: [PATCH 04/11] added unit test for x86 This test highlight the issue with the SHL instruction in the form (SHL r, CL), the flags values retrieved in the code hook are not correct. --- tests/unit/test_x86_shl.cpp | 228 ++++++++++++++++++++++++++++++++++++ 1 file changed, 228 insertions(+) create mode 100644 tests/unit/test_x86_shl.cpp diff --git a/tests/unit/test_x86_shl.cpp b/tests/unit/test_x86_shl.cpp new file mode 100644 index 00000000..809390db --- /dev/null +++ b/tests/unit/test_x86_shl.cpp @@ -0,0 +1,228 @@ +#include +#include + +extern "C" +{ +#include "unicorn_test.h" +} + + +#define OK(x) uc_assert_success(x) + +#define CF_MASK (1<<0) +#define PF_MASK (1<<2) +#define ZF_MASK (1<<6) +#define SF_MASK (1<<7) +#define OF_MASK (1<<11) +#define ALL_MASK (OF_MASK|SF_MASK|ZF_MASK|PF_MASK|CF_MASK) + + +struct instruction +{ + std::vector code; + const char* asmStr; + struct reg_value { + uint32_t regId, regValue, mask; + reg_value(uint32_t _rid, uint32_t _rval, uint32_t _msk = 0xFFFFFFFF) : regId(_rid), regValue(_rval), mask(_msk) + {} + }; + std::vector values; +}; + +struct exec_state +{ + uint32_t curr; + std::vector insts; +}; + +const char* getRegisterName(uint32_t _regid) +{ + switch (_regid) + { + //8 + case UC_X86_REG_AH: return "AH"; + case UC_X86_REG_AL: return "AL"; + case UC_X86_REG_BH: return "BH"; + case UC_X86_REG_BL: return "BL"; + case UC_X86_REG_CL: return "CL"; + case UC_X86_REG_CH: return "CH"; + case UC_X86_REG_DH: return "DH"; + case UC_X86_REG_DL: return "DL"; + //16 + case UC_X86_REG_AX: return "AX"; + case UC_X86_REG_BX: return "BX"; + case UC_X86_REG_CX: return "CX"; + case UC_X86_REG_DX: return "DX"; + //32 + case UC_X86_REG_EAX: return "EAX"; + case UC_X86_REG_EBX: return "EBX"; + case UC_X86_REG_ECX: return "ECX"; + case UC_X86_REG_EDX: return "EDX"; + case UC_X86_REG_EDI: return "EDI"; + case UC_X86_REG_ESI: return "ESI"; + case UC_X86_REG_EBP: return "EBP"; + case UC_X86_REG_ESP: return "ESP"; + case UC_X86_REG_EIP: return "EIP"; + case UC_X86_REG_EFLAGS: return "EFLAGS"; + + default: fail(); + } +} + +uint32_t getRegisterValue(uc_engine *uc, uint32_t _regid) +{ + switch (_regid) + { + //8 + case UC_X86_REG_AH: case UC_X86_REG_AL: + case UC_X86_REG_BH: case UC_X86_REG_BL: + case UC_X86_REG_CL: case UC_X86_REG_CH: + case UC_X86_REG_DH: case UC_X86_REG_DL: + { + uint8_t val = 0; + uc_reg_read(uc, _regid, &val); + return val; + } + //16 + case UC_X86_REG_AX: case UC_X86_REG_BX: + case UC_X86_REG_CX: case UC_X86_REG_DX: + { + uint16_t val = 0; + uc_reg_read(uc, _regid, &val); + return val; + } + //32 + case UC_X86_REG_EAX: case UC_X86_REG_EBX: + case UC_X86_REG_ECX: case UC_X86_REG_EDX: + case UC_X86_REG_EDI: case UC_X86_REG_ESI: + case UC_X86_REG_EBP: case UC_X86_REG_ESP: + case UC_X86_REG_EIP: case UC_X86_REG_EFLAGS: + { + uint32_t val = 0; + uc_reg_read(uc, _regid, &val); + return val; + } + + default: fail(); + } +} + +void hook_code_test_i386_shl(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + exec_state* es = (exec_state*)user_data; + + print_message("\teip=%08x - %s\n", (uint32_t)address, es->insts[es->curr].asmStr); + + std::vector& rval = es->insts[es->curr].values; + for (auto& v : rval) + { + uint32_t regValue = getRegisterValue(uc, v.regId); + print_message("\t\ttesting %s : ", getRegisterName(v.regId)); + assert_int_equal(regValue & v.mask, v.regValue); + print_message("ok\n"); + } + + es->curr++; +} + +std::vector codeSHL_prob = { + { { 0xBB, 0x3C, 0x00, 0x00, 0x00 }, "mov ebx, 3Ch", {} }, + { { 0xB1, 0x02 }, "mov cl, 2", { { UC_X86_REG_EBX, 0x3C } } }, + { { 0xD3, 0xE3 }, "shl ebx, cl", { { UC_X86_REG_EBX, 0x3C }, { UC_X86_REG_CL, 0x2 } } }, + { { 0x9F }, "lahf", { { UC_X86_REG_EBX, 0xF0 }, { UC_X86_REG_CL, 0x2 }, { UC_X86_REG_EFLAGS, 0x4, ALL_MASK } } }, + { { 0xCC }, "int3", { { UC_X86_REG_AH, 0x4, PF_MASK }, { UC_X86_REG_EBX, 0xF0 }, { UC_X86_REG_CL, 0x2 }, { UC_X86_REG_EFLAGS, 0x4, ALL_MASK } } } +}; + +std::vector codeSHL_ok = { + { { 0xBB, 0x3C, 0x00, 0x00, 0x00 }, "mov ebx, 3Ch", {} }, + { { 0xC1, 0xE3, 0x02 }, "shl ebx, 2", { { UC_X86_REG_EBX, 0x3C } } }, + { { 0x9F }, "lahf", { { UC_X86_REG_EBX, 0xF0 }, { UC_X86_REG_EFLAGS, 0x4, ALL_MASK } } }, + { { 0xCC }, "int3", { { UC_X86_REG_AH, 0x4, PF_MASK }, { UC_X86_REG_EBX, 0xF0 }, { UC_X86_REG_EFLAGS, 0x4, ALL_MASK } } } +}; + +uint32_t loadCode(uc_engine *_uc, const std::vector& _insts, uint32_t _at) +{ + std::vector code; + for (auto& inst : _insts) + code.insert(code.end(), inst.code.begin(), inst.code.end()); + + OK(uc_mem_write(_uc, _at, code.data(), code.size())); + + return code.size(); +} + +#define ADDR_START 0x100000 + +static void test_i386_shl_prob(void **state) +{ + uc_engine *uc; + uc_err err; + uc_hook trace1; + + // Initialize emulator in X86-32bit mode + OK(uc_open(UC_ARCH_X86, UC_MODE_32, &uc)); + OK(uc_mem_map(uc, ADDR_START, 0x1000, UC_PROT_ALL)); + + uint32_t codeSize = loadCode(uc, codeSHL_prob, ADDR_START); + + exec_state es; + es.curr = 0; + es.insts = codeSHL_prob; + + // initialize machine registers + uint32_t zero = 0; + OK(uc_reg_write(uc, UC_X86_REG_EAX, &zero)); + OK(uc_reg_write(uc, UC_X86_REG_EBX, &zero)); + OK(uc_reg_write(uc, UC_X86_REG_ECX, &zero)); + OK(uc_reg_write(uc, UC_X86_REG_EDX, &zero)); + + OK(uc_hook_add(uc, &trace1, UC_HOOK_CODE, hook_code_test_i386_shl, &es, 1, 0)); + + // emulate machine code in infinite time + OK(uc_emu_start(uc, ADDR_START, ADDR_START + codeSize - 1, 0, 0)); + + uc_close(uc); +} + +static void test_i386_shl_ok(void **state) +{ + uc_engine *uc; + uc_err err; + uc_hook trace1; + + // Initialize emulator in X86-32bit mode + OK(uc_open(UC_ARCH_X86, UC_MODE_32, &uc)); + OK(uc_mem_map(uc, ADDR_START, 0x1000, UC_PROT_ALL)); + + uint32_t codeSize = loadCode(uc, codeSHL_ok, ADDR_START); + + exec_state es; + es.curr = 0; + es.insts = codeSHL_ok; + + // initialize machine registers + uint32_t zero = 0; + OK(uc_reg_write(uc, UC_X86_REG_EAX, &zero)); + OK(uc_reg_write(uc, UC_X86_REG_EBX, &zero)); + OK(uc_reg_write(uc, UC_X86_REG_ECX, &zero)); + OK(uc_reg_write(uc, UC_X86_REG_EDX, &zero)); + + OK(uc_hook_add(uc, &trace1, UC_HOOK_CODE, hook_code_test_i386_shl, &es, 1, 0)); + + // emulate machine code in infinite time + OK(uc_emu_start(uc, ADDR_START, ADDR_START + codeSize - 1, 0, 0)); + + uc_close(uc); +} + +/******************************************************************************/ + +int main(void) { + const struct CMUnitTest tests[] = { + + cmocka_unit_test(test_i386_shl_prob), + cmocka_unit_test(test_i386_shl_ok), + + }; + return cmocka_run_group_tests(tests, NULL, NULL); +} From c1cd06ec522ff29a63b2c33014ad73225faf2d58 Mon Sep 17 00:00:00 2001 From: samothtronicien Date: Sat, 30 Jul 2016 16:41:40 +0200 Subject: [PATCH 05/11] ported test to C --- tests/unit/test_x86_shl.c | 308 ++++++++++++++++++++++++++++++++++++ tests/unit/test_x86_shl.cpp | 228 -------------------------- 2 files changed, 308 insertions(+), 228 deletions(-) create mode 100644 tests/unit/test_x86_shl.c delete mode 100644 tests/unit/test_x86_shl.cpp diff --git a/tests/unit/test_x86_shl.c b/tests/unit/test_x86_shl.c new file mode 100644 index 00000000..33a7271f --- /dev/null +++ b/tests/unit/test_x86_shl.c @@ -0,0 +1,308 @@ +#include + +#include "unicorn_test.h" + + +#define OK(x) uc_assert_success(x) + +#define CF_MASK (1<<0) +#define PF_MASK (1<<2) +#define ZF_MASK (1<<6) +#define SF_MASK (1<<7) +#define OF_MASK (1<<11) +#define ALL_MASK (OF_MASK|SF_MASK|ZF_MASK|PF_MASK|CF_MASK) +#define NO_MASK 0xFFFFFFFF + +typedef struct _reg_value +{ + uint32_t regId, regValue, mask; +} reg_value; + +typedef struct _instruction +{ + const char* asmStr; + const uint8_t* code; + uint32_t codeSize; + const reg_value* values; + uint32_t nbValues; +} instruction; + +typedef struct _block +{ + instruction* insts[255]; + uint32_t nbInsts; + uint32_t size; +} block; + +typedef struct _exec_state +{ + uint32_t curr; + block* block; +} exec_state; + +/******************************************************************************/ + +#define CAT2(X, Y) X ## Y +#define CAT(X, Y) CAT2(X, Y) + +#define ADD_INSTRUCTION(BLOCK, CODE_ASM, CODE, REGVALUES) \ + const uint8_t CAT(code, __LINE__)[] = CODE; \ + const reg_value CAT(regValues, __LINE__)[] = REGVALUES; \ + inst = newInstruction(CAT(code, __LINE__), sizeof(CAT(code, __LINE__)), CODE_ASM, CAT(regValues, __LINE__), sizeof(CAT(regValues, __LINE__)) / sizeof(reg_value)); \ + addInstructionToBlock(BLOCK, inst); + +#define V(...) { __VA_ARGS__ } + +/******************************************************************************/ + +instruction* newInstruction(const uint8_t * _code, uint32_t _codeSize, const char* _asmStr, const reg_value* _values, uint32_t _nbValues); +void addInstructionToBlock(block* _b, instruction* _i); +uint32_t loadBlock(uc_engine *_uc, block* _block, uint32_t _at); +void freeBlock(block* _block); +const char* getRegisterName(uint32_t _regid); +uint32_t getRegisterValue(uc_engine *uc, uint32_t _regid); + +/******************************************************************************/ + +void hook_code_test_i386_shl(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + uint32_t i; + exec_state* es = (exec_state*)user_data; + instruction* currInst = es->block->insts[es->curr]; + + print_message("|\teip=%08x - %s\n", (uint32_t)address, es->block->insts[es->curr]->asmStr); + + for (i = 0; i < currInst->nbValues; i++) + { + if (currInst->values[i].regId == UC_X86_REG_INVALID) continue; + uint32_t regValue = getRegisterValue(uc, currInst->values[i].regId); + print_message("|\t\ttesting %s : ", getRegisterName(currInst->values[i].regId)); + assert_int_equal(regValue & currInst->values[i].mask, currInst->values[i].regValue); + print_message("ok\n"); + } + + es->curr++; + if (es->curr >= es->block->nbInsts) + { + print_message("stopping emulation\n"); + uc_emu_stop(uc); + } +} + +#define ADDR_START 0x100000 + +static void test_i386_shl_prob(void **state) +{ + uc_engine *uc; + uc_hook trace1; + + // Initialize emulator in X86-32bit mode + OK(uc_open(UC_ARCH_X86, UC_MODE_32, &uc)); + OK(uc_mem_map(uc, ADDR_START, 0x1000, UC_PROT_ALL)); + + { + exec_state es; + block block_shl_prob; + instruction* inst; + + es.curr = 0; + es.block = &block_shl_prob; + + block_shl_prob.nbInsts = 0; + + ADD_INSTRUCTION(&block_shl_prob, "mov ebx, 3Ch", V(0xBB, 0x3C, 0x00, 0x00, 0x00), V(V(UC_X86_REG_INVALID, 0x0, NO_MASK))); + ADD_INSTRUCTION(&block_shl_prob, "mov cl, 2", V(0xB1, 0x02), V(V(UC_X86_REG_EBX, 0x3C, NO_MASK))); + ADD_INSTRUCTION(&block_shl_prob, "shl ebx, cl", V(0xD3, 0xE3), V(V(UC_X86_REG_EBX, 0x3C, NO_MASK), V(UC_X86_REG_CL, 0x2, NO_MASK))); + ADD_INSTRUCTION(&block_shl_prob, "lahf", V(0x9F), V(V(UC_X86_REG_EBX, 0xF0, NO_MASK), V(UC_X86_REG_CL, 0x2, NO_MASK), V(UC_X86_REG_EFLAGS, 0x4, ALL_MASK))); + ADD_INSTRUCTION(&block_shl_prob, "int3", V(0xCC), V(V(UC_X86_REG_AH, 0x4, PF_MASK), V(UC_X86_REG_EBX, 0xF0, NO_MASK), V(UC_X86_REG_CL, 0x2, NO_MASK), V(UC_X86_REG_EFLAGS, 0x4, ALL_MASK))); + + loadBlock(uc, &block_shl_prob, ADDR_START); + + // initialize machine registers + uint32_t zero = 0; + OK(uc_reg_write(uc, UC_X86_REG_EAX, &zero)); + OK(uc_reg_write(uc, UC_X86_REG_EBX, &zero)); + OK(uc_reg_write(uc, UC_X86_REG_ECX, &zero)); + OK(uc_reg_write(uc, UC_X86_REG_EDX, &zero)); + + OK(uc_hook_add(uc, &trace1, UC_HOOK_CODE, hook_code_test_i386_shl, &es, 1, 0)); + + // emulate machine code in infinite time + OK(uc_emu_start(uc, ADDR_START, ADDR_START + block_shl_prob.size - 1, 0, 0)); + + freeBlock(&block_shl_prob); + } + + uc_close(uc); +} + +static void test_i386_shl_ok(void **state) +{ + uc_engine *uc; + uc_hook trace1; + + // Initialize emulator in X86-32bit mode + OK(uc_open(UC_ARCH_X86, UC_MODE_32, &uc)); + OK(uc_mem_map(uc, ADDR_START, 0x1000, UC_PROT_ALL)); + + { + exec_state es; + block block_shl_ok; + instruction* inst; + + es.curr = 0; + es.block = &block_shl_ok; + + block_shl_ok.nbInsts = 0; + + ADD_INSTRUCTION(&block_shl_ok, "mov ebx, 3Ch", V(0xBB, 0x3C, 0x00, 0x00, 0x00), V(V(UC_X86_REG_INVALID, 0x0, NO_MASK))); + ADD_INSTRUCTION(&block_shl_ok, "shl ebx, 2", V(0xC1, 0xE3, 0x02), V(V(UC_X86_REG_EBX, 0x3C, NO_MASK))); + ADD_INSTRUCTION(&block_shl_ok, "lahf", V(0x9F), V(V(UC_X86_REG_EBX, 0xF0, NO_MASK), V(UC_X86_REG_EFLAGS, 0x4, ALL_MASK))); + ADD_INSTRUCTION(&block_shl_ok, "int3", V(0xCC), V(V(UC_X86_REG_AH, 0x4, PF_MASK), V(UC_X86_REG_EBX, 0xF0, NO_MASK), V(UC_X86_REG_EFLAGS, 0x4, ALL_MASK))); + + loadBlock(uc, &block_shl_ok, ADDR_START); + + // initialize machine registers + uint32_t zero = 0; + OK(uc_reg_write(uc, UC_X86_REG_EAX, &zero)); + OK(uc_reg_write(uc, UC_X86_REG_EBX, &zero)); + OK(uc_reg_write(uc, UC_X86_REG_ECX, &zero)); + OK(uc_reg_write(uc, UC_X86_REG_EDX, &zero)); + + OK(uc_hook_add(uc, &trace1, UC_HOOK_CODE, hook_code_test_i386_shl, &es, 1, 0)); + + // emulate machine code in infinite time + OK(uc_emu_start(uc, ADDR_START, ADDR_START + block_shl_ok.size - 1, 0, 0)); + + freeBlock(&block_shl_ok); + } + + uc_close(uc); +} + +/******************************************************************************/ + +int main(void) { + const struct CMUnitTest tests[] = { + + cmocka_unit_test(test_i386_shl_prob), + cmocka_unit_test(test_i386_shl_ok), + + }; + return cmocka_run_group_tests(tests, NULL, NULL); +} + +/******************************************************************************/ + +instruction* newInstruction(const uint8_t * _code, uint32_t _codeSize, const char* _asmStr, const reg_value* _values, uint32_t _nbValues) +{ + instruction* inst = (instruction*)malloc(sizeof(instruction)); + + inst->asmStr = _asmStr; + inst->code = _code; + inst->codeSize = _codeSize; + inst->values = _values; + inst->nbValues = _nbValues; + + return inst; +} + +void addInstructionToBlock(block* _b, instruction* _i) +{ + _b->insts[_b->nbInsts++] = _i; +} + +uint32_t loadBlock(uc_engine *_uc, block* _block, uint32_t _at) +{ + uint32_t i, offset; + + for (i = 0, offset = 0; i < _block->nbInsts; i++) + { + OK(uc_mem_write(_uc, _at + offset, _block->insts[i]->code, _block->insts[i]->codeSize)); + offset += _block->insts[i]->codeSize; + } + _block->size = offset; + return offset; +} + +void freeBlock(block* _block) +{ + uint32_t i; + + for (i = 0; i < _block->nbInsts; i++) + free(_block->insts[i]); +} + +const char* getRegisterName(uint32_t _regid) +{ + switch (_regid) + { + //8 + case UC_X86_REG_AH: return "AH"; + case UC_X86_REG_AL: return "AL"; + case UC_X86_REG_BH: return "BH"; + case UC_X86_REG_BL: return "BL"; + case UC_X86_REG_CL: return "CL"; + case UC_X86_REG_CH: return "CH"; + case UC_X86_REG_DH: return "DH"; + case UC_X86_REG_DL: return "DL"; + //16 + case UC_X86_REG_AX: return "AX"; + case UC_X86_REG_BX: return "BX"; + case UC_X86_REG_CX: return "CX"; + case UC_X86_REG_DX: return "DX"; + //32 + case UC_X86_REG_EAX: return "EAX"; + case UC_X86_REG_EBX: return "EBX"; + case UC_X86_REG_ECX: return "ECX"; + case UC_X86_REG_EDX: return "EDX"; + case UC_X86_REG_EDI: return "EDI"; + case UC_X86_REG_ESI: return "ESI"; + case UC_X86_REG_EBP: return "EBP"; + case UC_X86_REG_ESP: return "ESP"; + case UC_X86_REG_EIP: return "EIP"; + case UC_X86_REG_EFLAGS: return "EFLAGS"; + + default: fail(); + } + return "UNKNOWN"; +} + +uint32_t getRegisterValue(uc_engine *uc, uint32_t _regid) +{ + switch (_regid) + { + //8 + case UC_X86_REG_AH: case UC_X86_REG_AL: + case UC_X86_REG_BH: case UC_X86_REG_BL: + case UC_X86_REG_CL: case UC_X86_REG_CH: + case UC_X86_REG_DH: case UC_X86_REG_DL: + { + uint8_t val = 0; + uc_reg_read(uc, _regid, &val); + return val; + } + //16 + case UC_X86_REG_AX: case UC_X86_REG_BX: + case UC_X86_REG_CX: case UC_X86_REG_DX: + { + uint16_t val = 0; + uc_reg_read(uc, _regid, &val); + return val; + } + //32 + case UC_X86_REG_EAX: case UC_X86_REG_EBX: + case UC_X86_REG_ECX: case UC_X86_REG_EDX: + case UC_X86_REG_EDI: case UC_X86_REG_ESI: + case UC_X86_REG_EBP: case UC_X86_REG_ESP: + case UC_X86_REG_EIP: case UC_X86_REG_EFLAGS: + { + uint32_t val = 0; + uc_reg_read(uc, _regid, &val); + return val; + } + + default: fail(); + } + return 0; +} diff --git a/tests/unit/test_x86_shl.cpp b/tests/unit/test_x86_shl.cpp deleted file mode 100644 index 809390db..00000000 --- a/tests/unit/test_x86_shl.cpp +++ /dev/null @@ -1,228 +0,0 @@ -#include -#include - -extern "C" -{ -#include "unicorn_test.h" -} - - -#define OK(x) uc_assert_success(x) - -#define CF_MASK (1<<0) -#define PF_MASK (1<<2) -#define ZF_MASK (1<<6) -#define SF_MASK (1<<7) -#define OF_MASK (1<<11) -#define ALL_MASK (OF_MASK|SF_MASK|ZF_MASK|PF_MASK|CF_MASK) - - -struct instruction -{ - std::vector code; - const char* asmStr; - struct reg_value { - uint32_t regId, regValue, mask; - reg_value(uint32_t _rid, uint32_t _rval, uint32_t _msk = 0xFFFFFFFF) : regId(_rid), regValue(_rval), mask(_msk) - {} - }; - std::vector values; -}; - -struct exec_state -{ - uint32_t curr; - std::vector insts; -}; - -const char* getRegisterName(uint32_t _regid) -{ - switch (_regid) - { - //8 - case UC_X86_REG_AH: return "AH"; - case UC_X86_REG_AL: return "AL"; - case UC_X86_REG_BH: return "BH"; - case UC_X86_REG_BL: return "BL"; - case UC_X86_REG_CL: return "CL"; - case UC_X86_REG_CH: return "CH"; - case UC_X86_REG_DH: return "DH"; - case UC_X86_REG_DL: return "DL"; - //16 - case UC_X86_REG_AX: return "AX"; - case UC_X86_REG_BX: return "BX"; - case UC_X86_REG_CX: return "CX"; - case UC_X86_REG_DX: return "DX"; - //32 - case UC_X86_REG_EAX: return "EAX"; - case UC_X86_REG_EBX: return "EBX"; - case UC_X86_REG_ECX: return "ECX"; - case UC_X86_REG_EDX: return "EDX"; - case UC_X86_REG_EDI: return "EDI"; - case UC_X86_REG_ESI: return "ESI"; - case UC_X86_REG_EBP: return "EBP"; - case UC_X86_REG_ESP: return "ESP"; - case UC_X86_REG_EIP: return "EIP"; - case UC_X86_REG_EFLAGS: return "EFLAGS"; - - default: fail(); - } -} - -uint32_t getRegisterValue(uc_engine *uc, uint32_t _regid) -{ - switch (_regid) - { - //8 - case UC_X86_REG_AH: case UC_X86_REG_AL: - case UC_X86_REG_BH: case UC_X86_REG_BL: - case UC_X86_REG_CL: case UC_X86_REG_CH: - case UC_X86_REG_DH: case UC_X86_REG_DL: - { - uint8_t val = 0; - uc_reg_read(uc, _regid, &val); - return val; - } - //16 - case UC_X86_REG_AX: case UC_X86_REG_BX: - case UC_X86_REG_CX: case UC_X86_REG_DX: - { - uint16_t val = 0; - uc_reg_read(uc, _regid, &val); - return val; - } - //32 - case UC_X86_REG_EAX: case UC_X86_REG_EBX: - case UC_X86_REG_ECX: case UC_X86_REG_EDX: - case UC_X86_REG_EDI: case UC_X86_REG_ESI: - case UC_X86_REG_EBP: case UC_X86_REG_ESP: - case UC_X86_REG_EIP: case UC_X86_REG_EFLAGS: - { - uint32_t val = 0; - uc_reg_read(uc, _regid, &val); - return val; - } - - default: fail(); - } -} - -void hook_code_test_i386_shl(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) -{ - exec_state* es = (exec_state*)user_data; - - print_message("\teip=%08x - %s\n", (uint32_t)address, es->insts[es->curr].asmStr); - - std::vector& rval = es->insts[es->curr].values; - for (auto& v : rval) - { - uint32_t regValue = getRegisterValue(uc, v.regId); - print_message("\t\ttesting %s : ", getRegisterName(v.regId)); - assert_int_equal(regValue & v.mask, v.regValue); - print_message("ok\n"); - } - - es->curr++; -} - -std::vector codeSHL_prob = { - { { 0xBB, 0x3C, 0x00, 0x00, 0x00 }, "mov ebx, 3Ch", {} }, - { { 0xB1, 0x02 }, "mov cl, 2", { { UC_X86_REG_EBX, 0x3C } } }, - { { 0xD3, 0xE3 }, "shl ebx, cl", { { UC_X86_REG_EBX, 0x3C }, { UC_X86_REG_CL, 0x2 } } }, - { { 0x9F }, "lahf", { { UC_X86_REG_EBX, 0xF0 }, { UC_X86_REG_CL, 0x2 }, { UC_X86_REG_EFLAGS, 0x4, ALL_MASK } } }, - { { 0xCC }, "int3", { { UC_X86_REG_AH, 0x4, PF_MASK }, { UC_X86_REG_EBX, 0xF0 }, { UC_X86_REG_CL, 0x2 }, { UC_X86_REG_EFLAGS, 0x4, ALL_MASK } } } -}; - -std::vector codeSHL_ok = { - { { 0xBB, 0x3C, 0x00, 0x00, 0x00 }, "mov ebx, 3Ch", {} }, - { { 0xC1, 0xE3, 0x02 }, "shl ebx, 2", { { UC_X86_REG_EBX, 0x3C } } }, - { { 0x9F }, "lahf", { { UC_X86_REG_EBX, 0xF0 }, { UC_X86_REG_EFLAGS, 0x4, ALL_MASK } } }, - { { 0xCC }, "int3", { { UC_X86_REG_AH, 0x4, PF_MASK }, { UC_X86_REG_EBX, 0xF0 }, { UC_X86_REG_EFLAGS, 0x4, ALL_MASK } } } -}; - -uint32_t loadCode(uc_engine *_uc, const std::vector& _insts, uint32_t _at) -{ - std::vector code; - for (auto& inst : _insts) - code.insert(code.end(), inst.code.begin(), inst.code.end()); - - OK(uc_mem_write(_uc, _at, code.data(), code.size())); - - return code.size(); -} - -#define ADDR_START 0x100000 - -static void test_i386_shl_prob(void **state) -{ - uc_engine *uc; - uc_err err; - uc_hook trace1; - - // Initialize emulator in X86-32bit mode - OK(uc_open(UC_ARCH_X86, UC_MODE_32, &uc)); - OK(uc_mem_map(uc, ADDR_START, 0x1000, UC_PROT_ALL)); - - uint32_t codeSize = loadCode(uc, codeSHL_prob, ADDR_START); - - exec_state es; - es.curr = 0; - es.insts = codeSHL_prob; - - // initialize machine registers - uint32_t zero = 0; - OK(uc_reg_write(uc, UC_X86_REG_EAX, &zero)); - OK(uc_reg_write(uc, UC_X86_REG_EBX, &zero)); - OK(uc_reg_write(uc, UC_X86_REG_ECX, &zero)); - OK(uc_reg_write(uc, UC_X86_REG_EDX, &zero)); - - OK(uc_hook_add(uc, &trace1, UC_HOOK_CODE, hook_code_test_i386_shl, &es, 1, 0)); - - // emulate machine code in infinite time - OK(uc_emu_start(uc, ADDR_START, ADDR_START + codeSize - 1, 0, 0)); - - uc_close(uc); -} - -static void test_i386_shl_ok(void **state) -{ - uc_engine *uc; - uc_err err; - uc_hook trace1; - - // Initialize emulator in X86-32bit mode - OK(uc_open(UC_ARCH_X86, UC_MODE_32, &uc)); - OK(uc_mem_map(uc, ADDR_START, 0x1000, UC_PROT_ALL)); - - uint32_t codeSize = loadCode(uc, codeSHL_ok, ADDR_START); - - exec_state es; - es.curr = 0; - es.insts = codeSHL_ok; - - // initialize machine registers - uint32_t zero = 0; - OK(uc_reg_write(uc, UC_X86_REG_EAX, &zero)); - OK(uc_reg_write(uc, UC_X86_REG_EBX, &zero)); - OK(uc_reg_write(uc, UC_X86_REG_ECX, &zero)); - OK(uc_reg_write(uc, UC_X86_REG_EDX, &zero)); - - OK(uc_hook_add(uc, &trace1, UC_HOOK_CODE, hook_code_test_i386_shl, &es, 1, 0)); - - // emulate machine code in infinite time - OK(uc_emu_start(uc, ADDR_START, ADDR_START + codeSize - 1, 0, 0)); - - uc_close(uc); -} - -/******************************************************************************/ - -int main(void) { - const struct CMUnitTest tests[] = { - - cmocka_unit_test(test_i386_shl_prob), - cmocka_unit_test(test_i386_shl_ok), - - }; - return cmocka_run_group_tests(tests, NULL, NULL); -} From 8120b7732e9204b3ec8d39a76122e0254641b2b5 Mon Sep 17 00:00:00 2001 From: samothtronicien Date: Sat, 30 Jul 2016 16:42:51 +0200 Subject: [PATCH 06/11] added test_x86_shl_pf to makefile --- tests/unit/Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/unit/Makefile b/tests/unit/Makefile index 55f38be5..9f2126e3 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_hang + test_hookcounts test_hang test_x86_shl_pf .PHONY: all all: ${ALL_TESTS} @@ -36,6 +36,7 @@ test: ${ALL_TESTS} ./test_x86_soft_paging ./test_hookcounts ./test_hang + ./test_x86_shl_pf test_sanity: test_sanity.c test_x86: test_x86.c @@ -48,6 +49,7 @@ 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 +test_x86_shl_pf: test_x86_shl_pf.c ${ALL_TESTS}: ${CC} ${CFLAGS} -o $@ $^ From 1ecc5abdbc4946045d170d7a945624561728530c Mon Sep 17 00:00:00 2001 From: samothtronicien Date: Sat, 30 Jul 2016 16:44:54 +0200 Subject: [PATCH 07/11] fixed typo: test_x86_shl_pf -> test_x86_shl --- tests/unit/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/unit/Makefile b/tests/unit/Makefile index 9f2126e3..81b35898 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_hang test_x86_shl_pf + test_hookcounts test_hang test_x86_shl .PHONY: all all: ${ALL_TESTS} @@ -36,7 +36,7 @@ test: ${ALL_TESTS} ./test_x86_soft_paging ./test_hookcounts ./test_hang - ./test_x86_shl_pf + ./test_x86_shl test_sanity: test_sanity.c test_x86: test_x86.c @@ -49,7 +49,7 @@ 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 -test_x86_shl_pf: test_x86_shl_pf.c +test_x86_shl: test_x86_shl.c ${ALL_TESTS}: ${CC} ${CFLAGS} -o $@ $^ From ae8e34173adec2f9390b7b0274c248875975ce84 Mon Sep 17 00:00:00 2001 From: samothtronicien Date: Sun, 31 Jul 2016 03:19:52 +0200 Subject: [PATCH 08/11] added tests with enter/leave --- tests/unit/Makefile | 6 +- tests/unit/test_x86_shl_enter_leave.c | 487 ++++++++++++++++++++++++++ 2 files changed, 490 insertions(+), 3 deletions(-) create mode 100644 tests/unit/test_x86_shl_enter_leave.c diff --git a/tests/unit/Makefile b/tests/unit/Makefile index 81b35898..39f2747d 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_hang test_x86_shl + test_hookcounts test_hang test_x86_shl_enter_leave .PHONY: all all: ${ALL_TESTS} @@ -36,7 +36,7 @@ test: ${ALL_TESTS} ./test_x86_soft_paging ./test_hookcounts ./test_hang - ./test_x86_shl + ./test_x86_shl_enter_leave test_sanity: test_sanity.c test_x86: test_x86.c @@ -49,7 +49,7 @@ 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 -test_x86_shl: test_x86_shl.c +test_x86_shl_enter_leave: test_x86_shl_enter_leave.c ${ALL_TESTS}: ${CC} ${CFLAGS} -o $@ $^ diff --git a/tests/unit/test_x86_shl_enter_leave.c b/tests/unit/test_x86_shl_enter_leave.c new file mode 100644 index 00000000..5844a4c9 --- /dev/null +++ b/tests/unit/test_x86_shl_enter_leave.c @@ -0,0 +1,487 @@ +#include +#include + +#include "unicorn_test.h" + + +#define OK(x) uc_assert_success(x) + +#define CF_MASK (1<<0) +#define PF_MASK (1<<2) +#define ZF_MASK (1<<6) +#define SF_MASK (1<<7) +#define OF_MASK (1<<11) +#define ALL_MASK (OF_MASK|SF_MASK|ZF_MASK|PF_MASK|CF_MASK) +#define NO_MASK 0xFFFFFFFF + +typedef struct _reg_value +{ + uint32_t regId, regValue, mask; +} reg_value; + +typedef struct _instruction +{ + const char* asmStr; + const uint8_t* code; + uint32_t codeSize; + const reg_value* values; + uint32_t nbValues; + uint32_t addr; +} instruction; + +typedef struct _block +{ + instruction* insts[255]; + uint32_t nbInsts; + uint32_t size; +} block; + +/******************************************************************************/ + +#define CAT2(X, Y) X ## Y +#define CAT(X, Y) CAT2(X, Y) + +#define ADD_INSTRUCTION(BLOCK, CODE_ASM, CODE, REGVALUES) \ + const uint8_t CAT(code, __LINE__)[] = CODE; \ + const reg_value CAT(regValues, __LINE__)[] = REGVALUES; \ + inst = newInstruction(CAT(code, __LINE__), sizeof(CAT(code, __LINE__)), CODE_ASM, CAT(regValues, __LINE__), sizeof(CAT(regValues, __LINE__)) / sizeof(reg_value)); \ + addInstructionToBlock(BLOCK, inst); + +#define V(...) { __VA_ARGS__ } + +/******************************************************************************/ + +instruction* newInstruction(const uint8_t * _code, uint32_t _codeSize, const char* _asmStr, const reg_value* _values, uint32_t _nbValues); +void addInstructionToBlock(block* _b, instruction* _i); +uint32_t loadBlock(uc_engine *_uc, block* _block, uint32_t _at); +void freeBlock(block* _block); +const char* getRegisterName(uint32_t _regid); +uint32_t getRegisterValue(uc_engine *uc, uint32_t _regid); +instruction* getInstruction(block * _block, uint32_t _addr); + +/******************************************************************************/ + +void hook_code_test_i386_shl(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + uint32_t i; + block* b = (block*)user_data; + instruction* currInst = getInstruction(b, (uint32_t)address); + assert_true(currInst != NULL); + + print_message("|\teip=%08x - %s\n", (uint32_t)address, currInst->asmStr); + + for (i = 0; i < currInst->nbValues; i++) + { + if (currInst->values[i].regId == UC_X86_REG_INVALID) continue; + + uint32_t regValue = getRegisterValue(uc, currInst->values[i].regId); + print_message("|\t\ttesting %s : ", getRegisterName(currInst->values[i].regId)); + assert_int_equal(regValue & currInst->values[i].mask, currInst->values[i].regValue); + print_message("ok\n"); + } + + if (currInst->code[0] == 0xCC) + OK(uc_emu_stop(uc)); +} + +bool hook_mem_invalid(uc_engine *uc, uc_mem_type type, uint64_t addr, int size, int64_t value, void *user_data) +{ + switch (type) + { + default: + print_message("hook_mem_invalid: UC_HOOK_MEM_INVALID type: %d at 0x%" PRIx64 "\n", type, addr); break; + case UC_MEM_READ_UNMAPPED: + print_message("hook_mem_invalid: Read from invalid memory at 0x%" PRIx64 ", data size = %u\n", addr, size); break; + case UC_MEM_WRITE_UNMAPPED: + print_message("hook_mem_invalid: Write to invalid memory at 0x%" PRIx64 ", data size = %u, data value = 0x%" PRIx64 "\n", addr, size, value); break; + case UC_MEM_FETCH_PROT: + print_message("hook_mem_invalid: Fetch from non-executable memory at 0x%" PRIx64 "\n", addr); break; + case UC_MEM_WRITE_PROT: + print_message("hook_mem_invalid: Write to non-writeable memory at 0x%" PRIx64 ", data size = %u, data value = 0x%" PRIx64 "\n", addr, size, value); break; + case UC_MEM_READ_PROT: + print_message("hook_mem_invalid: Read from non-readable memory at 0x%" PRIx64 ", data size = %u\n", addr, size); break; + } + return false; +} + +#define ADDR_CODE 0x100000 +#define ADDR_STACK 0x200000 + +static void test_i386_shl_cl(void **state) +{ + uc_engine *uc; + uc_hook trace1; + + // Initialize emulator in X86-32bit mode + OK(uc_open(UC_ARCH_X86, UC_MODE_32, &uc)); + OK(uc_mem_map(uc, ADDR_CODE, 0x1000, UC_PROT_ALL)); + + { + block block; + instruction* inst; + + block.nbInsts = 0; + + ADD_INSTRUCTION(&block, "mov ebx, 3Ch", + V(0xBB, 0x3C, 0x00, 0x00, 0x00), + V(V(UC_X86_REG_INVALID, 0x0, NO_MASK))); + ADD_INSTRUCTION(&block, "mov cl, 2", + V(0xB1, 0x02), + V(V(UC_X86_REG_EBX, 0x3C, NO_MASK))); + ADD_INSTRUCTION(&block, "shl ebx, cl", + V(0xD3, 0xE3), + V(V(UC_X86_REG_EBX, 0x3C, NO_MASK), V(UC_X86_REG_CL, 0x2, NO_MASK))); + ADD_INSTRUCTION(&block, "lahf", + V(0x9F), + V(V(UC_X86_REG_EBX, 0xF0, NO_MASK), V(UC_X86_REG_CL, 0x2, NO_MASK), V(UC_X86_REG_EFLAGS, 0x4, ALL_MASK))); + ADD_INSTRUCTION(&block, "int3", + V(0xCC), + V(V(UC_X86_REG_AH, 0x4, PF_MASK), V(UC_X86_REG_EBX, 0xF0, NO_MASK), V(UC_X86_REG_CL, 0x2, NO_MASK), V(UC_X86_REG_EFLAGS, 0x4, ALL_MASK))); + + loadBlock(uc, &block, ADDR_CODE); + + // initialize machine registers + uint32_t zero = 0; + OK(uc_reg_write(uc, UC_X86_REG_EAX, &zero)); + OK(uc_reg_write(uc, UC_X86_REG_EBX, &zero)); + OK(uc_reg_write(uc, UC_X86_REG_ECX, &zero)); + OK(uc_reg_write(uc, UC_X86_REG_EDX, &zero)); + + OK(uc_hook_add(uc, &trace1, UC_HOOK_CODE, hook_code_test_i386_shl, &block, 1, 0)); + OK(uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL, 1, 0)); + + // emulate machine code in infinite time + OK(uc_emu_start(uc, ADDR_CODE, ADDR_CODE + block.size, 0, 0)); + + freeBlock(&block); + } + + uc_close(uc); +} + +static void test_i386_shl_imm(void **state) +{ + uc_engine *uc; + uc_hook trace1; + + // Initialize emulator in X86-32bit mode + OK(uc_open(UC_ARCH_X86, UC_MODE_32, &uc)); + OK(uc_mem_map(uc, ADDR_CODE, 0x1000, UC_PROT_ALL)); + + { + block block; + instruction* inst; + + block.nbInsts = 0; + + ADD_INSTRUCTION(&block, "mov ebx, 3Ch", + V(0xBB, 0x3C, 0x00, 0x00, 0x00), + V(V(UC_X86_REG_INVALID, 0x0, NO_MASK))); + ADD_INSTRUCTION(&block, "shl ebx, 2", + V(0xC1, 0xE3, 0x02), + V(V(UC_X86_REG_EBX, 0x3C, NO_MASK))); + ADD_INSTRUCTION(&block, "lahf", + V(0x9F), + V(V(UC_X86_REG_EBX, 0xF0, NO_MASK), V(UC_X86_REG_EFLAGS, 0x4, ALL_MASK))); + ADD_INSTRUCTION(&block, "int3", + V(0xCC), + V(V(UC_X86_REG_AH, 0x4, PF_MASK), V(UC_X86_REG_EBX, 0xF0, NO_MASK), V(UC_X86_REG_EFLAGS, 0x4, ALL_MASK))); + + loadBlock(uc, &block, ADDR_CODE); + + // initialize machine registers + uint32_t zero = 0; + OK(uc_reg_write(uc, UC_X86_REG_EAX, &zero)); + OK(uc_reg_write(uc, UC_X86_REG_EBX, &zero)); + OK(uc_reg_write(uc, UC_X86_REG_ECX, &zero)); + OK(uc_reg_write(uc, UC_X86_REG_EDX, &zero)); + + OK(uc_hook_add(uc, &trace1, UC_HOOK_CODE, hook_code_test_i386_shl, &block, 1, 0)); + OK(uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL, 1, 0)); + + // emulate machine code in infinite time + OK(uc_emu_start(uc, ADDR_CODE, ADDR_CODE + block.size, 0, 0)); + + freeBlock(&block); + } + + uc_close(uc); +} + +static void test_i386_enter_leave(void **state) +{ + uc_engine *uc; + uc_hook trace1; + + // Initialize emulator in X86-32bit mode + OK(uc_open(UC_ARCH_X86, UC_MODE_32, &uc)); + OK(uc_mem_map(uc, ADDR_CODE, 0x1000, UC_PROT_ALL)); + OK(uc_mem_map(uc, ADDR_STACK - 0x1000, 0x1000, UC_PROT_ALL)); + + { + block block; + instruction* inst; + + block.nbInsts = 0; + + ADD_INSTRUCTION(&block, "mov esp, 0x200000", + V(0xBC, 0x00, 0x00, 0x20, 0x00), + V(V(UC_X86_REG_INVALID, 0x0, NO_MASK))); + ADD_INSTRUCTION(&block, "mov eax, 1", + V(0xB8, 0x01, 0x00, 0x00, 0x00), + V(V(UC_X86_REG_ESP, 0x200000, NO_MASK))); + ADD_INSTRUCTION(&block, "call 0x100015", + V(0xE8, 0x06, 0x00, 0x00, 0x00), + V(V(UC_X86_REG_EAX, 0x1, NO_MASK), V(UC_X86_REG_ESP, 0x200000, NO_MASK))); + ADD_INSTRUCTION(&block, "mov eax, 3", + V(0xB8, 0x03, 0x00, 0x00, 0x00), + V(V(UC_X86_REG_EAX, 0x2, NO_MASK))); + ADD_INSTRUCTION(&block, "int3", + V(0xCC), + V(V(UC_X86_REG_EAX, 0x3, NO_MASK))); + ADD_INSTRUCTION(&block, "enter 0x10,0", + V(0xC8, 0x10, 0x00, 0x00), + V(V(UC_X86_REG_ESP, 0x200000 - 4, NO_MASK))); + ADD_INSTRUCTION(&block, "mov eax, 2", + V(0xB8, 0x02, 0x00, 0x00, 0x00), + V(V(UC_X86_REG_ESP, 0x200000 - 4 - 4 - 0x10, NO_MASK), V(UC_X86_REG_EBP, 0x200000 - 4 - 4, NO_MASK))); + ADD_INSTRUCTION(&block, "leave", + V(0xC9), + V(V(UC_X86_REG_EAX, 0x2, NO_MASK), V(UC_X86_REG_INVALID, 0x0, NO_MASK))); + ADD_INSTRUCTION(&block, "mov eax, 2", + V(0xB8, 0x02, 0x00, 0x00, 0x00), + V(V(UC_X86_REG_INVALID, 0x0, NO_MASK))); + ADD_INSTRUCTION(&block, "ret", + V(0xC3), + V(V(UC_X86_REG_ESP, 0x200000 - 4, NO_MASK))); + + loadBlock(uc, &block, ADDR_CODE); + + // initialize machine registers + uint32_t zero = 0; + OK(uc_reg_write(uc, UC_X86_REG_EAX, &zero)); + OK(uc_reg_write(uc, UC_X86_REG_EBX, &zero)); + OK(uc_reg_write(uc, UC_X86_REG_ECX, &zero)); + OK(uc_reg_write(uc, UC_X86_REG_EDX, &zero)); + + OK(uc_hook_add(uc, &trace1, UC_HOOK_CODE, hook_code_test_i386_shl, &block, 1, 0)); + OK(uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL, 1, 0)); + + // emulate machine code in infinite time + OK(uc_emu_start(uc, ADDR_CODE, ADDR_CODE + block.size, 0, 0)); + + freeBlock(&block); + } + + uc_close(uc); +} + +static void test_i386_enter_nested_leave(void **state) +{ + uc_engine *uc; + uc_hook trace1; + + // Initialize emulator in X86-32bit mode + OK(uc_open(UC_ARCH_X86, UC_MODE_32, &uc)); + OK(uc_mem_map(uc, ADDR_CODE, 0x1000, UC_PROT_ALL)); + OK(uc_mem_map(uc, ADDR_STACK - 0x1000, 0x1000, UC_PROT_ALL)); + + { + block block; + instruction* inst; + + block.nbInsts = 0; + + ADD_INSTRUCTION(&block, "mov esp, 0x200000", + V(0xBC, 0x00, 0x00, 0x20, 0x00), + V(V(UC_X86_REG_INVALID, 0x0, NO_MASK))); + ADD_INSTRUCTION(&block, "mov eax, 1", + V(0xB8, 0x01, 0x00, 0x00, 0x00), + V(V(UC_X86_REG_ESP, 0x200000, NO_MASK))); + ADD_INSTRUCTION(&block, "call 0x100015", + V(0xE8, 0x06, 0x00, 0x00, 0x00), + V(V(UC_X86_REG_EAX, 0x1, NO_MASK), V(UC_X86_REG_ESP, 0x200000, NO_MASK))); + ADD_INSTRUCTION(&block, "mov eax, 3", + V(0xB8, 0x03, 0x00, 0x00, 0x00), + V(V(UC_X86_REG_EAX, 0x2, NO_MASK))); + ADD_INSTRUCTION(&block, "int3", + V(0xCC), + V(V(UC_X86_REG_EAX, 0x3, NO_MASK))); + ADD_INSTRUCTION(&block, "enter 0x10,1", + V(0xC8, 0x10, 0x00, 0x01), + V(V(UC_X86_REG_ESP, 0x200000 - 4, NO_MASK))); + ADD_INSTRUCTION(&block, "mov eax, 2", + V(0xB8, 0x02, 0x00, 0x00, 0x00), + V(V(UC_X86_REG_ESP, 0x200000 - 4 - 2*4 - 0x10, NO_MASK), V(UC_X86_REG_EBP, 0x200000 - 4 - 4, NO_MASK))); + ADD_INSTRUCTION(&block, "leave", + V(0xC9), + V(V(UC_X86_REG_EAX, 0x2, NO_MASK))); + ADD_INSTRUCTION(&block, "ret", + V(0xC3), + V(V(UC_X86_REG_ESP, 0x200000 - 4, NO_MASK))); + + loadBlock(uc, &block, ADDR_CODE); + + // initialize machine registers + uint32_t zero = 0; + OK(uc_reg_write(uc, UC_X86_REG_EAX, &zero)); + OK(uc_reg_write(uc, UC_X86_REG_EBX, &zero)); + OK(uc_reg_write(uc, UC_X86_REG_ECX, &zero)); + OK(uc_reg_write(uc, UC_X86_REG_EDX, &zero)); + + OK(uc_hook_add(uc, &trace1, UC_HOOK_CODE, hook_code_test_i386_shl, &block, 1, 0)); + OK(uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL, 1, 0)); + + // emulate machine code in infinite time + OK(uc_emu_start(uc, ADDR_CODE, ADDR_CODE + block.size, 0, 0)); + + freeBlock(&block); + } + + uc_close(uc); +} + +/******************************************************************************/ + +int main(void) { + const struct CMUnitTest tests[] = { + + cmocka_unit_test(test_i386_shl_cl), + cmocka_unit_test(test_i386_shl_imm), + cmocka_unit_test(test_i386_enter_leave), + cmocka_unit_test(test_i386_enter_nested_leave), + }; + return cmocka_run_group_tests(tests, NULL, NULL); +} + +/******************************************************************************/ + +instruction* newInstruction(const uint8_t * _code, uint32_t _codeSize, const char* _asmStr, const reg_value* _values, uint32_t _nbValues) +{ + instruction* inst = (instruction*)malloc(sizeof(instruction)); + + inst->asmStr = _asmStr; + inst->code = _code; + inst->codeSize = _codeSize; + inst->values = _values; + inst->nbValues = _nbValues; + + return inst; +} + +void addInstructionToBlock(block* _b, instruction* _i) +{ + _b->insts[_b->nbInsts++] = _i; +} + +uint32_t loadBlock(uc_engine *_uc, block* _block, uint32_t _at) +{ + uint32_t i, j, offset; + + for (i = 0, offset = 0; i < _block->nbInsts; i++) + { + const uint32_t codeSize = _block->insts[i]->codeSize; + const uint8_t* code = _block->insts[i]->code; + _block->insts[i]->addr = _at + offset; + print_message("load: %08X: ", _block->insts[i]->addr); + for (j = 0; j < codeSize; j++) print_message("%02X ", code[j]); + for (j = 0; j < 15 - codeSize; j++) print_message(" "); + print_message("%s\n", _block->insts[i]->asmStr); + OK(uc_mem_write(_uc, _at + offset, code, codeSize)); + offset += codeSize; + } + _block->size = offset; + return offset; +} + +void freeBlock(block* _block) +{ + uint32_t i; + for (i = 0; i < _block->nbInsts; i++) + free(_block->insts[i]); +} + +instruction* getInstruction(block* _block, uint32_t _addr) +{ + uint32_t i; + for (i = 0; i < _block->nbInsts; i++) + { + if (_block->insts[i]->addr == _addr) + return _block->insts[i]; + } + return NULL; +} + +const char* getRegisterName(uint32_t _regid) +{ + switch (_regid) + { + //8 + case UC_X86_REG_AH: return "AH"; + case UC_X86_REG_AL: return "AL"; + case UC_X86_REG_BH: return "BH"; + case UC_X86_REG_BL: return "BL"; + case UC_X86_REG_CL: return "CL"; + case UC_X86_REG_CH: return "CH"; + case UC_X86_REG_DH: return "DH"; + case UC_X86_REG_DL: return "DL"; + //16 + case UC_X86_REG_AX: return "AX"; + case UC_X86_REG_BX: return "BX"; + case UC_X86_REG_CX: return "CX"; + case UC_X86_REG_DX: return "DX"; + //32 + case UC_X86_REG_EAX: return "EAX"; + case UC_X86_REG_EBX: return "EBX"; + case UC_X86_REG_ECX: return "ECX"; + case UC_X86_REG_EDX: return "EDX"; + case UC_X86_REG_EDI: return "EDI"; + case UC_X86_REG_ESI: return "ESI"; + case UC_X86_REG_EBP: return "EBP"; + case UC_X86_REG_ESP: return "ESP"; + case UC_X86_REG_EIP: return "EIP"; + case UC_X86_REG_EFLAGS: return "EFLAGS"; + + default: fail(); + } + return "UNKNOWN"; +} + +uint32_t getRegisterValue(uc_engine *uc, uint32_t _regid) +{ + switch (_regid) + { + //8 + case UC_X86_REG_AH: case UC_X86_REG_AL: + case UC_X86_REG_BH: case UC_X86_REG_BL: + case UC_X86_REG_CL: case UC_X86_REG_CH: + case UC_X86_REG_DH: case UC_X86_REG_DL: + { + uint8_t val = 0; + OK(uc_reg_read(uc, _regid, &val)); + return val; + } + //16 + case UC_X86_REG_AX: case UC_X86_REG_BX: + case UC_X86_REG_CX: case UC_X86_REG_DX: + { + uint16_t val = 0; + OK(uc_reg_read(uc, _regid, &val)); + return val; + } + //32 + case UC_X86_REG_EAX: case UC_X86_REG_EBX: + case UC_X86_REG_ECX: case UC_X86_REG_EDX: + case UC_X86_REG_EDI: case UC_X86_REG_ESI: + case UC_X86_REG_EBP: case UC_X86_REG_ESP: + case UC_X86_REG_EIP: case UC_X86_REG_EFLAGS: + { + uint32_t val = 0; + OK(uc_reg_read(uc, _regid, &val)); + return val; + } + + default: fail(); + } + return 0; +} From f1041a26151393a379d887f0e99636715195e302 Mon Sep 17 00:00:00 2001 From: samothtronicien Date: Sun, 31 Jul 2016 03:23:00 +0200 Subject: [PATCH 09/11] renamed to test_x86_shl_enter_leave.c --- tests/unit/test_x86_shl.c | 308 -------------------------------------- 1 file changed, 308 deletions(-) delete mode 100644 tests/unit/test_x86_shl.c diff --git a/tests/unit/test_x86_shl.c b/tests/unit/test_x86_shl.c deleted file mode 100644 index 33a7271f..00000000 --- a/tests/unit/test_x86_shl.c +++ /dev/null @@ -1,308 +0,0 @@ -#include - -#include "unicorn_test.h" - - -#define OK(x) uc_assert_success(x) - -#define CF_MASK (1<<0) -#define PF_MASK (1<<2) -#define ZF_MASK (1<<6) -#define SF_MASK (1<<7) -#define OF_MASK (1<<11) -#define ALL_MASK (OF_MASK|SF_MASK|ZF_MASK|PF_MASK|CF_MASK) -#define NO_MASK 0xFFFFFFFF - -typedef struct _reg_value -{ - uint32_t regId, regValue, mask; -} reg_value; - -typedef struct _instruction -{ - const char* asmStr; - const uint8_t* code; - uint32_t codeSize; - const reg_value* values; - uint32_t nbValues; -} instruction; - -typedef struct _block -{ - instruction* insts[255]; - uint32_t nbInsts; - uint32_t size; -} block; - -typedef struct _exec_state -{ - uint32_t curr; - block* block; -} exec_state; - -/******************************************************************************/ - -#define CAT2(X, Y) X ## Y -#define CAT(X, Y) CAT2(X, Y) - -#define ADD_INSTRUCTION(BLOCK, CODE_ASM, CODE, REGVALUES) \ - const uint8_t CAT(code, __LINE__)[] = CODE; \ - const reg_value CAT(regValues, __LINE__)[] = REGVALUES; \ - inst = newInstruction(CAT(code, __LINE__), sizeof(CAT(code, __LINE__)), CODE_ASM, CAT(regValues, __LINE__), sizeof(CAT(regValues, __LINE__)) / sizeof(reg_value)); \ - addInstructionToBlock(BLOCK, inst); - -#define V(...) { __VA_ARGS__ } - -/******************************************************************************/ - -instruction* newInstruction(const uint8_t * _code, uint32_t _codeSize, const char* _asmStr, const reg_value* _values, uint32_t _nbValues); -void addInstructionToBlock(block* _b, instruction* _i); -uint32_t loadBlock(uc_engine *_uc, block* _block, uint32_t _at); -void freeBlock(block* _block); -const char* getRegisterName(uint32_t _regid); -uint32_t getRegisterValue(uc_engine *uc, uint32_t _regid); - -/******************************************************************************/ - -void hook_code_test_i386_shl(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) -{ - uint32_t i; - exec_state* es = (exec_state*)user_data; - instruction* currInst = es->block->insts[es->curr]; - - print_message("|\teip=%08x - %s\n", (uint32_t)address, es->block->insts[es->curr]->asmStr); - - for (i = 0; i < currInst->nbValues; i++) - { - if (currInst->values[i].regId == UC_X86_REG_INVALID) continue; - uint32_t regValue = getRegisterValue(uc, currInst->values[i].regId); - print_message("|\t\ttesting %s : ", getRegisterName(currInst->values[i].regId)); - assert_int_equal(regValue & currInst->values[i].mask, currInst->values[i].regValue); - print_message("ok\n"); - } - - es->curr++; - if (es->curr >= es->block->nbInsts) - { - print_message("stopping emulation\n"); - uc_emu_stop(uc); - } -} - -#define ADDR_START 0x100000 - -static void test_i386_shl_prob(void **state) -{ - uc_engine *uc; - uc_hook trace1; - - // Initialize emulator in X86-32bit mode - OK(uc_open(UC_ARCH_X86, UC_MODE_32, &uc)); - OK(uc_mem_map(uc, ADDR_START, 0x1000, UC_PROT_ALL)); - - { - exec_state es; - block block_shl_prob; - instruction* inst; - - es.curr = 0; - es.block = &block_shl_prob; - - block_shl_prob.nbInsts = 0; - - ADD_INSTRUCTION(&block_shl_prob, "mov ebx, 3Ch", V(0xBB, 0x3C, 0x00, 0x00, 0x00), V(V(UC_X86_REG_INVALID, 0x0, NO_MASK))); - ADD_INSTRUCTION(&block_shl_prob, "mov cl, 2", V(0xB1, 0x02), V(V(UC_X86_REG_EBX, 0x3C, NO_MASK))); - ADD_INSTRUCTION(&block_shl_prob, "shl ebx, cl", V(0xD3, 0xE3), V(V(UC_X86_REG_EBX, 0x3C, NO_MASK), V(UC_X86_REG_CL, 0x2, NO_MASK))); - ADD_INSTRUCTION(&block_shl_prob, "lahf", V(0x9F), V(V(UC_X86_REG_EBX, 0xF0, NO_MASK), V(UC_X86_REG_CL, 0x2, NO_MASK), V(UC_X86_REG_EFLAGS, 0x4, ALL_MASK))); - ADD_INSTRUCTION(&block_shl_prob, "int3", V(0xCC), V(V(UC_X86_REG_AH, 0x4, PF_MASK), V(UC_X86_REG_EBX, 0xF0, NO_MASK), V(UC_X86_REG_CL, 0x2, NO_MASK), V(UC_X86_REG_EFLAGS, 0x4, ALL_MASK))); - - loadBlock(uc, &block_shl_prob, ADDR_START); - - // initialize machine registers - uint32_t zero = 0; - OK(uc_reg_write(uc, UC_X86_REG_EAX, &zero)); - OK(uc_reg_write(uc, UC_X86_REG_EBX, &zero)); - OK(uc_reg_write(uc, UC_X86_REG_ECX, &zero)); - OK(uc_reg_write(uc, UC_X86_REG_EDX, &zero)); - - OK(uc_hook_add(uc, &trace1, UC_HOOK_CODE, hook_code_test_i386_shl, &es, 1, 0)); - - // emulate machine code in infinite time - OK(uc_emu_start(uc, ADDR_START, ADDR_START + block_shl_prob.size - 1, 0, 0)); - - freeBlock(&block_shl_prob); - } - - uc_close(uc); -} - -static void test_i386_shl_ok(void **state) -{ - uc_engine *uc; - uc_hook trace1; - - // Initialize emulator in X86-32bit mode - OK(uc_open(UC_ARCH_X86, UC_MODE_32, &uc)); - OK(uc_mem_map(uc, ADDR_START, 0x1000, UC_PROT_ALL)); - - { - exec_state es; - block block_shl_ok; - instruction* inst; - - es.curr = 0; - es.block = &block_shl_ok; - - block_shl_ok.nbInsts = 0; - - ADD_INSTRUCTION(&block_shl_ok, "mov ebx, 3Ch", V(0xBB, 0x3C, 0x00, 0x00, 0x00), V(V(UC_X86_REG_INVALID, 0x0, NO_MASK))); - ADD_INSTRUCTION(&block_shl_ok, "shl ebx, 2", V(0xC1, 0xE3, 0x02), V(V(UC_X86_REG_EBX, 0x3C, NO_MASK))); - ADD_INSTRUCTION(&block_shl_ok, "lahf", V(0x9F), V(V(UC_X86_REG_EBX, 0xF0, NO_MASK), V(UC_X86_REG_EFLAGS, 0x4, ALL_MASK))); - ADD_INSTRUCTION(&block_shl_ok, "int3", V(0xCC), V(V(UC_X86_REG_AH, 0x4, PF_MASK), V(UC_X86_REG_EBX, 0xF0, NO_MASK), V(UC_X86_REG_EFLAGS, 0x4, ALL_MASK))); - - loadBlock(uc, &block_shl_ok, ADDR_START); - - // initialize machine registers - uint32_t zero = 0; - OK(uc_reg_write(uc, UC_X86_REG_EAX, &zero)); - OK(uc_reg_write(uc, UC_X86_REG_EBX, &zero)); - OK(uc_reg_write(uc, UC_X86_REG_ECX, &zero)); - OK(uc_reg_write(uc, UC_X86_REG_EDX, &zero)); - - OK(uc_hook_add(uc, &trace1, UC_HOOK_CODE, hook_code_test_i386_shl, &es, 1, 0)); - - // emulate machine code in infinite time - OK(uc_emu_start(uc, ADDR_START, ADDR_START + block_shl_ok.size - 1, 0, 0)); - - freeBlock(&block_shl_ok); - } - - uc_close(uc); -} - -/******************************************************************************/ - -int main(void) { - const struct CMUnitTest tests[] = { - - cmocka_unit_test(test_i386_shl_prob), - cmocka_unit_test(test_i386_shl_ok), - - }; - return cmocka_run_group_tests(tests, NULL, NULL); -} - -/******************************************************************************/ - -instruction* newInstruction(const uint8_t * _code, uint32_t _codeSize, const char* _asmStr, const reg_value* _values, uint32_t _nbValues) -{ - instruction* inst = (instruction*)malloc(sizeof(instruction)); - - inst->asmStr = _asmStr; - inst->code = _code; - inst->codeSize = _codeSize; - inst->values = _values; - inst->nbValues = _nbValues; - - return inst; -} - -void addInstructionToBlock(block* _b, instruction* _i) -{ - _b->insts[_b->nbInsts++] = _i; -} - -uint32_t loadBlock(uc_engine *_uc, block* _block, uint32_t _at) -{ - uint32_t i, offset; - - for (i = 0, offset = 0; i < _block->nbInsts; i++) - { - OK(uc_mem_write(_uc, _at + offset, _block->insts[i]->code, _block->insts[i]->codeSize)); - offset += _block->insts[i]->codeSize; - } - _block->size = offset; - return offset; -} - -void freeBlock(block* _block) -{ - uint32_t i; - - for (i = 0; i < _block->nbInsts; i++) - free(_block->insts[i]); -} - -const char* getRegisterName(uint32_t _regid) -{ - switch (_regid) - { - //8 - case UC_X86_REG_AH: return "AH"; - case UC_X86_REG_AL: return "AL"; - case UC_X86_REG_BH: return "BH"; - case UC_X86_REG_BL: return "BL"; - case UC_X86_REG_CL: return "CL"; - case UC_X86_REG_CH: return "CH"; - case UC_X86_REG_DH: return "DH"; - case UC_X86_REG_DL: return "DL"; - //16 - case UC_X86_REG_AX: return "AX"; - case UC_X86_REG_BX: return "BX"; - case UC_X86_REG_CX: return "CX"; - case UC_X86_REG_DX: return "DX"; - //32 - case UC_X86_REG_EAX: return "EAX"; - case UC_X86_REG_EBX: return "EBX"; - case UC_X86_REG_ECX: return "ECX"; - case UC_X86_REG_EDX: return "EDX"; - case UC_X86_REG_EDI: return "EDI"; - case UC_X86_REG_ESI: return "ESI"; - case UC_X86_REG_EBP: return "EBP"; - case UC_X86_REG_ESP: return "ESP"; - case UC_X86_REG_EIP: return "EIP"; - case UC_X86_REG_EFLAGS: return "EFLAGS"; - - default: fail(); - } - return "UNKNOWN"; -} - -uint32_t getRegisterValue(uc_engine *uc, uint32_t _regid) -{ - switch (_regid) - { - //8 - case UC_X86_REG_AH: case UC_X86_REG_AL: - case UC_X86_REG_BH: case UC_X86_REG_BL: - case UC_X86_REG_CL: case UC_X86_REG_CH: - case UC_X86_REG_DH: case UC_X86_REG_DL: - { - uint8_t val = 0; - uc_reg_read(uc, _regid, &val); - return val; - } - //16 - case UC_X86_REG_AX: case UC_X86_REG_BX: - case UC_X86_REG_CX: case UC_X86_REG_DX: - { - uint16_t val = 0; - uc_reg_read(uc, _regid, &val); - return val; - } - //32 - case UC_X86_REG_EAX: case UC_X86_REG_EBX: - case UC_X86_REG_ECX: case UC_X86_REG_EDX: - case UC_X86_REG_EDI: case UC_X86_REG_ESI: - case UC_X86_REG_EBP: case UC_X86_REG_ESP: - case UC_X86_REG_EIP: case UC_X86_REG_EFLAGS: - { - uint32_t val = 0; - uc_reg_read(uc, _regid, &val); - return val; - } - - default: fail(); - } - return 0; -} From 92f97da49fb429cced05cbe201eae8dd4f4d2be6 Mon Sep 17 00:00:00 2001 From: samothtronicien Date: Sun, 31 Jul 2016 19:45:46 +0200 Subject: [PATCH 10/11] bit of refactoring --- tests/unit/test_x86_shl_enter_leave.c | 305 +++++++++++--------------- 1 file changed, 126 insertions(+), 179 deletions(-) diff --git a/tests/unit/test_x86_shl_enter_leave.c b/tests/unit/test_x86_shl_enter_leave.c index 5844a4c9..f7fe9ad3 100644 --- a/tests/unit/test_x86_shl_enter_leave.c +++ b/tests/unit/test_x86_shl_enter_leave.c @@ -1,4 +1,5 @@ #include +#include #include #include "unicorn_test.h" @@ -21,12 +22,12 @@ typedef struct _reg_value typedef struct _instruction { - const char* asmStr; - const uint8_t* code; - uint32_t codeSize; - const reg_value* values; - uint32_t nbValues; - uint32_t addr; + const char* asmStr; + uint8_t code[16]; //x86 inst == 15 bytes max + uint32_t codeSize; + reg_value* values; + uint32_t nbValues; + uint32_t addr; } instruction; typedef struct _block @@ -41,11 +42,24 @@ typedef struct _block #define CAT2(X, Y) X ## Y #define CAT(X, Y) CAT2(X, Y) -#define ADD_INSTRUCTION(BLOCK, CODE_ASM, CODE, REGVALUES) \ +#define BLOCK_START(BLOCK) \ + { \ + block* blockPtr = &BLOCK; \ + blockPtr->nbInsts = 0; \ + instruction* instPtr = NULL; + +#define BLOCK_END() } + +#define BLOCK_ADD(CODE_ASM, CODE) \ + const uint8_t CAT(code, __LINE__)[] = CODE; \ + instPtr = newInstruction(CAT(code, __LINE__), sizeof(CAT(code, __LINE__)), CODE_ASM, NULL, 0); \ + addInstructionToBlock(blockPtr, instPtr); + +#define BLOCK_ADD_CHECK(CODE_ASM, CODE, REGVALUES) \ const uint8_t CAT(code, __LINE__)[] = CODE; \ const reg_value CAT(regValues, __LINE__)[] = REGVALUES; \ - inst = newInstruction(CAT(code, __LINE__), sizeof(CAT(code, __LINE__)), CODE_ASM, CAT(regValues, __LINE__), sizeof(CAT(regValues, __LINE__)) / sizeof(reg_value)); \ - addInstructionToBlock(BLOCK, inst); + instPtr = newInstruction(CAT(code, __LINE__), sizeof(CAT(code, __LINE__)), CODE_ASM, CAT(regValues, __LINE__), sizeof(CAT(regValues, __LINE__)) / sizeof(reg_value)); \ + addInstructionToBlock(blockPtr, instPtr); #define V(...) { __VA_ARGS__ } @@ -58,6 +72,7 @@ void freeBlock(block* _block); const char* getRegisterName(uint32_t _regid); uint32_t getRegisterValue(uc_engine *uc, uint32_t _regid); instruction* getInstruction(block * _block, uint32_t _addr); +void initRegisters(uc_engine *uc); /******************************************************************************/ @@ -72,8 +87,6 @@ void hook_code_test_i386_shl(uc_engine *uc, uint64_t address, uint32_t size, voi for (i = 0; i < currInst->nbValues; i++) { - if (currInst->values[i].regId == UC_X86_REG_INVALID) continue; - uint32_t regValue = getRegisterValue(uc, currInst->values[i].regId); print_message("|\t\ttesting %s : ", getRegisterName(currInst->values[i].regId)); assert_int_equal(regValue & currInst->values[i].mask, currInst->values[i].regValue); @@ -107,54 +120,37 @@ bool hook_mem_invalid(uc_engine *uc, uc_mem_type type, uint64_t addr, int size, #define ADDR_CODE 0x100000 #define ADDR_STACK 0x200000 + + static void test_i386_shl_cl(void **state) { uc_engine *uc; uc_hook trace1; + block b; // Initialize emulator in X86-32bit mode OK(uc_open(UC_ARCH_X86, UC_MODE_32, &uc)); OK(uc_mem_map(uc, ADDR_CODE, 0x1000, UC_PROT_ALL)); + + initRegisters(uc); - { - block block; - instruction* inst; + BLOCK_START(b); + BLOCK_ADD( "mov ebx, 3Ch", V(0xBB, 0x3C, 0x00, 0x00, 0x00)); + BLOCK_ADD_CHECK("mov cl, 2", V(0xB1, 0x02), V(V(UC_X86_REG_EBX, 0x3C, NO_MASK))); + BLOCK_ADD_CHECK("shl ebx, cl", V(0xD3, 0xE3), V(V(UC_X86_REG_CL, 0x2, NO_MASK))); + BLOCK_ADD_CHECK("lahf", V(0x9F), V(V(UC_X86_REG_EBX, 0xF0, NO_MASK), V(UC_X86_REG_EFLAGS, 0x4, ALL_MASK))); + BLOCK_ADD_CHECK("int3", V(0xCC), V(V(UC_X86_REG_AH, 0x4, PF_MASK))); + BLOCK_END(); - block.nbInsts = 0; + loadBlock(uc, &b, ADDR_CODE); - ADD_INSTRUCTION(&block, "mov ebx, 3Ch", - V(0xBB, 0x3C, 0x00, 0x00, 0x00), - V(V(UC_X86_REG_INVALID, 0x0, NO_MASK))); - ADD_INSTRUCTION(&block, "mov cl, 2", - V(0xB1, 0x02), - V(V(UC_X86_REG_EBX, 0x3C, NO_MASK))); - ADD_INSTRUCTION(&block, "shl ebx, cl", - V(0xD3, 0xE3), - V(V(UC_X86_REG_EBX, 0x3C, NO_MASK), V(UC_X86_REG_CL, 0x2, NO_MASK))); - ADD_INSTRUCTION(&block, "lahf", - V(0x9F), - V(V(UC_X86_REG_EBX, 0xF0, NO_MASK), V(UC_X86_REG_CL, 0x2, NO_MASK), V(UC_X86_REG_EFLAGS, 0x4, ALL_MASK))); - ADD_INSTRUCTION(&block, "int3", - V(0xCC), - V(V(UC_X86_REG_AH, 0x4, PF_MASK), V(UC_X86_REG_EBX, 0xF0, NO_MASK), V(UC_X86_REG_CL, 0x2, NO_MASK), V(UC_X86_REG_EFLAGS, 0x4, ALL_MASK))); + OK(uc_hook_add(uc, &trace1, UC_HOOK_CODE, hook_code_test_i386_shl, &b, 1, 0)); + OK(uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL, 1, 0)); - loadBlock(uc, &block, ADDR_CODE); + // emulate machine code in infinite time + OK(uc_emu_start(uc, ADDR_CODE, ADDR_CODE + b.size, 0, 0)); - // initialize machine registers - uint32_t zero = 0; - OK(uc_reg_write(uc, UC_X86_REG_EAX, &zero)); - OK(uc_reg_write(uc, UC_X86_REG_EBX, &zero)); - OK(uc_reg_write(uc, UC_X86_REG_ECX, &zero)); - OK(uc_reg_write(uc, UC_X86_REG_EDX, &zero)); - - OK(uc_hook_add(uc, &trace1, UC_HOOK_CODE, hook_code_test_i386_shl, &block, 1, 0)); - OK(uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL, 1, 0)); - - // emulate machine code in infinite time - OK(uc_emu_start(uc, ADDR_CODE, ADDR_CODE + block.size, 0, 0)); - - freeBlock(&block); - } + freeBlock(&b); uc_close(uc); } @@ -163,47 +159,30 @@ static void test_i386_shl_imm(void **state) { uc_engine *uc; uc_hook trace1; + block b; // Initialize emulator in X86-32bit mode OK(uc_open(UC_ARCH_X86, UC_MODE_32, &uc)); OK(uc_mem_map(uc, ADDR_CODE, 0x1000, UC_PROT_ALL)); - { - block block; - instruction* inst; + initRegisters(uc); - block.nbInsts = 0; + BLOCK_START(b); + BLOCK_ADD( "mov ebx, 3Ch", V(0xBB, 0x3C, 0x00, 0x00, 0x00)); + BLOCK_ADD( "shl ebx, 2", V(0xC1, 0xE3, 0x02)); + BLOCK_ADD_CHECK("lahf", V(0x9F), V(V(UC_X86_REG_EBX, 0xF0, NO_MASK), V(UC_X86_REG_EFLAGS, 0x4, ALL_MASK))); + BLOCK_ADD_CHECK("int3", V(0xCC), V(V(UC_X86_REG_AH, 0x4, PF_MASK))); + BLOCK_END(); - ADD_INSTRUCTION(&block, "mov ebx, 3Ch", - V(0xBB, 0x3C, 0x00, 0x00, 0x00), - V(V(UC_X86_REG_INVALID, 0x0, NO_MASK))); - ADD_INSTRUCTION(&block, "shl ebx, 2", - V(0xC1, 0xE3, 0x02), - V(V(UC_X86_REG_EBX, 0x3C, NO_MASK))); - ADD_INSTRUCTION(&block, "lahf", - V(0x9F), - V(V(UC_X86_REG_EBX, 0xF0, NO_MASK), V(UC_X86_REG_EFLAGS, 0x4, ALL_MASK))); - ADD_INSTRUCTION(&block, "int3", - V(0xCC), - V(V(UC_X86_REG_AH, 0x4, PF_MASK), V(UC_X86_REG_EBX, 0xF0, NO_MASK), V(UC_X86_REG_EFLAGS, 0x4, ALL_MASK))); - - loadBlock(uc, &block, ADDR_CODE); - - // initialize machine registers - uint32_t zero = 0; - OK(uc_reg_write(uc, UC_X86_REG_EAX, &zero)); - OK(uc_reg_write(uc, UC_X86_REG_EBX, &zero)); - OK(uc_reg_write(uc, UC_X86_REG_ECX, &zero)); - OK(uc_reg_write(uc, UC_X86_REG_EDX, &zero)); - - OK(uc_hook_add(uc, &trace1, UC_HOOK_CODE, hook_code_test_i386_shl, &block, 1, 0)); - OK(uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL, 1, 0)); - - // emulate machine code in infinite time - OK(uc_emu_start(uc, ADDR_CODE, ADDR_CODE + block.size, 0, 0)); - - freeBlock(&block); - } + loadBlock(uc, &b, ADDR_CODE); + + OK(uc_hook_add(uc, &trace1, UC_HOOK_CODE, hook_code_test_i386_shl, &b, 1, 0)); + OK(uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL, 1, 0)); + + // emulate machine code in infinite time + OK(uc_emu_start(uc, ADDR_CODE, ADDR_CODE + b.size, 0, 0)); + + freeBlock(&b); uc_close(uc); } @@ -212,66 +191,36 @@ static void test_i386_enter_leave(void **state) { uc_engine *uc; uc_hook trace1; + block b; // Initialize emulator in X86-32bit mode OK(uc_open(UC_ARCH_X86, UC_MODE_32, &uc)); OK(uc_mem_map(uc, ADDR_CODE, 0x1000, UC_PROT_ALL)); OK(uc_mem_map(uc, ADDR_STACK - 0x1000, 0x1000, UC_PROT_ALL)); - { - block block; - instruction* inst; + initRegisters(uc); - block.nbInsts = 0; + BLOCK_START(b); + BLOCK_ADD( "mov esp, 0x200000", V(0xBC, 0x00, 0x00, 0x20, 0x00)); + BLOCK_ADD_CHECK("mov eax, 1", V(0xB8, 0x01, 0x00, 0x00, 0x00), V(V(UC_X86_REG_ESP, 0x200000, NO_MASK))); + BLOCK_ADD_CHECK("call 0x100015", V(0xE8, 0x06, 0x00, 0x00, 0x00), V(V(UC_X86_REG_EAX, 0x1, NO_MASK))); + BLOCK_ADD_CHECK("mov eax, 3", V(0xB8, 0x03, 0x00, 0x00, 0x00), V(V(UC_X86_REG_EAX, 0x2, NO_MASK))); + BLOCK_ADD_CHECK("int3", V(0xCC), V(V(UC_X86_REG_EAX, 0x3, NO_MASK))); + BLOCK_ADD_CHECK("enter 0x10,0", V(0xC8, 0x10, 0x00, 0x00), V(V(UC_X86_REG_ESP, 0x200000 - 4, NO_MASK))); + BLOCK_ADD_CHECK("mov eax, 2", V(0xB8, 0x02, 0x00, 0x00, 0x00), V(V(UC_X86_REG_ESP, 0x200000 - 4 - 4 - 0x10, NO_MASK), V(UC_X86_REG_EBP, 0x200000 - 4 - 4, NO_MASK))); + BLOCK_ADD_CHECK("leave", V(0xC9), V(V(UC_X86_REG_EAX, 0x2, NO_MASK))); + BLOCK_ADD_CHECK("ret", V(0xC3), V(V(UC_X86_REG_ESP, 0x200000 - 4, NO_MASK))); + BLOCK_END(); - ADD_INSTRUCTION(&block, "mov esp, 0x200000", - V(0xBC, 0x00, 0x00, 0x20, 0x00), - V(V(UC_X86_REG_INVALID, 0x0, NO_MASK))); - ADD_INSTRUCTION(&block, "mov eax, 1", - V(0xB8, 0x01, 0x00, 0x00, 0x00), - V(V(UC_X86_REG_ESP, 0x200000, NO_MASK))); - ADD_INSTRUCTION(&block, "call 0x100015", - V(0xE8, 0x06, 0x00, 0x00, 0x00), - V(V(UC_X86_REG_EAX, 0x1, NO_MASK), V(UC_X86_REG_ESP, 0x200000, NO_MASK))); - ADD_INSTRUCTION(&block, "mov eax, 3", - V(0xB8, 0x03, 0x00, 0x00, 0x00), - V(V(UC_X86_REG_EAX, 0x2, NO_MASK))); - ADD_INSTRUCTION(&block, "int3", - V(0xCC), - V(V(UC_X86_REG_EAX, 0x3, NO_MASK))); - ADD_INSTRUCTION(&block, "enter 0x10,0", - V(0xC8, 0x10, 0x00, 0x00), - V(V(UC_X86_REG_ESP, 0x200000 - 4, NO_MASK))); - ADD_INSTRUCTION(&block, "mov eax, 2", - V(0xB8, 0x02, 0x00, 0x00, 0x00), - V(V(UC_X86_REG_ESP, 0x200000 - 4 - 4 - 0x10, NO_MASK), V(UC_X86_REG_EBP, 0x200000 - 4 - 4, NO_MASK))); - ADD_INSTRUCTION(&block, "leave", - V(0xC9), - V(V(UC_X86_REG_EAX, 0x2, NO_MASK), V(UC_X86_REG_INVALID, 0x0, NO_MASK))); - ADD_INSTRUCTION(&block, "mov eax, 2", - V(0xB8, 0x02, 0x00, 0x00, 0x00), - V(V(UC_X86_REG_INVALID, 0x0, NO_MASK))); - ADD_INSTRUCTION(&block, "ret", - V(0xC3), - V(V(UC_X86_REG_ESP, 0x200000 - 4, NO_MASK))); + loadBlock(uc, &b, ADDR_CODE); - loadBlock(uc, &block, ADDR_CODE); + OK(uc_hook_add(uc, &trace1, UC_HOOK_CODE, hook_code_test_i386_shl, &b, 1, 0)); + OK(uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL, 1, 0)); - // initialize machine registers - uint32_t zero = 0; - OK(uc_reg_write(uc, UC_X86_REG_EAX, &zero)); - OK(uc_reg_write(uc, UC_X86_REG_EBX, &zero)); - OK(uc_reg_write(uc, UC_X86_REG_ECX, &zero)); - OK(uc_reg_write(uc, UC_X86_REG_EDX, &zero)); + // emulate machine code in infinite time + OK(uc_emu_start(uc, ADDR_CODE, ADDR_CODE + b.size, 0, 0)); - OK(uc_hook_add(uc, &trace1, UC_HOOK_CODE, hook_code_test_i386_shl, &block, 1, 0)); - OK(uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL, 1, 0)); - - // emulate machine code in infinite time - OK(uc_emu_start(uc, ADDR_CODE, ADDR_CODE + block.size, 0, 0)); - - freeBlock(&block); - } + freeBlock(&b); uc_close(uc); } @@ -280,64 +229,38 @@ static void test_i386_enter_nested_leave(void **state) { uc_engine *uc; uc_hook trace1; + block b; // Initialize emulator in X86-32bit mode OK(uc_open(UC_ARCH_X86, UC_MODE_32, &uc)); OK(uc_mem_map(uc, ADDR_CODE, 0x1000, UC_PROT_ALL)); OK(uc_mem_map(uc, ADDR_STACK - 0x1000, 0x1000, UC_PROT_ALL)); - { - block block; - instruction* inst; + initRegisters(uc); - block.nbInsts = 0; + BLOCK_START(b); + BLOCK_ADD( "mov esp, 0x200000", V(0xBC, 0x00, 0x00, 0x20, 0x00)); + BLOCK_ADD_CHECK("mov eax, 1", V(0xB8, 0x01, 0x00, 0x00, 0x00), V(V(UC_X86_REG_ESP, 0x200000, NO_MASK))); + BLOCK_ADD_CHECK("call 0x100015", V(0xE8, 0x06, 0x00, 0x00, 0x00), V(V(UC_X86_REG_EAX, 0x1, NO_MASK))); + BLOCK_ADD_CHECK("mov eax, 3", V(0xB8, 0x03, 0x00, 0x00, 0x00), V(V(UC_X86_REG_EAX, 0x2, NO_MASK))); + BLOCK_ADD_CHECK("int3", V(0xCC), V(V(UC_X86_REG_EAX, 0x3, NO_MASK))); + BLOCK_ADD_CHECK("mov ebp, esp", V(0x89, 0xE5), V(V(UC_X86_REG_ESP, 0x200000 - 4, NO_MASK))); + BLOCK_ADD_CHECK("enter 0x10,1", V(0xC8, 0x10, 0x00, 0x01), V(V(UC_X86_REG_EBP, 0x200000 - 4, NO_MASK))); + BLOCK_ADD_CHECK("mov eax, 2", V(0xB8, 0x02, 0x00, 0x00, 0x00), V(V(UC_X86_REG_ESP, 0x200000 - 4 - 2*4 - 0x10, NO_MASK), V(UC_X86_REG_EBP, 0x200000 - 4 - 4, NO_MASK))); + BLOCK_ADD_CHECK("leave", V(0xC9), V(V(UC_X86_REG_EAX, 0x2, NO_MASK))); + BLOCK_ADD_CHECK("ret", V(0xC3), V(V(UC_X86_REG_ESP, 0x200000 - 4, NO_MASK))); + BLOCK_END(); - ADD_INSTRUCTION(&block, "mov esp, 0x200000", - V(0xBC, 0x00, 0x00, 0x20, 0x00), - V(V(UC_X86_REG_INVALID, 0x0, NO_MASK))); - ADD_INSTRUCTION(&block, "mov eax, 1", - V(0xB8, 0x01, 0x00, 0x00, 0x00), - V(V(UC_X86_REG_ESP, 0x200000, NO_MASK))); - ADD_INSTRUCTION(&block, "call 0x100015", - V(0xE8, 0x06, 0x00, 0x00, 0x00), - V(V(UC_X86_REG_EAX, 0x1, NO_MASK), V(UC_X86_REG_ESP, 0x200000, NO_MASK))); - ADD_INSTRUCTION(&block, "mov eax, 3", - V(0xB8, 0x03, 0x00, 0x00, 0x00), - V(V(UC_X86_REG_EAX, 0x2, NO_MASK))); - ADD_INSTRUCTION(&block, "int3", - V(0xCC), - V(V(UC_X86_REG_EAX, 0x3, NO_MASK))); - ADD_INSTRUCTION(&block, "enter 0x10,1", - V(0xC8, 0x10, 0x00, 0x01), - V(V(UC_X86_REG_ESP, 0x200000 - 4, NO_MASK))); - ADD_INSTRUCTION(&block, "mov eax, 2", - V(0xB8, 0x02, 0x00, 0x00, 0x00), - V(V(UC_X86_REG_ESP, 0x200000 - 4 - 2*4 - 0x10, NO_MASK), V(UC_X86_REG_EBP, 0x200000 - 4 - 4, NO_MASK))); - ADD_INSTRUCTION(&block, "leave", - V(0xC9), - V(V(UC_X86_REG_EAX, 0x2, NO_MASK))); - ADD_INSTRUCTION(&block, "ret", - V(0xC3), - V(V(UC_X86_REG_ESP, 0x200000 - 4, NO_MASK))); + loadBlock(uc, &b, ADDR_CODE); - loadBlock(uc, &block, ADDR_CODE); + OK(uc_hook_add(uc, &trace1, UC_HOOK_CODE, hook_code_test_i386_shl, &b, 1, 0)); + OK(uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL, 1, 0)); - // initialize machine registers - uint32_t zero = 0; - OK(uc_reg_write(uc, UC_X86_REG_EAX, &zero)); - OK(uc_reg_write(uc, UC_X86_REG_EBX, &zero)); - OK(uc_reg_write(uc, UC_X86_REG_ECX, &zero)); - OK(uc_reg_write(uc, UC_X86_REG_EDX, &zero)); - - OK(uc_hook_add(uc, &trace1, UC_HOOK_CODE, hook_code_test_i386_shl, &block, 1, 0)); - OK(uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL, 1, 0)); - - // emulate machine code in infinite time - OK(uc_emu_start(uc, ADDR_CODE, ADDR_CODE + block.size, 0, 0)); - - freeBlock(&block); - } + // emulate machine code in infinite time + OK(uc_emu_start(uc, ADDR_CODE, ADDR_CODE + b.size, 0, 0)); + freeBlock(&b); + uc_close(uc); } @@ -361,10 +284,15 @@ instruction* newInstruction(const uint8_t * _code, uint32_t _codeSize, const cha instruction* inst = (instruction*)malloc(sizeof(instruction)); inst->asmStr = _asmStr; - inst->code = _code; + memcpy(inst->code, _code, _codeSize); inst->codeSize = _codeSize; - inst->values = _values; - inst->nbValues = _nbValues; + inst->nbValues = 0; + if (_values) + { + inst->values = (reg_value*)malloc(_nbValues*sizeof(reg_value)); + memcpy(inst->values, _values, _nbValues*sizeof(reg_value)); + inst->nbValues = _nbValues; + } return inst; } @@ -398,7 +326,26 @@ void freeBlock(block* _block) { uint32_t i; for (i = 0; i < _block->nbInsts; i++) + { + if (_block->insts[i]->nbValues > 0) + free(_block->insts[i]->values); free(_block->insts[i]); + } +} + +void initRegisters(uc_engine *uc) +{ + // initialize machine registers + uint32_t zero = 0; + OK(uc_reg_write(uc, UC_X86_REG_EAX, &zero)); + OK(uc_reg_write(uc, UC_X86_REG_EBX, &zero)); + OK(uc_reg_write(uc, UC_X86_REG_ECX, &zero)); + OK(uc_reg_write(uc, UC_X86_REG_EDX, &zero)); + OK(uc_reg_write(uc, UC_X86_REG_EBP, &zero)); + OK(uc_reg_write(uc, UC_X86_REG_ESP, &zero)); + OK(uc_reg_write(uc, UC_X86_REG_EDI, &zero)); + OK(uc_reg_write(uc, UC_X86_REG_ESI, &zero)); + OK(uc_reg_write(uc, UC_X86_REG_EFLAGS, &zero)); } instruction* getInstruction(block* _block, uint32_t _addr) From edd37f7a1c7fc944304bf147e742d2d5954bb714 Mon Sep 17 00:00:00 2001 From: samothtronicien Date: Mon, 1 Aug 2016 10:31:10 +0200 Subject: [PATCH 11/11] removing tests/regress/test_x86_shl.cpp --- tests/regress/test_x86_shl.cpp | 165 --------------------------------- 1 file changed, 165 deletions(-) delete mode 100644 tests/regress/test_x86_shl.cpp diff --git a/tests/regress/test_x86_shl.cpp b/tests/regress/test_x86_shl.cpp deleted file mode 100644 index 41955b61..00000000 --- a/tests/regress/test_x86_shl.cpp +++ /dev/null @@ -1,165 +0,0 @@ -#include -#include -#include -#include - -#ifdef _WIN32 -# include -# define printf OutputDebugStringA -#endif - -char buffer[256]; - -void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) -{ - uint32_t eax = 0, ebx = 0, eflags = 0; - uc_reg_read(uc, UC_X86_REG_EAX, &eax); - uc_reg_read(uc, UC_X86_REG_EBX, &ebx); - uc_reg_read(uc, UC_X86_REG_EFLAGS, &eflags); - sprintf(buffer, "eip=%08x - eax=%08x - ebx=%08x - eflags=%08X\n", (uint32_t)address, eax, ebx, eflags); - printf(buffer); -} - -const char code32_prob[] = { - 0xBB, 0x3C, 0x00, 0x00, 0x00, //0x100000: mov ebx, 3Ch - 0xB1, 0x02, //0x100005: mov cl, 2 - 0xD3, 0xE3, //0x100007: shl ebx, cl - 0x9F, //0x100009: lahf - 0xCC //0x10000A: int3 -}; - -const char code32_ok[] = { - 0xBB, 0x3C, 0x00, 0x00, 0x00, //0x100000: mov ebx, 3Ch - 0xC1, 0xE3, 0x02, //0x100005: shl ebx, 2 - 0x9F, //0x100008: lahf - 0xCC //0x100009: int3 -}; - -const char code16_prob[] = { - 0x66, 0xBB, 0x3C, 0x00, //0x100000: mov bx, 3Ch - 0xB1, 0x02, //0x100004: mov cl, 2 - 0x66, 0xD3, 0xE3, //0x100006: shl bx, cl - 0x9F, //0x100009: lahf - 0xCC //0x10000A: int3 -}; - -const char code16_ok[] = { - 0x66, 0xBB, 0x3C, 0x00, //0x100000: mov bx, 3Ch - 0x66, 0xC1, 0xE3, 0x02, //0x100004: shl bx, 2 - 0x9F, //0x100008: lahf - 0xCC //0x10000A: int3 -}; - -const char code8_prob[] = { - 0xB3, 0x3C, //0x100000: mov bl, 3Ch - 0xB1, 0x02, //0x100002: mov cl, 2 - 0xD2, 0xE3, //0x100004: shl bl, 2 - 0x9F, //0x100006: lahf - 0xCC //0x100007: int3 -}; - -const char code8_ok[] = { - 0xB3, 0x3C, //0x100000: mov bl, 3Ch - 0xC0, 0xE3, 0x02, //0x100002: shl bl, 2 - 0x9F, //0x100005: lahf - 0xCC //0x100006: int3 -}; - -const char code_SHL_JP_CL[] = { - 0xB4, 0x00, //0x100000: mov ah, 0 - 0x9E, //0x100002: sahf - 0xB8, 0x3C, 0x00, 0x00, 0x00, //0x100003: mov eax, 3Ch - 0xB1, 0x02, //0x100008: mov cl, 2 - 0xD3, 0xE0, //0x10000A: shl eax, cl - 0x7A, 0x07, //0x10000C: jp +7 - 0xB8, 0x00, 0x00, 0x00, 0x00, //0x10000E: mov eax, 0 - 0xEB, 0x05, //0x100014: jmp +5 - 0xB8, 0x01, 0x00, 0x00, 0x00, //0x100016: mov eax, 1 - 0xCC //0x10001B: int3 -}; - -const char code_SHL_JP_NOCL[] = { - 0xB4, 0x00, //0x100000: mov ah, 0 - 0x9E, //0x100002: sahf - 0xB8, 0x3C, 0x00, 0x00, 0x00, //0x100003: mov eax, 3Ch - 0xC1, 0xE0, 0x02, //0x100008: shl eax, 2 - 0x7A, 0x07, //0x10000B: jp +7 - 0xB8, 0x00, 0x00, 0x00, 0x00, //0x10000D: mov eax, 0 - 0xEB, 0x05, //0x100014: - 0xB8, 0x01, 0x00, 0x00, 0x00, //0x100016: mov eax, 1 - 0xCC //0x100017: int3 -}; - - -#define ADDR_START 0x100000 - -#define TEST(X) if((X) != UC_ERR_OK) { \ - printf("error: '" #X "' failed\n"); \ - return 1; \ - } - -int main() -{ - uint32_t eflags = 0, eax = 0; - uc_engine * uc = NULL; - - TEST(uc_open(UC_ARCH_X86, UC_MODE_32, &uc)); - - uc_hook trace_hook_code; - TEST(uc_hook_add(uc, &trace_hook_code, UC_HOOK_CODE, hook_code, NULL, 1, 0)); - TEST(uc_mem_map(uc, ADDR_START, 0x1000, UC_PROT_READ | UC_PROT_EXEC)); - -#define RUN_CODE(CODE) { \ - TEST(uc_mem_write(uc, ADDR_START, CODE, sizeof(CODE))); \ - printf("running " #CODE "...\n"); \ - eflags = 0; \ - uc_reg_write(uc, UC_X86_REG_EFLAGS, &eflags); \ - TEST(uc_emu_start(uc, ADDR_START, ADDR_START + sizeof(CODE) - 1, 0, 0)); \ - uc_reg_read(uc, UC_X86_REG_EFLAGS, &eflags); \ - uc_reg_read(uc, UC_X86_REG_EAX, &eax); \ - sprintf(buffer, "after uc_emu_start: eflags=%08X - ah=%08X - %s\n", eflags, (eax>>8) & 0xFF, eflags & 4 ? "success" : "failed"); \ - printf(buffer); \ -} - - //32 bits - RUN_CODE(code32_prob); - RUN_CODE(code32_ok); - - //16 bits - RUN_CODE(code16_prob); - RUN_CODE(code16_ok); - - //8 bits - RUN_CODE(code8_prob); - RUN_CODE(code8_ok); - - //test with JP-CL - eflags = 0; - uc_reg_write(uc, UC_X86_REG_EFLAGS, &eflags); - - TEST(uc_mem_write(uc, ADDR_START, code_SHL_JP_CL, sizeof(code_SHL_JP_CL))); - printf("running code_SHL_JP_CL ...\n"); - TEST(uc_emu_start(uc, ADDR_START, ADDR_START + sizeof(code_SHL_JP_CL) - 1, 0, 0)); - - eax = 0; - uc_reg_read(uc, UC_X86_REG_EAX, &eax); - if (eax == 1) printf("success\n"); - else printf("failed\n"); - - //test with JP-NOCL - eflags = 0; - uc_reg_write(uc, UC_X86_REG_EFLAGS, &eflags); - - TEST(uc_mem_write(uc, ADDR_START, code_SHL_JP_NOCL, sizeof(code_SHL_JP_NOCL))); - printf("running code_SHL_JP_NOCL ...\n"); - TEST(uc_emu_start(uc, ADDR_START, ADDR_START + sizeof(code_SHL_JP_NOCL) - 1, 0, 0)); - - eax = 0; - uc_reg_read(uc, UC_X86_REG_EAX, &eax); - if (eax == 1) printf("success\n"); - else printf("failed\n"); - - TEST(uc_close(uc)); - - return 0; -}