Merge branch 'master' into m1
This commit is contained in:
30
tests/regress/LICENSE
Normal file
30
tests/regress/LICENSE
Normal file
@@ -0,0 +1,30 @@
|
||||
This is the software license for Unicorn regression tests. The regression tests
|
||||
are written by several Unicorn contributors (See CREDITS.TXT) and maintained by
|
||||
Hoang-Vu Dang <dang.hvu@gmail.com>
|
||||
|
||||
Copyright (c) 2015, Unicorn contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of the developer(s) nor the names of its
|
||||
contributors may be used to endorse or promote products derived from this
|
||||
software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
167
tests/regress/jumping.py
Executable file
167
tests/regress/jumping.py
Executable file
@@ -0,0 +1,167 @@
|
||||
#!/usr/bin/env python
|
||||
# Mariano Graziano
|
||||
|
||||
from unicorn import *
|
||||
from unicorn.x86_const import *
|
||||
|
||||
import regress
|
||||
|
||||
#echo -ne "\x48\x31\xc0\x48\xb8\x04\x00\x00\x00\x00\x00\x00\x00\x48\x3d\x05\x00\x00\x00\x74\x05\xe9\x0f\x00\x00\x00\x48\xba\xbe\xba\x00\x00\x00\x00\x00\x00\xe9\x0f\x00\x00\x00\x48\xba\xca\xc0\x00\x00\x00\x00\x00\x00\xe9\x00\x00\x00\x00\x90" | ndisasm - -b64
|
||||
#00000000 4831C0 xor rax,rax
|
||||
#00000003 48B8040000000000 mov rax,0x4
|
||||
# -0000
|
||||
#0000000D 483D05000000 cmp rax,0x5
|
||||
#00000013 7405 jz 0x1a
|
||||
#00000015 E90F000000 jmp qword 0x29
|
||||
#0000001A 48BABEBA00000000 mov rdx,0xbabe
|
||||
# -0000
|
||||
#00000024 E90F000000 jmp qword 0x38
|
||||
#00000029 48BACAC000000000 mov rdx,0xc0ca
|
||||
# -0000
|
||||
#00000033 E900000000 jmp qword 0x38
|
||||
#00000038 90 nop
|
||||
|
||||
|
||||
mu = 0
|
||||
zf = 1 # (0:clear, 1:set)
|
||||
|
||||
|
||||
class Init(regress.RegressTest):
|
||||
def clear_zf(self):
|
||||
eflags_cur = mu.reg_read(UC_X86_REG_EFLAGS)
|
||||
eflags = eflags_cur & ~(1 << 6)
|
||||
#eflags = 0x0
|
||||
print "[clear_zf] - eflags from %x to %x" % (eflags_cur, eflags)
|
||||
if eflags != eflags_cur:
|
||||
print "[clear_zf] - writing new eflags..."
|
||||
mu.reg_write(UC_X86_REG_EFLAGS, eflags)
|
||||
|
||||
def set_zf(self):
|
||||
eflags_cur = mu.reg_read(UC_X86_REG_EFLAGS)
|
||||
eflags = eflags_cur | (1 << 6)
|
||||
#eflags = 0xFFFFFFFF
|
||||
print "[set_zf] - eflags from %x to %x" % (eflags_cur, eflags)
|
||||
if eflags != eflags_cur:
|
||||
print "[set_zf] - writing new eflags..."
|
||||
mu.reg_write(UC_X86_REG_EFLAGS, eflags)
|
||||
|
||||
def handle_zf(self, zf):
|
||||
print "[handle_zf] - eflags " , zf
|
||||
if zf == 0: self.clear_zf()
|
||||
else: self.set_zf()
|
||||
|
||||
def multipath(self):
|
||||
print "[multipath] - handling ZF (%s) - default" % zf
|
||||
self.handle_zf(zf)
|
||||
|
||||
# callback for tracing basic blocks
|
||||
def hook_block(self, uc, address, size, user_data):
|
||||
print(">>> Tracing basic block at 0x%x, block size = 0x%x" %(address, size))
|
||||
|
||||
# callback for tracing instructions
|
||||
def hook_code(self, uc, address, size, user_data):
|
||||
print(">>> Tracing instruction at 0x%x, instruction size = %u" %(address, size))
|
||||
rax = mu.reg_read(UC_X86_REG_RAX)
|
||||
rbx = mu.reg_read(UC_X86_REG_RBX)
|
||||
rcx = mu.reg_read(UC_X86_REG_RCX)
|
||||
rdx = mu.reg_read(UC_X86_REG_RDX)
|
||||
rsi = mu.reg_read(UC_X86_REG_RSI)
|
||||
rdi = mu.reg_read(UC_X86_REG_RDI)
|
||||
r8 = mu.reg_read(UC_X86_REG_R8)
|
||||
r9 = mu.reg_read(UC_X86_REG_R9)
|
||||
r10 = mu.reg_read(UC_X86_REG_R10)
|
||||
r11 = mu.reg_read(UC_X86_REG_R11)
|
||||
r12 = mu.reg_read(UC_X86_REG_R12)
|
||||
r13 = mu.reg_read(UC_X86_REG_R13)
|
||||
r14 = mu.reg_read(UC_X86_REG_R14)
|
||||
r15 = mu.reg_read(UC_X86_REG_R15)
|
||||
eflags = mu.reg_read(UC_X86_REG_EFLAGS)
|
||||
|
||||
print(">>> RAX = %x" %rax)
|
||||
print(">>> RBX = %x" %rbx)
|
||||
print(">>> RCX = %x" %rcx)
|
||||
print(">>> RDX = %x" %rdx)
|
||||
print(">>> RSI = %x" %rsi)
|
||||
print(">>> RDI = %x" %rdi)
|
||||
print(">>> R8 = %x" %r8)
|
||||
print(">>> R9 = %x" %r9)
|
||||
print(">>> R10 = %x" %r10)
|
||||
print(">>> R11 = %x" %r11)
|
||||
print(">>> R12 = %x" %r12)
|
||||
print(">>> R13 = %x" %r13)
|
||||
print(">>> R14 = %x" %r14)
|
||||
print(">>> R15 = %x" %r15)
|
||||
print(">>> ELAGS = %x" %eflags)
|
||||
print "-"*11
|
||||
self.multipath()
|
||||
print "-"*11
|
||||
|
||||
# callback for tracing memory access (READ or WRITE)
|
||||
def hook_mem_access(self, uc, access, address, size, value, user_data):
|
||||
if access == UC_MEM_WRITE:
|
||||
print(">>> Memory is being WRITE at 0x%x, data size = %u, data value = 0x%x" \
|
||||
%(address, size, value))
|
||||
else: # READ
|
||||
print(">>> Memory is being READ at 0x%x, data size = %u" \
|
||||
%(address, size))
|
||||
|
||||
# callback for tracing invalid memory access (READ or WRITE)
|
||||
def hook_mem_invalid(self, uc, access, address, size, value, user_data):
|
||||
print("[ HOOK_MEM_INVALID - Address: %s ]" % hex(address))
|
||||
if access == UC_MEM_WRITE_UNMAPPED:
|
||||
print(">>> Missing memory is being WRITE at 0x%x, data size = %u, data value = 0x%x" %(address, size, value))
|
||||
return True
|
||||
else:
|
||||
print(">>> Missing memory is being READ at 0x%x, data size = %u, data value = 0x%x" %(address, size, value))
|
||||
return True
|
||||
|
||||
|
||||
def hook_mem_fetch_unmapped(self, uc, access, address, size, value, user_data):
|
||||
print("[ HOOK_MEM_FETCH - Address: %s ]" % hex(address))
|
||||
print("[ mem_fetch_unmapped: faulting address at %s ]" % hex(address).strip("L"))
|
||||
return True
|
||||
|
||||
def runTest(self):
|
||||
global mu
|
||||
|
||||
JUMP = "\x48\x31\xc0\x48\xb8\x04\x00\x00\x00\x00\x00\x00\x00\x48\x3d\x05\x00\x00\x00\x74\x05\xe9\x0f\x00\x00\x00\x48\xba\xbe\xba\x00\x00\x00\x00\x00\x00\xe9\x0f\x00\x00\x00\x48\xba\xca\xc0\x00\x00\x00\x00\x00\x00\xe9\x00\x00\x00\x00\x90"
|
||||
|
||||
ADDRESS = 0x1000000
|
||||
|
||||
print("Emulate x86_64 code")
|
||||
# Initialize emulator in X86-64bit mode
|
||||
mu = Uc(UC_ARCH_X86, UC_MODE_64)
|
||||
|
||||
# map 2MB memory for this emulation
|
||||
mu.mem_map(ADDRESS, 2 * 1024 * 1024)
|
||||
|
||||
# write machine code to be emulated to memory
|
||||
mu.mem_write(ADDRESS, JUMP)
|
||||
|
||||
# setup stack
|
||||
mu.reg_write(UC_X86_REG_RSP, ADDRESS + 0x200000)
|
||||
|
||||
# tracing all basic blocks with customized callback
|
||||
mu.hook_add(UC_HOOK_BLOCK, self.hook_block)
|
||||
|
||||
# tracing all instructions in range [ADDRESS, ADDRESS+0x60]
|
||||
mu.hook_add(UC_HOOK_CODE, self.hook_code, None, ADDRESS, ADDRESS+0x60)
|
||||
|
||||
# tracing all memory READ & WRITE access
|
||||
mu.hook_add(UC_HOOK_MEM_WRITE, self.hook_mem_access)
|
||||
mu.hook_add(UC_HOOK_MEM_READ, self.hook_mem_access)
|
||||
mu.hook_add(UC_HOOK_MEM_FETCH_UNMAPPED, self.hook_mem_fetch_unmapped)
|
||||
mu.hook_add(UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED, self.hook_mem_invalid)
|
||||
|
||||
try:
|
||||
# emulate machine code in infinite time
|
||||
mu.emu_start(ADDRESS, ADDRESS + len(JUMP))
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
rdx = mu.reg_read(UC_X86_REG_RDX)
|
||||
self.assertEqual(rdx, 0xbabe, "RDX contains the wrong value. Eflags modification failed.")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
regress.main()
|
||||
@@ -5,7 +5,7 @@ CFLAGS += -lcmocka -lunicorn
|
||||
CFLAGS += -I ../../include
|
||||
|
||||
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_tb_x86 test_multihook test_pc_change test_x86_soft_paging
|
||||
|
||||
.PHONY: all
|
||||
all: ${ALL_TESTS}
|
||||
@@ -25,6 +25,7 @@ test: ${ALL_TESTS}
|
||||
./test_tb_x86
|
||||
./test_multihook
|
||||
./test_pc_change
|
||||
./test_x86_soft_paging
|
||||
|
||||
test_sanity: test_sanity.c
|
||||
test_x86: test_x86.c
|
||||
@@ -34,6 +35,7 @@ test_mem_high: test_mem_high.c
|
||||
test_tb_x86: test_tb_x86.c
|
||||
test_multihook: test_multihook.c
|
||||
test_pc_change: test_pc_change.c
|
||||
test_x86_soft_paging: test_x86_soft_paging.c
|
||||
|
||||
${ALL_TESTS}:
|
||||
${CC} ${CFLAGS} -o $@ $^
|
||||
|
||||
@@ -79,7 +79,7 @@ static void test_high_address_reads(void **state)
|
||||
uint8_t code[] = {0x48,0x8b,0x00,0x90,0x90,0x90,0x90}; // mov rax, [rax], nops
|
||||
uc_assert_success(uc_mem_map(uc, base_addr, 4096, UC_PROT_ALL));
|
||||
uc_assert_success(uc_mem_write(uc, base_addr, code, 7));
|
||||
uc_assert_success(uc_hook_add(uc, &trace2, UC_HOOK_MEM_READ, hook_mem64, NULL, (uint64_t)1, (uint64_t)0));
|
||||
uc_assert_success(uc_hook_add(uc, &trace2, UC_HOOK_MEM_READ, hook_mem64, NULL, 1, 0));
|
||||
uc_assert_success(uc_emu_start(uc, base_addr, base_addr + 3, 0, 0));
|
||||
if(number_of_memory_reads != 1) {
|
||||
fail_msg("wrong number of memory reads for instruction %i", number_of_memory_reads);
|
||||
|
||||
@@ -158,6 +158,15 @@ static void test_strange_map(void **state)
|
||||
uc_mem_unmap(uc, 0x0,0x1000);
|
||||
}
|
||||
|
||||
static void test_query_page_size(void **state)
|
||||
{
|
||||
uc_engine *uc = *state;
|
||||
|
||||
size_t page_size;
|
||||
uc_assert_success(uc_query(uc, UC_QUERY_PAGE_SIZE, &page_size));
|
||||
assert_int_equal(4096, page_size);
|
||||
}
|
||||
|
||||
void write(uc_engine* uc, uint64_t addr, uint64_t len){
|
||||
uint8_t* buff = alloca(len);
|
||||
memset(buff,0,len);
|
||||
@@ -220,6 +229,7 @@ int main(void) {
|
||||
test(test_unmap_double_map),
|
||||
test(test_overlap_unmap_double_map),
|
||||
test(test_strange_map),
|
||||
test(test_query_page_size),
|
||||
};
|
||||
#undef test
|
||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
|
||||
@@ -96,8 +96,8 @@ static void test_basic_blocks(void **state)
|
||||
OK(uc_mem_write(uc, address, code, sizeof(code)));
|
||||
|
||||
// trace all basic blocks
|
||||
OK(uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, test_basic_blocks_hook, &bbtest, (uint64_t)1, (uint64_t)0));
|
||||
OK(uc_hook_add(uc, &trace2, UC_HOOK_BLOCK, test_basic_blocks_hook2, &bbtest, (uint64_t)1, (uint64_t)0));
|
||||
OK(uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, test_basic_blocks_hook, &bbtest, 1, 0));
|
||||
OK(uc_hook_add(uc, &trace2, UC_HOOK_BLOCK, test_basic_blocks_hook2, &bbtest, 1, 0));
|
||||
|
||||
OK(uc_emu_start(uc, address, address+sizeof(code), 0, 0));
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ static void test_pc_change(void **state)
|
||||
printf("ECX = %u, EDX = %u\n", r_ecx, r_edx);
|
||||
|
||||
// trace all instructions
|
||||
OK(uc_hook_add(uc, &trace1, UC_HOOK_CODE, test_code_hook, NULL, (uint64_t)1, (uint64_t)0));
|
||||
OK(uc_hook_add(uc, &trace1, UC_HOOK_CODE, test_code_hook, NULL, 1, 0));
|
||||
|
||||
OK(uc_emu_start(uc, address, address+sizeof(code), 0, 0));
|
||||
|
||||
|
||||
@@ -273,16 +273,16 @@ static void test_tb_x86_64_32_imul_Gv_Ev_Ib(void **state)
|
||||
UC_HOOK_CODE,
|
||||
hook_code32,
|
||||
NULL,
|
||||
(uint64_t)1,
|
||||
(uint64_t)0));
|
||||
1,
|
||||
0));
|
||||
|
||||
uc_assert_success(uc_hook_add(uc,
|
||||
&trace2,
|
||||
UC_HOOK_MEM_VALID,
|
||||
hook_mem32,
|
||||
NULL,
|
||||
(uint64_t)1,
|
||||
(uint64_t)0));
|
||||
1,
|
||||
0));
|
||||
|
||||
uc_assert_success(uc_emu_start(uc,
|
||||
#ifdef RIP_NEXT_TO_THE_SELFMODIFY_OPCODE
|
||||
|
||||
@@ -85,7 +85,7 @@ static void test_basic_blocks(void **state)
|
||||
OK(uc_mem_write(uc, address, code, sizeof(code)));
|
||||
|
||||
// trace all basic blocks
|
||||
OK(uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, test_basic_blocks_hook, &bbtest, (uint64_t)1, (uint64_t)0));
|
||||
OK(uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, test_basic_blocks_hook, &bbtest, 1, 0));
|
||||
|
||||
OK(uc_emu_start(uc, address, address+sizeof(code), 0, 0));
|
||||
}
|
||||
@@ -144,11 +144,11 @@ static void test_i386(void **state)
|
||||
uc_assert_success(err);
|
||||
|
||||
// tracing all basic blocks with customized callback
|
||||
err = uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0);
|
||||
err = uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0);
|
||||
uc_assert_success(err);
|
||||
|
||||
// tracing all instruction by having @begin > @end
|
||||
err = uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0);
|
||||
err = uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0);
|
||||
uc_assert_success(err);
|
||||
|
||||
// emulate machine code in infinite time
|
||||
@@ -194,11 +194,11 @@ static void test_i386_jump(void **state)
|
||||
uc_assert_success(err);
|
||||
|
||||
// tracing 1 basic block with customized callback
|
||||
err = uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)address, (uint64_t)address);
|
||||
err = uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, address, address);
|
||||
uc_assert_success(err);
|
||||
|
||||
// tracing 1 instruction at address
|
||||
err = uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)address, (uint64_t)address);
|
||||
err = uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, address, address);
|
||||
uc_assert_success(err);
|
||||
|
||||
// emulate machine code in infinite time
|
||||
@@ -302,19 +302,19 @@ static void test_i386_inout(void **state)
|
||||
uc_assert_success(err);
|
||||
|
||||
// tracing all basic blocks with customized callback
|
||||
err = uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0);
|
||||
err = uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0);
|
||||
uc_assert_success(err);
|
||||
|
||||
// tracing all instructions
|
||||
err = uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0);
|
||||
err = uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0);
|
||||
uc_assert_success(err);
|
||||
|
||||
// uc IN instruction
|
||||
err = uc_hook_add(uc, &trace3, UC_HOOK_INSN, hook_in, NULL, UC_X86_INS_IN);
|
||||
err = uc_hook_add(uc, &trace3, UC_HOOK_INSN, hook_in, NULL, 1, 0, UC_X86_INS_IN);
|
||||
uc_assert_success(err);
|
||||
|
||||
// uc OUT instruction
|
||||
err = uc_hook_add(uc, &trace4, UC_HOOK_INSN, hook_out, NULL, UC_X86_INS_OUT);
|
||||
err = uc_hook_add(uc, &trace4, UC_HOOK_INSN, hook_out, NULL, 1, 0, UC_X86_INS_OUT);
|
||||
uc_assert_success(err);
|
||||
|
||||
// emulate machine code in infinite time
|
||||
@@ -566,19 +566,19 @@ static void test_x86_64(void **state)
|
||||
uc_assert_success(uc_reg_write(uc, UC_X86_REG_R15, &r15));
|
||||
|
||||
// tracing all basic blocks with customized callback
|
||||
err = uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0);
|
||||
err = uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0);
|
||||
uc_assert_success(err);
|
||||
|
||||
// tracing all instructions in the range [address, address+20]
|
||||
err = uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code64, NULL, (uint64_t)address, (uint64_t)(address+20));
|
||||
err = uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code64, NULL, address, address+20);
|
||||
uc_assert_success(err);
|
||||
|
||||
// tracing all memory WRITE access (with @begin > @end)
|
||||
err = uc_hook_add(uc, &trace3, UC_HOOK_MEM_WRITE, hook_mem64, NULL, (uint64_t)1, (uint64_t)0);
|
||||
err = uc_hook_add(uc, &trace3, UC_HOOK_MEM_WRITE, hook_mem64, NULL, 1, 0);
|
||||
uc_assert_success(err);
|
||||
|
||||
// tracing all memory READ access (with @begin > @end)
|
||||
err = uc_hook_add(uc, &trace4, UC_HOOK_MEM_READ, hook_mem64, NULL, (uint64_t)1, (uint64_t)0);
|
||||
err = uc_hook_add(uc, &trace4, UC_HOOK_MEM_READ, hook_mem64, NULL, 1, 0);
|
||||
uc_assert_success(err);
|
||||
|
||||
// emulate machine code in infinite time (last param = 0), or when
|
||||
@@ -662,7 +662,7 @@ static void test_x86_64_syscall(void **state)
|
||||
uc_assert_success(err);
|
||||
|
||||
// hook interrupts for syscall
|
||||
err = uc_hook_add(uc, &trace1, UC_HOOK_INSN, hook_syscall, NULL, UC_X86_INS_SYSCALL);
|
||||
err = uc_hook_add(uc, &trace1, UC_HOOK_INSN, hook_syscall, NULL, 1, 0, UC_X86_INS_SYSCALL);
|
||||
uc_assert_success(err);
|
||||
|
||||
// initialize machine registers
|
||||
|
||||
210
tests/unit/test_x86_soft_paging.c
Normal file
210
tests/unit/test_x86_soft_paging.c
Normal file
@@ -0,0 +1,210 @@
|
||||
#include "unicorn_test.h"
|
||||
#include <inttypes.h>
|
||||
|
||||
/*
|
||||
Two tests here for software paging
|
||||
Low paging: Test paging using virtual addresses already mapped by Unicorn
|
||||
High paging: Test paging using virtual addresses not mapped by Unicorn
|
||||
*/
|
||||
|
||||
static void test_low_paging(void **state) {
|
||||
uc_engine *uc;
|
||||
uc_err err;
|
||||
int r_eax;
|
||||
|
||||
/* The following x86 code will map emulated physical memory
|
||||
to virtual memory using pages and attempt
|
||||
to read/write from virtual memory
|
||||
|
||||
Specifically, the virtual memory address range
|
||||
has been mapped by Unicorn (0x7FF000 - 0x7FFFFF)
|
||||
|
||||
Memory area purposes:
|
||||
0x1000 = page directory
|
||||
0x2000 = page table (identity map first 4 MiB)
|
||||
0x3000 = page table (0x007FF000 -> 0x00004000)
|
||||
0x4000 = data area (0xBEEF)
|
||||
*/
|
||||
const uint8_t code[] = {
|
||||
/* Zero memory for page directories and page tables */
|
||||
0xBF, 0x00, 0x10, 0x00, 0x00, /* MOV EDI, 0x1000 */
|
||||
0xB9, 0x00, 0x10, 0x00, 0x00, /* MOV ECX, 0x1000 */
|
||||
0x31, 0xC0, /* XOR EAX, EAX */
|
||||
0xF3, 0xAB, /* REP STOSD */
|
||||
|
||||
/* Load DWORD [0x4000] with 0xDEADBEEF to retrieve later */
|
||||
0xBF, 0x00, 0x40, 0x00, 0x00, /* MOV EDI, 0x4000 */
|
||||
0xB8, 0xEF, 0xBE, 0x00, 0x00, /* MOV EAX, 0xBEEF */
|
||||
0x89, 0x07, /* MOV [EDI], EAX */
|
||||
|
||||
/* Identity map the first 4MiB of memory */
|
||||
0xB9, 0x00, 0x04, 0x00, 0x00, /* MOV ECX, 0x400 */
|
||||
0xBF, 0x00, 0x20, 0x00, 0x00, /* MOV EDI, 0x2000 */
|
||||
0xB8, 0x03, 0x00, 0x00, 0x00, /* MOV EAX, 3 */
|
||||
/* aLoop: */
|
||||
0xAB, /* STOSD */
|
||||
0x05, 0x00, 0x10, 0x00, 0x00, /* ADD EAX, 0x1000 */
|
||||
0xE2, 0xF8, /* LOOP aLoop */
|
||||
|
||||
/* Map physical address 0x4000 to virtual address 0x7FF000 */
|
||||
0xBF, 0xFC, 0x3F, 0x00, 0x00, /* MOV EDI, 0x3FFC */
|
||||
0xB8, 0x03, 0x40, 0x00, 0x00, /* MOV EAX, 0x4003 */
|
||||
0x89, 0x07, /* MOV [EDI], EAX */
|
||||
|
||||
/* Add page tables into page directory */
|
||||
0xBF, 0x00, 0x10, 0x00, 0x00, /* MOV EDI, 0x1000 */
|
||||
0xB8, 0x03, 0x20, 0x00, 0x00, /* MOV EAX, 0x2003 */
|
||||
0x89, 0x07, /* MOV [EDI], EAX */
|
||||
0xBF, 0x04, 0x10, 0x00, 0x00, /* MOV EDI, 0x1004 */
|
||||
0xB8, 0x03, 0x30, 0x00, 0x00, /* MOV EAX, 0x3003 */
|
||||
0x89, 0x07, /* MOV [EDI], EAX */
|
||||
|
||||
/* Load the page directory register */
|
||||
0xB8, 0x00, 0x10, 0x00, 0x00, /* MOV EAX, 0x1000 */
|
||||
0x0F, 0x22, 0xD8, /* MOV CR3, EAX */
|
||||
|
||||
/* Enable paging */
|
||||
0x0F, 0x20, 0xC0, /* MOV EAX, CR0 */
|
||||
0x0D, 0x00, 0x00, 0x00, 0x80, /* OR EAX, 0x80000000 */
|
||||
0x0F, 0x22, 0xC0, /* MOV CR0, EAX */
|
||||
|
||||
/* Clear EAX */
|
||||
0x31, 0xC0, /* XOR EAX, EAX */
|
||||
|
||||
/* Load using virtual memory address; EAX = 0xBEEF */
|
||||
0xBE, 0x00, 0xF0, 0x7F, 0x00, /* MOV ESI, 0x7FF000 */
|
||||
0x8B, 0x06, /* MOV EAX, [ESI] */
|
||||
0xF4, /* HLT */
|
||||
};
|
||||
|
||||
/* Initialise X86-32bit mode */
|
||||
err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc);
|
||||
uc_assert_success(err);
|
||||
|
||||
/* Map 8MB of memory at base address 0 */
|
||||
err = uc_mem_map(uc, 0, (8 * 1024 * 1024), UC_PROT_ALL);
|
||||
uc_assert_success(err);
|
||||
|
||||
/* Write code into memory at address 0 */
|
||||
err = uc_mem_write(uc, 0, code, sizeof(code));
|
||||
uc_assert_success(err);
|
||||
|
||||
/* Start emulation */
|
||||
err = uc_emu_start(uc, 0, sizeof(code), 0, 0);
|
||||
uc_assert_success(err);
|
||||
|
||||
/* The code should have loaded 0xBEEF into EAX */
|
||||
uc_reg_read(uc, UC_X86_REG_EAX, &r_eax);
|
||||
assert_int_equal(r_eax, 0xBEEF);
|
||||
|
||||
uc_close(uc);
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
|
||||
static void test_high_paging(void **state) {
|
||||
uc_engine *uc;
|
||||
uc_err err;
|
||||
int r_eax;
|
||||
|
||||
/* The following x86 code will map emulated physical memory
|
||||
to virtual memory using pages and attempt
|
||||
to read/write from virtual memory
|
||||
|
||||
Specifically, the virtual memory address range
|
||||
has not been mapped by UC (0xFFFFF000 - 0xFFFFFFFF)
|
||||
|
||||
Memory area purposes:
|
||||
0x1000 = page directory
|
||||
0x2000 = page table (identity map first 4 MiB)
|
||||
0x3000 = page table (0xFFFFF000 -> 0x00004000)
|
||||
0x4000 = data area (0xDEADBEEF)
|
||||
*/
|
||||
const uint8_t code[] = {
|
||||
/* Zero memory for page directories and page tables */
|
||||
0xBF, 0x00, 0x10, 0x00, 0x00, /* MOV EDI, 0x1000 */
|
||||
0xB9, 0x00, 0x10, 0x00, 0x00, /* MOV ECX, 0x1000 */
|
||||
0x31, 0xC0, /* XOR EAX, EAX */
|
||||
0xF3, 0xAB, /* REP STOSD */
|
||||
|
||||
/* Load DWORD [0x4000] with 0xDEADBEEF to retrieve later */
|
||||
0xBF, 0x00, 0x40, 0x00, 0x00, /* MOV EDI, 0x4000 */
|
||||
0xB8, 0xEF, 0xBE, 0x00, 0x00, /* MOV EAX, 0xBEEF */
|
||||
0x89, 0x07, /* MOV [EDI], EAX */
|
||||
|
||||
/* Identity map the first 4MiB of memory */
|
||||
0xB9, 0x00, 0x04, 0x00, 0x00, /* MOV ECX, 0x400 */
|
||||
0xBF, 0x00, 0x20, 0x00, 0x00, /* MOV EDI, 0x2000 */
|
||||
0xB8, 0x03, 0x00, 0x00, 0x00, /* MOV EAX, 3 */
|
||||
/* aLoop: */
|
||||
0xAB, /* STOSD */
|
||||
0x05, 0x00, 0x10, 0x00, 0x00, /* ADD EAX, 0x1000 */
|
||||
0xE2, 0xF8, /* LOOP aLoop */
|
||||
|
||||
/* Map physical address 0x4000 to virtual address 0xFFFFF000 */
|
||||
0xBF, 0xFC, 0x3F, 0x00, 0x00, /* MOV EDI, 0x3FFC */
|
||||
0xB8, 0x03, 0x40, 0x00, 0x00, /* MOV EAX, 0x4003 */
|
||||
0x89, 0x07, /* MOV [EDI], EAX */
|
||||
|
||||
/* Add page tables into page directory */
|
||||
0xBF, 0x00, 0x10, 0x00, 0x00, /* MOV EDI, 0x1000 */
|
||||
0xB8, 0x03, 0x20, 0x00, 0x00, /* MOV EAX, 0x2003 */
|
||||
0x89, 0x07, /* MOV [EDI], EAX */
|
||||
0xBF, 0xFC, 0x1F, 0x00, 0x00, /* MOV EDI, 0x1FFC */
|
||||
0xB8, 0x03, 0x30, 0x00, 0x00, /* MOV EAX, 0x3003 */
|
||||
0x89, 0x07, /* MOV [EDI], EAX */
|
||||
|
||||
/* Load the page directory register */
|
||||
0xB8, 0x00, 0x10, 0x00, 0x00, /* MOV EAX, 0x1000 */
|
||||
0x0F, 0x22, 0xD8, /* MOV CR3, EAX */
|
||||
|
||||
/* Enable paging */
|
||||
0x0F, 0x20, 0xC0, /* MOV EAX, CR0 */
|
||||
0x0D, 0x00, 0x00, 0x00, 0x80, /* OR EAX, 0x80000000 */
|
||||
0x0F, 0x22, 0xC0, /* MOV CR0, EAX */
|
||||
|
||||
/* Clear EAX */
|
||||
0x31, 0xC0, /* XOR EAX, EAX */
|
||||
|
||||
/* Load using virtual memory address; EAX = 0xBEEF */
|
||||
0xBE, 0x00, 0xF0, 0xFF, 0xFF, /* MOV ESI, 0xFFFFF000 */
|
||||
0x8B, 0x06, /* MOV EAX, [ESI] */
|
||||
0xF4, /* HLT */
|
||||
};
|
||||
|
||||
/* Initialise X86-32bit mode */
|
||||
err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc);
|
||||
uc_assert_success(err);
|
||||
|
||||
/* Map 4MB of memory at base address 0 */
|
||||
err = uc_mem_map(uc, 0, (4 * 1024 * 1024), UC_PROT_ALL);
|
||||
uc_assert_success(err);
|
||||
|
||||
/* Write code into memory at address 0 */
|
||||
err = uc_mem_write(uc, 0, code, sizeof(code));
|
||||
uc_assert_success(err);
|
||||
|
||||
/* Start emulation */
|
||||
err = uc_emu_start(uc, 0, sizeof(code), 0, 0);
|
||||
uc_assert_success(err);
|
||||
|
||||
/* The code should have loaded 0xBEEF into EAX */
|
||||
uc_reg_read(uc, UC_X86_REG_EAX, &r_eax);
|
||||
assert_int_equal(r_eax, 0xBEEF);
|
||||
|
||||
uc_close(uc);
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
|
||||
int main(void) {
|
||||
const struct CMUnitTest tests[] = {
|
||||
cmocka_unit_test(test_low_paging),
|
||||
cmocka_unit_test(test_high_paging),
|
||||
};
|
||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
}
|
||||
Reference in New Issue
Block a user