mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2024-12-23 08:15:37 +00:00
75d90aff52
* make cleanup * Update .travis.yml Update eflags_nosync.c Update sigill2.c Update ro_mem_test.c Update ro_mem_test.c Update nr_mem_test.c Update mem_fuzz.c Update mem_double_unmap.c Update emu_stop_in_hook_overrun.c Update eflags_nosync.c remove unused Update Makefile Update Makefile Update Makefile Update Makefile Update Makefile Update Makefile Update Makefile Update mem_64_c.c Update mem_64_c.c Update Makefile Update Makefile Update Makefile Update Makefile Update Makefile Update Makefile Update .travis.yml try android ndk build Update unicorn.py Update unicorn.py Update Makefile Update unicorn.py Update unicorn.py remove an untrue comment if a dll/so/dylib gets loaded at runtime is dependent on many different factors, primarily the LD/DYLD paths. Those do not always include the current working directory Update Makefile Update .appveyor.yml Update .travis.yml Update Makefile Update .appveyor.yml Fix bad sample * Update Makefile * Update Makefile * Update install-cmocka-linux.sh * remove verbose option from tar * add upgrade to pacman for cmake * pacman double update, needed to get new packages * enable cmocka unit testing * rejigger commands to fail on any step should get fails in msys builds for cmocka * fix quote * make cmocka in cygwin only * add msys cache
1048 lines
33 KiB
C
1048 lines
33 KiB
C
/* Unicorn Emulator Engine */
|
|
/* By Nguyen Anh Quynh & Dang Hoang Vu, 2015 */
|
|
|
|
/* Sample code to demonstrate how to emulate X86 code */
|
|
|
|
// 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>
|
|
|
|
|
|
// code to be emulated
|
|
#define X86_CODE32 "\x41\x4a\x66\x0f\xef\xc1" // INC ecx; DEC edx; PXOR xmm0, xmm1
|
|
#define X86_CODE32_JUMP "\xeb\x02\x90\x90\x90\x90\x90\x90" // jmp 4; nop; nop; nop; nop; nop; nop
|
|
// #define X86_CODE32_SELF "\xeb\x1c\x5a\x89\xd6\x8b\x02\x66\x3d\xca\x7d\x75\x06\x66\x05\x03\x03\x89\x02\xfe\xc2\x3d\x41\x41\x41\x41\x75\xe9\xff\xe6\xe8\xdf\xff\xff\xff\x31\xd2\x6a\x0b\x58\x99\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xca\x7d\x41\x41\x41\x41"
|
|
//#define X86_CODE32 "\x51\x51\x51\x51" // PUSH ecx;
|
|
#define X86_CODE32_LOOP "\x41\x4a\xeb\xfe" // INC ecx; DEC edx; JMP self-loop
|
|
#define X86_CODE32_MEM_WRITE "\x89\x0D\xAA\xAA\xAA\xAA\x41\x4a" // mov [0xaaaaaaaa], ecx; INC ecx; DEC edx
|
|
#define X86_CODE32_MEM_READ "\x8B\x0D\xAA\xAA\xAA\xAA\x41\x4a" // mov ecx,[0xaaaaaaaa]; INC ecx; DEC edx
|
|
|
|
#define X86_CODE32_JMP_INVALID "\xe9\xe9\xee\xee\xee\x41\x4a" // JMP outside; INC ecx; DEC edx
|
|
#define X86_CODE32_INOUT "\x41\xE4\x3F\x4a\xE6\x46\x43" // INC ecx; IN AL, 0x3f; DEC edx; OUT 0x46, AL; INC ebx
|
|
#define X86_CODE32_INC "\x40" // INC eax
|
|
|
|
//#define X86_CODE64 "\x41\xBC\x3B\xB0\x28\x2A \x49\x0F\xC9 \x90 \x4D\x0F\xAD\xCF\x49\x87\xFD\x90\x48\x81\xD2\x8A\xCE\x77\x35\x48\xF7\xD9" // <== still crash
|
|
//#define X86_CODE64 "\x41\xBC\x3B\xB0\x28\x2A\x49\x0F\xC9\x90\x4D\x0F\xAD\xCF\x49\x87\xFD\x90\x48\x81\xD2\x8A\xCE\x77\x35\x48\xF7\xD9"
|
|
#define X86_CODE64 "\x41\xBC\x3B\xB0\x28\x2A\x49\x0F\xC9\x90\x4D\x0F\xAD\xCF\x49\x87\xFD\x90\x48\x81\xD2\x8A\xCE\x77\x35\x48\xF7\xD9\x4D\x29\xF4\x49\x81\xC9\xF6\x8A\xC6\x53\x4D\x87\xED\x48\x0F\xAD\xD2\x49\xF7\xD4\x48\xF7\xE1\x4D\x19\xC5\x4D\x89\xC5\x48\xF7\xD6\x41\xB8\x4F\x8D\x6B\x59\x4D\x87\xD0\x68\x6A\x1E\x09\x3C\x59"
|
|
#define X86_CODE16 "\x00\x00" // add byte ptr [bx + si], al
|
|
#define X86_CODE64_SYSCALL "\x0f\x05" // SYSCALL
|
|
|
|
// memory address where emulation starts
|
|
#define ADDRESS 0x1000000
|
|
|
|
// callback for tracing basic blocks
|
|
static void hook_block(uc_engine *uc, uint64_t address, uint32_t size, void *user_data)
|
|
{
|
|
printf(">>> Tracing basic block at 0x%"PRIx64 ", block size = 0x%x\n", address, size);
|
|
}
|
|
|
|
// callback for tracing instruction
|
|
static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data)
|
|
{
|
|
int eflags;
|
|
printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size);
|
|
|
|
uc_reg_read(uc, UC_X86_REG_EFLAGS, &eflags);
|
|
printf(">>> --- EFLAGS is 0x%x\n", eflags);
|
|
|
|
// Uncomment below code to stop the emulation using uc_emu_stop()
|
|
// if (address == 0x1000009)
|
|
// uc_emu_stop(uc);
|
|
}
|
|
|
|
// callback for tracing instruction
|
|
static void hook_code64(uc_engine *uc, uint64_t address, uint32_t size, void *user_data)
|
|
{
|
|
uint64_t rip;
|
|
|
|
uc_reg_read(uc, UC_X86_REG_RIP, &rip);
|
|
printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size);
|
|
printf(">>> RIP is 0x%"PRIx64 "\n", rip);
|
|
|
|
// Uncomment below code to stop the emulation using uc_emu_stop()
|
|
// if (address == 0x1000009)
|
|
// uc_emu_stop(uc);
|
|
}
|
|
|
|
// callback for tracing memory access (READ or WRITE)
|
|
static bool hook_mem_invalid(uc_engine *uc, uc_mem_type type,
|
|
uint64_t address, int size, int64_t value, void *user_data)
|
|
{
|
|
switch(type) {
|
|
default:
|
|
// return false to indicate we want to stop emulation
|
|
return false;
|
|
case UC_MEM_WRITE_UNMAPPED:
|
|
printf(">>> Missing memory is being WRITE at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n",
|
|
address, size, value);
|
|
// map this memory in with 2MB in size
|
|
uc_mem_map(uc, 0xaaaa0000, 2 * 1024*1024, UC_PROT_ALL);
|
|
// return true to indicate we want to continue
|
|
return true;
|
|
}
|
|
}
|
|
|
|
static void hook_mem64(uc_engine *uc, uc_mem_type type,
|
|
uint64_t address, int size, int64_t value, void *user_data)
|
|
{
|
|
switch(type) {
|
|
default: break;
|
|
case UC_MEM_READ:
|
|
printf(">>> Memory is being READ at 0x%"PRIx64 ", data size = %u\n",
|
|
address, size);
|
|
break;
|
|
case UC_MEM_WRITE:
|
|
printf(">>> Memory is being WRITE at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n",
|
|
address, size, value);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// callback for IN instruction (X86).
|
|
// this returns the data read from the port
|
|
static uint32_t hook_in(uc_engine *uc, uint32_t port, int size, void *user_data)
|
|
{
|
|
uint32_t eip;
|
|
|
|
uc_reg_read(uc, UC_X86_REG_EIP, &eip);
|
|
|
|
printf("--- reading from port 0x%x, size: %u, address: 0x%x\n", port, size, eip);
|
|
|
|
switch(size) {
|
|
default:
|
|
return 0; // should never reach this
|
|
case 1:
|
|
// read 1 byte to AL
|
|
return 0xf1;
|
|
case 2:
|
|
// read 2 byte to AX
|
|
return 0xf2;
|
|
break;
|
|
case 4:
|
|
// read 4 byte to EAX
|
|
return 0xf4;
|
|
}
|
|
}
|
|
|
|
// callback for OUT instruction (X86).
|
|
static void hook_out(uc_engine *uc, uint32_t port, int size, uint32_t value, void *user_data)
|
|
{
|
|
uint32_t tmp = 0;
|
|
uint32_t eip;
|
|
|
|
uc_reg_read(uc, UC_X86_REG_EIP, &eip);
|
|
|
|
printf("--- writing to port 0x%x, size: %u, value: 0x%x, address: 0x%x\n", port, size, value, eip);
|
|
|
|
// confirm that value is indeed the value of AL/AX/EAX
|
|
switch(size) {
|
|
default:
|
|
return; // should never reach this
|
|
case 1:
|
|
uc_reg_read(uc, UC_X86_REG_AL, &tmp);
|
|
break;
|
|
case 2:
|
|
uc_reg_read(uc, UC_X86_REG_AX, &tmp);
|
|
break;
|
|
case 4:
|
|
uc_reg_read(uc, UC_X86_REG_EAX, &tmp);
|
|
break;
|
|
}
|
|
|
|
printf("--- register value = 0x%x\n", tmp);
|
|
}
|
|
|
|
// callback for SYSCALL instruction (X86).
|
|
static void hook_syscall(uc_engine *uc, void *user_data)
|
|
{
|
|
uint64_t rax;
|
|
|
|
uc_reg_read(uc, UC_X86_REG_RAX, &rax);
|
|
if (rax == 0x100) {
|
|
rax = 0x200;
|
|
uc_reg_write(uc, UC_X86_REG_RAX, &rax);
|
|
} else
|
|
printf("ERROR: was not expecting rax=0x%"PRIx64 " in syscall\n", rax);
|
|
}
|
|
|
|
static void test_i386(void)
|
|
{
|
|
uc_engine *uc;
|
|
uc_err err;
|
|
uint32_t tmp;
|
|
uc_hook trace1, trace2;
|
|
|
|
int r_ecx = 0x1234; // ECX register
|
|
int r_edx = 0x7890; // EDX register
|
|
// XMM0 and XMM1 registers, low qword then high qword
|
|
uint64_t r_xmm0[2] = {0x08090a0b0c0d0e0f, 0x0001020304050607};
|
|
uint64_t r_xmm1[2] = {0x8090a0b0c0d0e0f0, 0x0010203040506070};
|
|
|
|
printf("Emulate i386 code\n");
|
|
|
|
// Initialize emulator in X86-32bit mode
|
|
err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc);
|
|
if (err) {
|
|
printf("Failed on uc_open() with error returned: %u\n", err);
|
|
return;
|
|
}
|
|
|
|
// map 2MB memory for this emulation
|
|
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
|
|
|
// write machine code to be emulated to memory
|
|
if (uc_mem_write(uc, ADDRESS, X86_CODE32, sizeof(X86_CODE32) - 1)) {
|
|
printf("Failed to write emulation code to memory, quit!\n");
|
|
return;
|
|
}
|
|
|
|
// initialize machine registers
|
|
uc_reg_write(uc, UC_X86_REG_ECX, &r_ecx);
|
|
uc_reg_write(uc, UC_X86_REG_EDX, &r_edx);
|
|
uc_reg_write(uc, UC_X86_REG_XMM0, &r_xmm0);
|
|
uc_reg_write(uc, UC_X86_REG_XMM1, &r_xmm1);
|
|
|
|
// tracing all basic blocks with customized callback
|
|
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0);
|
|
|
|
// tracing all instruction by having @begin > @end
|
|
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0);
|
|
|
|
// emulate machine code in infinite time
|
|
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32) - 1, 0, 0);
|
|
if (err) {
|
|
printf("Failed on uc_emu_start() with error returned %u: %s\n",
|
|
err, uc_strerror(err));
|
|
}
|
|
|
|
// now print out some registers
|
|
printf(">>> Emulation done. Below is the CPU context\n");
|
|
|
|
uc_reg_read(uc, UC_X86_REG_ECX, &r_ecx);
|
|
uc_reg_read(uc, UC_X86_REG_EDX, &r_edx);
|
|
uc_reg_read(uc, UC_X86_REG_XMM0, &r_xmm0);
|
|
printf(">>> ECX = 0x%x\n", r_ecx);
|
|
printf(">>> EDX = 0x%x\n", r_edx);
|
|
printf(">>> XMM0 = 0x%.16"PRIx64"%.16"PRIx64"\n", r_xmm0[1], r_xmm0[0]);
|
|
|
|
// read from memory
|
|
if (!uc_mem_read(uc, ADDRESS, &tmp, sizeof(tmp)))
|
|
printf(">>> Read 4 bytes from [0x%x] = 0x%x\n", ADDRESS, tmp);
|
|
else
|
|
printf(">>> Failed to read 4 bytes from [0x%x]\n", ADDRESS);
|
|
|
|
uc_close(uc);
|
|
}
|
|
|
|
static void test_i386_map_ptr(void)
|
|
{
|
|
uc_engine *uc;
|
|
uc_err err;
|
|
uint32_t tmp;
|
|
uc_hook trace1, trace2;
|
|
void *mem;
|
|
|
|
int r_ecx = 0x1234; // ECX register
|
|
int r_edx = 0x7890; // EDX register
|
|
|
|
printf("===================================\n");
|
|
printf("Emulate i386 code - use uc_mem_map_ptr()\n");
|
|
|
|
// Initialize emulator in X86-32bit mode
|
|
err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc);
|
|
if (err) {
|
|
printf("Failed on uc_open() with error returned: %u\n", err);
|
|
return;
|
|
}
|
|
|
|
// malloc 2MB memory for this emulation
|
|
mem = calloc(1, 2 * 1024 * 1024);
|
|
if (mem == NULL) {
|
|
printf("Failed to malloc()\n");
|
|
return;
|
|
}
|
|
|
|
uc_mem_map_ptr(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL, mem);
|
|
|
|
// write machine code to be emulated to memory
|
|
if (!memcpy(mem, X86_CODE32, sizeof(X86_CODE32) - 1)) {
|
|
printf("Failed to write emulation code to memory, quit!\n");
|
|
return;
|
|
}
|
|
|
|
// initialize machine registers
|
|
uc_reg_write(uc, UC_X86_REG_ECX, &r_ecx);
|
|
uc_reg_write(uc, UC_X86_REG_EDX, &r_edx);
|
|
|
|
// tracing all basic blocks with customized callback
|
|
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0);
|
|
|
|
// tracing all instruction by having @begin > @end
|
|
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0);
|
|
|
|
// emulate machine code in infinite time
|
|
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32) - 1, 0, 0);
|
|
if (err) {
|
|
printf("Failed on uc_emu_start() with error returned %u: %s\n",
|
|
err, uc_strerror(err));
|
|
}
|
|
|
|
// now print out some registers
|
|
printf(">>> Emulation done. Below is the CPU context\n");
|
|
|
|
uc_reg_read(uc, UC_X86_REG_ECX, &r_ecx);
|
|
uc_reg_read(uc, UC_X86_REG_EDX, &r_edx);
|
|
printf(">>> ECX = 0x%x\n", r_ecx);
|
|
printf(">>> EDX = 0x%x\n", r_edx);
|
|
|
|
// read from memory
|
|
if (!uc_mem_read(uc, ADDRESS, &tmp, sizeof(tmp)))
|
|
printf(">>> Read 4 bytes from [0x%x] = 0x%x\n", ADDRESS, tmp);
|
|
else
|
|
printf(">>> Failed to read 4 bytes from [0x%x]\n", ADDRESS);
|
|
|
|
uc_close(uc);
|
|
}
|
|
|
|
static void test_i386_jump(void)
|
|
{
|
|
uc_engine *uc;
|
|
uc_err err;
|
|
uc_hook trace1, trace2;
|
|
|
|
printf("===================================\n");
|
|
printf("Emulate i386 code with jump\n");
|
|
|
|
// Initialize emulator in X86-32bit mode
|
|
err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc);
|
|
if (err) {
|
|
printf("Failed on uc_open() with error returned: %u\n", err);
|
|
return;
|
|
}
|
|
|
|
// map 2MB memory for this emulation
|
|
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
|
|
|
// write machine code to be emulated to memory
|
|
if (uc_mem_write(uc, ADDRESS, X86_CODE32_JUMP,
|
|
sizeof(X86_CODE32_JUMP) - 1)) {
|
|
printf("Failed to write emulation code to memory, quit!\n");
|
|
return;
|
|
}
|
|
|
|
// tracing 1 basic block with customized callback
|
|
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, ADDRESS, ADDRESS);
|
|
|
|
// tracing 1 instruction at ADDRESS
|
|
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, ADDRESS, ADDRESS);
|
|
|
|
// emulate machine code in infinite time
|
|
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_JUMP) - 1, 0, 0);
|
|
if (err) {
|
|
printf("Failed on uc_emu_start() with error returned %u: %s\n",
|
|
err, uc_strerror(err));
|
|
}
|
|
|
|
printf(">>> Emulation done. Below is the CPU context\n");
|
|
|
|
uc_close(uc);
|
|
}
|
|
|
|
// emulate code that loop forever
|
|
static void test_i386_loop(void)
|
|
{
|
|
uc_engine *uc;
|
|
uc_err err;
|
|
|
|
int r_ecx = 0x1234; // ECX register
|
|
int r_edx = 0x7890; // EDX register
|
|
|
|
printf("===================================\n");
|
|
printf("Emulate i386 code that loop forever\n");
|
|
|
|
// Initialize emulator in X86-32bit mode
|
|
err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc);
|
|
if (err) {
|
|
printf("Failed on uc_open() with error returned: %u\n", err);
|
|
return;
|
|
}
|
|
|
|
// map 2MB memory for this emulation
|
|
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
|
|
|
// write machine code to be emulated to memory
|
|
if (uc_mem_write(uc, ADDRESS, X86_CODE32_LOOP, sizeof(X86_CODE32_LOOP) - 1)) {
|
|
printf("Failed to write emulation code to memory, quit!\n");
|
|
return;
|
|
}
|
|
|
|
// initialize machine registers
|
|
uc_reg_write(uc, UC_X86_REG_ECX, &r_ecx);
|
|
uc_reg_write(uc, UC_X86_REG_EDX, &r_edx);
|
|
|
|
// emulate machine code in 2 seconds, so we can quit even
|
|
// if the code loops
|
|
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_LOOP) - 1, 2 * UC_SECOND_SCALE, 0);
|
|
if (err) {
|
|
printf("Failed on uc_emu_start() with error returned %u: %s\n",
|
|
err, uc_strerror(err));
|
|
}
|
|
|
|
// now print out some registers
|
|
printf(">>> Emulation done. Below is the CPU context\n");
|
|
|
|
uc_reg_read(uc, UC_X86_REG_ECX, &r_ecx);
|
|
uc_reg_read(uc, UC_X86_REG_EDX, &r_edx);
|
|
printf(">>> ECX = 0x%x\n", r_ecx);
|
|
printf(">>> EDX = 0x%x\n", r_edx);
|
|
|
|
uc_close(uc);
|
|
}
|
|
|
|
// emulate code that read invalid memory
|
|
static void test_i386_invalid_mem_read(void)
|
|
{
|
|
uc_engine *uc;
|
|
uc_err err;
|
|
uc_hook trace1, trace2;
|
|
|
|
int r_ecx = 0x1234; // ECX register
|
|
int r_edx = 0x7890; // EDX register
|
|
|
|
printf("===================================\n");
|
|
printf("Emulate i386 code that read from invalid memory\n");
|
|
|
|
// Initialize emulator in X86-32bit mode
|
|
err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc);
|
|
if (err) {
|
|
printf("Failed on uc_open() with error returned: %u\n", err);
|
|
return;
|
|
}
|
|
|
|
// map 2MB memory for this emulation
|
|
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
|
|
|
// write machine code to be emulated to memory
|
|
if (uc_mem_write(uc, ADDRESS, X86_CODE32_MEM_READ, sizeof(X86_CODE32_MEM_READ) - 1)) {
|
|
printf("Failed to write emulation code to memory, quit!\n");
|
|
return;
|
|
}
|
|
|
|
// initialize machine registers
|
|
uc_reg_write(uc, UC_X86_REG_ECX, &r_ecx);
|
|
uc_reg_write(uc, UC_X86_REG_EDX, &r_edx);
|
|
|
|
// tracing all basic blocks with customized callback
|
|
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0);
|
|
|
|
// tracing all instruction by having @begin > @end
|
|
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0);
|
|
|
|
// emulate machine code in infinite time
|
|
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_MEM_READ) - 1, 0, 0);
|
|
if (err) {
|
|
printf("Failed on uc_emu_start() with error returned %u: %s\n",
|
|
err, uc_strerror(err));
|
|
}
|
|
|
|
// now print out some registers
|
|
printf(">>> Emulation done. Below is the CPU context\n");
|
|
|
|
uc_reg_read(uc, UC_X86_REG_ECX, &r_ecx);
|
|
uc_reg_read(uc, UC_X86_REG_EDX, &r_edx);
|
|
printf(">>> ECX = 0x%x\n", r_ecx);
|
|
printf(">>> EDX = 0x%x\n", r_edx);
|
|
|
|
uc_close(uc);
|
|
}
|
|
|
|
// emulate code that write invalid memory
|
|
static void test_i386_invalid_mem_write(void)
|
|
{
|
|
uc_engine *uc;
|
|
uc_err err;
|
|
uc_hook trace1, trace2, trace3;
|
|
uint32_t tmp;
|
|
|
|
int r_ecx = 0x1234; // ECX register
|
|
int r_edx = 0x7890; // EDX register
|
|
|
|
printf("===================================\n");
|
|
printf("Emulate i386 code that write to invalid memory\n");
|
|
|
|
// Initialize emulator in X86-32bit mode
|
|
err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc);
|
|
if (err) {
|
|
printf("Failed on uc_open() with error returned: %u\n", err);
|
|
return;
|
|
}
|
|
|
|
// map 2MB memory for this emulation
|
|
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
|
|
|
// write machine code to be emulated to memory
|
|
if (uc_mem_write(uc, ADDRESS, X86_CODE32_MEM_WRITE, sizeof(X86_CODE32_MEM_WRITE) - 1)) {
|
|
printf("Failed to write emulation code to memory, quit!\n");
|
|
return;
|
|
}
|
|
|
|
// initialize machine registers
|
|
uc_reg_write(uc, UC_X86_REG_ECX, &r_ecx);
|
|
uc_reg_write(uc, UC_X86_REG_EDX, &r_edx);
|
|
|
|
// tracing all basic blocks with customized callback
|
|
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0);
|
|
|
|
// tracing all instruction by having @begin > @end
|
|
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0);
|
|
|
|
// intercept invalid memory events
|
|
uc_hook_add(uc, &trace3, UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED, hook_mem_invalid, NULL, 1, 0);
|
|
|
|
// emulate machine code in infinite time
|
|
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_MEM_WRITE) - 1, 0, 0);
|
|
if (err) {
|
|
printf("Failed on uc_emu_start() with error returned %u: %s\n",
|
|
err, uc_strerror(err));
|
|
}
|
|
|
|
// now print out some registers
|
|
printf(">>> Emulation done. Below is the CPU context\n");
|
|
|
|
uc_reg_read(uc, UC_X86_REG_ECX, &r_ecx);
|
|
uc_reg_read(uc, UC_X86_REG_EDX, &r_edx);
|
|
printf(">>> ECX = 0x%x\n", r_ecx);
|
|
printf(">>> EDX = 0x%x\n", r_edx);
|
|
|
|
// read from memory
|
|
if (!uc_mem_read(uc, 0xaaaaaaaa, &tmp, sizeof(tmp)))
|
|
printf(">>> Read 4 bytes from [0x%x] = 0x%x\n", 0xaaaaaaaa, tmp);
|
|
else
|
|
printf(">>> Failed to read 4 bytes from [0x%x]\n", 0xaaaaaaaa);
|
|
|
|
if (!uc_mem_read(uc, 0xffffffaa, &tmp, sizeof(tmp)))
|
|
printf(">>> Read 4 bytes from [0x%x] = 0x%x\n", 0xffffffaa, tmp);
|
|
else
|
|
printf(">>> Failed to read 4 bytes from [0x%x]\n", 0xffffffaa);
|
|
|
|
uc_close(uc);
|
|
}
|
|
|
|
// emulate code that jump to invalid memory
|
|
static void test_i386_jump_invalid(void)
|
|
{
|
|
uc_engine *uc;
|
|
uc_err err;
|
|
uc_hook trace1, trace2;
|
|
|
|
int r_ecx = 0x1234; // ECX register
|
|
int r_edx = 0x7890; // EDX register
|
|
|
|
printf("===================================\n");
|
|
printf("Emulate i386 code that jumps to invalid memory\n");
|
|
|
|
// Initialize emulator in X86-32bit mode
|
|
err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc);
|
|
if (err) {
|
|
printf("Failed on uc_open() with error returned: %u\n", err);
|
|
return;
|
|
}
|
|
|
|
// map 2MB memory for this emulation
|
|
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
|
|
|
// write machine code to be emulated to memory
|
|
if (uc_mem_write(uc, ADDRESS, X86_CODE32_JMP_INVALID, sizeof(X86_CODE32_JMP_INVALID) - 1)) {
|
|
printf("Failed to write emulation code to memory, quit!\n");
|
|
return;
|
|
}
|
|
|
|
// initialize machine registers
|
|
uc_reg_write(uc, UC_X86_REG_ECX, &r_ecx);
|
|
uc_reg_write(uc, UC_X86_REG_EDX, &r_edx);
|
|
|
|
// tracing all basic blocks with customized callback
|
|
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0);
|
|
|
|
// tracing all instructions by having @begin > @end
|
|
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0);
|
|
|
|
// emulate machine code in infinite time
|
|
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_JMP_INVALID) - 1, 0, 0);
|
|
if (err) {
|
|
printf("Failed on uc_emu_start() with error returned %u: %s\n",
|
|
err, uc_strerror(err));
|
|
}
|
|
|
|
// now print out some registers
|
|
printf(">>> Emulation done. Below is the CPU context\n");
|
|
|
|
uc_reg_read(uc, UC_X86_REG_ECX, &r_ecx);
|
|
uc_reg_read(uc, UC_X86_REG_EDX, &r_edx);
|
|
printf(">>> ECX = 0x%x\n", r_ecx);
|
|
printf(">>> EDX = 0x%x\n", r_edx);
|
|
|
|
uc_close(uc);
|
|
}
|
|
|
|
static void test_i386_inout(void)
|
|
{
|
|
uc_engine *uc;
|
|
uc_err err;
|
|
uc_hook trace1, trace2, trace3, trace4;
|
|
|
|
|
|
int r_eax = 0x1234; // EAX register
|
|
int r_ecx = 0x6789; // ECX register
|
|
|
|
printf("===================================\n");
|
|
printf("Emulate i386 code with IN/OUT instructions\n");
|
|
|
|
// Initialize emulator in X86-32bit mode
|
|
err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc);
|
|
if (err) {
|
|
printf("Failed on uc_open() with error returned: %u\n", err);
|
|
return;
|
|
}
|
|
|
|
// map 2MB memory for this emulation
|
|
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
|
|
|
// write machine code to be emulated to memory
|
|
if (uc_mem_write(uc, ADDRESS, X86_CODE32_INOUT, sizeof(X86_CODE32_INOUT) - 1)) {
|
|
printf("Failed to write emulation code to memory, quit!\n");
|
|
return;
|
|
}
|
|
|
|
// initialize machine registers
|
|
uc_reg_write(uc, UC_X86_REG_EAX, &r_eax);
|
|
uc_reg_write(uc, UC_X86_REG_ECX, &r_ecx);
|
|
|
|
// tracing all basic blocks with customized callback
|
|
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0);
|
|
|
|
// tracing all instructions
|
|
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0);
|
|
|
|
// uc IN instruction
|
|
uc_hook_add(uc, &trace3, UC_HOOK_INSN, hook_in, NULL, 1, 0, UC_X86_INS_IN);
|
|
// uc OUT instruction
|
|
uc_hook_add(uc, &trace4, UC_HOOK_INSN, hook_out, NULL, 1, 0, UC_X86_INS_OUT);
|
|
|
|
// emulate machine code in infinite time
|
|
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_INOUT) - 1, 0, 0);
|
|
if (err) {
|
|
printf("Failed on uc_emu_start() with error returned %u: %s\n",
|
|
err, uc_strerror(err));
|
|
}
|
|
|
|
// now print out some registers
|
|
printf(">>> Emulation done. Below is the CPU context\n");
|
|
|
|
uc_reg_read(uc, UC_X86_REG_EAX, &r_eax);
|
|
uc_reg_read(uc, UC_X86_REG_ECX, &r_ecx);
|
|
printf(">>> EAX = 0x%x\n", r_eax);
|
|
printf(">>> ECX = 0x%x\n", r_ecx);
|
|
|
|
uc_close(uc);
|
|
}
|
|
|
|
// emulate code and save/restore the CPU context
|
|
static void test_i386_context_save(void)
|
|
{
|
|
uc_engine *uc;
|
|
uc_context *context;
|
|
uc_err err;
|
|
|
|
int r_eax = 0x1; // EAX register
|
|
|
|
printf("===================================\n");
|
|
printf("Save/restore CPU context in opaque blob\n");
|
|
|
|
// initialize emulator in X86-32bit mode
|
|
err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc);
|
|
if (err) {
|
|
printf("Failed on uc_open() with error returned: %u\n", err);
|
|
return;
|
|
}
|
|
|
|
// map 8KB memory for this emulation
|
|
uc_mem_map(uc, ADDRESS, 8 * 1024, UC_PROT_ALL);
|
|
|
|
// write machine code to be emulated to memory
|
|
if (uc_mem_write(uc, ADDRESS, X86_CODE32_INC, sizeof(X86_CODE32_INC) - 1)) {
|
|
printf("Failed to write emulation code to memory, quit!\n");
|
|
return;
|
|
}
|
|
|
|
// initialize machine registers
|
|
uc_reg_write(uc, UC_X86_REG_EAX, &r_eax);
|
|
|
|
// emulate machine code in infinite time
|
|
printf(">>> Running emulation for the first time\n");
|
|
|
|
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_INC) - 1, 0, 0);
|
|
if (err) {
|
|
printf("Failed on uc_emu_start() with error returned %u: %s\n",
|
|
err, uc_strerror(err));
|
|
}
|
|
|
|
// now print out some registers
|
|
printf(">>> Emulation done. Below is the CPU context\n");
|
|
|
|
uc_reg_read(uc, UC_X86_REG_EAX, &r_eax);
|
|
printf(">>> EAX = 0x%x\n", r_eax);
|
|
|
|
// allocate and save the CPU context
|
|
printf(">>> Saving CPU context\n");
|
|
|
|
err = uc_context_alloc(uc, &context);
|
|
if (err) {
|
|
printf("Failed on uc_context_alloc() with error returned: %u\n", err);
|
|
return;
|
|
}
|
|
|
|
err = uc_context_save(uc, context);
|
|
if (err) {
|
|
printf("Failed on uc_context_save() with error returned: %u\n", err);
|
|
return;
|
|
}
|
|
|
|
// emulate machine code again
|
|
printf(">>> Running emulation for the second time\n");
|
|
|
|
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_INC) - 1, 0, 0);
|
|
if (err) {
|
|
printf("Failed on uc_emu_start() with error returned %u: %s\n",
|
|
err, uc_strerror(err));
|
|
}
|
|
|
|
// now print out some registers
|
|
printf(">>> Emulation done. Below is the CPU context\n");
|
|
|
|
uc_reg_read(uc, UC_X86_REG_EAX, &r_eax);
|
|
printf(">>> EAX = 0x%x\n", r_eax);
|
|
|
|
// restore CPU context
|
|
err = uc_context_restore(uc, context);
|
|
if (err) {
|
|
printf("Failed on uc_context_restore() with error returned: %u\n", err);
|
|
return;
|
|
}
|
|
|
|
// now print out some registers
|
|
printf(">>> CPU context restored. Below is the CPU context\n");
|
|
|
|
uc_reg_read(uc, UC_X86_REG_EAX, &r_eax);
|
|
printf(">>> EAX = 0x%x\n", r_eax);
|
|
|
|
// free the CPU context
|
|
err = uc_context_free(context);
|
|
if (err) {
|
|
printf("Failed on uc_context_free() with error returned: %u\n", err);
|
|
return;
|
|
}
|
|
|
|
uc_close(uc);
|
|
}
|
|
|
|
static void test_x86_64(void)
|
|
{
|
|
uc_engine *uc;
|
|
uc_err err;
|
|
uc_hook trace1, trace2, trace3, trace4;
|
|
|
|
int64_t rax = 0x71f3029efd49d41d;
|
|
int64_t rbx = 0xd87b45277f133ddb;
|
|
int64_t rcx = 0xab40d1ffd8afc461;
|
|
int64_t rdx = 0x919317b4a733f01;
|
|
int64_t rsi = 0x4c24e753a17ea358;
|
|
int64_t rdi = 0xe509a57d2571ce96;
|
|
int64_t r8 = 0xea5b108cc2b9ab1f;
|
|
int64_t r9 = 0x19ec097c8eb618c1;
|
|
int64_t r10 = 0xec45774f00c5f682;
|
|
int64_t r11 = 0xe17e9dbec8c074aa;
|
|
int64_t r12 = 0x80f86a8dc0f6d457;
|
|
int64_t r13 = 0x48288ca5671c5492;
|
|
int64_t r14 = 0x595f72f6e4017f6e;
|
|
int64_t r15 = 0x1efd97aea331cccc;
|
|
|
|
int64_t rsp = ADDRESS + 0x200000;
|
|
|
|
|
|
printf("Emulate x86_64 code\n");
|
|
|
|
// Initialize emulator in X86-64bit mode
|
|
err = uc_open(UC_ARCH_X86, UC_MODE_64, &uc);
|
|
if (err) {
|
|
printf("Failed on uc_open() with error returned: %u\n", err);
|
|
return;
|
|
}
|
|
|
|
// map 2MB memory for this emulation
|
|
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
|
|
|
// write machine code to be emulated to memory
|
|
if (uc_mem_write(uc, ADDRESS, X86_CODE64, sizeof(X86_CODE64) - 1)) {
|
|
printf("Failed to write emulation code to memory, quit!\n");
|
|
return;
|
|
}
|
|
|
|
// initialize machine registers
|
|
uc_reg_write(uc, UC_X86_REG_RSP, &rsp);
|
|
|
|
uc_reg_write(uc, UC_X86_REG_RAX, &rax);
|
|
uc_reg_write(uc, UC_X86_REG_RBX, &rbx);
|
|
uc_reg_write(uc, UC_X86_REG_RCX, &rcx);
|
|
uc_reg_write(uc, UC_X86_REG_RDX, &rdx);
|
|
uc_reg_write(uc, UC_X86_REG_RSI, &rsi);
|
|
uc_reg_write(uc, UC_X86_REG_RDI, &rdi);
|
|
uc_reg_write(uc, UC_X86_REG_R8, &r8);
|
|
uc_reg_write(uc, UC_X86_REG_R9, &r9);
|
|
uc_reg_write(uc, UC_X86_REG_R10, &r10);
|
|
uc_reg_write(uc, UC_X86_REG_R11, &r11);
|
|
uc_reg_write(uc, UC_X86_REG_R12, &r12);
|
|
uc_reg_write(uc, UC_X86_REG_R13, &r13);
|
|
uc_reg_write(uc, UC_X86_REG_R14, &r14);
|
|
uc_reg_write(uc, UC_X86_REG_R15, &r15);
|
|
|
|
// tracing all basic blocks with customized callback
|
|
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0);
|
|
|
|
// tracing all instructions in the range [ADDRESS, ADDRESS+20]
|
|
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code64, NULL, ADDRESS, ADDRESS+20);
|
|
|
|
// tracing all memory WRITE access (with @begin > @end)
|
|
uc_hook_add(uc, &trace3, UC_HOOK_MEM_WRITE, hook_mem64, NULL, 1, 0);
|
|
|
|
// tracing all memory READ access (with @begin > @end)
|
|
uc_hook_add(uc, &trace4, UC_HOOK_MEM_READ, hook_mem64, NULL, 1, 0);
|
|
|
|
// emulate machine code in infinite time (last param = 0), or when
|
|
// finishing all the code.
|
|
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE64) - 1, 0, 0);
|
|
if (err) {
|
|
printf("Failed on uc_emu_start() with error returned %u: %s\n",
|
|
err, uc_strerror(err));
|
|
}
|
|
|
|
// now print out some registers
|
|
printf(">>> Emulation done. Below is the CPU context\n");
|
|
|
|
uc_reg_read(uc, UC_X86_REG_RAX, &rax);
|
|
uc_reg_read(uc, UC_X86_REG_RBX, &rbx);
|
|
uc_reg_read(uc, UC_X86_REG_RCX, &rcx);
|
|
uc_reg_read(uc, UC_X86_REG_RDX, &rdx);
|
|
uc_reg_read(uc, UC_X86_REG_RSI, &rsi);
|
|
uc_reg_read(uc, UC_X86_REG_RDI, &rdi);
|
|
uc_reg_read(uc, UC_X86_REG_R8, &r8);
|
|
uc_reg_read(uc, UC_X86_REG_R9, &r9);
|
|
uc_reg_read(uc, UC_X86_REG_R10, &r10);
|
|
uc_reg_read(uc, UC_X86_REG_R11, &r11);
|
|
uc_reg_read(uc, UC_X86_REG_R12, &r12);
|
|
uc_reg_read(uc, UC_X86_REG_R13, &r13);
|
|
uc_reg_read(uc, UC_X86_REG_R14, &r14);
|
|
uc_reg_read(uc, UC_X86_REG_R15, &r15);
|
|
|
|
printf(">>> RAX = 0x%" PRIx64 "\n", rax);
|
|
printf(">>> RBX = 0x%" PRIx64 "\n", rbx);
|
|
printf(">>> RCX = 0x%" PRIx64 "\n", rcx);
|
|
printf(">>> RDX = 0x%" PRIx64 "\n", rdx);
|
|
printf(">>> RSI = 0x%" PRIx64 "\n", rsi);
|
|
printf(">>> RDI = 0x%" PRIx64 "\n", rdi);
|
|
printf(">>> R8 = 0x%" PRIx64 "\n", r8);
|
|
printf(">>> R9 = 0x%" PRIx64 "\n", r9);
|
|
printf(">>> R10 = 0x%" PRIx64 "\n", r10);
|
|
printf(">>> R11 = 0x%" PRIx64 "\n", r11);
|
|
printf(">>> R12 = 0x%" PRIx64 "\n", r12);
|
|
printf(">>> R13 = 0x%" PRIx64 "\n", r13);
|
|
printf(">>> R14 = 0x%" PRIx64 "\n", r14);
|
|
printf(">>> R15 = 0x%" PRIx64 "\n", r15);
|
|
|
|
uc_close(uc);
|
|
}
|
|
|
|
static void test_x86_64_syscall(void)
|
|
{
|
|
uc_engine *uc;
|
|
uc_hook trace1;
|
|
uc_err err;
|
|
|
|
int64_t rax = 0x100;
|
|
|
|
printf("===================================\n");
|
|
printf("Emulate x86_64 code with 'syscall' instruction\n");
|
|
|
|
// Initialize emulator in X86-64bit mode
|
|
err = uc_open(UC_ARCH_X86, UC_MODE_64, &uc);
|
|
if (err) {
|
|
printf("Failed on uc_open() with error returned: %u\n", err);
|
|
return;
|
|
}
|
|
|
|
// map 2MB memory for this emulation
|
|
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
|
|
|
// write machine code to be emulated to memory
|
|
if (uc_mem_write(uc, ADDRESS, X86_CODE64_SYSCALL, sizeof(X86_CODE64_SYSCALL) - 1)) {
|
|
printf("Failed to write emulation code to memory, quit!\n");
|
|
return;
|
|
}
|
|
|
|
// hook interrupts for syscall
|
|
uc_hook_add(uc, &trace1, UC_HOOK_INSN, hook_syscall, NULL, 1, 0, UC_X86_INS_SYSCALL);
|
|
|
|
// initialize machine registers
|
|
uc_reg_write(uc, UC_X86_REG_RAX, &rax);
|
|
|
|
// emulate machine code in infinite time (last param = 0), or when
|
|
// finishing all the code.
|
|
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE64_SYSCALL) - 1, 0, 0);
|
|
if (err) {
|
|
printf("Failed on uc_emu_start() with error returned %u: %s\n",
|
|
err, uc_strerror(err));
|
|
}
|
|
|
|
// now print out some registers
|
|
printf(">>> Emulation done. Below is the CPU context\n");
|
|
|
|
uc_reg_read(uc, UC_X86_REG_RAX, &rax);
|
|
|
|
printf(">>> RAX = 0x%" PRIx64 "\n", rax);
|
|
|
|
uc_close(uc);
|
|
}
|
|
|
|
static void test_x86_16(void)
|
|
{
|
|
uc_engine *uc;
|
|
uc_err err;
|
|
uint8_t tmp;
|
|
|
|
int32_t eax = 7;
|
|
int32_t ebx = 5;
|
|
int32_t esi = 6;
|
|
|
|
printf("Emulate x86 16-bit code\n");
|
|
|
|
// Initialize emulator in X86-16bit mode
|
|
err = uc_open(UC_ARCH_X86, UC_MODE_16, &uc);
|
|
if (err) {
|
|
printf("Failed on uc_open() with error returned: %u\n", err);
|
|
return;
|
|
}
|
|
|
|
// map 8KB memory for this emulation
|
|
uc_mem_map(uc, 0, 8 * 1024, UC_PROT_ALL);
|
|
|
|
// write machine code to be emulated to memory
|
|
if (uc_mem_write(uc, 0, X86_CODE16, sizeof(X86_CODE16) - 1)) {
|
|
printf("Failed to write emulation code to memory, quit!\n");
|
|
return;
|
|
}
|
|
|
|
// initialize machine registers
|
|
uc_reg_write(uc, UC_X86_REG_EAX, &eax);
|
|
uc_reg_write(uc, UC_X86_REG_EBX, &ebx);
|
|
uc_reg_write(uc, UC_X86_REG_ESI, &esi);
|
|
|
|
// emulate machine code in infinite time (last param = 0), or when
|
|
// finishing all the code.
|
|
err = uc_emu_start(uc, 0, sizeof(X86_CODE16) - 1, 0, 0);
|
|
if (err) {
|
|
printf("Failed on uc_emu_start() with error returned %u: %s\n",
|
|
err, uc_strerror(err));
|
|
}
|
|
|
|
// now print out some registers
|
|
printf(">>> Emulation done. Below is the CPU context\n");
|
|
|
|
// read from memory
|
|
if (!uc_mem_read(uc, 11, &tmp, 1))
|
|
printf(">>> Read 1 bytes from [0x%x] = 0x%x\n", 11, tmp);
|
|
else
|
|
printf(">>> Failed to read 1 bytes from [0x%x]\n", 11);
|
|
|
|
uc_close(uc);
|
|
}
|
|
|
|
int main(int argc, char **argv, char **envp)
|
|
{
|
|
// dynamically load shared library
|
|
#ifdef DYNLOAD
|
|
if (!uc_dyn_load(NULL, 0)) {
|
|
printf("Error dynamically loading shared library.\n");
|
|
printf("Please check that unicorn.dll/unicorn.so is available as well as\n");
|
|
printf("any other dependent dll/so files.\n");
|
|
return 1;
|
|
}
|
|
#endif
|
|
|
|
if (argc == 2) {
|
|
if (!strcmp(argv[1], "-16")) {
|
|
test_x86_16();
|
|
}
|
|
else if (!strcmp(argv[1], "-32")) {
|
|
test_i386();
|
|
test_i386_map_ptr();
|
|
test_i386_inout();
|
|
test_i386_context_save();
|
|
test_i386_jump();
|
|
test_i386_loop();
|
|
test_i386_invalid_mem_read();
|
|
test_i386_invalid_mem_write();
|
|
test_i386_jump_invalid();
|
|
}
|
|
else if (!strcmp(argv[1], "-64")) {
|
|
test_x86_64();
|
|
test_x86_64_syscall();
|
|
}
|
|
else if (!strcmp(argv[1], "-h")) {
|
|
printf("Syntax: %s <-16|-32|-64>\n", argv[0]);
|
|
}
|
|
}
|
|
else {
|
|
test_x86_16();
|
|
test_i386();
|
|
test_i386_map_ptr();
|
|
test_i386_inout();
|
|
test_i386_context_save();
|
|
test_i386_jump();
|
|
test_i386_loop();
|
|
test_i386_invalid_mem_read();
|
|
test_i386_invalid_mem_write();
|
|
test_i386_jump_invalid();
|
|
test_x86_64();
|
|
test_x86_64_syscall();
|
|
|
|
}
|
|
// dynamically free shared library
|
|
#ifdef DYNLOAD
|
|
uc_dyn_free();
|
|
#endif
|
|
|
|
return 0;
|
|
}
|