fix conflicts when merging map-ptr branch to master branch

This commit is contained in:
Nguyen Anh Quynh
2015-12-17 08:12:02 +08:00
57 changed files with 3907 additions and 54 deletions

View File

@ -1,5 +1,11 @@
CFLAGS += -I../include
CFLAGS += -I../../include
ifeq (MING,$(findstring MING,$(shell uname -s)))
LDFLAGS += ../../unicorn.lib $(shell pkg-config --libs glib-2.0) -lpthread -lm
else
LDFLAGS += ../../libunicorn.a $(shell pkg-config --libs glib-2.0) -lpthread -lm
endif
TESTS = map_crash map_write
TESTS += sigill sigill2
@ -18,6 +24,14 @@ TESTS += eflags_noset
TESTS += mem_map_large
TESTS += invalid_read_in_cpu_tb_exec
TESTS += invalid_write_in_cpu_tb_exec_x86_64
TESTS += x86_16_segfault
TESTS += mips_invalid_read_of_size_4_when_tracing
TESTS += invalid_read_in_tb_flush_x86_64
TESTS += sparc_jump_to_zero
TESTS += mips_delay_slot_code_hook
TESTS += mem_nofree
TESTS += rw_hookstack
TESTS += threaded_emu_start
all: $(TESTS)

View File

@ -0,0 +1,27 @@
#include <unicorn/unicorn.h>
#define HARDWARE_ARCHITECTURE UC_ARCH_X86
#define HARDWARE_MODE UC_MODE_64
#define MEMORY_STARTING_ADDRESS 0x1000000
#define MEMORY_SIZE 2 * 1024 * 1024
#define MEMORY_PERMISSIONS UC_PROT_READ
#define BINARY_CODE "\x90"
int main(int argc, char **argv, char **envp) {
uc_engine *uc;
if (uc_open(HARDWARE_ARCHITECTURE, HARDWARE_MODE, &uc)) {
printf("uc_open(…) failed\n");
return 1;
}
uc_mem_map(uc, MEMORY_STARTING_ADDRESS, MEMORY_SIZE, MEMORY_PERMISSIONS);
if (uc_mem_write(uc, MEMORY_STARTING_ADDRESS, BINARY_CODE, sizeof(BINARY_CODE) - 1)) {
printf("uc_mem_write(…) failed\n");
return 1;
}
printf("uc_emu_start(…)\n");
uc_emu_start(uc, MEMORY_STARTING_ADDRESS, MEMORY_STARTING_ADDRESS + sizeof(BINARY_CODE) - 1, 0, 20);
printf("done\n");
return 0;
}

View File

@ -0,0 +1,72 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <unicorn/unicorn.h>
#define ADDRESS1 0x1000000
#define ADDRESS2 0x2000000
#define SIZE (80 * 1024 * 1024)
static void VM_exec()
{
int c;
uc_engine *uc;
uc_err err;
// Initialize emulator in X86-64bit mode
err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc);
if(err)
{
printf("Failed on uc_open() with error returned: %s\n", uc_strerror(err));
return;
}
repeat:
err = uc_mem_map(uc, ADDRESS1, SIZE, UC_PROT_ALL);
if(err != UC_ERR_OK)
{
printf("Failed to map memory %s\n", uc_strerror(err));
goto err;
}
err = uc_mem_map(uc, ADDRESS2, SIZE, UC_PROT_ALL);
if(err != UC_ERR_OK)
{
printf("Failed to map memory %s\n", uc_strerror(err));
goto err;
}
err = uc_mem_unmap(uc, ADDRESS1, SIZE);
if(err != UC_ERR_OK)
{
printf("Failed to unmap memory %s\n", uc_strerror(err));
goto err;
}
err = uc_mem_unmap(uc, ADDRESS2, SIZE);
if(err != UC_ERR_OK)
{
printf("Failed to unmap memory %s\n", uc_strerror(err));
goto err;
}
for(;;)
{
c = getchar(); //pause here and analyse memory usage before exiting with a program like VMMap;
if(c != 'e')
goto repeat;
else
break;
}
err:
uc_close(uc);
}
int main(int argc, char *argv[])
{
VM_exec();
return 0;
}

