mirror of
https://github.com/Vita3K/unicorn.git
synced 2024-11-23 21:39:44 +00:00
Merge remote-tracking branch 'upstream/master' into change-handle-based-api
# Conflicts: # qemu/target-i386/unicorn.c
This commit is contained in:
commit
2c802a3e4b
2
.gitignore
vendored
2
.gitignore
vendored
@ -87,3 +87,5 @@ regress/block_test
|
||||
regress/map_write
|
||||
regress/ro_mem_test
|
||||
regress/nr_mem_test
|
||||
regress/timeout_segfault
|
||||
regress/rep_movsb
|
||||
|
45
COMPILE.TXT
45
COMPILE.TXT
@ -87,7 +87,7 @@ Unicorn requires few dependent packages as followings
|
||||
Users are then required to enter root password to copy Unicorn into machine
|
||||
system directories.
|
||||
|
||||
Afterwards, run ./tests/test* to see the tests disassembling sample code.
|
||||
Afterwards, run ./samples/sample_all.sh to see the sample emulations.
|
||||
|
||||
|
||||
NOTE: The core framework installed by "./make.sh install" consist of
|
||||
@ -120,11 +120,10 @@ Unicorn requires few dependent packages as followings
|
||||
|
||||
$ ./make.sh cross-win64
|
||||
|
||||
Resulted files libunicorn.dll, libunicorn.dll.a & tests/test*.exe can then
|
||||
Resulted files unicorn.dll, unicorn.lib & samples/sample*.exe can then
|
||||
be used on Windows machine.
|
||||
|
||||
To run sample_x86.exe on Windows 32-bit, you need the following files:
|
||||
|
||||
- unicorn.dll
|
||||
- /usr/i686-w64-mingw32/sys-root/mingw/bin/libglib-2.0-0.dll
|
||||
- /usr/lib/gcc/i686-w64-mingw32/4.8/libgcc_s_sjlj-1.dll
|
||||
@ -176,21 +175,43 @@ Unicorn requires few dependent packages as followings
|
||||
|
||||
|
||||
|
||||
[7] Compile on Windows with Cygwin
|
||||
[7] Compile on Windows with MinGW (MSYS2)
|
||||
|
||||
To compile under Cygwin gcc-mingw-w64-i686 or x86_64-w64-mingw32 run:
|
||||
To compile with MinGW you need to install MSYS2: https://msys2.github.io/
|
||||
Follow the install instructions and don't forget to update the system packages as written in 5 & 6 paragraphs
|
||||
|
||||
- To compile Windows 32-bit binary under Cygwin, run:
|
||||
- To compile Windows 32-bit binary with MinGW, run:
|
||||
$ pacman -S make
|
||||
$ pacman -S pkg-config
|
||||
$ pacman -S mingw-w64-i686-glib2
|
||||
$ pacman -S mingw-w64-i686-toolchain
|
||||
$ ./make.sh cross-win32
|
||||
|
||||
$ ./make.sh cygwin-mingw32
|
||||
- To compile Windows 64-bit binary with MinGW, run:
|
||||
$ pacman -S make
|
||||
$ pacman -S pkg-config
|
||||
$ pacman -S mingw-w64-x86_64-glib2
|
||||
$ pacman -S mingw-w64-x86_64-toolchain
|
||||
$ ./make.sh cross-win64
|
||||
|
||||
- To compile Windows 64-bit binary under Cygwin, run:
|
||||
|
||||
$ ./make.sh cygwin-mingw64
|
||||
|
||||
Resulted files libunicorn.dll, libunicorn.dll.a & tests/test*.exe can then
|
||||
Resulted files unicorn.dll, unicorn.lib & samples/sample*.exe can then
|
||||
be used on Windows machine.
|
||||
|
||||
To run sample_x86.exe on Windows 32-bit, you need the following files:
|
||||
- unicorn.dll
|
||||
- %MSYS2%\mingw32\bin\libiconv-2.dll
|
||||
- %MSYS2%\mingw32\bin\libintl-8.dll
|
||||
- %MSYS2%\mingw32\bin\libglib-2.0-0.dll
|
||||
- %MSYS2%\mingw32\bin\libgcc_s_dw2-1.dll
|
||||
- %MSYS2%\mingw32\bin\libwinpthread-1.dll
|
||||
|
||||
To run sample_x86.exe on Windows 64-bit, you need the following files:
|
||||
- unicorn.dll
|
||||
- %MSYS2%\mingw64\bin\libiconv-2.dll
|
||||
- %MSYS2%\mingw64\bin\libintl-8.dll
|
||||
- %MSYS2%\mingw64\bin\libglib-2.0-0.dll
|
||||
- %MSYS2%\mingw64\bin\libgcc_s_seh-1.dll
|
||||
- %MSYS2%\mingw64\bin\libwinpthread-1.dll
|
||||
|
||||
|
||||
[8] By default, "cc" (default C compiler on the system) is used as compiler.
|
||||
|
@ -37,6 +37,8 @@ Luke Burnett
|
||||
Parker Thompson
|
||||
Daniel Godas-Lopez
|
||||
Antonio "s4tan" Parata
|
||||
Corey Kallenberg
|
||||
Shift
|
||||
|
||||
Contributors (in no particular order)
|
||||
=====================================
|
||||
|
@ -17,6 +17,10 @@ void hookMemAccess_cgo(uch handle, uc_mem_type type, uint64_t addr, int size, in
|
||||
hookMemAccess(handle, type, addr, size, value, user);
|
||||
}
|
||||
|
||||
void hookInterrupt_cgo(uch handle, uint32_t intno, void *user) {
|
||||
hookInterrupt(handle, intno, user);
|
||||
}
|
||||
|
||||
uint32_t hookX86In_cgo(uch handle, uint32_t port, uint32_t size, void *user) {
|
||||
return hookX86In(handle, port, size, user);
|
||||
}
|
||||
|
@ -17,33 +17,39 @@ type HookData struct {
|
||||
}
|
||||
|
||||
//export hookCode
|
||||
func hookCode(handle C.uch, addr C.uint64_t, size C.uint32_t, user unsafe.Pointer) {
|
||||
func hookCode(handle C.uch, addr uint64, size uint32, user unsafe.Pointer) {
|
||||
hook := (*HookData)(user)
|
||||
hook.Callback.(func(*Uc, uint64, uint32))(hook.Uc, uint64(addr), uint32(size))
|
||||
}
|
||||
|
||||
//export hookMemInvalid
|
||||
func hookMemInvalid(handle C.uch, typ C.uc_mem_type, addr C.uint64_t, size int, value C.int64_t, user unsafe.Pointer) C.bool {
|
||||
func hookMemInvalid(handle C.uch, typ C.uc_mem_type, addr uint64, size int, value int64, user unsafe.Pointer) bool {
|
||||
hook := (*HookData)(user)
|
||||
return C.bool(hook.Callback.(func(*Uc, int, uint64, int, int64) bool)(hook.Uc, int(typ), uint64(addr), size, int64(value)))
|
||||
return hook.Callback.(func(*Uc, int, uint64, int, int64) bool)(hook.Uc, int(typ), addr, size, value)
|
||||
}
|
||||
|
||||
//export hookMemAccess
|
||||
func hookMemAccess(handle C.uch, typ C.uc_mem_type, addr C.uint64_t, size int, value C.int64_t, user unsafe.Pointer) {
|
||||
func hookMemAccess(handle C.uch, typ C.uc_mem_type, addr uint64, size int, value int64, user unsafe.Pointer) {
|
||||
hook := (*HookData)(user)
|
||||
hook.Callback.(func(*Uc, int, uint64, int, int64))(hook.Uc, int(typ), uint64(addr), size, int64(value))
|
||||
hook.Callback.(func(*Uc, int, uint64, int, int64))(hook.Uc, int(typ), addr, size, value)
|
||||
}
|
||||
|
||||
//export hookInterrupt
|
||||
func hookInterrupt(handle C.uch, intno uint32, user unsafe.Pointer) {
|
||||
hook := (*HookData)(user)
|
||||
hook.Callback.(func(*Uc, uint32))(hook.Uc, intno)
|
||||
}
|
||||
|
||||
//export hookX86In
|
||||
func hookX86In(handle C.uch, port, size uint32, user unsafe.Pointer) C.uint32_t {
|
||||
func hookX86In(handle C.uch, port, size uint32, user unsafe.Pointer) uint32 {
|
||||
hook := (*HookData)(user)
|
||||
return C.uint32_t(hook.Callback.(func(*Uc, uint32, uint32) uint32)(hook.Uc, port, size))
|
||||
return hook.Callback.(func(*Uc, uint32, uint32) uint32)(hook.Uc, port, size)
|
||||
}
|
||||
|
||||
//export hookX86Out
|
||||
func hookX86Out(handle C.uch, port, size, value uint32, user unsafe.Pointer) {
|
||||
hook := (*HookData)(user)
|
||||
hook.Callback.(func(*Uc, uint32, uint32, uint32))(hook.Uc, uint32(port), uint32(size), uint32(value))
|
||||
hook.Callback.(func(*Uc, uint32, uint32, uint32))(hook.Uc, port, size, value)
|
||||
}
|
||||
|
||||
//export hookX86Syscall
|
||||
@ -64,6 +70,8 @@ func (u *Uc) HookAdd(htype int, cb interface{}, insn ...int) (C.uch, error) {
|
||||
callback = C.hookMemInvalid_cgo
|
||||
case UC_HOOK_MEM_READ, UC_HOOK_MEM_WRITE, UC_HOOK_MEM_READ_WRITE:
|
||||
callback = C.hookMemAccess_cgo
|
||||
case UC_HOOK_INTR:
|
||||
callback = C.hookInterrupt_cgo
|
||||
case UC_HOOK_INSN:
|
||||
extra = C.int(insn[0])
|
||||
switch extra {
|
||||
|
@ -2,6 +2,7 @@ uc_err uc_hook_add2(uch handle, uch *h2, uc_hook_t type, void *callback, void *u
|
||||
void hookCode_cgo(uch handle, uint64_t addr, uint32_t size, void *user);
|
||||
bool hookMemInvalid_cgo(uch handle, uc_mem_type type, uint64_t addr, int size, int64_t value, void *user);
|
||||
void hookMemAccess_cgo(uch handle, uc_mem_type type, uint64_t addr, int size, int64_t value, void *user);
|
||||
void hookInterrupt_cgo(uch handle, uint32_t intno, void *user);
|
||||
uint32_t hookX86In_cgo(uch handle, uint32_t port, uint32_t size, void *user);
|
||||
void hookX86Out_cgo(uch handle, uint32_t port, uint32_t size, uint32_t value, void *user);
|
||||
void hookX86Syscall_cgo(uch handle, void *user);
|
||||
|
@ -1,19 +1,19 @@
|
||||
/\'. _,,
|
||||
|.\ \ .'_/
|
||||
_.-- |(\\ \ .'_.'
|
||||
_.-' \_\\ \\_),/ _/
|
||||
_).' .:::::::.___ .'
|
||||
// ' ./::::::\\o\(
|
||||
// //::/ '"( \
|
||||
//_ //::( '. '.
|
||||
/_'/ /||:::\ '. \
|
||||
'// '\\:::':\_ -<_' _'-
|
||||
/ | '\::/|::::.._ _ )(
|
||||
| | \:| \:( '.(_'._)
|
||||
/\'. _,.
|
||||
|:\ \. .'_/
|
||||
_.- |(\\ \ .'_.'
|
||||
_.-' ,__\\ \\_),/ _/
|
||||
_:.' .:::::::.___ ,'
|
||||
// ' ./::::::\<o\(
|
||||
// /|::/ `"( \
|
||||
;/_ / ::( `. `.
|
||||
/_'/ | ::::\ `. \
|
||||
'// '\ :::':\_ _, ` _'-
|
||||
/ | '\.:/|::::.._ `-__ )/
|
||||
| | \;| \:( '.(_ \_)
|
||||
| | \( \::. '-)
|
||||
\ \ . '""""---.
|
||||
\ \ \ . _.-...)
|
||||
\ \/\. \:.___.-'..:::/
|
||||
\ |\\:..\:::::'.::::/
|
||||
' '.:::::'..:::"'
|
||||
'":::""'
|
||||
\ \ , '""""---.
|
||||
\ \ \ , _.-...)
|
||||
\ \/\. \:,___.-'..:::/
|
||||
\ |\\:,.\:::::'.::::/
|
||||
` `:;::::'.::;::'
|
||||
'":;:""'
|
||||
|
@ -205,6 +205,8 @@ int cpu_exec(struct uc_struct *uc, CPUArchState *env) // qq
|
||||
have_tb_lock = true;
|
||||
tb = tb_find_fast(env); // qq
|
||||
if (!tb) { // invalid TB due to invalid code?
|
||||
uc->invalid_error = UC_ERR_CODE_INVALID;
|
||||
ret = EXCP_HLT;
|
||||
break;
|
||||
}
|
||||
/* Note: we do it here to avoid a gcc bug on Mac OS X when
|
||||
|
@ -986,12 +986,22 @@ void helper_fstenv(CPUX86State *env, target_ulong ptr, int data32)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (data32) {
|
||||
|
||||
// DFLAG enum: tcg.h, case here to int
|
||||
if (env->hflags & HF_CS64_MASK) {
|
||||
cpu_stl_data(env, ptr, env->fpuc);
|
||||
cpu_stl_data(env, ptr + 4, fpus);
|
||||
cpu_stl_data(env, ptr + 8, fptag);
|
||||
cpu_stl_data(env, ptr + 12, env->fpip); /* fpip */
|
||||
cpu_stl_data(env, ptr + 20, 0); /* fpcs */
|
||||
cpu_stl_data(env, ptr + 24, 0); /* fpoo */
|
||||
cpu_stl_data(env, ptr + 28, 0); /* fpos */
|
||||
} else if (data32) {
|
||||
/* 32 bit */
|
||||
cpu_stl_data(env, ptr, env->fpuc);
|
||||
cpu_stl_data(env, ptr + 4, fpus);
|
||||
cpu_stl_data(env, ptr + 8, fptag);
|
||||
cpu_stl_data(env, ptr + 12, 0); /* fpip */
|
||||
cpu_stl_data(env, ptr + 12, env->fpip); /* fpip */
|
||||
cpu_stl_data(env, ptr + 16, 0); /* fpcs */
|
||||
cpu_stl_data(env, ptr + 20, 0); /* fpoo */
|
||||
cpu_stl_data(env, ptr + 24, 0); /* fpos */
|
||||
@ -1000,11 +1010,12 @@ void helper_fstenv(CPUX86State *env, target_ulong ptr, int data32)
|
||||
cpu_stw_data(env, ptr, env->fpuc);
|
||||
cpu_stw_data(env, ptr + 2, fpus);
|
||||
cpu_stw_data(env, ptr + 4, fptag);
|
||||
cpu_stw_data(env, ptr + 6, 0);
|
||||
cpu_stw_data(env, ptr + 6, env->fpip);
|
||||
cpu_stw_data(env, ptr + 8, 0);
|
||||
cpu_stw_data(env, ptr + 10, 0);
|
||||
cpu_stw_data(env, ptr + 12, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void helper_fldenv(CPUX86State *env, target_ulong ptr, int data32)
|
||||
|
@ -248,6 +248,11 @@ static void gen_update_cc_op(DisasContext *s)
|
||||
}
|
||||
}
|
||||
|
||||
static void fpu_update_ip(CPUX86State *env, target_ulong pc)
|
||||
{
|
||||
env->fpip = pc;
|
||||
}
|
||||
|
||||
#ifdef TARGET_X86_64
|
||||
|
||||
#define NB_OP_SIZES 4
|
||||
@ -6110,6 +6115,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
|
||||
/* fcomp needs pop */
|
||||
gen_helper_fpop(tcg_ctx, cpu_env);
|
||||
}
|
||||
fpu_update_ip(env, pc_start);
|
||||
}
|
||||
break;
|
||||
case 0x08: /* flds */
|
||||
@ -6194,6 +6200,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
|
||||
gen_helper_fpop(tcg_ctx, cpu_env);
|
||||
break;
|
||||
}
|
||||
fpu_update_ip(env, pc_start);
|
||||
break;
|
||||
case 0x0c: /* fldenv mem */
|
||||
gen_update_cc_op(s);
|
||||
@ -6219,12 +6226,14 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
|
||||
gen_update_cc_op(s);
|
||||
gen_jmp_im(s, pc_start - s->cs_base);
|
||||
gen_helper_fldt_ST0(tcg_ctx, cpu_env, cpu_A0);
|
||||
fpu_update_ip(env, pc_start);
|
||||
break;
|
||||
case 0x1f: /* fstpt mem */
|
||||
gen_update_cc_op(s);
|
||||
gen_jmp_im(s, pc_start - s->cs_base);
|
||||
gen_helper_fstt_ST0(tcg_ctx, cpu_env, cpu_A0);
|
||||
gen_helper_fpop(tcg_ctx, cpu_env);
|
||||
fpu_update_ip(env, pc_start);
|
||||
break;
|
||||
case 0x2c: /* frstor mem */
|
||||
gen_update_cc_op(s);
|
||||
@ -6245,21 +6254,25 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
|
||||
gen_update_cc_op(s);
|
||||
gen_jmp_im(s, pc_start - s->cs_base);
|
||||
gen_helper_fbld_ST0(tcg_ctx, cpu_env, cpu_A0);
|
||||
fpu_update_ip(env, pc_start);
|
||||
break;
|
||||
case 0x3e: /* fbstp */
|
||||
gen_update_cc_op(s);
|
||||
gen_jmp_im(s, pc_start - s->cs_base);
|
||||
gen_helper_fbst_ST0(tcg_ctx, cpu_env, cpu_A0);
|
||||
gen_helper_fpop(tcg_ctx, cpu_env);
|
||||
fpu_update_ip(env, pc_start);
|
||||
break;
|
||||
case 0x3d: /* fildll */
|
||||
tcg_gen_qemu_ld_i64(s->uc, cpu_tmp1_i64, cpu_A0, s->mem_index, MO_LEQ);
|
||||
gen_helper_fildll_ST0(tcg_ctx, cpu_env, cpu_tmp1_i64);
|
||||
fpu_update_ip(env, pc_start);
|
||||
break;
|
||||
case 0x3f: /* fistpll */
|
||||
gen_helper_fistll_ST0(tcg_ctx, cpu_tmp1_i64, cpu_env);
|
||||
tcg_gen_qemu_st_i64(s->uc, cpu_tmp1_i64, cpu_A0, s->mem_index, MO_LEQ);
|
||||
gen_helper_fpop(tcg_ctx, cpu_env);
|
||||
fpu_update_ip(env, pc_start);
|
||||
break;
|
||||
default:
|
||||
goto illegal_op;
|
||||
@ -6574,6 +6587,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
|
||||
default:
|
||||
goto illegal_op;
|
||||
}
|
||||
fpu_update_ip(env, pc_start);
|
||||
}
|
||||
break;
|
||||
/************************/
|
||||
|
@ -52,6 +52,12 @@ void x86_reg_reset(struct uc_struct *uc)
|
||||
{
|
||||
CPUArchState *env = first_cpu->env_ptr;
|
||||
|
||||
env->features[FEAT_1_EDX] = CPUID_CX8 | CPUID_CMOV | CPUID_SSE2 | CPUID_FXSR | CPUID_SSE | CPUID_CLFLUSH;
|
||||
env->features[FEAT_1_ECX] = CPUID_EXT_SSSE3 | CPUID_EXT_SSE41 | CPUID_EXT_SSE42 | CPUID_EXT_AES;
|
||||
env->features[FEAT_8000_0001_EDX] = CPUID_EXT2_3DNOW | CPUID_EXT2_RDTSCP;
|
||||
env->features[FEAT_8000_0001_ECX] = CPUID_EXT3_LAHF_LM | CPUID_EXT3_ABM | CPUID_EXT3_SKINIT | CPUID_EXT3_CR8LEG;
|
||||
env->features[FEAT_7_0_EBX] = CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ADX | CPUID_7_0_EBX_SMAP;
|
||||
|
||||
env->invalid_error = UC_ERR_OK; // no error
|
||||
memset(env->regs, 0, sizeof(env->regs));
|
||||
memset(env->segs, 0, sizeof(env->segs));
|
||||
|
@ -6,6 +6,7 @@ TESTS += sigill sigill2
|
||||
TESTS += block_test
|
||||
TESTS += ro_mem_test nr_mem_test
|
||||
TESTS += timeout_segfault
|
||||
TESTS += rep_movsb
|
||||
|
||||
all: $(TESTS)
|
||||
|
||||
|
61
regress/fpu_ip.py
Executable file
61
regress/fpu_ip.py
Executable file
@ -0,0 +1,61 @@
|
||||
#!/usr/bin/python
|
||||
from unicorn import *
|
||||
from unicorn.x86_const import *
|
||||
from capstone import *
|
||||
|
||||
ESP = 0x2000
|
||||
PAGE_SIZE = 2 * 1024 * 1024
|
||||
|
||||
# mov [esp], DWORD 0x37f
|
||||
# fldcw [esp]
|
||||
# fnop
|
||||
# fnstenv [esp + 8]
|
||||
# pop ecx
|
||||
CODE = b'\xc7\x04\x24\x7f\x03\x00\x00\xd9\x2c\x24\xd9\xd0\xd9\x74\x24\x08\x59'
|
||||
|
||||
class SimpleEngine:
|
||||
def __init__(self):
|
||||
self.capmd = Cs(CS_ARCH_X86, CS_MODE_32)
|
||||
|
||||
def disas_single(self, data):
|
||||
for i in self.capmd.disasm(data, 16):
|
||||
print("\t%s\t%s" % (i.mnemonic, i.op_str))
|
||||
break
|
||||
|
||||
disasm = SimpleEngine()
|
||||
|
||||
def hook_code(uc, addr, size, user_data):
|
||||
mem = uc.mem_read(addr, size)
|
||||
print(" 0x%X:" % (addr)),
|
||||
disasm.disas_single(str(mem))
|
||||
|
||||
def mem_reader(addr, size):
|
||||
tmp = mu.mem_read(addr, size)
|
||||
|
||||
for i in tmp:
|
||||
print(" 0x%x" % i),
|
||||
print("")
|
||||
|
||||
|
||||
mu = Uc(UC_ARCH_X86, UC_MODE_32)
|
||||
|
||||
mu.mem_map(0x0, PAGE_SIZE)
|
||||
mu.mem_write(0x4000, CODE)
|
||||
mu.reg_write(UC_X86_REG_ESP, ESP)
|
||||
mu.hook_add(UC_HOOK_CODE, hook_code)
|
||||
|
||||
|
||||
mu.emu_start(0x4000, 0, 0, 5)
|
||||
esp = mu.reg_read(UC_X86_REG_ESP)
|
||||
print("value at ESP [0x%X - 4]: " % esp)
|
||||
mem_reader(esp + 14, 4)
|
||||
|
||||
# EXPECTED OUTPUT:
|
||||
# 0x4000: mov dword ptr [esp], 0x37f
|
||||
# 0x4007: fldcw word ptr [esp]
|
||||
# 0x400A: fnop
|
||||
# 0x400C: fnstenv dword ptr [esp + 8]
|
||||
# 0x4010: pop ecx
|
||||
# value at ESP [0x2004 - 4]:
|
||||
# 0x0 0x0 0xa 0x40
|
||||
# ^ this value should match the fnop instuction addr
|
62
regress/fpu_ip64.py
Executable file
62
regress/fpu_ip64.py
Executable file
@ -0,0 +1,62 @@
|
||||
#!/usr/bin/python
|
||||
from unicorn import *
|
||||
from unicorn.x86_const import *
|
||||
from capstone import *
|
||||
|
||||
ESP = 0x2000
|
||||
PAGE_SIZE = 2 * 1024 * 1024
|
||||
|
||||
# mov [esp], DWORD 0x37f
|
||||
# fldcw [esp]
|
||||
# fnop
|
||||
# fnstenv [esp + 8]
|
||||
# pop ecx
|
||||
CODE = "C704247F030000D92C24D9D0D974240859".decode('hex')
|
||||
|
||||
class SimpleEngine:
|
||||
def __init__(self):
|
||||
self.capmd = Cs(CS_ARCH_X86, CS_MODE_64)
|
||||
|
||||
def disas_single(self, data):
|
||||
for i in self.capmd.disasm(data, 16):
|
||||
print("\t%s\t%s" % (i.mnemonic, i.op_str))
|
||||
break
|
||||
|
||||
disasm = SimpleEngine()
|
||||
|
||||
def hook_code(uc, addr, size, user_data):
|
||||
mem = uc.mem_read(addr, size)
|
||||
print(" 0x%X:" % (addr)),
|
||||
disasm.disas_single(str(mem))
|
||||
|
||||
def mem_reader(addr, size):
|
||||
tmp = mu.mem_read(addr, size)
|
||||
|
||||
for i in tmp:
|
||||
print(" 0x%x" % i),
|
||||
print("")
|
||||
|
||||
|
||||
mu = Uc(UC_ARCH_X86, UC_MODE_64)
|
||||
|
||||
mu.mem_map(0x0, PAGE_SIZE)
|
||||
mu.mem_write(0x4000, CODE)
|
||||
mu.reg_write(UC_X86_REG_RSP, ESP)
|
||||
mu.hook_add(UC_HOOK_CODE, hook_code)
|
||||
|
||||
|
||||
mu.emu_start(0x4000, 0, 0, 5)
|
||||
rsp = mu.reg_read(UC_X86_REG_RSP)
|
||||
print("Value of FPIP: [0x%X]" % (rsp + 10))
|
||||
mem_reader(rsp + 10, 8)
|
||||
# EXPECTED OUTPUT:
|
||||
|
||||
# 0x4000: mov dword ptr [rsp], 0x37f
|
||||
# 0x4007: fldcw word ptr [rsp]
|
||||
# 0x400A: fnop
|
||||
# 0x400C: fnstenv dword ptr [rsp + 8]
|
||||
# 0x4010: pop rcx
|
||||
# Value of FPIP: [0x2012]
|
||||
# 0x0 0x0 0xa 0x40 0x0 0x0 0x0 0x0
|
||||
|
||||
# WHERE: the value of FPIP should be the address of fnop
|
37
regress/jmp_ebx_hang.py
Executable file
37
regress/jmp_ebx_hang.py
Executable file
@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""See https://github.com/unicorn-engine/unicorn/issues/82"""
|
||||
|
||||
import unicorn
|
||||
CODE_ADDR = 0x10101000
|
||||
CODE = b'\xff\xe3' # jmp ebx
|
||||
mu = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32)
|
||||
mu.mem_map(CODE_ADDR, 1024 * 4)
|
||||
mu.mem_write(CODE_ADDR, CODE)
|
||||
# If EBX is zero then an exception is raised, as expected
|
||||
mu.reg_write(unicorn.x86_const.UC_X86_REG_EBX, 0x0)
|
||||
|
||||
print(">>> jmp ebx (ebx = 0)");
|
||||
try:
|
||||
mu.emu_start(CODE_ADDR, CODE_ADDR + 2, count=1)
|
||||
except unicorn.UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
assert(e.errno == unicorn.UC_ERR_CODE_INVALID)
|
||||
else:
|
||||
assert(False)
|
||||
|
||||
print(">>> jmp ebx (ebx = 0xaa96a47f)");
|
||||
mu = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32)
|
||||
mu.mem_map(CODE_ADDR, 1024 * 4)
|
||||
# If we write this address to EBX then the emulator hangs on emu_start
|
||||
mu.reg_write(unicorn.x86_const.UC_X86_REG_EBX, 0xaa96a47f)
|
||||
mu.mem_write(CODE_ADDR, CODE)
|
||||
try:
|
||||
mu.emu_start(CODE_ADDR, CODE_ADDR + 2, count=1)
|
||||
except unicorn.UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
assert(e.errno == unicorn.UC_ERR_CODE_INVALID)
|
||||
else:
|
||||
assert(False)
|
||||
|
||||
print "Success"
|
12
regress/pshufb.py
Executable file
12
regress/pshufb.py
Executable file
@ -0,0 +1,12 @@
|
||||
#!/usr/bin/python
|
||||
# By Ryan Hileman, issue #91
|
||||
|
||||
# Invalid instruction = test failed
|
||||
|
||||
from unicorn import *
|
||||
from unicorn.x86_const import *
|
||||
uc = Uc(UC_ARCH_X86, UC_MODE_64)
|
||||
uc.mem_map(0x2000, 0x1000)
|
||||
# pshufb xmm0, xmm1
|
||||
uc.mem_write(0x2000, '660f3800c1'.decode('hex'))
|
||||
uc.emu_start(0x2000, 0x2005)
|
183
regress/rep_movsb.c
Normal file
183
regress/rep_movsb.c
Normal file
@ -0,0 +1,183 @@
|
||||
/*
|
||||
|
||||
rep movsb regression
|
||||
|
||||
Copyright(c) 2015 Chris Eagle
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
version 2 as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
*/
|
||||
|
||||
#define __STDC_FORMAT_MACROS
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <unicorn/unicorn.h>
|
||||
|
||||
unsigned char PROGRAM[] =
|
||||
"\xbe\x00\x00\x20\x00\xbf\x00\x10\x20\x00\xb9\x14\x00\x00\x00\xf3"
|
||||
"\xa4\xf4";
|
||||
// total size: 18 bytes
|
||||
|
||||
/*
|
||||
bits 32
|
||||
|
||||
; assumes code section at 0x100000 r-x
|
||||
; assumes data section at 0x200000-0x202000, rw-
|
||||
|
||||
mov esi, 0x200000
|
||||
mov edi, 0x201000
|
||||
mov ecx, 20
|
||||
rep movsb
|
||||
hlt
|
||||
*/
|
||||
|
||||
static int log_num = 1;
|
||||
|
||||
// callback for tracing instruction
|
||||
static void hook_code(uch handle, uint64_t addr, uint32_t size, void *user_data)
|
||||
{
|
||||
uint8_t opcode;
|
||||
if (uc_mem_read(handle, addr, &opcode, 1) != UC_ERR_OK) {
|
||||
printf("not ok %d - uc_mem_read fail during hook_code callback, addr: 0x%" PRIx64 "\n", log_num++, addr);
|
||||
_exit(-1);
|
||||
}
|
||||
switch (opcode) {
|
||||
case 0xf4: //hlt
|
||||
printf("# Handling HLT\n");
|
||||
if (uc_emu_stop(handle) != UC_ERR_OK) {
|
||||
printf("not ok %d - uc_emu_stop fail during hook_code callback, addr: 0x%" PRIx64 "\n", log_num++, addr);
|
||||
_exit(-1);
|
||||
}
|
||||
else {
|
||||
printf("ok %d - hlt encountered, uc_emu_stop called\n", log_num++);
|
||||
}
|
||||
break;
|
||||
default: //all others
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// callback for tracing memory access (READ or WRITE)
|
||||
static void hook_mem_write(uch handle, uc_mem_type type,
|
||||
uint64_t addr, int size, int64_t value, void *user_data)
|
||||
{
|
||||
printf("# write to memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value);
|
||||
if (addr < 0x201000L) {
|
||||
//this is actually a read, we don't write in this range
|
||||
printf("not ok %d - write hook called for read of 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", log_num++, addr, size, value);
|
||||
}
|
||||
else {
|
||||
printf("ok %d - write hook called for write of 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", log_num++, addr, size, value);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv, char **envp)
|
||||
{
|
||||
uch handle, trace1, trace2;
|
||||
uc_err err;
|
||||
uint8_t buf1[100], readbuf[100];
|
||||
|
||||
printf("# rep movsb test\n");
|
||||
|
||||
memset(buf1, 'A', 20);
|
||||
|
||||
// Initialize emulator in X86-32bit mode
|
||||
err = uc_open(UC_ARCH_X86, UC_MODE_32, &handle);
|
||||
if (err) {
|
||||
printf("not ok %d - Failed on uc_open() with error returned: %u\n", log_num++, err);
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
printf("ok %d - uc_open() success\n", log_num++);
|
||||
}
|
||||
|
||||
uc_mem_map(handle, 0x100000, 0x1000, UC_PROT_READ);
|
||||
uc_mem_map(handle, 0x200000, 0x2000, UC_PROT_READ | UC_PROT_WRITE);
|
||||
|
||||
// fill in the data that we want to copy
|
||||
if (uc_mem_write(handle, 0x200000, (uint8_t*)buf1, 20)) {
|
||||
printf("not ok %d - Failed to write read buffer to memory, quit!\n", log_num++);
|
||||
return 2;
|
||||
}
|
||||
else {
|
||||
printf("ok %d - Read buffer written to memory\n", log_num++);
|
||||
}
|
||||
|
||||
// write machine code to be emulated to memory
|
||||
if (uc_mem_write(handle, 0x100000, PROGRAM, sizeof(PROGRAM))) {
|
||||
printf("not ok %d - Failed to write emulation code to memory, quit!\n", log_num++);
|
||||
return 4;
|
||||
}
|
||||
else {
|
||||
printf("ok %d - Program written to memory\n", log_num++);
|
||||
}
|
||||
|
||||
if (uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0) != UC_ERR_OK) {
|
||||
printf("not ok %d - Failed to install UC_HOOK_CODE handler\n", log_num++);
|
||||
return 5;
|
||||
}
|
||||
else {
|
||||
printf("ok %d - UC_HOOK_CODE installed\n", log_num++);
|
||||
}
|
||||
|
||||
// intercept memory write events only, NOT read events
|
||||
if (uc_hook_add(handle, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL) != UC_ERR_OK) {
|
||||
printf("not ok %d - Failed to install UC_HOOK_MEM_WRITE handler\n", log_num++);
|
||||
return 6;
|
||||
}
|
||||
else {
|
||||
printf("ok %d - UC_HOOK_MEM_WRITE installed\n", log_num++);
|
||||
}
|
||||
|
||||
// emulate machine code until told to stop by hook_code
|
||||
printf("# BEGIN execution\n");
|
||||
err = uc_emu_start(handle, 0x100000, 0x101000, 0, 0);
|
||||
if (err != UC_ERR_OK) {
|
||||
printf("not ok %d - Failure on uc_emu_start() with error %u:%s\n", log_num++, err, uc_strerror(err));
|
||||
return 8;
|
||||
}
|
||||
else {
|
||||
printf("ok %d - uc_emu_start complete\n", log_num++);
|
||||
}
|
||||
printf("# END execution\n");
|
||||
|
||||
//make sure that data got copied
|
||||
// fill in sections that shouldn't get touched
|
||||
if (uc_mem_read(handle, 0x201000, (uint8_t*)readbuf, 20)) {
|
||||
printf("not ok %d - Failed to read random buffer 1 from memory\n", log_num++);
|
||||
}
|
||||
else {
|
||||
printf("ok %d - Random buffer 1 read from memory\n", log_num++);
|
||||
if (memcmp(buf1, readbuf, 20)) {
|
||||
printf("not ok %d - write buffer contents are incorrect\n", log_num++);
|
||||
}
|
||||
else {
|
||||
printf("ok %d - write buffer contents are correct\n", log_num++);
|
||||
}
|
||||
}
|
||||
|
||||
if (uc_close(&handle) == UC_ERR_OK) {
|
||||
printf("ok %d - uc_close complete\n", log_num++);
|
||||
}
|
||||
else {
|
||||
printf("not ok %d - uc_close complete\n", log_num++);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user