View File

@ -11,7 +11,7 @@ class MipsBranchDelay(regress.RegressTest):
def disas(code, addr):
for i in md.disasm(code, addr):
print '0x%x: %s %s' % (i.address, str(i.bytes).encode('hex'), i.op_str)
print '0x%x: %s %-6s %s' % (i.address, str(i.bytes).encode('hex'), i.mnemonic, i.op_str)
def hook_code(uc, addr, size, _):
mem = str(uc.mem_read(addr, size))

View File

@ -0,0 +1,140 @@
/*
Test for code hook being called for instructions in branch delay slot in MIPS cpu.
See issue https://github.com/unicorn-engine/unicorn/issues/290
The code hook should be called for every instruction executed.
This test checks that the code hook is correctly called for instructions in branch delay slots.
In this test the loop check value is decremented inside the branch delay shot.
This helps to show that the instruction in the branch delay slot is being executed,
but that the code hook is just not occurring.
*/
// windows specific
#ifdef _MSC_VER
#include <io.h>
#include <windows.h>
#define PRIx64 "llX"
#ifdef DYNLOAD
#include <unicorn_dynload.h>
#else // DYNLOAD
#include <unicorn/unicorn.h>
#ifdef _WIN64
#pragma comment(lib, "unicorn_staload64.lib")
#else // _WIN64
#pragma comment(lib, "unicorn_staload.lib")
#endif // _WIN64
#endif // DYNLOAD
// posix specific
#else // _MSC_VER
#include <unistd.h>
#include <inttypes.h>
#include <unicorn/unicorn.h>
#endif // _MSC_VER
// common includes
#include <string.h>
// Test MIPS little endian code.
// It should loop 3 times before ending.
const uint64_t addr = 0x100000;
const unsigned char loop_test_code[] = {
0x02,0x00,0x04,0x24, // 100000: li $a0, 2
// loop1
0x00,0x00,0x00,0x00, // 100004: nop
0xFE,0xFF,0x80,0x14, // 100008: bnez $a0, loop1
0xFF,0xFF,0x84,0x24, // 10000C: addiu $a0, -1
};
bool test_passed_ok = false;
int loop_count = 0;
static void mips_codehook(uc_engine *uc, uint64_t address, uint32_t size, void *user_data)
{
if( address == 0x10000C )
test_passed_ok = true;
if( address == 0x100004 )
{
printf("\nloop %d:\n", loop_count);
loop_count++;
}
printf("Code: %llX\n", address);
}
int main(int argc, char **argv, char **envp)
{
uc_engine *uc;
uc_err err;
uc_hook hhc;
uint32_t val;
// dynamically load shared library
#ifdef DYNLOAD
uc_dyn_load(NULL, 0);
#endif
// Initialize emulator in MIPS 32bit little endian mode
err = uc_open(UC_ARCH_MIPS, UC_MODE_MIPS32, &uc);
if (err)
{
printf("Failed on uc_open() with error returned: %u\n", err);
return err;
}
// map in a page of mem
err = uc_mem_map(uc, addr, 0x1000, UC_PROT_ALL);
if (err)
{
printf("Failed on uc_mem_map() with error returned: %u\n", err);
return err;
}
// write machine code to be emulated to memory
err = uc_mem_write(uc, addr, loop_test_code, sizeof(loop_test_code));
if( err )
{
printf("Failed on uc_mem_write() with error returned: %u\n", err);
return err;
}
// hook all instructions by having @begin > @end
uc_hook_add(uc, &hhc, UC_HOOK_CODE, mips_codehook, NULL, (uint64_t)1, (uint64_t)0);
if( err )
{
printf("Failed on uc_hook_add(code) with error returned: %u\n", err);
return err;
}
// execute code
printf("---- Executing Code ----\n");
err = uc_emu_start(uc, addr, addr + sizeof(loop_test_code), 0, 0);
if (err)
{
printf("Failed on uc_emu_start() with error returned %u: %s\n",
err, uc_strerror(err));
return err;
}
// done executing, print some reg values as a test
printf("---- Execution Complete ----\n\n");
uc_reg_read(uc, UC_MIPS_REG_PC, &val); printf("pc is %X\n", val);
uc_reg_read(uc, UC_MIPS_REG_A0, &val); printf("a0 is %X\n", val);
// free resources
uc_close(uc);
if( test_passed_ok )
printf("\n\nTEST PASSED!\n\n");
else
printf("\n\nTEST FAILED!\n\n");
// dynamically free shared library
#ifdef DYNLOAD
uc_dyn_free();
#endif
return 0;
}

View File

@ -0,0 +1,33 @@
#include <unicorn/unicorn.h>
static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) {
printf("tracing\n");
}
#define HARDWARE_ARCHITECTURE UC_ARCH_MIPS
#define HARDWARE_MODE UC_MODE_MIPS32
#define MEMORY_STARTING_ADDRESS 0x1000000
#define MEMORY_SIZE 2 * 1024 * 1024
#define MEMORY_PERMISSIONS UC_PROT_ALL
#define BINARY_CODE "00000000000000000000000000AA"
int main(int argc, char **argv, char **envp) {
uc_engine *uc;
if (uc_open(HARDWARE_ARCHITECTURE, HARDWARE_MODE, &uc)) {
printf("uc_open(…) failed\n");
return 1;
}
uc_mem_map(uc, MEMORY_STARTING_ADDRESS, MEMORY_SIZE, MEMORY_PERMISSIONS);
if (uc_mem_write(uc, MEMORY_STARTING_ADDRESS, BINARY_CODE, sizeof(BINARY_CODE) - 1)) {
printf("uc_mem_write(…) failed\n");
return 1;
}
uc_hook trace;
uc_hook_add(uc, &trace, UC_HOOK_CODE, hook_code, NULL, (uint64_t)MEMORY_STARTING_ADDRESS, (uint64_t)(MEMORY_STARTING_ADDRESS + 1));
printf("uc_emu_start(…)\n");
uc_emu_start(uc, MEMORY_STARTING_ADDRESS, MEMORY_STARTING_ADDRESS + sizeof(BINARY_CODE) - 1, 0, 0);
printf("done\n");
return 0;
}

View File

@ -0,0 +1,109 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
#include <inttypes.h>
#include <unicorn/unicorn.h>
#define ADDRESS 0x1000000
#define STACK 0x0020D000
#define STACK2 0x0030D000
#define STACK_SIZE 16384
#define SIZE (2 * 1024 * 1024)
#define CODE32 "\x8B\x04\x24\xA3\x40\x00\x00\x01\xA1\x40\x00\x00\x01"
bool hook_mem_rw(uc_engine *uc, uc_mem_type type, uint64_t address, int size, int64_t value, void *user_data)
{
unsigned int EIP;
uc_reg_read(uc, UC_X86_REG_EIP, &EIP);
switch(type)
{
default:
return false;
break;
case UC_MEM_WRITE:
printf("Hooked write to address 0x%08"PRIX64" with value 0x%08"PRIX64" at EIP %08X\n", address, value, EIP);
return true;
break;
case UC_MEM_READ:
printf("Hooked read from address 0x%08"PRIX64" with value 0x%08"PRIX64" at EIP %08X\n", address, value, EIP);
return true;
break;
}
}
int main(int argc, char *argv[])
{
uc_engine *uc;
uc_hook trace;
uc_err err;
unsigned int EAX, ESP, val = 0x0c0c0c0c, stkval = STACK;
EAX = 0;
ESP = STACK+0x4;
// Initialize emulator in X86-64bit mode
err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc);
if(err) {
printf("Failed on uc_open() with error returned: %s\n", uc_strerror(err));
return 1;
}
err = uc_mem_map(uc, ADDRESS, SIZE, UC_PROT_ALL);
if(err != UC_ERR_OK) {
printf("Failed to map memory %s\n", uc_strerror(err));
return 1;
}
err = uc_mem_write(uc, ADDRESS, CODE32, sizeof(CODE32) - 1);
if(err != UC_ERR_OK) {
printf("Failed to write to memory %s\n", uc_strerror(err));
return 1;
}
loop:
err = uc_mem_map(uc, stkval, STACK_SIZE, UC_PROT_ALL);
if(err != UC_ERR_OK) {
printf("Failed to map memory %s\n", uc_strerror(err));
return 1;
}
err = uc_mem_write(uc, ESP, &val, sizeof(val));
if(err != UC_ERR_OK) {
printf("Failed to write to memory %s\n", uc_strerror(err));
return 1;
}
uc_hook_add(uc, &trace, UC_HOOK_MEM_WRITE | UC_HOOK_MEM_READ, (void *)hook_mem_rw, NULL);
uc_reg_write(uc, UC_X86_REG_EAX, &EAX);
uc_reg_write(uc, UC_X86_REG_ESP, &ESP);
err = uc_emu_start(uc, ADDRESS, ADDRESS + (sizeof(CODE32) - 1), 0, 0);
if(err) {
printf("Failed on uc_emu_start() with error returned %u: %s\n", err, uc_strerror(err));
uc_close(uc);
return 1;
}
uc_reg_read(uc, UC_X86_REG_EAX, &EAX);
printf(">>> EAX = %08X\n", EAX);
if(stkval != STACK2)
{
printf("=== Beginning test two ===\n");
ESP = STACK2+0x4;
EAX = 0;
stkval = STACK2;
goto loop;
}
uc_close(uc);
return 0;
}

View File

@ -0,0 +1,27 @@
#include <unicorn/unicorn.h>
#define HARDWARE_ARCHITECTURE UC_ARCH_SPARC
#define HARDWARE_MODE UC_MODE_32
#define MEMORY_STARTING_ADDRESS 0x1000000
#define MEMORY_SIZE 2 * 1024 * 1024
#define MEMORY_PERMISSIONS UC_PROT_ALL
#define BINARY_CODE "\x02\xbc\x00\x00"
int main(int argc, char **argv, char **envp) {
uc_engine *uc;
if (uc_open(HARDWARE_ARCHITECTURE, HARDWARE_MODE, &uc)) {
printf("uc_open(…) failed\n");
return 1;
}
uc_mem_map(uc, MEMORY_STARTING_ADDRESS, MEMORY_SIZE, MEMORY_PERMISSIONS);
if (uc_mem_write(uc, MEMORY_STARTING_ADDRESS, BINARY_CODE, sizeof(BINARY_CODE) - 1)) {
printf("uc_mem_write(…) failed\n");
return 1;
}
printf("uc_emu_start(…)\n");
uc_emu_start(uc, MEMORY_STARTING_ADDRESS, MEMORY_STARTING_ADDRESS + sizeof(BINARY_CODE) - 1, 0, 20);
printf("done\n");
return 0;
}

View File

@ -0,0 +1,243 @@
/*
Test for uc_open() and uc_emu_start() being called by different threads.
This code will call uc_open() in the main thread and then attempt
to call uc_emu_start() from its own thread. This would enable the emulator
to run in the background while you do other things like handle user interface
etc in the foreground.
Currently "uc->qemu_global_mutex" is locked by uc_open() and unlocked
by uc_emu_start(). This is a problem because the mutex implementation
must be locked and unlocked by the same thread. This means that uc_open()
and uc_emu_start() must be executed in the same thread. This is an unnecessary
limitation which prevents the emulator from being able to be executed in the
background.
*/
// windows specific
#ifdef _MSC_VER
#include <io.h>
#include <windows.h>
#include <process.h>
#define PRIx64 "llX"
#ifdef DYNLOAD
#include <unicorn_dynload.h>
#else // DYNLOAD
#include <unicorn/unicorn.h>
#ifdef _WIN64
#pragma comment(lib, "unicorn_staload64.lib")
#else // _WIN64
#pragma comment(lib, "unicorn_staload.lib")
#endif // _WIN64
#endif // DYNLOAD
// posix specific
#else // _MSC_VER
#include <unistd.h>
#include <inttypes.h>
#include <unicorn/unicorn.h>
#include "pthread.h"
#endif // _MSC_VER
// for win32 threads in mingw
#ifdef _WIN32
#include <windows.h>
#endif
// common includes
#include <string.h>
// Test MIPS little endian code.
// This should loop forever.
const uint64_t addr = 0x100000;
const unsigned char loop_test_code[] = {
0x02,0x00,0x04,0x24, // 100000: li $a0, 2
// loop1
0x00,0x00,0x00,0x00, // 100004: nop
0xFE,0xFF,0x80,0x14, // 100008: bnez $a0, loop1
0x00,0x00,0x00,0x00, // 10000C: nop
};
bool test_passed_ok = false;
int loop_count = 0;
// This hook is used to show that code is executing in the emulator.
static void mips_codehook(uc_engine *uc, uint64_t address, uint32_t size, void *user_data)
{
printf("Code: %llX\n", address);
}
typedef struct {
uc_engine *uc;
uint64_t startAddr;
uint64_t endAddr;
} EmuStarterParam_t;
// This is a thread that just runs uc_emu_start() in it.
// The code that it is executing in this case will run forever until it is stopped by uc_emu_stop().
static uc_err emu_starter(void* param)
{
uc_engine *uc;
uint64_t start_addr;
uint64_t end_addr;
uc_err err;
EmuStarterParam_t* starter_params = (EmuStarterParam_t *)param;
uc = starter_params->uc;
start_addr = starter_params->startAddr;
end_addr = starter_params->endAddr;
printf("uc_emu_start()\n");
err = uc_emu_start(uc, start_addr, end_addr, 0, 0);
if (err)
{
printf("Failed on uc_emu_start() with error returned %u: %s\n",
err, uc_strerror(err));
}
return err;
}
#ifdef _WIN32
static unsigned int __stdcall win32_emu_starter(void* param)
{
uc_err err = emu_starter(param);
_endthreadex(err);
return err;
}
#else
static void* posix_emu_starter(void* param)
{
uc_err err = emu_starter(param);
return (void*)err;
}
#endif
int main(int argc, char **argv, char **envp)
{
uc_engine *uc;
uc_err err;
int ret;
uc_hook hhc;
uint32_t val;
EmuStarterParam_t starter_params;
#ifdef _WIN32
HANDLE th = (HANDLE)-1;
#else
pthread_t th;
#endif
// dynamically load shared library
#ifdef DYNLOAD
uc_dyn_load(NULL, 0);
#endif
// Initialize emulator in MIPS 32bit little endian mode
printf("uc_open()\n");
err = uc_open(UC_ARCH_MIPS, UC_MODE_MIPS32, &uc);
if (err)
{
printf("Failed on uc_open() with error returned: %u\n", err);
return err;
}
// map in a page of mem
printf("uc_mem_map()\n");
err = uc_mem_map(uc, addr, 0x1000, UC_PROT_ALL);
if (err)
{
printf("Failed on uc_mem_map() with error returned: %u\n", err);
return err;
}
// write machine code to be emulated to memory
printf("uc_mem_write()\n");
err = uc_mem_write(uc, addr, loop_test_code, sizeof(loop_test_code));
if( err )
{
printf("Failed on uc_mem_write() with error returned: %u\n", err);
return err;
}
// hook all instructions by having @begin > @end
printf("uc_hook_add()\n");
uc_hook_add(uc, &hhc, UC_HOOK_CODE, mips_codehook, NULL, (uint64_t)1, (uint64_t)0);
if( err )
{
printf("Failed on uc_hook_add(code) with error returned: %u\n", err);
return err;
}
// start background thread
printf("---- Thread Starting ----\n");
starter_params.uc = uc;
starter_params.startAddr = addr;
starter_params.endAddr = addr + sizeof(loop_test_code);
#ifdef _WIN32
// create thread
th = (HANDLE)_beginthreadex(NULL, 0, win32_emu_starter, &starter_params, CREATE_SUSPENDED, NULL);
if(th == (HANDLE)-1)
{
printf("Failed on _beginthreadex() with error returned: %u\n", _errno());
return -1;
}
// start thread
ret = ResumeThread(th);
if( ret == -1 )
{
printf("Failed on ResumeThread() with error returned: %u\n", _errno());
return -2;
}
// wait 3 seconds
Sleep(3 * 1000);
#else
// add posix code to start the emu_starter() thread
ret = pthread_create(&th, NULL, posix_emu_starter, &starter_params);
if( ret )
{
printf("Failed on pthread_create() with error returned: %u\n", err);
return -2;
}
// wait 3 seconds
sleep(3);
#endif
// Stop the thread after it has been let to run in the background for a while
printf("---- Thread Stopping ----\n");
printf("uc_emu_stop()\n");
err = uc_emu_stop(uc);
if( err )
{
printf("Failed on uc_emu_stop() with error returned: %u\n", err);
return err;
}
test_passed_ok = true;
// done executing, print some reg values as a test
uc_reg_read(uc, UC_MIPS_REG_PC, &val); printf("pc is %X\n", val);
uc_reg_read(uc, UC_MIPS_REG_A0, &val); printf("a0 is %X\n", val);
// free resources
printf("uc_close()\n");
uc_close(uc);
if( test_passed_ok )
printf("\n\nTEST PASSED!\n\n");
else
printf("\n\nTEST FAILED!\n\n");
// dynamically free shared library
#ifdef DYNLOAD
uc_dyn_free();
#endif
return 0;
}

View File

@ -0,0 +1,22 @@
#include <unicorn/unicorn.h>
#define BINARY "\x90"
#define MEMORY_SIZE 4 * 1024
#define STARTING_ADDRESS 100 * 1024
int main(int argc, char **argv, char **envp) {
uc_engine *uc;
if (uc_open(UC_ARCH_X86, UC_MODE_16, &uc)) {
printf("uc_open(…) failed\n");
return 1;
}
uc_mem_map(uc, STARTING_ADDRESS, MEMORY_SIZE, UC_PROT_ALL);
if (uc_mem_write(uc, STARTING_ADDRESS, BINARY, sizeof(BINARY) - 1)) {
printf("uc_mem_write(…) failed\n");
return 1;
}
printf("uc_emu_start(…)\n");
uc_emu_start(uc, STARTING_ADDRESS, STARTING_ADDRESS + sizeof(BINARY) - 1, 0, 20);
printf("done\n");
return 0;
}

View File

@ -4,7 +4,7 @@ CFLAGS += -L ../../
CFLAGS += -lcmocka -lunicorn
CFLAGS += -I ../../include
ALL_TESTS = test_sanity test_x86 test_mem_map test_mem_map_ptr
ALL_TESTS = test_sanity test_x86 test_mem_map test_mem_high test_mem_map_ptr
.PHONY: all
all: ${ALL_TESTS}
@ -24,6 +24,7 @@ test_sanity: test_sanity.c
test_x86: test_x86.c
test_mem_map: test_mem_map.c
test_mem_map_ptr: test_mem_map_ptr.c
test_mem_high: test_mem_high.c
${ALL_TESTS}:
gcc ${CFLAGS} -o $@ $^

125
tests/unit/test_mem_high.c Normal file
View File

@ -0,0 +1,125 @@
/**
* Unicorn memory API tests
*
* This tests memory read/write and map/unmap functionality.
* One is necessary for doing the other.
*/
#include "unicorn_test.h"
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
/* Called before every test to set up a new instance */
static int setup(void **state)
{
uc_engine *uc;
uc_assert_success(uc_open(UC_ARCH_X86, UC_MODE_64, &uc));
*state = uc;
return 0;
}
/* Called after every test to clean up */
static int teardown(void **state)
{
uc_engine *uc = *state;
uc_assert_success(uc_close(uc));
*state = NULL;
return 0;
}
/******************************************************************************/
// mapping the last pages will silently fail
static void test_last_page_map(void **state)
{
uc_engine *uc = *state;
uint8_t writebuf[0x10];
memset(writebuf, 0xCC, sizeof(writebuf));
const uint64_t mem_len = 0x1000;
const uint64_t last_page = 0xfffffffffffff000;
uc_assert_success(uc_mem_map(uc, last_page, mem_len, UC_PROT_NONE));
uc_assert_success(uc_mem_write(uc, last_page, writebuf, sizeof(writebuf)));
}
// segfaults with NULL-deref (caused by UC_PROT_NONE)
static void test_nullptr_deref_wrong_perms(void **state){
uc_engine *uc = *state;
const uint64_t base_addr = 0x400000;
uc_assert_success(uc_mem_map(uc, base_addr, 4096, UC_PROT_NONE));
uc_emu_start(uc, base_addr, base_addr + 1, 0, 0);
}
static int number_of_memory_reads = 0;
static void hook_mem64(uc_engine *uc, uc_mem_type type, uint64_t address, int size, int64_t value, void *user_data)
{
number_of_memory_reads += 1;
printf(">>> Memory is being accessed at 0x%"PRIx64 ", data size = %u\n", address, size);
}
//if a read is performed from a big address whith a non-zero last digit, multiple read events are triggered
static void test_high_address_reads(void **state)
{
uc_engine *uc = *state;
uc_hook trace2;
uint64_t addr = 0x0010000000000001;
//addr = 0x0010000000000000; // uncomment to fix wrong? behaviour
//addr = 90000000; // uncomment to fix wrong? behaviour
//
uc_mem_map(uc, addr-(addr%4096), 4096*2, UC_PROT_ALL);
uc_assert_success(uc_reg_write(uc, UC_X86_REG_RAX, &addr));
const uint64_t base_addr = 0x40000;
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_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);
}
}
//if a read is performed from a big address whith a non-zero last digit, 0 will be read
static void test_high_address_read_values(void **state)
{
uc_engine *uc = *state;
uint64_t addr = 0x0010000000000001;
//addr = 0x000ffffffffffff8; // uncomment to fix wrong behaviour
//addr = 90000000; // uncomment to fix wrong behaviour
//
uint8_t content[] = {0x42,0x42,0x42,0x42, 0x42,0x42,0x42,0x42};
uc_assert_success(uc_mem_map(uc, addr-(addr%4096), 4096*2, UC_PROT_ALL));
uc_assert_success(uc_mem_write(uc, addr, content, 8));
uc_assert_success(uc_reg_write(uc, UC_X86_REG_RAX, &addr));
const uint64_t base_addr = 0x40000;
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_emu_start(uc, base_addr, base_addr + 3, 0, 0));
uint64_t rax = 0;
uc_assert_success(uc_reg_read(uc, UC_X86_REG_RAX, &rax));
if(rax != 0x4242424242424242) {
fail_msg("wrong memory read from code %"PRIx64, rax);
}
}
int main(void) {
#define test(x) cmocka_unit_test_setup_teardown(x, setup, teardown)
const struct CMUnitTest tests[] = {
test(test_last_page_map),
test(test_high_address_reads),
test(test_high_address_read_values),
test(test_nullptr_deref_wrong_perms),
};
#undef test
return cmocka_run_group_tests(tests, NULL, NULL);
}