diff --git a/.gitignore b/.gitignore index 99d9edc7..f4d49d9e 100644 --- a/.gitignore +++ b/.gitignore @@ -51,6 +51,16 @@ shellcode.static sample_m68k sample_m68k.exe sample_m68k.static +mem_exec +mem_exec.exe +mem_exec.static +mem_protect +mem_protect.exe +mem_protect.static +mem_unmap +mem_unmap.exe +mem_unmap.static + libunicorn*.dll libunicorn*.so @@ -88,3 +98,4 @@ regress/map_write regress/ro_mem_test regress/nr_mem_test regress/timeout_segfault +regress/rep_movsb diff --git a/COMPILE.TXT b/COMPILE.TXT index bd0910be..fa2b1d7c 100644 --- a/COMPILE.TXT +++ b/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 @@ -178,8 +178,16 @@ Unicorn requires few dependent packages as followings [7] Compile on Windows with MinGW (MSYS2) 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 + Follow the install instructions and don't forget to update the system packages with: + + $ pacman --needed -Sy bash pacman pacman-mirrors msys2-runtime + + Then close MSYS2, run it again from Start menu and update the rest with: + + $ pacman -Su + Finally, compile Unicorn with the next steps: + - To compile Windows 32-bit binary with MinGW, run: $ pacman -S make $ pacman -S pkg-config diff --git a/bindings/go/unicorn/hook.c b/bindings/go/unicorn/hook.c index a06f9901..f24dd1f1 100644 --- a/bindings/go/unicorn/hook.c +++ b/bindings/go/unicorn/hook.c @@ -1,8 +1,12 @@ #include #include "_cgo_export.h" -uc_err uc_hook_add2(uch handle, uch *h2, uc_hook_t type, void *callback, void *user_data, int extra) { - return uc_hook_add(handle, h2, type, callback, user_data, extra); +uc_err uc_hook_add_i1(uch handle, uch *h2, uc_hook_t type, void *callback, void *user, int arg1) { + return uc_hook_add(handle, h2, type, callback, user, arg1); +} + +uc_err uc_hook_add_u2(uch handle, uch *h2, uc_hook_t type, void *callback, void *user, uint64_t arg1, uint64_t arg2) { + return uc_hook_add(handle, h2, type, callback, user, arg1, arg2); } void hookCode_cgo(uch handle, uint64_t addr, uint32_t size, void *user) { diff --git a/bindings/go/unicorn/hook.go b/bindings/go/unicorn/hook.go index dcab893a..e6e01617 100644 --- a/bindings/go/unicorn/hook.go +++ b/bindings/go/unicorn/hook.go @@ -60,21 +60,26 @@ func hookX86Syscall(handle C.uch, user unsafe.Pointer) { var hookRetain = make(map[C.uch]*HookData) -func (u *Uc) HookAdd(htype int, cb interface{}, insn ...int) (C.uch, error) { +func (u *Uc) HookAdd(htype int, cb interface{}, extra ...uint64) (C.uch, error) { var callback unsafe.Pointer - var extra C.int + var iarg1 C.int + var uarg1, uarg2 C.uint64_t + rangeMode := false switch htype { case UC_HOOK_BLOCK, UC_HOOK_CODE: + rangeMode = true callback = C.hookCode_cgo case UC_HOOK_MEM_INVALID: + rangeMode = true callback = C.hookMemInvalid_cgo case UC_HOOK_MEM_READ, UC_HOOK_MEM_WRITE, UC_HOOK_MEM_READ_WRITE: + rangeMode = true callback = C.hookMemAccess_cgo case UC_HOOK_INTR: callback = C.hookInterrupt_cgo case UC_HOOK_INSN: - extra = C.int(insn[0]) - switch extra { + iarg1 = C.int(extra[0]) + switch iarg1 { case UC_X86_INS_IN: callback = C.hookX86In_cgo case UC_X86_INS_OUT: @@ -89,7 +94,17 @@ func (u *Uc) HookAdd(htype int, cb interface{}, insn ...int) (C.uch, error) { } var h2 C.uch data := &HookData{u, cb} - C.uc_hook_add2(u.Handle, &h2, C.uc_hook_t(htype), callback, unsafe.Pointer(data), extra) + if rangeMode { + if len(extra) == 2 { + uarg1 = C.uint64_t(extra[0]) + uarg2 = C.uint64_t(extra[1]) + } else { + uarg1, uarg2 = 1, 0 + } + C.uc_hook_add_u2(u.Handle, &h2, C.uc_hook_t(htype), callback, unsafe.Pointer(data), uarg1, uarg2) + } else { + C.uc_hook_add_i1(u.Handle, &h2, C.uc_hook_t(htype), callback, unsafe.Pointer(data), iarg1) + } hookRetain[h2] = data return h2, nil } diff --git a/bindings/go/unicorn/hook.h b/bindings/go/unicorn/hook.h index c8c22267..b35fca27 100644 --- a/bindings/go/unicorn/hook.h +++ b/bindings/go/unicorn/hook.h @@ -1,4 +1,5 @@ -uc_err uc_hook_add2(uch handle, uch *h2, uc_hook_t type, void *callback, void *user_data, int extra); +uc_err uc_hook_add_i1(uch handle, uch *h2, uc_hook_t type, void *callback, void *user_data, int arg1); +uc_err uc_hook_add_u2(uch handle, uch *h2, uc_hook_t type, void *callback, void *user_data, uint64_t arg1, uint64_t arg2); 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); diff --git a/bindings/go/unicorn/unicorn_const.go b/bindings/go/unicorn/unicorn_const.go index 427b34cd..04c52639 100644 --- a/bindings/go/unicorn/unicorn_const.go +++ b/bindings/go/unicorn/unicorn_const.go @@ -34,25 +34,27 @@ const ( UC_MODE_MIPS64 = 8 UC_ERR_OK = 0 - UC_ERR_OOM = 1 + UC_ERR_NOMEM = 1 UC_ERR_ARCH = 2 UC_ERR_HANDLE = 3 - UC_ERR_UCH = 4 - UC_ERR_MODE = 5 - UC_ERR_VERSION = 6 - UC_ERR_MEM_READ = 7 - UC_ERR_MEM_WRITE = 8 - UC_ERR_CODE_INVALID = 9 - UC_ERR_HOOK = 10 - UC_ERR_INSN_INVALID = 11 - UC_ERR_MAP = 12 - UC_ERR_MEM_WRITE_NW = 13 - UC_ERR_MEM_READ_NR = 14 + UC_ERR_MODE = 4 + UC_ERR_VERSION = 5 + UC_ERR_MEM_READ = 6 + UC_ERR_MEM_WRITE = 7 + UC_ERR_CODE_INVALID = 8 + UC_ERR_HOOK = 9 + UC_ERR_INSN_INVALID = 10 + UC_ERR_MAP = 11 + UC_ERR_WRITE_PROT = 12 + UC_ERR_READ_PROT = 13 + UC_ERR_EXEC_PROT = 14 + UC_ERR_INVAL = 15 UC_MEM_READ = 16 UC_MEM_WRITE = 17 UC_MEM_READ_WRITE = 18 - UC_MEM_WRITE_NW = 19 - UC_MEM_READ_NR = 20 + UC_MEM_WRITE_PROT = 19 + UC_MEM_READ_PROT = 20 + UC_MEM_EXEC_PROT = 21 UC_HOOK_INTR = 32 UC_HOOK_INSN = 33 UC_HOOK_CODE = 34 @@ -65,5 +67,6 @@ const ( UC_PROT_NONE = 0 UC_PROT_READ = 1 UC_PROT_WRITE = 2 - UC_PROT_ALL = 3 + UC_PROT_EXEC = 4 + UC_PROT_ALL = 7 ) \ No newline at end of file diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index ae672227..ef3c03a3 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -60,37 +60,41 @@ def _setup_prototype(lib, fname, restype, *argtypes): getattr(lib, fname).restype = restype getattr(lib, fname).argtypes = argtypes -_setup_prototype(_uc, "uc_version", ctypes.c_int, ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int)) +ucerr = ctypes.c_int +ucengine = ctypes.c_void_p +uc_hook_h = ctypes.c_size_t + +_setup_prototype(_uc, "uc_version", ctypes.c_uint, ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int)) _setup_prototype(_uc, "uc_arch_supported", ctypes.c_bool, ctypes.c_int) -_setup_prototype(_uc, "uc_open", ctypes.c_int, ctypes.c_uint, ctypes.c_uint, ctypes.POINTER(ctypes.c_size_t)) -_setup_prototype(_uc, "uc_close", ctypes.c_int, ctypes.POINTER(ctypes.c_size_t)) -_setup_prototype(_uc, "uc_strerror", ctypes.c_char_p, ctypes.c_int) -_setup_prototype(_uc, "uc_errno", ctypes.c_int, ctypes.c_size_t) -_setup_prototype(_uc, "uc_reg_read", ctypes.c_int, ctypes.c_size_t, ctypes.c_int, ctypes.c_void_p) -_setup_prototype(_uc, "uc_reg_write", ctypes.c_int, ctypes.c_size_t, ctypes.c_int, ctypes.c_void_p) -_setup_prototype(_uc, "uc_mem_read", ctypes.c_int, ctypes.c_size_t, ctypes.c_uint64, ctypes.POINTER(ctypes.c_char), ctypes.c_size_t) -_setup_prototype(_uc, "uc_mem_write", ctypes.c_int, ctypes.c_size_t, ctypes.c_uint64, ctypes.POINTER(ctypes.c_char), ctypes.c_size_t) -_setup_prototype(_uc, "uc_emu_start", ctypes.c_int, ctypes.c_size_t, ctypes.c_uint64, ctypes.c_uint64, ctypes.c_uint64, ctypes.c_size_t) -_setup_prototype(_uc, "uc_emu_stop", ctypes.c_int, ctypes.c_size_t) -_setup_prototype(_uc, "uc_hook_del", ctypes.c_int, ctypes.c_size_t, ctypes.POINTER(ctypes.c_size_t)) -_setup_prototype(_uc, "uc_mem_map", ctypes.c_int, ctypes.c_size_t, ctypes.c_uint64, ctypes.c_size_t, ctypes.c_uint32) +_setup_prototype(_uc, "uc_open", ucerr, ctypes.c_uint, ctypes.c_uint, ctypes.POINTER(ucengine)) +_setup_prototype(_uc, "uc_close", ucerr, ucengine) +_setup_prototype(_uc, "uc_strerror", ctypes.c_char_p, ucerr) +_setup_prototype(_uc, "uc_errno", ucerr, ucengine) +_setup_prototype(_uc, "uc_reg_read", ucerr, ucengine, ctypes.c_int, ctypes.c_void_p) +_setup_prototype(_uc, "uc_reg_write", ucerr, ucengine, ctypes.c_int, ctypes.c_void_p) +_setup_prototype(_uc, "uc_mem_read", ucerr, ucengine, ctypes.c_uint64, ctypes.POINTER(ctypes.c_char), ctypes.c_size_t) +_setup_prototype(_uc, "uc_mem_write", ucerr, ucengine, ctypes.c_uint64, ctypes.POINTER(ctypes.c_char), ctypes.c_size_t) +_setup_prototype(_uc, "uc_emu_start", ucerr, ucengine, ctypes.c_uint64, ctypes.c_uint64, ctypes.c_uint64, ctypes.c_size_t) +_setup_prototype(_uc, "uc_emu_stop", ucerr, ucengine) +_setup_prototype(_uc, "uc_hook_del", ucerr, ucengine, uc_hook_h) +_setup_prototype(_uc, "uc_mem_map", ucerr, ucengine, ctypes.c_uint64, ctypes.c_size_t, ctypes.c_uint32) # uc_hook_add is special due to variable number of arguments _uc.uc_hook_add = getattr(_uc, "uc_hook_add") -_uc.uc_hook_add.restype = ctypes.c_int +_uc.uc_hook_add.restype = ucerr -UC_HOOK_CODE_CB = ctypes.CFUNCTYPE(None, ctypes.c_size_t, ctypes.c_uint64, ctypes.c_size_t, ctypes.c_void_p) -UC_HOOK_MEM_INVALID_CB = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_size_t, ctypes.c_int, \ +UC_HOOK_CODE_CB = ctypes.CFUNCTYPE(None, ucengine, ctypes.c_uint64, ctypes.c_size_t, ctypes.c_void_p) +UC_HOOK_MEM_INVALID_CB = ctypes.CFUNCTYPE(ctypes.c_bool, ucengine, ctypes.c_int, \ ctypes.c_uint64, ctypes.c_int, ctypes.c_int64, ctypes.c_void_p) -UC_HOOK_MEM_ACCESS_CB = ctypes.CFUNCTYPE(None, ctypes.c_size_t, ctypes.c_int, \ +UC_HOOK_MEM_ACCESS_CB = ctypes.CFUNCTYPE(None, ucengine, ctypes.c_int, \ ctypes.c_uint64, ctypes.c_int, ctypes.c_int64, ctypes.c_void_p) -UC_HOOK_INTR_CB = ctypes.CFUNCTYPE(None, ctypes.c_size_t, ctypes.c_uint32, \ +UC_HOOK_INTR_CB = ctypes.CFUNCTYPE(None, ucengine, ctypes.c_uint32, \ ctypes.c_void_p) -UC_HOOK_INSN_IN_CB = ctypes.CFUNCTYPE(ctypes.c_uint32, ctypes.c_size_t, ctypes.c_uint32, \ +UC_HOOK_INSN_IN_CB = ctypes.CFUNCTYPE(ctypes.c_uint32, ucengine, ctypes.c_uint32, \ ctypes.c_int, ctypes.c_void_p) -UC_HOOK_INSN_OUT_CB = ctypes.CFUNCTYPE(None, ctypes.c_size_t, ctypes.c_uint32, \ +UC_HOOK_INSN_OUT_CB = ctypes.CFUNCTYPE(None, ucengine, ctypes.c_uint32, \ ctypes.c_int, ctypes.c_uint32, ctypes.c_void_p) -UC_HOOK_INSN_SYSCALL_CB = ctypes.CFUNCTYPE(None, ctypes.c_size_t, ctypes.c_void_p) +UC_HOOK_INSN_SYSCALL_CB = ctypes.CFUNCTYPE(None, ucengine, ctypes.c_void_p) # access to error code via @errno of UcError @@ -130,7 +134,7 @@ class Uc(object): raise UcError(UC_ERR_VERSION) self._arch, self._mode = arch, mode - self._uch = ctypes.c_size_t() + self._uch = ctypes.c_void_p() status = _uc.uc_open(arch, mode, ctypes.byref(self._uch)) if status != UC_ERR_OK: self._uch = None @@ -144,7 +148,8 @@ class Uc(object): def __del__(self): if self._uch: try: - status = _uc.uc_close(ctypes.byref(self._uch)) + status = _uc.uc_close(self._uch) + self._uch = None if status != UC_ERR_OK: raise UcError(status) except: # _uc might be pulled from under our feet @@ -251,7 +256,7 @@ class Uc(object): # add a hook def hook_add(self, htype, callback, user_data=None, arg1=1, arg2=0): - _h2 = ctypes.c_size_t() + _h2 = uc_hook_h() # save callback & user_data self._callback_count += 1 @@ -296,8 +301,8 @@ class Uc(object): # delete a hook def hook_del(self, h): - _h = ctypes.c_size_t(h) - status = _uc.uc_hook_del(self._uch, ctypes.byref(_h)) + _h = uc_hook_h(h) + status = _uc.uc_hook_del(self._uch, _h) if status != UC_ERR_OK: raise UcError(status) h = 0 diff --git a/bindings/python/unicorn/unicorn_const.py b/bindings/python/unicorn/unicorn_const.py index f2c8f0db..0d667784 100644 --- a/bindings/python/unicorn/unicorn_const.py +++ b/bindings/python/unicorn/unicorn_const.py @@ -32,25 +32,27 @@ UC_MODE_MIPS32 = 4 UC_MODE_MIPS64 = 8 UC_ERR_OK = 0 -UC_ERR_OOM = 1 +UC_ERR_NOMEM = 1 UC_ERR_ARCH = 2 UC_ERR_HANDLE = 3 -UC_ERR_UCH = 4 -UC_ERR_MODE = 5 -UC_ERR_VERSION = 6 -UC_ERR_MEM_READ = 7 -UC_ERR_MEM_WRITE = 8 -UC_ERR_CODE_INVALID = 9 -UC_ERR_HOOK = 10 -UC_ERR_INSN_INVALID = 11 -UC_ERR_MAP = 12 -UC_ERR_MEM_WRITE_NW = 13 -UC_ERR_MEM_READ_NR = 14 +UC_ERR_MODE = 4 +UC_ERR_VERSION = 5 +UC_ERR_MEM_READ = 6 +UC_ERR_MEM_WRITE = 7 +UC_ERR_CODE_INVALID = 8 +UC_ERR_HOOK = 9 +UC_ERR_INSN_INVALID = 10 +UC_ERR_MAP = 11 +UC_ERR_WRITE_PROT = 12 +UC_ERR_READ_PROT = 13 +UC_ERR_EXEC_PROT = 14 +UC_ERR_INVAL = 15 UC_MEM_READ = 16 UC_MEM_WRITE = 17 UC_MEM_READ_WRITE = 18 -UC_MEM_WRITE_NW = 19 -UC_MEM_READ_NR = 20 +UC_MEM_WRITE_PROT = 19 +UC_MEM_READ_PROT = 20 +UC_MEM_EXEC_PROT = 21 UC_HOOK_INTR = 32 UC_HOOK_INSN = 33 UC_HOOK_CODE = 34 @@ -63,4 +65,5 @@ UC_HOOK_MEM_READ_WRITE = 39 UC_PROT_NONE = 0 UC_PROT_READ = 1 UC_PROT_WRITE = 2 -UC_PROT_ALL = 3 +UC_PROT_EXEC = 4 +UC_PROT_ALL = 7 diff --git a/hook.c b/hook.c index 6a26d70d..109a20d2 100644 --- a/hook.c +++ b/hook.c @@ -38,13 +38,9 @@ size_t hook_find_new(struct uc_struct *uc) } // return -1 on failure, index to hook_callbacks[] on success. -size_t hook_add(uch handle, int type, uint64_t begin, uint64_t end, void *callback, void *user_data) +size_t hook_add(struct uc_struct *uc, int type, uint64_t begin, uint64_t end, void *callback, void *user_data) { int i; - struct uc_struct *uc = (struct uc_struct *)(uintptr_t)handle; - - if (handle == 0) - return -1; // find the first free slot. skip slot 0, so index > 0 i = hook_find_new(uc); @@ -67,17 +63,17 @@ size_t hook_add(uch handle, int type, uint64_t begin, uint64_t end, void *callba if (begin > end) uc->hook_insn_idx = i; break; - case UC_MEM_READ: + case UC_HOOK_MEM_READ: uc->hook_mem_read = true; if (begin > end) uc->hook_read_idx = i; break; - case UC_MEM_WRITE: + case UC_HOOK_MEM_WRITE: uc->hook_mem_write = true; if (begin > end) uc->hook_write_idx = i; break; - case UC_MEM_READ_WRITE: + case UC_HOOK_MEM_READ_WRITE: uc->hook_mem_read = true; uc->hook_mem_write = true; if (begin > end) { @@ -95,52 +91,45 @@ size_t hook_add(uch handle, int type, uint64_t begin, uint64_t end, void *callba } // return 0 on success, -1 on failure -uc_err hook_del(uch handle, uch *h2) +uc_err hook_del(struct uc_struct *uc, uchook hh) { - struct uc_struct *uc = (struct uc_struct *)(uintptr_t)handle; - - if (handle == 0) - return UC_ERR_UCH; - - if (*h2 == uc->hook_block_idx) { + if (hh == uc->hook_block_idx) { uc->hook_block_idx = 0; } - if (*h2 == uc->hook_insn_idx) { + if (hh == uc->hook_insn_idx) { uc->hook_insn_idx = 0; } - if (*h2 == uc->hook_read_idx) { + if (hh == uc->hook_read_idx) { uc->hook_read_idx = 0; } - if (*h2 == uc->hook_write_idx) { + if (hh == uc->hook_write_idx) { uc->hook_write_idx = 0; } - if (*h2 == uc->hook_mem_idx) { + if (hh == uc->hook_mem_idx) { uc->hook_mem_idx = 0; } - if (*h2 == uc->hook_intr_idx) { + if (hh == uc->hook_intr_idx) { uc->hook_intr_idx = 0; } - if (*h2 == uc->hook_out_idx) { + if (hh == uc->hook_out_idx) { uc->hook_out_idx = 0; } - if (*h2 == uc->hook_in_idx) { + if (hh == uc->hook_in_idx) { uc->hook_in_idx = 0; } - uc->hook_callbacks[*h2].callback = NULL; - uc->hook_callbacks[*h2].user_data = NULL; - uc->hook_callbacks[*h2].hook_type = 0; - uc->hook_callbacks[*h2].begin = 0; - uc->hook_callbacks[*h2].end = 0; - - *h2 = 0; + uc->hook_callbacks[hh].callback = NULL; + uc->hook_callbacks[hh].user_data = NULL; + uc->hook_callbacks[hh].hook_type = 0; + uc->hook_callbacks[hh].begin = 0; + uc->hook_callbacks[hh].end = 0; return UC_ERR_OK; } @@ -162,12 +151,13 @@ static struct hook_struct *_hook_find(struct uc_struct *uc, int type, uint64_t a if (uc->hook_insn_idx) return &uc->hook_callbacks[uc->hook_insn_idx]; break; - case UC_MEM_READ: + case UC_HOOK_MEM_READ: // already hooked all memory read? - if (uc->hook_read_idx) + if (uc->hook_read_idx) { return &uc->hook_callbacks[uc->hook_read_idx]; + } break; - case UC_MEM_WRITE: + case UC_HOOK_MEM_WRITE: // already hooked all memory write? if (uc->hook_write_idx) return &uc->hook_callbacks[uc->hook_write_idx]; @@ -185,14 +175,14 @@ static struct hook_struct *_hook_find(struct uc_struct *uc, int type, uint64_t a return &uc->hook_callbacks[i]; } break; - case UC_MEM_READ: - if (uc->hook_callbacks[i].hook_type == UC_MEM_READ || uc->hook_callbacks[i].hook_type == UC_MEM_READ_WRITE) { + case UC_HOOK_MEM_READ: + if (uc->hook_callbacks[i].hook_type == UC_HOOK_MEM_READ || uc->hook_callbacks[i].hook_type == UC_HOOK_MEM_READ_WRITE) { if (uc->hook_callbacks[i].begin <= address && address <= uc->hook_callbacks[i].end) return &uc->hook_callbacks[i]; } break; - case UC_MEM_WRITE: - if (uc->hook_callbacks[i].hook_type == UC_MEM_WRITE || uc->hook_callbacks[i].hook_type == UC_MEM_READ_WRITE) { + case UC_HOOK_MEM_WRITE: + if (uc->hook_callbacks[i].hook_type == UC_HOOK_MEM_WRITE || uc->hook_callbacks[i].hook_type == UC_HOOK_MEM_READ_WRITE) { if (uc->hook_callbacks[i].begin <= address && address <= uc->hook_callbacks[i].end) return &uc->hook_callbacks[i]; } @@ -205,26 +195,19 @@ static struct hook_struct *_hook_find(struct uc_struct *uc, int type, uint64_t a } -static void hook_count_cb(uch handle, uint64_t address, uint32_t size, void *user_data) +static void hook_count_cb(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data) { - struct uc_struct *uc = (struct uc_struct *)(uintptr_t)handle; - // count this instruction uc->emu_counter++; if (uc->emu_counter > uc->emu_count) - uc_emu_stop(handle); + uc_emu_stop(uc); else if (uc->hook_count_callback) - uc->hook_count_callback(handle, address, size, user_data); + uc->hook_count_callback(uc, address, size, user_data); } -struct hook_struct *hook_find(uch handle, int type, uint64_t address) +struct hook_struct *hook_find(struct uc_struct *uc, int type, uint64_t address) { - struct uc_struct *uc = (struct uc_struct *)(uintptr_t)handle; - - if (handle == 0) - return NULL; - // stop executing callbacks if we already got stop request if (uc->stop_request) return NULL; @@ -269,6 +252,5 @@ void helper_uc_tracecode(int32_t size, void *callback, void *handle, int64_t add uc->set_pc(uc, address); } - ((uc_cb_hookcode_t)callback)((uch)handle, address, size, user_data); + ((uc_cb_hookcode_t)callback)(uc, address, size, user_data); } - diff --git a/include/hook.h b/include/hook.h index 5441071f..08e9e9b0 100644 --- a/include/hook.h +++ b/include/hook.h @@ -5,13 +5,13 @@ #define UC_HOOK_H // return -1 on failure, index to traces[] on success. -size_t hook_add(uch handle, int type, uint64_t begin, uint64_t end, void *callback, void *user_data); +size_t hook_add(struct uc_struct *uc, int type, uint64_t begin, uint64_t end, void *callback, void *user_data); // return 0 on success, -1 on failure -uc_err hook_del(uch handle, uch *traceh); +uc_err hook_del(struct uc_struct *uc, uchook hh); // return NULL on failure -struct hook_struct *hook_find(uch handle, int type, uint64_t address); +struct hook_struct *hook_find(struct uc_struct *uc, int type, uint64_t address); // return index of an free hook entry in hook_callbacks[] array. // this realloc memory if needed. diff --git a/include/uc_priv.h b/include/uc_priv.h index 007fecea..dc4fcfd6 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -24,10 +24,10 @@ typedef struct ModuleEntry { typedef QTAILQ_HEAD(, ModuleEntry) ModuleTypeList; // return 0 on success, -1 on failure -typedef int (*reg_read_t)(uch handle, unsigned int regid, void *value); -typedef int (*reg_write_t)(uch handle, unsigned int regid, const void *value); +typedef int (*reg_read_t)(struct uc_struct *uc, unsigned int regid, void *value); +typedef int (*reg_write_t)(struct uc_struct *uc, unsigned int regid, const void *value); -typedef void (*reg_reset_t)(uch handle); +typedef void (*reg_reset_t)(struct uc_struct *uc); typedef bool (*uc_write_mem_t)(AddressSpace *as, hwaddr addr, const uint8_t *buf, int len); @@ -47,6 +47,8 @@ typedef void (*uc_args_uc_u64_t)(struct uc_struct *, uint64_t addr); typedef MemoryRegion* (*uc_args_uc_ram_size_t)(struct uc_struct*, ram_addr_t begin, size_t size, uint32_t perms); +typedef void (*uc_mem_unmap_t)(struct uc_struct*, MemoryRegion *mr); + typedef void (*uc_readonly_mem_t)(MemoryRegion *mr, bool readonly); // which interrupt should make emulation stop? @@ -90,6 +92,7 @@ struct uc_struct { uc_args_tcg_enable_t tcg_enabled; uc_args_uc_long_t tcg_exec_init; uc_args_uc_ram_size_t memory_map; + uc_mem_unmap_t memory_unmap; uc_readonly_mem_t readonly_mem; // list of cpu void* cpu; @@ -172,6 +175,9 @@ struct uc_struct { bool block_full; MemoryRegion **mapped_blocks; uint32_t mapped_block_count; + void *qemu_thread_data; // to support cross compile to Windows (qemu-thread-win32.c) + uint32_t target_page_size; + uint32_t target_page_align; }; #include "qemu_macro.h" diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index f58ffcd3..1aae5c11 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -19,8 +19,10 @@ extern "C" { #include "platform.h" -// Handle to use with all APIs -typedef size_t uch; +struct uc_struct; +typedef struct uc_struct ucengine; + +typedef size_t uchook; #include "m68k.h" #include "x86.h" @@ -104,10 +106,9 @@ typedef enum uc_mode { // These are values returned by uc_errno() typedef enum uc_err { UC_ERR_OK = 0, // No error: everything was fine - UC_ERR_OOM, // Out-Of-Memory error: uc_open(), uc_emulate() + UC_ERR_NOMEM, // Out-Of-Memory error: uc_open(), uc_emulate() UC_ERR_ARCH, // Unsupported architecture: uc_open() UC_ERR_HANDLE, // Invalid handle - UC_ERR_UCH, // Invalid handle (uch) UC_ERR_MODE, // Invalid/unsupported mode: uc_open() UC_ERR_VERSION, // Unsupported version (bindings) UC_ERR_MEM_READ, // Quit emulation due to invalid memory READ: uc_emu_start() @@ -116,8 +117,10 @@ typedef enum uc_err { UC_ERR_HOOK, // Invalid hook type: uc_hook_add() UC_ERR_INSN_INVALID, // Quit emulation due to invalid instruction: uc_emu_start() UC_ERR_MAP, // Invalid memory mapping: uc_mem_map() - UC_ERR_MEM_WRITE_NW, // Quit emulation due to write to non-writable: uc_emu_start() - UC_ERR_MEM_READ_NR, // Quit emulation due to read from non-readable: uc_emu_start() + UC_ERR_WRITE_PROT, // Quit emulation due to UC_PROT_WRITE violation: uc_emu_start() + UC_ERR_READ_PROT, // Quit emulation due to UC_PROT_READ violation: uc_emu_start() + UC_ERR_EXEC_PROT, // Quit emulation due to UC_PROT_EXEC violation: uc_emu_start() + UC_ERR_INVAL, // Inavalid argument provided to uc_xxx function (See specific function API) } uc_err; @@ -125,32 +128,33 @@ typedef enum uc_err { // @address: address where the code is being executed // @size: size of machine instruction(s) being executed, or 0 when size is unknown // @user_data: user data passed to tracing APIs. -typedef void (*uc_cb_hookcode_t)(uch handle, uint64_t address, uint32_t size, void *user_data); +typedef void (*uc_cb_hookcode_t)(ucengine *uc, uint64_t address, uint32_t size, void *user_data); // Callback function for tracing interrupts (for uc_hook_intr()) // @intno: interrupt number // @user_data: user data passed to tracing APIs. -typedef void (*uc_cb_hookintr_t)(uch handle, uint32_t intno, void *user_data); +typedef void (*uc_cb_hookintr_t)(ucengine *uc, uint32_t intno, void *user_data); // Callback function for tracing IN instruction of X86 // @port: port number // @size: data size (1/2/4) to be read from this port // @user_data: user data passed to tracing APIs. -typedef uint32_t (*uc_cb_insn_in_t)(uch handle, uint32_t port, int size, void *user_data); +typedef uint32_t (*uc_cb_insn_in_t)(ucengine *uc, uint32_t port, int size, void *user_data); // x86's handler for OUT // @port: port number // @size: data size (1/2/4) to be written to this port // @value: data value to be written to this port -typedef void (*uc_cb_insn_out_t)(uch handle, uint32_t port, int size, uint32_t value, void *user_data); +typedef void (*uc_cb_insn_out_t)(ucengine *uc, uint32_t port, int size, uint32_t value, void *user_data); // All type of memory accesses for UC_HOOK_MEM_* typedef enum uc_mem_type { UC_MEM_READ = 16, // Memory is read from UC_MEM_WRITE, // Memory is written to UC_MEM_READ_WRITE, // Memory is accessed (either READ or WRITE) - UC_MEM_WRITE_NW, // write to non-writable - UC_MEM_READ_NR, // read from non-readable + UC_MEM_WRITE_PROT, // write to write protected memory + UC_MEM_READ_PROT, // read from read protected memory + UC_MEM_EXEC_PROT, // fetch from non-executable memory } uc_mem_type; // All type of hooks for uc_hook_add() API. @@ -171,7 +175,7 @@ typedef enum uc_hook_t { // @size: size of data being read or written // @value: value of data being written to memory, or irrelevant if type = READ. // @user_data: user data passed to tracing APIs -typedef void (*uc_cb_hookmem_t)(uch handle, uc_mem_type type, +typedef void (*uc_cb_hookmem_t)(ucengine *uc, uc_mem_type type, uint64_t address, int size, int64_t value, void *user_data); // Callback function for handling memory events (for UC_HOOK_MEM_INVALID) @@ -181,7 +185,7 @@ typedef void (*uc_cb_hookmem_t)(uch handle, uc_mem_type type, // @value: value of data being written to memory, or irrelevant if type = READ. // @user_data: user data passed to tracing APIs // @return: return true to continue, or false to stop program (due to invalid memory). -typedef bool (*uc_cb_eventmem_t)(uch handle, uc_mem_type type, +typedef bool (*uc_cb_eventmem_t)(ucengine *uc, uc_mem_type type, uint64_t address, int size, int64_t value, void *user_data); @@ -218,43 +222,43 @@ bool uc_arch_supported(uc_arch arch); /* - Initialize UC handle: this must be done before any usage of UC. + Create new instance of unicorn engine. @arch: architecture type (UC_ARCH_*) @mode: hardware mode. This is combined of UC_MODE_* - @handle: pointer to handle, which will be updated at return time + @uc: pointer to ucengine, which will be updated at return time @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum for detailed error). */ UNICORN_EXPORT -uc_err uc_open(uc_arch arch, uc_mode mode, uch *handle); +uc_err uc_open(uc_arch arch, uc_mode mode, ucengine **uc); /* - Close UC handle: MUST do to release the handle when it is not used anymore. + Close UC instance: MUST do to release the handle when it is not used anymore. NOTE: this must be called only when there is no longer usage of Unicorn. The reason is the this API releases some cached memory, thus access to any Unicorn API after uc_close() might crash your application. - After this, @handle is invalid, and nolonger usable. + After this, @uc is invalid, and nolonger usable. - @handle: pointer to a handle returned by uc_open() + @uc: pointer to a handle returned by uc_open() @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum for detailed error). */ UNICORN_EXPORT -uc_err uc_close(uch *handle); +uc_err uc_close(ucengine *uc); /* Report the last error number when some API function fail. Like glibc's errno, uc_errno might not retain its old value once accessed. - @handle: handle returned by uc_open() + @uc: handle returned by uc_open() @return: error code of uc_err enum type (UC_ERR_*, see above) */ UNICORN_EXPORT -uc_err uc_errno(uch handle); +uc_err uc_errno(ucengine *uc); /* Return a string describing given error code. @@ -270,7 +274,7 @@ const char *uc_strerror(uc_err code); /* Write to register. - @handle: handle returned by uc_open() + @uc: handle returned by uc_open() @regid: register ID that is to be modified. @value: pointer to the value that will set to register @regid @@ -278,12 +282,12 @@ const char *uc_strerror(uc_err code); for detailed error). */ UNICORN_EXPORT -uc_err uc_reg_write(uch handle, int regid, const void *value); +uc_err uc_reg_write(ucengine *uc, int regid, const void *value); /* Read register value. - @handle: handle returned by uc_open() + @uc: handle returned by uc_open() @regid: register ID that is to be retrieved. @value: pointer to a variable storing the register value. @@ -291,12 +295,12 @@ uc_err uc_reg_write(uch handle, int regid, const void *value); for detailed error). */ UNICORN_EXPORT -uc_err uc_reg_read(uch handle, int regid, void *value); +uc_err uc_reg_read(ucengine *uc, int regid, void *value); /* Write to a range of bytes in memory. - @handle: handle returned by uc_open() + @uc: handle returned by uc_open() @address: starting memory address of bytes to set. @bytes: pointer to a variable containing data to be written to memory. @size: size of memory to write to. @@ -307,12 +311,12 @@ uc_err uc_reg_read(uch handle, int regid, void *value); for detailed error). */ UNICORN_EXPORT -uc_err uc_mem_write(uch handle, uint64_t address, const uint8_t *bytes, size_t size); +uc_err uc_mem_write(ucengine *uc, uint64_t address, const uint8_t *bytes, size_t size); /* Read a range of bytes in memory. - @handle: handle returned by uc_open() + @uc: handle returned by uc_open() @address: starting memory address of bytes to get. @bytes: pointer to a variable containing data copied from memory. @size: size of memory to read. @@ -323,12 +327,12 @@ uc_err uc_mem_write(uch handle, uint64_t address, const uint8_t *bytes, size_t s for detailed error). */ UNICORN_EXPORT -uc_err uc_mem_read(uch handle, uint64_t address, uint8_t *bytes, size_t size); +uc_err uc_mem_read(ucengine *uc, uint64_t address, uint8_t *bytes, size_t size); /* Emulate machine code in a specific duration of time. - @handle: handle returned by uc_open() + @uc: handle returned by uc_open() @begin: address where emulation starts @until: address where emulation stops (i.e when this address is hit) @timeout: duration to emulate the code (in microseconds). When this value is 0, @@ -340,27 +344,27 @@ uc_err uc_mem_read(uch handle, uint64_t address, uint8_t *bytes, size_t size); for detailed error). */ UNICORN_EXPORT -uc_err uc_emu_start(uch handle, uint64_t begin, uint64_t until, uint64_t timeout, size_t count); +uc_err uc_emu_start(ucengine *uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count); /* Stop emulation (which was started by uc_emu_start() API. This is typically called from callback functions registered via tracing APIs. NOTE: for now, this will stop the execution only after the current block. - @handle: handle returned by uc_open() + @uc: handle returned by uc_open() @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum for detailed error). */ UNICORN_EXPORT -uc_err uc_emu_stop(uch handle); +uc_err uc_emu_stop(ucengine *uc); /* Register callback for a hook event. The callback will be run when the hook event is hit. - @handle: handle returned by uc_open() - @h2: hook handle returned from this registration. To be used in uc_hook_del() API + @uc: handle returned by uc_open() + @hh: hook handle returned from this registration. To be used in uc_hook_del() API @type: hook type @callback: callback to be run when instruction is hit @user_data: user-defined data. This will be passed to callback function in its @@ -371,48 +375,84 @@ uc_err uc_emu_stop(uch handle); for detailed error). */ UNICORN_EXPORT -uc_err uc_hook_add(uch handle, uch *h2, uc_hook_t type, void *callback, void *user_data, ...); +uc_err uc_hook_add(ucengine *uc, uchook *hh, uc_hook_t type, void *callback, void *user_data, ...); /* Unregister (remove) a hook callback. This API removes the hook callback registered by uc_hook_add(). NOTE: this should be called only when you no longer want to trace. - After this, @hhandle is invalid, and nolonger usable. + After this, @hh is invalid, and nolonger usable. - @handle: handle returned by uc_open() - @h2: handle returned by uc_hook_add() + @uc: handle returned by uc_open() + @hh: handle returned by uc_hook_add() @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum for detailed error). */ UNICORN_EXPORT -uc_err uc_hook_del(uch handle, uch *h2); +uc_err uc_hook_del(ucengine *uc, uchook hh); typedef enum uc_prot { UC_PROT_NONE = 0, UC_PROT_READ = 1, UC_PROT_WRITE = 2, - UC_PROT_ALL = 3, + UC_PROT_EXEC = 4, + UC_PROT_ALL = 7, } uc_prot; /* Map memory in for emulation. This API adds a memory region that can be used by emulation. - @handle: handle returned by uc_open() + @uc: handle returned by uc_open() @address: starting address of the new memory region to be mapped in. - This address must be aligned to 4KB, or this will return with UC_ERR_MAP error. + This address must be aligned to 4KB, or this will return with UC_ERR_INVAL error. @size: size of the new memory region to be mapped in. - This size must be multiple of 4KB, or this will return with UC_ERR_MAP error. + This size must be multiple of 4KB, or this will return with UC_ERR_INVAL error. @perms: Permissions for the newly mapped region. - This must be some combination of UC_PROT_READ & UC_PROT_WRITE, - or this will return with UC_ERR_MAP error. See uc_prot type above. + This must be some combination of UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC, + or this will return with UC_ERR_INVAL error. @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum for detailed error). */ UNICORN_EXPORT -uc_err uc_mem_map(uch handle, uint64_t address, size_t size, uint32_t perms); +uc_err uc_mem_map(ucengine *uc, uint64_t address, size_t size, uint32_t perms); + +/* + Unmap a region of emulation memory. + This API deletes a memory mapping from the emulation memory space. + + @handle: handle returned by uc_open() + @address: starting address of the memory region to be unmapped. + This address must be aligned to 4KB, or this will return with UC_ERR_INVAL error. + @size: size of the memory region to be modified. + This size must be multiple of 4KB, or this will return with UC_ERR_INVAL error. + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). +*/ +UNICORN_EXPORT +uc_err uc_mem_unmap(ucengine *uc, uint64_t address, size_t size); + +/* + Set memory permissions for emulation memory. + This API changes permissions on an existing memory region. + + @handle: handle returned by uc_open() + @address: starting address of the memory region to be modified. + This address must be aligned to 4KB, or this will return with UC_ERR_INVAL error. + @size: size of the memory region to be modified. + This size must be multiple of 4KB, or this will return with UC_ERR_INVAL error. + @perms: New permissions for the mapped region. + This must be some combination of UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC, + or this will return with UC_ERR_INVAL error. + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). +*/ +UNICORN_EXPORT +uc_err uc_mem_protect(ucengine *uc, uint64_t address, size_t size, uint32_t perms); #ifdef __cplusplus } diff --git a/include/unicorn/x86.h b/include/unicorn/x86.h index 4ee6945e..b279de58 100644 --- a/include/unicorn/x86.h +++ b/include/unicorn/x86.h @@ -10,7 +10,7 @@ extern "C" { // Callback function for tracing SYSCALL/SYSENTER (for uc_hook_intr()) // @user_data: user data passed to tracing APIs. -typedef void (*uc_cb_insn_syscall_t)(uch handle, void *user_data); +typedef void (*uc_cb_insn_syscall_t)(struct uc_struct *uc, void *user_data); //> X86 registers typedef enum uc_x86_reg { diff --git a/qemu/aarch64.h b/qemu/aarch64.h index 9ab06273..77de1644 100644 --- a/qemu/aarch64.h +++ b/qemu/aarch64.h @@ -7,6 +7,7 @@ #define phys_mem_clean phys_mem_clean_aarch64 #define tb_cleanup tb_cleanup_aarch64 #define memory_map memory_map_aarch64 +#define memory_unmap memory_unmap_aarch64 #define memory_free memory_free_aarch64 #define helper_raise_exception helper_raise_exception_aarch64 #define tcg_enabled tcg_enabled_aarch64 diff --git a/qemu/arm.h b/qemu/arm.h index c24329b3..3d405fac 100644 --- a/qemu/arm.h +++ b/qemu/arm.h @@ -7,6 +7,7 @@ #define phys_mem_clean phys_mem_clean_arm #define tb_cleanup tb_cleanup_arm #define memory_map memory_map_arm +#define memory_unmap memory_unmap_arm #define memory_free memory_free_arm #define helper_raise_exception helper_raise_exception_arm #define tcg_enabled tcg_enabled_arm diff --git a/qemu/cpu-exec.c b/qemu/cpu-exec.c index b7460385..700c913e 100644 --- a/qemu/cpu-exec.c +++ b/qemu/cpu-exec.c @@ -141,7 +141,7 @@ int cpu_exec(struct uc_struct *uc, CPUArchState *env) // qq // Unicorn: call interrupt callback if registered if (uc->hook_intr_idx) ((uc_cb_hookintr_t)uc->hook_callbacks[uc->hook_intr_idx].callback)( - (uch)uc, cpu->exception_index, + uc, cpu->exception_index, uc->hook_callbacks[uc->hook_intr_idx].user_data); cpu->exception_index = -1; #endif diff --git a/qemu/cpus.c b/qemu/cpus.c index ecc66e83..e274fe5a 100644 --- a/qemu/cpus.c +++ b/qemu/cpus.c @@ -124,7 +124,7 @@ static void *qemu_tcg_cpu_thread_fn(void *arg) struct uc_struct *uc = cpu->uc; //qemu_tcg_init_cpu_signals(); - qemu_thread_get_self(cpu->thread); + qemu_thread_get_self(uc, cpu->thread); qemu_mutex_lock(&uc->qemu_global_mutex); CPU_FOREACH(cpu) { @@ -185,7 +185,7 @@ static void qemu_tcg_init_vcpu(CPUState *cpu) uc->tcg_halt_cond = cpu->halt_cond; snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/TCG", cpu->cpu_index); - qemu_thread_create(cpu->thread, thread_name, qemu_tcg_cpu_thread_fn, + qemu_thread_create(uc, cpu->thread, thread_name, qemu_tcg_cpu_thread_fn, cpu, QEMU_THREAD_JOINABLE); #ifdef _WIN32 cpu->hThread = qemu_thread_get_handle(cpu->thread); diff --git a/qemu/cputlb.c b/qemu/cputlb.c index cde8e30e..ed120082 100644 --- a/qemu/cputlb.c +++ b/qemu/cputlb.c @@ -299,6 +299,11 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env1, target_ulong addr) if (unlikely(env1->tlb_table[mmu_idx][page_index].addr_code != (addr & TARGET_PAGE_MASK))) { cpu_ldub_code(env1, addr); + //check for NX related error from softmmu + if (env1->invalid_error == UC_ERR_MEM_READ) { + env1->invalid_error = UC_ERR_CODE_INVALID; + return -1; + } } pd = env1->iotlb[mmu_idx][page_index] & ~TARGET_PAGE_MASK; mr = iotlb_to_region(cpu->as, pd); diff --git a/qemu/header_gen.py b/qemu/header_gen.py index ff8a1ca5..67982502 100644 --- a/qemu/header_gen.py +++ b/qemu/header_gen.py @@ -13,6 +13,7 @@ symbols = ( 'phys_mem_clean', 'tb_cleanup', 'memory_map', + 'memory_unmap', 'memory_free', 'helper_raise_exception', 'tcg_enabled', diff --git a/qemu/include/exec/memory.h b/qemu/include/exec/memory.h index 4df8bd85..45c51e4d 100644 --- a/qemu/include/exec/memory.h +++ b/qemu/include/exec/memory.h @@ -939,6 +939,7 @@ void address_space_unmap(AddressSpace *as, void *buffer, hwaddr len, void memory_register_types(struct uc_struct *uc); MemoryRegion *memory_map(struct uc_struct *uc, ram_addr_t begin, size_t size, uint32_t perms); +void memory_unmap(struct uc_struct *uc, MemoryRegion *mr); int memory_free(struct uc_struct *uc); #endif diff --git a/qemu/include/qemu/thread.h b/qemu/include/qemu/thread.h index ef2f6962..de5956b2 100644 --- a/qemu/include/qemu/thread.h +++ b/qemu/include/qemu/thread.h @@ -52,12 +52,13 @@ void qemu_event_reset(QemuEvent *ev); void qemu_event_wait(QemuEvent *ev); void qemu_event_destroy(QemuEvent *ev); -void qemu_thread_create(QemuThread *thread, const char *name, +struct uc_struct; +void qemu_thread_create(struct uc_struct *uc, QemuThread *thread, const char *name, void *(*start_routine)(void *), void *arg, int mode); void *qemu_thread_join(QemuThread *thread); -void qemu_thread_get_self(QemuThread *thread); +void qemu_thread_get_self(struct uc_struct *uc, QemuThread *thread); bool qemu_thread_is_self(QemuThread *thread); -void qemu_thread_exit(void *retval); +void qemu_thread_exit(struct uc_struct *uc, void *retval); #endif diff --git a/qemu/ioport.c b/qemu/ioport.c index f4e56510..338a296a 100644 --- a/qemu/ioport.c +++ b/qemu/ioport.c @@ -69,7 +69,7 @@ void cpu_outb(struct uc_struct *uc, pio_addr_t addr, uint8_t val) // Unicorn: call interrupt callback if registered if (uc->hook_out_idx) ((uc_cb_insn_out_t)uc->hook_callbacks[uc->hook_out_idx].callback)( - (uch)uc, addr, 1, val, + uc, addr, 1, val, uc->hook_callbacks[uc->hook_out_idx].user_data); } @@ -79,7 +79,7 @@ void cpu_outw(struct uc_struct *uc, pio_addr_t addr, uint16_t val) // Unicorn: call interrupt callback if registered if (uc->hook_out_idx) ((uc_cb_insn_out_t)uc->hook_callbacks[uc->hook_out_idx].callback)( - (uch)uc, addr, 2, val, + uc, addr, 2, val, uc->hook_callbacks[uc->hook_out_idx].user_data); } @@ -88,7 +88,7 @@ void cpu_outl(struct uc_struct *uc, pio_addr_t addr, uint32_t val) //LOG_IOPORT("outl: %04"FMT_pioaddr" %08"PRIx32"\n", addr, val); if (uc->hook_out_idx) ((uc_cb_insn_out_t)uc->hook_callbacks[uc->hook_out_idx].callback)( - (uch)uc, addr, 4, val, + uc, addr, 4, val, uc->hook_callbacks[uc->hook_out_idx].user_data); } @@ -97,7 +97,7 @@ uint8_t cpu_inb(struct uc_struct *uc, pio_addr_t addr) //LOG_IOPORT("inb : %04"FMT_pioaddr" %02"PRIx8"\n", addr, val); if (uc->hook_in_idx) return ((uc_cb_insn_in_t)uc->hook_callbacks[uc->hook_in_idx].callback)( - (uch)uc, addr, 1, + uc, addr, 1, uc->hook_callbacks[uc->hook_in_idx].user_data); return 0; @@ -108,7 +108,7 @@ uint16_t cpu_inw(struct uc_struct *uc, pio_addr_t addr) //LOG_IOPORT("inw : %04"FMT_pioaddr" %04"PRIx16"\n", addr, val); if (uc->hook_in_idx) return ((uc_cb_insn_in_t)uc->hook_callbacks[uc->hook_in_idx].callback)( - (uch)uc, addr, 2, + uc, addr, 2, uc->hook_callbacks[uc->hook_in_idx].user_data); return 0; @@ -119,7 +119,7 @@ uint32_t cpu_inl(struct uc_struct *uc, pio_addr_t addr) //LOG_IOPORT("inl : %04"FMT_pioaddr" %08"PRIx32"\n", addr, val); if (uc->hook_in_idx) return ((uc_cb_insn_in_t)uc->hook_callbacks[uc->hook_in_idx].callback)( - (uch)uc, addr, 4, + uc, addr, 4, uc->hook_callbacks[uc->hook_in_idx].user_data); return 0; diff --git a/qemu/m68k.h b/qemu/m68k.h index 5dbefab7..4be757ba 100644 --- a/qemu/m68k.h +++ b/qemu/m68k.h @@ -7,6 +7,7 @@ #define phys_mem_clean phys_mem_clean_m68k #define tb_cleanup tb_cleanup_m68k #define memory_map memory_map_m68k +#define memory_unmap memory_unmap_m68k #define memory_free memory_free_m68k #define helper_raise_exception helper_raise_exception_m68k #define tcg_enabled tcg_enabled_m68k diff --git a/qemu/memory.c b/qemu/memory.c index 60f86ae4..be7933d5 100644 --- a/qemu/memory.c +++ b/qemu/memory.c @@ -45,6 +45,29 @@ MemoryRegion *memory_map(struct uc_struct *uc, ram_addr_t begin, size_t size, ui return ram; } +void memory_unmap(struct uc_struct *uc, MemoryRegion *mr) +{ + int i; + target_ulong addr; + //make sure all pages associated with the MemoryRegion are flushed + for (addr = mr->addr; addr < mr->end; addr += uc->target_page_size) { + tlb_flush_page(uc->current_cpu, addr); + } + mr->enabled = false; + memory_region_del_subregion(get_system_memory(uc), mr); + + for (i = 0; i < uc->mapped_block_count; i++) { + if (uc->mapped_blocks[i] == mr) { + uc->mapped_block_count--; + //shift remainder of array down over deleted pointer + memcpy(&uc->mapped_blocks[i], &uc->mapped_blocks[i + 1], sizeof(MemoryRegion*) * (uc->mapped_block_count - i)); + break; + } + } + + g_free(mr); +} + int memory_free(struct uc_struct *uc) { int i; diff --git a/qemu/mips.h b/qemu/mips.h index 059995e5..7a3e308a 100644 --- a/qemu/mips.h +++ b/qemu/mips.h @@ -7,6 +7,7 @@ #define phys_mem_clean phys_mem_clean_mips #define tb_cleanup tb_cleanup_mips #define memory_map memory_map_mips +#define memory_unmap memory_unmap_mips #define memory_free memory_free_mips #define helper_raise_exception helper_raise_exception_mips #define tcg_enabled tcg_enabled_mips diff --git a/qemu/mips64.h b/qemu/mips64.h index 74daddbc..9870cb15 100644 --- a/qemu/mips64.h +++ b/qemu/mips64.h @@ -7,6 +7,7 @@ #define phys_mem_clean phys_mem_clean_mips64 #define tb_cleanup tb_cleanup_mips64 #define memory_map memory_map_mips64 +#define memory_unmap memory_unmap_mips64 #define memory_free memory_free_mips64 #define helper_raise_exception helper_raise_exception_mips64 #define tcg_enabled tcg_enabled_mips64 diff --git a/qemu/mips64el.h b/qemu/mips64el.h index 6ffc2dbc..5fde9e53 100644 --- a/qemu/mips64el.h +++ b/qemu/mips64el.h @@ -7,6 +7,7 @@ #define phys_mem_clean phys_mem_clean_mips64el #define tb_cleanup tb_cleanup_mips64el #define memory_map memory_map_mips64el +#define memory_unmap memory_unmap_mips64el #define memory_free memory_free_mips64el #define helper_raise_exception helper_raise_exception_mips64el #define tcg_enabled tcg_enabled_mips64el diff --git a/qemu/mipsel.h b/qemu/mipsel.h index 94c4fdf7..caf1fe4d 100644 --- a/qemu/mipsel.h +++ b/qemu/mipsel.h @@ -7,6 +7,7 @@ #define phys_mem_clean phys_mem_clean_mipsel #define tb_cleanup tb_cleanup_mipsel #define memory_map memory_map_mipsel +#define memory_unmap memory_unmap_mipsel #define memory_free memory_free_mipsel #define helper_raise_exception helper_raise_exception_mipsel #define tcg_enabled tcg_enabled_mipsel diff --git a/qemu/powerpc.h b/qemu/powerpc.h index fd627665..92e614e1 100644 --- a/qemu/powerpc.h +++ b/qemu/powerpc.h @@ -7,6 +7,7 @@ #define phys_mem_clean phys_mem_clean_powerpc #define tb_cleanup tb_cleanup_powerpc #define memory_map memory_map_powerpc +#define memory_unmap memory_unmap_powerpc #define memory_free memory_free_powerpc #define helper_raise_exception helper_raise_exception_powerpc #define tcg_enabled tcg_enabled_powerpc diff --git a/qemu/softmmu_template.h b/qemu/softmmu_template.h index 56f657a4..3c851686 100644 --- a/qemu/softmmu_template.h +++ b/qemu/softmmu_template.h @@ -181,11 +181,28 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, struct uc_struct *uc = env->uc; MemoryRegion *mr = memory_mapping(uc, addr); +#if defined(SOFTMMU_CODE_ACCESS) + // Unicorn: callback on fetch from NX + if (mr != NULL && !(mr->perms & UC_PROT_EXEC)) { //non-executable + if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( + uc, UC_MEM_EXEC_PROT, addr, DATA_SIZE, 0, + uc->hook_callbacks[uc->hook_mem_idx].user_data)) { + env->invalid_error = UC_ERR_OK; + } else { + env->invalid_addr = addr; + env->invalid_error = UC_ERR_EXEC_PROT; + // printf("***** Invalid fetch (non-executable) at " TARGET_FMT_lx "\n", addr); + cpu_exit(uc->current_cpu); + return 0; + } + } +#endif + // Unicorn: callback on memory read if (env->uc->hook_mem_read && READ_ACCESS_TYPE == MMU_DATA_LOAD) { - struct hook_struct *trace = hook_find((uch)env->uc, UC_MEM_READ, addr); + struct hook_struct *trace = hook_find(env->uc, UC_HOOK_MEM_READ, addr); if (trace) { - ((uc_cb_hookmem_t)trace->callback)((uch)env->uc, UC_MEM_READ, + ((uc_cb_hookmem_t)trace->callback)(env->uc, UC_MEM_READ, (uint64_t)addr, (int)DATA_SIZE, (int64_t)0, trace->user_data); } } @@ -193,7 +210,7 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, // Unicorn: callback on invalid memory if (env->uc->hook_mem_idx && mr == NULL) { if (!((uc_cb_eventmem_t)env->uc->hook_callbacks[env->uc->hook_mem_idx].callback)( - (uch)env->uc, UC_MEM_READ, addr, DATA_SIZE, 0, + env->uc, UC_MEM_READ, addr, DATA_SIZE, 0, env->uc->hook_callbacks[env->uc->hook_mem_idx].user_data)) { // save error & quit env->invalid_addr = addr; @@ -206,20 +223,16 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, } } - // Unicorn: callback on read only memory + // Unicorn: callback on non-readable memory if (mr != NULL && !(mr->perms & UC_PROT_READ)) { //non-readable - bool result = false; - if (uc->hook_mem_idx) { - result = ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( - (uch)uc, UC_MEM_READ_NR, addr, DATA_SIZE, 0, - uc->hook_callbacks[uc->hook_mem_idx].user_data); - } - if (result) { + if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( + uc, UC_MEM_READ_PROT, addr, DATA_SIZE, 0, + uc->hook_callbacks[uc->hook_mem_idx].user_data)) { env->invalid_error = UC_ERR_OK; } else { env->invalid_addr = addr; - env->invalid_error = UC_ERR_MEM_READ_NR; + env->invalid_error = UC_ERR_READ_PROT; // printf("***** Invalid memory read (non-readable) at " TARGET_FMT_lx "\n", addr); cpu_exit(uc->current_cpu); return 0; @@ -326,11 +339,28 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, struct uc_struct *uc = env->uc; MemoryRegion *mr = memory_mapping(uc, addr); +#if defined(SOFTMMU_CODE_ACCESS) + // Unicorn: callback on fetch from NX + if (mr != NULL && !(mr->perms & UC_PROT_EXEC)) { //non-executable + if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( + uc, UC_MEM_EXEC_PROT, addr, DATA_SIZE, 0, + uc->hook_callbacks[uc->hook_mem_idx].user_data)) { + env->invalid_error = UC_ERR_OK; + } else { + env->invalid_addr = addr; + env->invalid_error = UC_ERR_EXEC_PROT; + // printf("***** Invalid fetch (non-executable) at " TARGET_FMT_lx "\n", addr); + cpu_exit(uc->current_cpu); + return 0; + } + } +#endif + // Unicorn: callback on memory read if (env->uc->hook_mem_read && READ_ACCESS_TYPE == MMU_DATA_LOAD) { - struct hook_struct *trace = hook_find((uch)env->uc, UC_MEM_READ, addr); + struct hook_struct *trace = hook_find(env->uc, UC_HOOK_MEM_READ, addr); if (trace) { - ((uc_cb_hookmem_t)trace->callback)((uch)env->uc, UC_MEM_READ, + ((uc_cb_hookmem_t)trace->callback)(env->uc, UC_MEM_READ, (uint64_t)addr, (int)DATA_SIZE, (int64_t)0, trace->user_data); } } @@ -338,7 +368,7 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, // Unicorn: callback on invalid memory if (env->uc->hook_mem_idx && mr == NULL) { if (!((uc_cb_eventmem_t)env->uc->hook_callbacks[env->uc->hook_mem_idx].callback)( - (uch)env->uc, UC_MEM_READ, addr, DATA_SIZE, 0, + env->uc, UC_MEM_READ, addr, DATA_SIZE, 0, env->uc->hook_callbacks[env->uc->hook_mem_idx].user_data)) { // save error & quit env->invalid_addr = addr; @@ -351,20 +381,15 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, } } - // Unicorn: callback on read only memory + // Unicorn: callback on non-readable memory if (mr != NULL && !(mr->perms & UC_PROT_READ)) { //non-readable - bool result = false; - if (uc->hook_mem_idx) { - result = ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( - (uch)uc, UC_MEM_READ_NR, addr, DATA_SIZE, 0, - uc->hook_callbacks[uc->hook_mem_idx].user_data); - } - if (result) { + if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( + uc, UC_MEM_READ_PROT, addr, DATA_SIZE, 0, + uc->hook_callbacks[uc->hook_mem_idx].user_data)) { env->invalid_error = UC_ERR_OK; - } - else { + } else { env->invalid_addr = addr; - env->invalid_error = UC_ERR_MEM_READ_NR; + env->invalid_error = UC_ERR_READ_PROT; // printf("***** Invalid memory read (non-readable) at " TARGET_FMT_lx "\n", addr); cpu_exit(uc->current_cpu); return 0; @@ -511,9 +536,9 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, // Unicorn: callback on memory write if (uc->hook_mem_write) { - struct hook_struct *trace = hook_find((uch)uc, UC_MEM_WRITE, addr); + struct hook_struct *trace = hook_find(uc, UC_HOOK_MEM_WRITE, addr); if (trace) { - ((uc_cb_hookmem_t)trace->callback)((uch)uc, UC_MEM_WRITE, + ((uc_cb_hookmem_t)trace->callback)(uc, UC_MEM_WRITE, (uint64_t)addr, (int)DATA_SIZE, (int64_t)val, trace->user_data); } } @@ -521,7 +546,7 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, // Unicorn: callback on invalid memory if (uc->hook_mem_idx && mr == NULL) { if (!((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( - (uch)uc, UC_MEM_WRITE, addr, DATA_SIZE, (int64_t)val, + uc, UC_MEM_WRITE, addr, DATA_SIZE, (int64_t)val, uc->hook_callbacks[uc->hook_mem_idx].user_data)) { // save error & quit env->invalid_addr = addr; @@ -534,20 +559,16 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, } } - // Unicorn: callback on read only memory - if (mr != NULL && !(mr->perms & UC_PROT_WRITE)) { //read only memory - bool result = false; - if (uc->hook_mem_idx) { - result = ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( - (uch)uc, UC_MEM_WRITE_NW, addr, DATA_SIZE, (int64_t)val, - uc->hook_callbacks[uc->hook_mem_idx].user_data); - } - if (result) { + // Unicorn: callback on non-writable memory + if (mr != NULL && !(mr->perms & UC_PROT_WRITE)) { //non-writable + if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( + uc, UC_MEM_WRITE_PROT, addr, DATA_SIZE, (int64_t)val, + uc->hook_callbacks[uc->hook_mem_idx].user_data)) { env->invalid_error = UC_ERR_OK; } else { env->invalid_addr = addr; - env->invalid_error = UC_ERR_MEM_WRITE_NW; + env->invalid_error = UC_ERR_WRITE_PROT; // printf("***** Invalid memory write (ro) at " TARGET_FMT_lx "\n", addr); cpu_exit(uc->current_cpu); return; @@ -649,9 +670,9 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, // Unicorn: callback on memory write if (uc->hook_mem_write) { - struct hook_struct *trace = hook_find((uch)uc, UC_MEM_WRITE, addr); + struct hook_struct *trace = hook_find(uc, UC_HOOK_MEM_WRITE, addr); if (trace) { - ((uc_cb_hookmem_t)trace->callback)((uch)uc, UC_MEM_WRITE, + ((uc_cb_hookmem_t)trace->callback)(uc, UC_MEM_WRITE, (uint64_t)addr, (int)DATA_SIZE, (int64_t)val, trace->user_data); } } @@ -659,7 +680,7 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, // Unicorn: callback on invalid memory if (uc->hook_mem_idx && mr == NULL) { if (!((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( - (uch)uc, UC_MEM_WRITE, addr, DATA_SIZE, (int64_t)val, + uc, UC_MEM_WRITE, addr, DATA_SIZE, (int64_t)val, uc->hook_callbacks[uc->hook_mem_idx].user_data)) { // save error & quit env->invalid_addr = addr; @@ -672,20 +693,16 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, } } - // Unicorn: callback on read only memory - if (mr != NULL && !(mr->perms & UC_PROT_WRITE)) { //read only memory - bool result = false; - if (uc->hook_mem_idx) { - result = ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( - (uch)uc, UC_MEM_WRITE_NW, addr, DATA_SIZE, (int64_t)val, - uc->hook_callbacks[uc->hook_mem_idx].user_data); - } - if (result) { + // Unicorn: callback on non-writable memory + if (mr != NULL && !(mr->perms & UC_PROT_WRITE)) { //non-writable + if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( + uc, UC_MEM_WRITE_PROT, addr, DATA_SIZE, (int64_t)val, + uc->hook_callbacks[uc->hook_mem_idx].user_data)) { env->invalid_error = UC_ERR_OK; } else { env->invalid_addr = addr; - env->invalid_error = UC_ERR_MEM_WRITE_NW; + env->invalid_error = UC_ERR_WRITE_PROT; // printf("***** Invalid memory write (ro) at " TARGET_FMT_lx "\n", addr); cpu_exit(uc->current_cpu); return; diff --git a/qemu/sparc.h b/qemu/sparc.h index 64803c11..6aa47aa5 100644 --- a/qemu/sparc.h +++ b/qemu/sparc.h @@ -7,6 +7,7 @@ #define phys_mem_clean phys_mem_clean_sparc #define tb_cleanup tb_cleanup_sparc #define memory_map memory_map_sparc +#define memory_unmap memory_unmap_sparc #define memory_free memory_free_sparc #define helper_raise_exception helper_raise_exception_sparc #define tcg_enabled tcg_enabled_sparc diff --git a/qemu/sparc64.h b/qemu/sparc64.h index 5042c38d..6d3d2a1d 100644 --- a/qemu/sparc64.h +++ b/qemu/sparc64.h @@ -7,6 +7,7 @@ #define phys_mem_clean phys_mem_clean_sparc64 #define tb_cleanup tb_cleanup_sparc64 #define memory_map memory_map_sparc64 +#define memory_unmap memory_unmap_sparc64 #define memory_free memory_free_sparc64 #define helper_raise_exception helper_raise_exception_sparc64 #define tcg_enabled tcg_enabled_sparc64 diff --git a/qemu/target-arm/translate-a64.c b/qemu/target-arm/translate-a64.c index 73e0c0ae..5dda2eba 100644 --- a/qemu/target-arm/translate-a64.c +++ b/qemu/target-arm/translate-a64.c @@ -10984,7 +10984,7 @@ static void disas_a64_insn(CPUARMState *env, DisasContext *s) // Unicorn: trace this instruction on request if (env->uc->hook_insn) { - struct hook_struct *trace = hook_find((uch)s->uc, UC_HOOK_CODE, s->pc - 4); + struct hook_struct *trace = hook_find(s->uc, UC_HOOK_CODE, s->pc - 4); if (trace) gen_uc_tracecode(tcg_ctx, 4, trace->callback, env->uc, s->pc - 4, trace->user_data); // if requested to emulate only some instructions, check if @@ -11109,7 +11109,7 @@ void gen_intermediate_code_internal_a64(ARMCPU *cpu, // Only hook this block if it is not broken from previous translation due to // full translation cache if (env->uc->hook_block && !env->uc->block_full) { - struct hook_struct *trace = hook_find((uch)env->uc, UC_HOOK_BLOCK, pc_start); + struct hook_struct *trace = hook_find(env->uc, UC_HOOK_BLOCK, pc_start); if (trace) { // save block address to see if we need to patch block size later env->uc->block_addr = pc_start; diff --git a/qemu/target-arm/translate.c b/qemu/target-arm/translate.c index 68b3b5ea..a3829ca2 100644 --- a/qemu/target-arm/translate.c +++ b/qemu/target-arm/translate.c @@ -7688,7 +7688,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) // qq // Unicorn: trace this instruction on request if (s->uc->hook_insn) { - struct hook_struct *trace = hook_find((uch)s->uc, UC_HOOK_CODE, s->pc - 4); + struct hook_struct *trace = hook_find(s->uc, UC_HOOK_CODE, s->pc - 4); if (trace) gen_uc_tracecode(tcg_ctx, 4, trace->callback, s->uc, s->pc - 4, trace->user_data); // if requested to emulate only some instructions, check if @@ -10411,7 +10411,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) // qq // Unicorn: trace this instruction on request if (env->uc->hook_insn) { - struct hook_struct *trace = hook_find((uch)s->uc, UC_HOOK_CODE, s->pc); + struct hook_struct *trace = hook_find(s->uc, UC_HOOK_CODE, s->pc); if (trace) gen_uc_tracecode(tcg_ctx, 2, trace->callback, env->uc, s->pc, trace->user_data); // if requested to emulate only some instructions, check to see @@ -11232,7 +11232,7 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu, // Only hook this block if it is not broken from previous translation due to // full translation cache if (env->uc->hook_block && !env->uc->block_full) { - struct hook_struct *trace = hook_find((uch)env->uc, UC_HOOK_BLOCK, pc_start); + struct hook_struct *trace = hook_find(env->uc, UC_HOOK_BLOCK, pc_start); if (trace) { // save block address to see if we need to patch block size later env->uc->block_addr = pc_start; diff --git a/qemu/target-arm/unicorn.h b/qemu/target-arm/unicorn.h index 0c355a71..797ef979 100644 --- a/qemu/target-arm/unicorn.h +++ b/qemu/target-arm/unicorn.h @@ -5,13 +5,13 @@ #define UC_QEMU_TARGET_ARM_H // functions to read & write registers -int arm_reg_read(uch handle, unsigned int regid, void *value); -int arm_reg_write(uch handle, unsigned int regid, const void *value); -int arm64_reg_read(uch handle, unsigned int regid, void *value); -int arm64_reg_write(uch handle, unsigned int regid, const void *value); +int arm_reg_read(struct uc_struct *uc, unsigned int regid, void *value); +int arm_reg_write(struct uc_struct *uc, unsigned int regid, const void *value); +int arm64_reg_read(struct uc_struct *uc, unsigned int regid, void *value); +int arm64_reg_write(struct uc_struct *uc, unsigned int regid, const void *value); -void arm_reg_reset(uch handle); -void arm64_reg_reset(uch handle); +void arm_reg_reset(struct uc_struct *uc); +void arm64_reg_reset(struct uc_struct *uc); __attribute__ ((visibility ("default"))) void arm_uc_init(struct uc_struct* uc); diff --git a/qemu/target-arm/unicorn_aarch64.c b/qemu/target-arm/unicorn_aarch64.c index b9474155..a8a674b0 100644 --- a/qemu/target-arm/unicorn_aarch64.c +++ b/qemu/target-arm/unicorn_aarch64.c @@ -25,23 +25,17 @@ static void arm64_set_pc(struct uc_struct *uc, uint64_t address) ((CPUARMState *)uc->current_cpu->env_ptr)->pc = address; } -void arm64_reg_reset(uch handle) +void arm64_reg_reset(struct uc_struct *uc) { - struct uc_struct *uc = (struct uc_struct *) handle; - CPUArchState *env; - - env = first_cpu->env_ptr; + CPUArchState *env = first_cpu->env_ptr; memset(env->xregs, 0, sizeof(env->xregs)); env->pc = 0; } -int arm64_reg_read(uch handle, unsigned int regid, void *value) +int arm64_reg_read(struct uc_struct *uc, unsigned int regid, void *value) { - CPUState *mycpu; - struct uc_struct *uc = (struct uc_struct *) handle; - - mycpu = first_cpu; + CPUState *mycpu = first_cpu; if (regid >= UC_ARM64_REG_X0 && regid <= UC_ARM64_REG_X28) *(int64_t *)value = ARM_CPU(uc, mycpu)->env.xregs[regid - UC_ARM64_REG_X0]; @@ -68,12 +62,9 @@ int arm64_reg_read(uch handle, unsigned int regid, void *value) #define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | (b & 0xff)) #define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) -int arm64_reg_write(uch handle, unsigned int regid, const void *value) +int arm64_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) { - CPUState *mycpu; - struct uc_struct *uc = (struct uc_struct *) handle; - - mycpu = first_cpu; + CPUState *mycpu = first_cpu; if (regid >= UC_ARM64_REG_X0 && regid <= UC_ARM64_REG_X28) ARM_CPU(uc, mycpu)->env.xregs[regid - UC_ARM64_REG_X0] = *(int64_t *)value; diff --git a/qemu/target-arm/unicorn_arm.c b/qemu/target-arm/unicorn_arm.c index 9737906c..dcb2a65f 100644 --- a/qemu/target-arm/unicorn_arm.c +++ b/qemu/target-arm/unicorn_arm.c @@ -25,9 +25,9 @@ static void arm_set_pc(struct uc_struct *uc, uint64_t address) ((CPUARMState *)uc->current_cpu->env_ptr)->regs[15] = address; } -void arm_reg_reset(uch handle) +void arm_reg_reset(struct uc_struct *uc) { - struct uc_struct *uc = (struct uc_struct *) handle; + (void)uc; CPUArchState *env; env = first_cpu->env_ptr; @@ -36,10 +36,9 @@ void arm_reg_reset(uch handle) env->pc = 0; } -int arm_reg_read(uch handle, unsigned int regid, void *value) +int arm_reg_read(struct uc_struct *uc, unsigned int regid, void *value) { CPUState *mycpu; - struct uc_struct *uc = (struct uc_struct *) handle; mycpu = first_cpu; @@ -78,12 +77,9 @@ int arm_reg_read(uch handle, unsigned int regid, void *value) #define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | (b & 0xff)) #define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) -int arm_reg_write(uch handle, unsigned int regid, const void *value) +int arm_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) { - CPUState *mycpu; - struct uc_struct *uc = (struct uc_struct *) handle; - - mycpu = first_cpu; + CPUState *mycpu = first_cpu; switch(uc->mode) { default: diff --git a/qemu/target-i386/seg_helper.c b/qemu/target-i386/seg_helper.c index 0bae3caa..2111ac7c 100644 --- a/qemu/target-i386/seg_helper.c +++ b/qemu/target-i386/seg_helper.c @@ -949,7 +949,7 @@ void helper_syscall(CPUX86State *env, int next_eip_addend) struct uc_struct *uc = env->uc; if (uc->hook_syscall_idx) { ((uc_cb_insn_syscall_t)uc->hook_callbacks[uc->hook_syscall_idx].callback)( - (uch)uc, uc->hook_callbacks[uc->hook_syscall_idx].user_data); + uc, uc->hook_callbacks[uc->hook_syscall_idx].user_data); env->eip += next_eip_addend; } diff --git a/qemu/target-i386/translate.c b/qemu/target-i386/translate.c index a3b09fd5..6d93efe2 100644 --- a/qemu/target-i386/translate.c +++ b/qemu/target-i386/translate.c @@ -2944,8 +2944,8 @@ typedef void (*SSEFunc_0_epl)(TCGContext *s, TCGv_ptr env, TCGv_ptr reg, TCGv_i6 typedef void (*SSEFunc_0_epp)(TCGContext *s, TCGv_ptr env, TCGv_ptr reg_a, TCGv_ptr reg_b); typedef void (*SSEFunc_0_eppi)(TCGContext *s, TCGv_ptr env, TCGv_ptr reg_a, TCGv_ptr reg_b, TCGv_i32 val); -typedef void (*SSEFunc_0_ppi)(TCGv_ptr reg_a, TCGv_ptr reg_b, TCGv_i32 val); -typedef void (*SSEFunc_0_eppt)(TCGv_ptr env, TCGv_ptr reg_a, TCGv_ptr reg_b, +typedef void (*SSEFunc_0_ppi)(TCGContext *s, TCGv_ptr reg_a, TCGv_ptr reg_b, TCGv_i32 val); +typedef void (*SSEFunc_0_eppt)(TCGContext *s, TCGv_ptr env, TCGv_ptr reg_a, TCGv_ptr reg_b, TCGv val); #define SSE_SPECIAL ((void *)1) @@ -4669,7 +4669,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, tcg_gen_addi_ptr(tcg_ctx, cpu_ptr1, cpu_env, op2_offset); /* XXX: introduce a new table? */ sse_fn_ppi = (SSEFunc_0_ppi)sse_fn_epp; - sse_fn_ppi(cpu_ptr0, cpu_ptr1, tcg_const_i32(tcg_ctx, val)); + sse_fn_ppi(tcg_ctx, cpu_ptr0, cpu_ptr1, tcg_const_i32(tcg_ctx, val)); break; case 0xc2: /* compare insns */ @@ -4694,7 +4694,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, tcg_gen_addi_ptr(tcg_ctx, cpu_ptr1, cpu_env, op2_offset); /* XXX: introduce a new table? */ sse_fn_eppt = (SSEFunc_0_eppt)sse_fn_epp; - sse_fn_eppt(cpu_env, cpu_ptr0, cpu_ptr1, cpu_A0); + sse_fn_eppt(tcg_ctx, cpu_env, cpu_ptr0, cpu_ptr1, cpu_A0); break; default: tcg_gen_addi_ptr(tcg_ctx, cpu_ptr0, cpu_env, op1_offset); @@ -4761,7 +4761,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, // Unicorn: trace this instruction on request if (env->uc->hook_insn) { - trace = hook_find((uch)env->uc, UC_HOOK_CODE, pc_start); + trace = hook_find(env->uc, UC_HOOK_CODE, pc_start); if (trace) { if (s->last_cc_op != s->cc_op) { sync_eflags(s, tcg_ctx); @@ -8175,9 +8175,15 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, // printf("\n"); if (changed_cc_op) { if (cc_op_dirty) +#if TCG_TARGET_REG_BITS == 32 + *(save_opparam_ptr + 16) = s->pc - pc_start; + else + *(save_opparam_ptr + 14) = s->pc - pc_start; +#else *(save_opparam_ptr + 12) = s->pc - pc_start; else *(save_opparam_ptr + 10) = s->pc - pc_start; +#endif } else { *(save_opparam_ptr + 1) = s->pc - pc_start; } @@ -8373,7 +8379,7 @@ static inline void gen_intermediate_code_internal(uint8_t *gen_opc_cc_op, // Only hook this block if it is not broken from previous translation due to // full translation cache if (env->uc->hook_block && !env->uc->block_full) { - struct hook_struct *trace = hook_find((uch)env->uc, UC_HOOK_BLOCK, pc_start); + struct hook_struct *trace = hook_find(env->uc, UC_HOOK_BLOCK, pc_start); if (trace) { env->uc->block_addr = pc_start; gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, pc_start, trace->user_data); diff --git a/qemu/target-i386/unicorn.c b/qemu/target-i386/unicorn.c index c6350213..393e64cc 100644 --- a/qemu/target-i386/unicorn.c +++ b/qemu/target-i386/unicorn.c @@ -48,12 +48,15 @@ void x86_release(void *ctx) g_free(s->tb_ctx.tbs); } -void x86_reg_reset(uch handle) +void x86_reg_reset(struct uc_struct *uc) { - struct uc_struct *uc = (struct uc_struct *) handle; - CPUArchState *env; + CPUArchState *env = first_cpu->env_ptr; - 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)); @@ -138,12 +141,9 @@ void x86_reg_reset(uch handle) } } -int x86_reg_read(uch handle, unsigned int regid, void *value) +int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value) { - CPUState *mycpu; - struct uc_struct *uc = (struct uc_struct *) handle; - - mycpu = first_cpu; + CPUState *mycpu = first_cpu; switch(uc->mode) { default: @@ -540,12 +540,9 @@ int x86_reg_read(uch handle, unsigned int regid, void *value) #define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | (b & 0xff)) #define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) -int x86_reg_write(uch handle, unsigned int regid, const void *value) +int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) { - CPUState *mycpu; - struct uc_struct *uc = (struct uc_struct *) handle; - - mycpu = first_cpu; + CPUState *mycpu = first_cpu; switch(uc->mode) { default: diff --git a/qemu/target-i386/unicorn.h b/qemu/target-i386/unicorn.h index b710236b..a4dda81e 100644 --- a/qemu/target-i386/unicorn.h +++ b/qemu/target-i386/unicorn.h @@ -5,10 +5,10 @@ #define UC_QEMU_TARGET_I386_H // functions to read & write registers -int x86_reg_read(uch handle, unsigned int regid, void *value); -int x86_reg_write(uch handle, unsigned int regid, const void *value); +int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value); +int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value); -void x86_reg_reset(uch handle); +void x86_reg_reset(struct uc_struct *uc); void x86_uc_init(struct uc_struct* uc); int x86_uc_machine_init(struct uc_struct *uc); diff --git a/qemu/target-m68k/translate.c b/qemu/target-m68k/translate.c index 6565056c..133957df 100644 --- a/qemu/target-m68k/translate.c +++ b/qemu/target-m68k/translate.c @@ -3044,7 +3044,7 @@ static void disas_m68k_insn(CPUM68KState * env, DisasContext *s) // Unicorn: trace this instruction on request if (env->uc->hook_insn) { - struct hook_struct *trace = hook_find((uch)env->uc, UC_HOOK_CODE, s->pc); + struct hook_struct *trace = hook_find(env->uc, UC_HOOK_CODE, s->pc); if (trace) gen_uc_tracecode(tcg_ctx, 2, trace->callback, env->uc, s->pc, trace->user_data); // if requested to emulate only some instructions, check if @@ -3105,7 +3105,7 @@ gen_intermediate_code_internal(M68kCPU *cpu, TranslationBlock *tb, // Only hook this block if it is not broken from previous translation due to // full translation cache if (env->uc->hook_block && !env->uc->block_full) { - struct hook_struct *trace = hook_find((uch)env->uc, UC_HOOK_BLOCK, pc_start); + struct hook_struct *trace = hook_find(env->uc, UC_HOOK_BLOCK, pc_start); if (trace) { // save block address to see if we need to patch block size later env->uc->block_addr = pc_start; diff --git a/qemu/target-m68k/unicorn.c b/qemu/target-m68k/unicorn.c index f085b53c..d8403c63 100644 --- a/qemu/target-m68k/unicorn.c +++ b/qemu/target-m68k/unicorn.c @@ -21,21 +21,18 @@ static void m68k_set_pc(struct uc_struct *uc, uint64_t address) ((CPUM68KState *)uc->current_cpu->env_ptr)->pc = address; } -void m68k_reg_reset(uch handle) +void m68k_reg_reset(struct uc_struct *uc) { - struct uc_struct *uc = (struct uc_struct *) handle; - CPUArchState *env; + CPUArchState *env = first_cpu->env_ptr; - env = first_cpu->env_ptr; memset(env->aregs, 0, sizeof(env->aregs)); memset(env->dregs, 0, sizeof(env->dregs)); env->pc = 0; } -int m68k_reg_read(uch handle, unsigned int regid, void *value) +int m68k_reg_read(struct uc_struct *uc, unsigned int regid, void *value) { - struct uc_struct *uc = (struct uc_struct *)handle; CPUState *mycpu = first_cpu; if (regid >= UC_M68K_REG_A0 && regid <= UC_M68K_REG_A7) @@ -60,9 +57,8 @@ int m68k_reg_read(uch handle, unsigned int regid, void *value) #define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | (b & 0xff)) #define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) -int m68k_reg_write(uch handle, unsigned int regid, const void *value) +int m68k_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) { - struct uc_struct *uc = (struct uc_struct *) handle; CPUState *mycpu = first_cpu; if (regid >= UC_M68K_REG_A0 && regid <= UC_M68K_REG_A7) diff --git a/qemu/target-m68k/unicorn.h b/qemu/target-m68k/unicorn.h index 5fcca5f3..37ea828f 100644 --- a/qemu/target-m68k/unicorn.h +++ b/qemu/target-m68k/unicorn.h @@ -5,10 +5,10 @@ #define UC_QEMU_TARGET_M68K_H // functions to read & write registers -int m68k_reg_read(uch handle, unsigned int regid, void *value); -int m68k_reg_write(uch handle, unsigned int regid, const void *value); +int m68k_reg_read(struct uc_struct *uc, unsigned int regid, void *value); +int m68k_reg_write(struct uc_struct *uc, unsigned int regid, const void *value); -void m68k_reg_reset(uch handle); +void m68k_reg_reset(struct uc_struct *uc); void m68k_uc_init(struct uc_struct* uc); diff --git a/qemu/target-mips/translate.c b/qemu/target-mips/translate.c index 97e28225..718d69aa 100644 --- a/qemu/target-mips/translate.c +++ b/qemu/target-mips/translate.c @@ -11344,7 +11344,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) // Unicorn: trace this instruction on request if (env->uc->hook_insn) { - struct hook_struct *trace = hook_find((uch)env->uc, UC_HOOK_CODE, ctx->pc); + struct hook_struct *trace = hook_find(env->uc, UC_HOOK_CODE, ctx->pc); if (trace) gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, ctx->pc, trace->user_data); // if requested to emulate only some instructions, check if @@ -13944,7 +13944,7 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx) // Unicorn: trace this instruction on request if (env->uc->hook_insn) { - struct hook_struct *trace = hook_find((uch)env->uc, UC_HOOK_CODE, ctx->pc); + struct hook_struct *trace = hook_find(env->uc, UC_HOOK_CODE, ctx->pc); if (trace) gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, ctx->pc, trace->user_data); // if requested to emulate only some instructions, check if @@ -18523,7 +18523,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) // Unicorn: trace this instruction on request if (env->uc->hook_insn) { - struct hook_struct *trace = hook_find((uch)env->uc, UC_HOOK_CODE, ctx->pc); + struct hook_struct *trace = hook_find(env->uc, UC_HOOK_CODE, ctx->pc); if (trace) gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, ctx->pc, trace->user_data); // if requested to emulate only some instructions, check if @@ -19211,7 +19211,7 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, // Only hook this block if it is not broken from previous translation due to // full translation cache if (env->uc->hook_block && !env->uc->block_full) { - struct hook_struct *trace = hook_find((uch)env->uc, UC_HOOK_BLOCK, pc_start); + struct hook_struct *trace = hook_find(env->uc, UC_HOOK_BLOCK, pc_start); if (trace) { // save block address to see if we need to patch block size later env->uc->block_addr = pc_start; diff --git a/qemu/target-mips/unicorn.c b/qemu/target-mips/unicorn.c index a66efdaf..33f1d6c0 100644 --- a/qemu/target-mips/unicorn.c +++ b/qemu/target-mips/unicorn.c @@ -22,19 +22,17 @@ static void mips_set_pc(struct uc_struct *uc, uint64_t address) ((CPUMIPSState *)uc->current_cpu->env_ptr)->active_tc.PC = address; } -void mips_reg_reset(uch handle) +void mips_reg_reset(struct uc_struct *uc) { - struct uc_struct *uc = (struct uc_struct *) handle; - CPUArchState *env; - - env = first_cpu->env_ptr; + (void)uc; + CPUArchState *env = first_cpu->env_ptr; memset(env->active_tc.gpr, 0, sizeof(env->active_tc.gpr)); - env->active_tc.PC = 0; } + env->active_tc.PC = 0; +} -int mips_reg_read(uch handle, unsigned int regid, void *value) +int mips_reg_read(struct uc_struct *uc, unsigned int regid, void *value) { - struct uc_struct *uc = (struct uc_struct *) handle; CPUState *mycpu = first_cpu; if (regid >= UC_MIPS_REG_0 && regid <= UC_MIPS_REG_31) @@ -57,9 +55,8 @@ int mips_reg_read(uch handle, unsigned int regid, void *value) #define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | (b & 0xff)) #define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) -int mips_reg_write(uch handle, unsigned int regid, const void *value) +int mips_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) { - struct uc_struct *uc = (struct uc_struct *) handle; CPUState *mycpu = first_cpu; if (regid >= UC_MIPS_REG_0 && regid <= UC_MIPS_REG_31) diff --git a/qemu/target-mips/unicorn.h b/qemu/target-mips/unicorn.h index 29d36a7d..874b82f1 100644 --- a/qemu/target-mips/unicorn.h +++ b/qemu/target-mips/unicorn.h @@ -5,10 +5,10 @@ #define UC_QEMU_TARGET_MIPS_H // functions to read & write registers -int mips_reg_read(uch handle, unsigned int regid, void *value); -int mips_reg_write(uch handle, unsigned int regid, const void *value); +int mips_reg_read(struct uc_struct *uc, unsigned int regid, void *value); +int mips_reg_write(struct uc_struct *uc, unsigned int regid, const void *value); -void mips_reg_reset(uch handle); +void mips_reg_reset(struct uc_struct *uc); void mips_uc_init(struct uc_struct* uc); void mipsel_uc_init(struct uc_struct* uc); diff --git a/qemu/target-sparc/translate.c b/qemu/target-sparc/translate.c index d36d1a7f..ff68fd64 100644 --- a/qemu/target-sparc/translate.c +++ b/qemu/target-sparc/translate.c @@ -2632,7 +2632,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) // Unicorn: trace this instruction on request if (dc->uc->hook_insn) { - struct hook_struct *trace = hook_find((uch)dc->uc, UC_HOOK_CODE, dc->pc); + struct hook_struct *trace = hook_find(dc->uc, UC_HOOK_CODE, dc->pc); if (trace) gen_uc_tracecode(tcg_ctx, 4, trace->callback, dc->uc, dc->pc, trace->user_data); // if requested to emulate only some instructions, check if @@ -5409,7 +5409,7 @@ static inline void gen_intermediate_code_internal(SPARCCPU *cpu, // Only hook this block if it is not broken from previous translation due to // full translation cache if (env->uc->hook_block && !env->uc->block_full) { - struct hook_struct *trace = hook_find((uch)env->uc, UC_HOOK_BLOCK, pc_start); + struct hook_struct *trace = hook_find(env->uc, UC_HOOK_BLOCK, pc_start); if (trace) { // save block address to see if we need to patch block size later env->uc->block_addr = pc_start; diff --git a/qemu/target-sparc/unicorn.c b/qemu/target-sparc/unicorn.c index 31c79cd7..2ca74743 100644 --- a/qemu/target-sparc/unicorn.c +++ b/qemu/target-sparc/unicorn.c @@ -32,12 +32,10 @@ static void sparc_set_pc(struct uc_struct *uc, uint64_t address) ((CPUSPARCState *)uc->current_cpu->env_ptr)->npc = address + 4; } -void sparc_reg_reset(uch handle) +void sparc_reg_reset(struct uc_struct *uc) { - struct uc_struct *uc = (struct uc_struct *) handle; - CPUArchState *env; + CPUArchState *env = first_cpu->env_ptr; - env = first_cpu->env_ptr; memset(env->gregs, 0, sizeof(env->gregs)); memset(env->fpr, 0, sizeof(env->fpr)); memset(env->regbase, 0, sizeof(env->regbase)); @@ -46,9 +44,8 @@ void sparc_reg_reset(uch handle) env->npc = 0; } -int sparc_reg_read(uch handle, unsigned int regid, void *value) +int sparc_reg_read(struct uc_struct *uc, unsigned int regid, void *value) { - struct uc_struct *uc = (struct uc_struct *) handle; CPUState *mycpu = first_cpu; if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) @@ -71,9 +68,8 @@ int sparc_reg_read(uch handle, unsigned int regid, void *value) #define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | (b & 0xff)) #define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) -int sparc_reg_write(uch handle, unsigned int regid, const void *value) +int sparc_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) { - struct uc_struct *uc = (struct uc_struct *) handle; CPUState *mycpu = first_cpu; if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) diff --git a/qemu/target-sparc/unicorn.h b/qemu/target-sparc/unicorn.h index 492a7ffb..89771827 100644 --- a/qemu/target-sparc/unicorn.h +++ b/qemu/target-sparc/unicorn.h @@ -5,10 +5,10 @@ #define UC_QEMU_TARGET_SPARC_H // functions to read & write registers -int sparc_reg_read(uch handle, unsigned int regid, void *value); -int sparc_reg_write(uch handle, unsigned int regid, const void *value); +int sparc_reg_read(struct uc_struct *uc, unsigned int regid, void *value); +int sparc_reg_write(struct uc_struct *uc, unsigned int regid, const void *value); -void sparc_reg_reset(uch handle); +void sparc_reg_reset(struct uc_struct *uc); void sparc_uc_init(struct uc_struct* uc); void sparc64_uc_init(struct uc_struct* uc); diff --git a/qemu/target-sparc/unicorn64.c b/qemu/target-sparc/unicorn64.c index f9baef0c..20a3928e 100644 --- a/qemu/target-sparc/unicorn64.c +++ b/qemu/target-sparc/unicorn64.c @@ -15,12 +15,10 @@ #define READ_BYTE_L(x) (x & 0xff) -void sparc_reg_reset(uch handle) +void sparc_reg_reset(struct uc_struct *uc) { - struct uc_struct *uc = (struct uc_struct *) handle; - CPUArchState *env; + CPUArchState *env = first_cpu->env_ptr; - env = first_cpu->env_ptr; memset(env->gregs, 0, sizeof(env->gregs)); memset(env->fpr, 0, sizeof(env->fpr)); memset(env->regbase, 0, sizeof(env->regbase)); @@ -29,9 +27,8 @@ void sparc_reg_reset(uch handle) env->npc = 0; } -int sparc_reg_read(uch handle, unsigned int regid, void *value) +int sparc_reg_read(struct uc_struct *uc, unsigned int regid, void *value) { - struct uc_struct *uc = (struct uc_struct *) handle; CPUState *mycpu = first_cpu; if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) @@ -54,9 +51,8 @@ int sparc_reg_read(uch handle, unsigned int regid, void *value) #define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | (b & 0xff)) #define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) -int sparc_reg_write(uch handle, unsigned int regid, const void *value) +int sparc_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) { - struct uc_struct *uc = (struct uc_struct *) handle; CPUState *mycpu = first_cpu; if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) diff --git a/qemu/unicorn_common.h b/qemu/unicorn_common.h index 176900cb..adfb5f05 100644 --- a/qemu/unicorn_common.h +++ b/qemu/unicorn_common.h @@ -73,8 +73,12 @@ static inline void uc_common_init(struct uc_struct* uc) uc->pause_all_vcpus = pause_all_vcpus; uc->vm_start = vm_start; uc->memory_map = memory_map; + uc->memory_unmap = memory_unmap; uc->readonly_mem = memory_region_set_readonly; + uc->target_page_size = TARGET_PAGE_SIZE; + uc->target_page_align = TARGET_PAGE_SIZE - 1; + if (!uc->release) uc->release = release_common; } diff --git a/qemu/util/qemu-thread-posix.c b/qemu/util/qemu-thread-posix.c index 1e8f8304..34632bca 100644 --- a/qemu/util/qemu-thread-posix.c +++ b/qemu/util/qemu-thread-posix.c @@ -389,7 +389,7 @@ void qemu_event_wait(QemuEvent *ev) } } -void qemu_thread_create(QemuThread *thread, const char *name, +void qemu_thread_create(struct uc_struct *uc, QemuThread *thread, const char *name, void *(*start_routine)(void*), void *arg, int mode) { @@ -426,7 +426,7 @@ void qemu_thread_create(QemuThread *thread, const char *name, pthread_attr_destroy(&attr); } -void qemu_thread_get_self(QemuThread *thread) +void qemu_thread_get_self(struct uc_struct *uc, QemuThread *thread) { thread->thread = pthread_self(); } @@ -436,7 +436,7 @@ bool qemu_thread_is_self(QemuThread *thread) return pthread_equal(pthread_self(), thread->thread); } -void qemu_thread_exit(void *retval) +void qemu_thread_exit(struct uc_struct *uc, void *retval) { pthread_exit(retval); } diff --git a/qemu/util/qemu-thread-win32.c b/qemu/util/qemu-thread-win32.c index 004f17bf..3f7f7015 100644 --- a/qemu/util/qemu-thread-win32.c +++ b/qemu/util/qemu-thread-win32.c @@ -16,6 +16,8 @@ #include #include +#include "uc_priv.h" + static void error_exit(int err, const char *msg) { @@ -264,10 +266,9 @@ struct QemuThreadData { bool exited; void *ret; CRITICAL_SECTION cs; + struct uc_struct *uc; }; -static __thread QemuThreadData *qemu_thread_data; - static unsigned __stdcall win32_start_routine(void *arg) { QemuThreadData *data = (QemuThreadData *) arg; @@ -278,14 +279,13 @@ static unsigned __stdcall win32_start_routine(void *arg) g_free(data); data = NULL; } - qemu_thread_data = data; - qemu_thread_exit(start_routine(thread_arg)); + qemu_thread_exit(data->uc, start_routine(thread_arg)); abort(); } -void qemu_thread_exit(void *arg) +void qemu_thread_exit(struct uc_struct *uc, void *arg) { - QemuThreadData *data = qemu_thread_data; + QemuThreadData *data = uc->qemu_thread_data; if (data) { assert(data->mode != QEMU_THREAD_DETACHED); @@ -326,7 +326,7 @@ void *qemu_thread_join(QemuThread *thread) return ret; } -void qemu_thread_create(QemuThread *thread, const char *name, +void qemu_thread_create(struct uc_struct *uc, QemuThread *thread, const char *name, void *(*start_routine)(void *), void *arg, int mode) { @@ -338,6 +338,9 @@ void qemu_thread_create(QemuThread *thread, const char *name, data->arg = arg; data->mode = mode; data->exited = false; + data->uc = uc; + + uc->qemu_thread_data = data; if (data->mode != QEMU_THREAD_DETACHED) { InitializeCriticalSection(&data->cs); @@ -352,9 +355,9 @@ void qemu_thread_create(QemuThread *thread, const char *name, thread->data = (mode == QEMU_THREAD_DETACHED) ? NULL : data; } -void qemu_thread_get_self(QemuThread *thread) +void qemu_thread_get_self(struct uc_struct *uc, QemuThread *thread) { - thread->data = qemu_thread_data; + thread->data = uc->qemu_thread_data; thread->tid = GetCurrentThreadId(); } diff --git a/qemu/x86_64.h b/qemu/x86_64.h index 9a148e95..ac9f34f0 100644 --- a/qemu/x86_64.h +++ b/qemu/x86_64.h @@ -7,6 +7,7 @@ #define phys_mem_clean phys_mem_clean_x86_64 #define tb_cleanup tb_cleanup_x86_64 #define memory_map memory_map_x86_64 +#define memory_unmap memory_unmap_x86_64 #define memory_free memory_free_x86_64 #define helper_raise_exception helper_raise_exception_x86_64 #define tcg_enabled tcg_enabled_x86_64 diff --git a/regress/Makefile b/regress/Makefile index bbb49c2a..806db172 100644 --- a/regress/Makefile +++ b/regress/Makefile @@ -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) diff --git a/regress/block_test.c b/regress/block_test.c index 3788f6f4..7aaf1b93 100644 --- a/regress/block_test.c +++ b/regress/block_test.c @@ -12,7 +12,7 @@ static int count = 1; // @address: address where the code is being executed // @size: size of machine instruction being executed // @user_data: user data passed to tracing APIs. -void cb_hookblock(uch handle, uint64_t address, uint32_t size, void *user_data) { +void cb_hookblock(ucengine *uc, uint64_t address, uint32_t size, void *user_data) { fprintf(stderr, "# >>> Tracing basic block at 0x%llx, block size = 0x%x\n", address, size); if (address != 0x1000000 && address != 0x1000200) { fprintf(stderr, "not ok %d - address != 0x1000000 && address != 0x1000200\n", count++); @@ -27,19 +27,19 @@ void cb_hookblock(uch handle, uint64_t address, uint32_t size, void *user_data) } int main() { - uch u; + ucengine *uc; fprintf(stderr, "# basic block callback test\n"); fprintf(stderr, "# there are only two basic blocks 0x1000000-0x10001ff and 0x1000200-0x10003ff\n"); - uc_err err = uc_open(UC_ARCH_X86, UC_MODE_32, &u); + uc_err err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); if (err != UC_ERR_OK) { fprintf(stderr, "not ok %d - %s\n", count++, uc_strerror(err)); exit(0); } fprintf(stderr, "ok %d - uc_open\n", count++); - err = uc_mem_map(u, 0x1000000, 4096, UC_PROT_ALL); + err = uc_mem_map(uc, 0x1000000, 4096, UC_PROT_ALL); if (err != UC_ERR_OK) { fprintf(stderr, "not ok %d - %s\n", count++, uc_strerror(err)); exit(0); @@ -55,23 +55,23 @@ int main() { memset(code, 0x90, sizeof(code)); memcpy(code + 1024 - 5, "\xe9\x00\xfe\xff\xff", 5); - err = uc_mem_write(u, 0x1000000, code, sizeof(code)); + err = uc_mem_write(uc, 0x1000000, code, sizeof(code)); if (err != UC_ERR_OK) { fprintf(stderr, "not ok %d - %s\n", count++, uc_strerror(err)); exit(0); } fprintf(stderr, "ok %d - uc_mem_write\n", count++); - uch h1, h2; + uchook h1, h2; - err = uc_hook_add(u, &h1, UC_HOOK_BLOCK, cb_hookblock, NULL, (uint64_t)1, (uint64_t)0); + err = uc_hook_add(uc, &h1, UC_HOOK_BLOCK, cb_hookblock, NULL, (uint64_t)1, (uint64_t)0); if (err != UC_ERR_OK) { fprintf(stderr, "not ok %d - %s\n", count++, uc_strerror(err)); exit(0); } fprintf(stderr, "ok %d - uc_hook_add\n", count++); - err = uc_emu_start(u, 0x1000000, 0x1000000 + sizeof(code), 0, 1030); + err = uc_emu_start(uc, 0x1000000, 0x1000000 + sizeof(code), 0, 1030); if (err != UC_ERR_OK) { fprintf(stderr, "not ok %d - %s\n", count++, uc_strerror(err)); exit(0); diff --git a/regress/map_crash.c b/regress/map_crash.c index 54bcfacc..e7fbf38c 100644 --- a/regress/map_crash.c +++ b/regress/map_crash.c @@ -10,8 +10,8 @@ int main() { int size; uint8_t *buf; - uch uh; - uc_err err = uc_open (UC_ARCH_X86, UC_MODE_64, &uh); + ucengine *uc; + uc_err err = uc_open (UC_ARCH_X86, UC_MODE_64, &uc); if (err) { fprintf (stderr, "Cannot initialize unicorn\n"); return 1; @@ -23,9 +23,9 @@ int main() return 1; } memset (buf, 0, size); - if (!uc_mem_map (uh, UC_BUG_WRITE_ADDR, size, UC_PROT_ALL)) { - uc_mem_write (uh, UC_BUG_WRITE_ADDR, buf, size); + if (!uc_mem_map (uc, UC_BUG_WRITE_ADDR, size, UC_PROT_ALL)) { + uc_mem_write (uc, UC_BUG_WRITE_ADDR, buf, size); } - uc_close (&uh); + uc_close(uc); return 0; } diff --git a/regress/map_write.c b/regress/map_write.c index e5b94366..40fada8d 100644 --- a/regress/map_write.c +++ b/regress/map_write.c @@ -8,17 +8,17 @@ int main() { - uch uh; + ucengine *uc; uint8_t *buf, *buf2; int i; uc_err err; - err = uc_open (UC_ARCH_X86, UC_MODE_64, &uh); + err = uc_open (UC_ARCH_X86, UC_MODE_64, &uc); if (err) { printf ("uc_open %d\n", err); return 1; } - err = uc_mem_map (uh, ADDR, SIZE, UC_PROT_ALL); + err = uc_mem_map (uc, ADDR, SIZE, UC_PROT_ALL); if (err) { printf ("uc_mem_map %d\n", err); return 1; @@ -29,12 +29,12 @@ int main() buf[i] = i & 0xff; } /* crash here */ - err = uc_mem_write (uh, ADDR, buf, SIZE+OVERFLOW); + err = uc_mem_write (uc, ADDR, buf, SIZE+OVERFLOW); if (err) { printf ("uc_mem_map %d\n", err); return 1; } - err = uc_mem_read (uh, ADDR+10, buf2, 4); + err = uc_mem_read (uc, ADDR+10, buf2, 4); if (err) { printf ("uc_mem_map %d\n", err); return 1; diff --git a/regress/nr_mem_test.c b/regress/nr_mem_test.c index 37c344de..4aa6db9c 100644 --- a/regress/nr_mem_test.c +++ b/regress/nr_mem_test.c @@ -36,7 +36,7 @@ bits 32 */ // callback for tracing memory access (READ or WRITE) -static bool hook_mem_invalid(uch handle, uc_mem_type type, +static bool hook_mem_invalid(ucengine *uc, uc_mem_type type, uint64_t address, int size, int64_t value, void *user_data) { @@ -44,7 +44,7 @@ static bool hook_mem_invalid(uch handle, uc_mem_type type, default: // return false to indicate we want to stop emulation return false; - case UC_MEM_READ_NR: + case UC_MEM_READ_PROT: printf(">>> non-readable memory is being read at 0x%"PRIx64 ", data size = %u\n", address, size); return false; @@ -54,42 +54,43 @@ static bool hook_mem_invalid(uch handle, uc_mem_type type, int main(int argc, char **argv, char **envp) { - uch handle, trace1, trace2; + ucengine *uc; + uchook trace1, trace2; uc_err err; uint32_t eax, ebx; printf("Memory protections test\n"); // Initialize emulator in X86-32bit mode - err = uc_open(UC_ARCH_X86, UC_MODE_32, &handle); + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); if (err) { printf("Failed on uc_open() with error returned: %u\n", err); return 1; } - uc_mem_map(handle, 0x100000, 0x1000, UC_PROT_READ); - uc_mem_map(handle, 0x300000, 0x1000, UC_PROT_READ | UC_PROT_WRITE); - uc_mem_map(handle, 0x400000, 0x1000, UC_PROT_WRITE); + uc_mem_map(uc, 0x100000, 0x1000, UC_PROT_READ); + uc_mem_map(uc, 0x300000, 0x1000, UC_PROT_READ | UC_PROT_WRITE); + uc_mem_map(uc, 0x400000, 0x1000, UC_PROT_WRITE); // write machine code to be emulated to memory - if (uc_mem_write(handle, 0x100000, PROGRAM, sizeof(PROGRAM))) { + if (uc_mem_write(uc, 0x100000, PROGRAM, sizeof(PROGRAM))) { printf("Failed to write emulation code to memory, quit!\n"); return 2; } else { printf("Allowed to write to read only memory via uc_mem_write\n"); } - uc_mem_write(handle, 0x300000, (const uint8_t*)"\x41\x41\x41\x41", 4); - uc_mem_write(handle, 0x400000, (const uint8_t*)"\x42\x42\x42\x42", 4); + uc_mem_write(uc, 0x300000, (const uint8_t*)"\x41\x41\x41\x41", 4); + uc_mem_write(uc, 0x400000, (const uint8_t*)"\x42\x42\x42\x42", 4); - //uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)0x400000, (uint64_t)0x400fff); + //uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)0x400000, (uint64_t)0x400fff); // intercept invalid memory events - uc_hook_add(handle, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL); + uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL); // emulate machine code in infinite time printf("BEGIN execution\n"); - err = uc_emu_start(handle, 0x100000, 0x100000 + sizeof(PROGRAM), 0, 2); + err = uc_emu_start(uc, 0x100000, 0x100000 + sizeof(PROGRAM), 0, 2); if (err) { printf("Expected failure on uc_emu_start() with error returned %u: %s\n", err, uc_strerror(err)); @@ -98,12 +99,12 @@ int main(int argc, char **argv, char **envp) } printf("END execution\n"); - uc_reg_read(handle, UC_X86_REG_EAX, &eax); + uc_reg_read(uc, UC_X86_REG_EAX, &eax); printf("Final eax = 0x%x\n", eax); - uc_reg_read(handle, UC_X86_REG_EBX, &ebx); + uc_reg_read(uc, UC_X86_REG_EBX, &ebx); printf("Final ebx = 0x%x\n", ebx); - uc_close(&handle); + uc_close(uc); return 0; } diff --git a/regress/pshufb.py b/regress/pshufb.py index 0d01bf5e..432a2300 100755 --- a/regress/pshufb.py +++ b/regress/pshufb.py @@ -9,4 +9,4 @@ 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, 0) +uc.emu_start(0x2000, 0x2005) diff --git a/regress/reg_write_sign_extension.py b/regress/reg_write_sign_extension.py new file mode 100755 index 00000000..69347c0f --- /dev/null +++ b/regress/reg_write_sign_extension.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python + +"""See https://github.com/unicorn-engine/unicorn/issues/98""" + +import unicorn +ADDR = 0xffaabbcc + +def hook_mem_invalid(mu, access, address, size, value, user_data): + print ">>> Expected value: 0x%x, actual value: 0x%x" % (ADDR, address) + assert(address == ADDR) + mu.mem_map(address & 0xfffff000, 4 * 1024) + mu.mem_write(address, b'\xcc') + return True + +mu = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32) +mu.reg_write(unicorn.x86_const.UC_X86_REG_EBX, ADDR) + +mu.mem_map(0x10000000, 1024 * 4) +# jmp ebx +mu.mem_write(0x10000000, b'\xff\xe3') + +mu.hook_add(unicorn.UC_HOOK_MEM_INVALID, hook_mem_invalid) +mu.emu_start(0x10000000, 0x10000000 + 2, count=1) diff --git a/regress/rep_movsb.c b/regress/rep_movsb.c new file mode 100644 index 00000000..0d91cbef --- /dev/null +++ b/regress/rep_movsb.c @@ -0,0 +1,184 @@ +/* + +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 +#include +#include +#include +#include +#include + +#include + +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(ucengine *uc, uint64_t addr, uint32_t size, void *user_data) +{ + uint8_t opcode; + if (uc_mem_read(uc, 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(uc) != 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(ucengine *uc, 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) +{ + ucengine *uc; + uchook 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, &uc); + 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(uc, 0x100000, 0x1000, UC_PROT_READ); + uc_mem_map(uc, 0x200000, 0x2000, UC_PROT_READ | UC_PROT_WRITE); + + // fill in the data that we want to copy + if (uc_mem_write(uc, 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(uc, 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(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)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(uc, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL, (uint64_t)1, (uint64_t)0) != 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(uc, 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(uc, 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(uc) == 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; +} diff --git a/regress/ro_mem_test.c b/regress/ro_mem_test.c index 06edf068..330e3c49 100644 --- a/regress/ro_mem_test.c +++ b/regress/ro_mem_test.c @@ -46,22 +46,22 @@ bottom: */ // callback for tracing instruction -static void hook_code(uch handle, uint64_t address, uint32_t size, void *user_data) +static void hook_code(ucengine *uc, uint64_t address, uint32_t size, void *user_data) { uint32_t esp; printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); - uc_reg_read(handle, UC_X86_REG_ESP, &esp); + uc_reg_read(uc, UC_X86_REG_ESP, &esp); printf(">>> --- ESP is 0x%x\n", esp); } // callback for tracing memory access (READ or WRITE) -static bool hook_mem_invalid(uch handle, uc_mem_type type, +static bool hook_mem_invalid(ucengine *uc, uc_mem_type type, uint64_t address, int size, int64_t value, void *user_data) { uint32_t esp; - uc_reg_read(handle, UC_X86_REG_ESP, &esp); + uc_reg_read(uc, UC_X86_REG_ESP, &esp); switch(type) { default: @@ -74,14 +74,14 @@ static bool hook_mem_invalid(uch handle, uc_mem_type type, upper = (esp + 0xfff) & ~0xfff; printf(">>> Stack appears to be missing at 0x%"PRIx64 ", allocating now\n", address); // map this memory in with 2MB in size - uc_mem_map(handle, upper - 0x8000, 0x8000, UC_PROT_READ | UC_PROT_WRITE); + uc_mem_map(uc, upper - 0x8000, 0x8000, UC_PROT_READ | UC_PROT_WRITE); // return true to indicate we want to continue return true; } printf(">>> Missing memory is being WRITTEN at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", address, size, value); return false; - case UC_MEM_WRITE_NW: + case UC_MEM_WRITE_PROT: printf(">>> RO memory is being WRITTEN at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", address, size, value); return false; @@ -94,7 +94,8 @@ static bool hook_mem_invalid(uch handle, uc_mem_type type, int main(int argc, char **argv, char **envp) { - uch handle, trace1, trace2; + ucengine *uc; + uchook trace1, trace2; uc_err err; uint8_t bytes[8]; uint32_t esp; @@ -108,44 +109,44 @@ int main(int argc, char **argv, char **envp) printf("Memory mapping test\n"); // Initialize emulator in X86-32bit mode - err = uc_open(UC_ARCH_X86, UC_MODE_32, &handle); + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); if (err) { printf("Failed on uc_open() with error returned: %u\n", err); return 1; } - uc_mem_map(handle, 0x100000, 0x1000, UC_PROT_ALL); - uc_mem_map(handle, 0x200000, 0x2000, UC_PROT_ALL); - uc_mem_map(handle, 0x300000, 0x3000, UC_PROT_ALL); - uc_mem_map(handle, 0x400000, 0x4000, UC_PROT_READ); + uc_mem_map(uc, 0x100000, 0x1000, UC_PROT_ALL); + uc_mem_map(uc, 0x200000, 0x2000, UC_PROT_ALL); + uc_mem_map(uc, 0x300000, 0x3000, UC_PROT_ALL); + uc_mem_map(uc, 0x400000, 0x4000, UC_PROT_READ); if (map_stack) { printf("Pre-mapping stack\n"); - uc_mem_map(handle, STACK, STACK_SIZE, UC_PROT_READ | UC_PROT_WRITE); + uc_mem_map(uc, STACK, STACK_SIZE, UC_PROT_READ | UC_PROT_WRITE); } else { printf("Mapping stack on first invalid memory access\n"); } esp = STACK + STACK_SIZE; - uc_reg_write(handle, UC_X86_REG_ESP, &esp); + uc_reg_write(uc, UC_X86_REG_ESP, &esp); // write machine code to be emulated to memory - if (uc_mem_write(handle, 0x400000, PROGRAM, sizeof(PROGRAM))) { + if (uc_mem_write(uc, 0x400000, PROGRAM, sizeof(PROGRAM))) { printf("Failed to write emulation code to memory, quit!\n"); return 2; } else { printf("Allowed to write to read only memory via uc_mem_write\n"); } - //uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)0x400000, (uint64_t)0x400fff); + //uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)0x400000, (uint64_t)0x400fff); // intercept invalid memory events - uc_hook_add(handle, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL); + uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL); // emulate machine code in infinite time printf("BEGIN execution - 1\n"); - err = uc_emu_start(handle, 0x400000, 0x400000 + sizeof(PROGRAM), 0, 10); + err = uc_emu_start(uc, 0x400000, 0x400000 + sizeof(PROGRAM), 0, 10); if (err) { printf("Expected failue on uc_emu_start() with error returned %u: %s\n", err, uc_strerror(err)); @@ -156,9 +157,12 @@ int main(int argc, char **argv, char **envp) // emulate machine code in infinite time printf("BEGIN execution - 2\n"); + //update eax to point to aligned memory (same as add eax,7 above) uint32_t eax = 0x40002C; - uc_reg_write(handle, UC_X86_REG_EAX, &eax); - err = uc_emu_start(handle, 0x400015, 0x400000 + sizeof(PROGRAM), 0, 2); + uc_reg_write(uc, UC_X86_REG_EAX, &eax); + //resume execution at the mov dword [eax], 0x87654321 + //to test an aligned write as well + err = uc_emu_start(uc, 0x400015, 0x400000 + sizeof(PROGRAM), 0, 2); if (err) { printf("Expected failure on uc_emu_start() with error returned %u: %s\n", err, uc_strerror(err)); @@ -168,7 +172,7 @@ int main(int argc, char **argv, char **envp) printf("END execution - 2\n"); printf("Verifying content at 0x400025 is unchanged\n"); - if (!uc_mem_read(handle, 0x400025, bytes, 4)) { + if (!uc_mem_read(uc, 0x400025, bytes, 4)) { printf(">>> Read 4 bytes from [0x%x] = 0x%x\n", (uint32_t)0x400025, *(uint32_t*) bytes); if (0x41414141 != *(uint32_t*) bytes) { printf("ERROR content in read only memory changed\n"); @@ -181,7 +185,7 @@ int main(int argc, char **argv, char **envp) } printf("Verifying content at 0x40002C is unchanged\n"); - if (!uc_mem_read(handle, 0x40002C, bytes, 4)) { + if (!uc_mem_read(uc, 0x40002C, bytes, 4)) { printf(">>> Read 4 bytes from [0x%x] = 0x%x\n", (uint32_t)0x40002C, *(uint32_t*) bytes); if (0x42424242 != *(uint32_t*) bytes) { printf("ERROR content in read only memory changed\n"); @@ -194,14 +198,14 @@ int main(int argc, char **argv, char **envp) } printf("Verifying content at bottom of stack is readable and correct\n"); - if (!uc_mem_read(handle, esp - 4, bytes, 4)) { + if (!uc_mem_read(uc, esp - 4, bytes, 4)) { printf(">>> Read 4 bytes from [0x%x] = 0x%x\n", (uint32_t)(esp - 4), *(uint32_t*) bytes); } else { printf(">>> Failed to read 4 bytes from [0x%x]\n", (uint32_t)(esp - 4)); return 4; } - uc_close(&handle); + uc_close(uc); return 0; } diff --git a/regress/sigill.c b/regress/sigill.c index c8b5517a..b7317888 100644 --- a/regress/sigill.c +++ b/regress/sigill.c @@ -8,10 +8,10 @@ int got_sigill = 0; -void _interrupt(uch handle, uint32_t intno, void *user_data) +void _interrupt(ucengine *uc, uint32_t intno, void *user_data) { if (intno == 6) { - uc_emu_stop (handle); + uc_emu_stop(uc); got_sigill = 1; } } @@ -20,9 +20,9 @@ int main() { int size; uint8_t *buf; - uch uh; - uch uh_trap; - uc_err err = uc_open (UC_ARCH_X86, UC_MODE_64, &uh); + ucengine *uc; + uchook uh_trap; + uc_err err = uc_open (UC_ARCH_X86, UC_MODE_64, &uc); if (err) { fprintf (stderr, "Cannot initialize unicorn\n"); return 1; @@ -34,13 +34,13 @@ int main() return 1; } memset (buf, 0, size); - if (!uc_mem_map (uh, UC_BUG_WRITE_ADDR, size, UC_PROT_ALL)) { - uc_mem_write (uh, UC_BUG_WRITE_ADDR, + if (!uc_mem_map(uc, UC_BUG_WRITE_ADDR, size, UC_PROT_ALL)) { + uc_mem_write(uc, UC_BUG_WRITE_ADDR, (const uint8_t*)"\xff\xff\xff\xff\xff\xff\xff\xff", 8); } - uc_hook_add (uh, &uh_trap, UC_HOOK_INTR, _interrupt, NULL); - uc_emu_start (uh, UC_BUG_WRITE_ADDR, UC_BUG_WRITE_ADDR+8, 0, 1); - uc_close (&uh); + uc_hook_add(uc, &uh_trap, UC_HOOK_INTR, _interrupt, NULL); + uc_emu_start(uc, UC_BUG_WRITE_ADDR, UC_BUG_WRITE_ADDR+8, 0, 1); + uc_close(uc); printf ("Correct: %s\n", got_sigill? "YES": "NO"); return got_sigill? 0: 1; } diff --git a/regress/sigill2.c b/regress/sigill2.c index a2a2d4f1..1d955144 100644 --- a/regress/sigill2.c +++ b/regress/sigill2.c @@ -10,20 +10,20 @@ int main() { int size; uint8_t *buf; - uch uh; - uch uh_trap; - uc_err err = uc_open (UC_ARCH_X86, UC_MODE_64, &uh); + ucengine *uc; + + uc_err err = uc_open (UC_ARCH_X86, UC_MODE_64, &uc); if (err) { fprintf (stderr, "Cannot initialize unicorn\n"); return 1; } size = UC_BUG_WRITE_SIZE; - if (!uc_mem_map (uh, UC_BUG_WRITE_ADDR, size, UC_PROT_ALL)) { - uc_mem_write (uh, UC_BUG_WRITE_ADDR, + if (!uc_mem_map (uc, UC_BUG_WRITE_ADDR, size, UC_PROT_ALL)) { + uc_mem_write (uc, UC_BUG_WRITE_ADDR, (const uint8_t*)"\xff\xff\xff\xff\xff\xff\xff\xff", 8); } - err = uc_emu_start (uh, UC_BUG_WRITE_ADDR, UC_BUG_WRITE_ADDR+8, 0, 1); - uc_close (&uh); + err = uc_emu_start(uc, UC_BUG_WRITE_ADDR, UC_BUG_WRITE_ADDR+8, 0, 1); + uc_close(uc); printf ("Error = %u (%s)\n", err, uc_strerror(err)); return err? -1: 0; } diff --git a/regress/timeout_segfault.c b/regress/timeout_segfault.c index a1378e6a..73070978 100644 --- a/regress/timeout_segfault.c +++ b/regress/timeout_segfault.c @@ -24,21 +24,21 @@ https://github.com/unicorn-engine/unicorn/issues/78 // number of seconds to wait before timeout #define TIMEOUT 5 -static void hook_block(uch handle, uint64_t address, uint32_t size, void *user_data) +static void hook_block(ucengine *uc, uint64_t address, uint32_t size, void *user_data) { printf(">>> Tracing basic block at 0x%"PRIx64 ", block size = 0x%x\n", address, size); } -static void hook_code(uch handle, uint64_t address, uint32_t size, void *user_data) +static void hook_code(ucengine *uc, uint64_t address, uint32_t size, void *user_data) { printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); } static void test_arm(void) { - uch handle; + ucengine *uc; uc_err err; - uch trace1, trace2; + uchook trace1, trace2; int r0 = 0x1234; // R0 register int r2 = 0x6789; // R1 register @@ -48,7 +48,7 @@ static void test_arm(void) printf("Emulate ARM code\n"); // Initialize emulator in ARM mode - err = uc_open(UC_ARCH_ARM, UC_MODE_ARM, &handle); + err = uc_open(UC_ARCH_ARM, UC_MODE_ARM, &uc); if (err) { printf("Failed on uc_open() with error returned: %u (%s)\n", err, uc_strerror(err)); @@ -56,25 +56,25 @@ static void test_arm(void) } // map 2MB memory for this emulation - uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory - uc_mem_write(handle, ADDRESS, (uint8_t *)ARM_CODE, sizeof(ARM_CODE) - 1); + uc_mem_write(uc, ADDRESS, (uint8_t *)ARM_CODE, sizeof(ARM_CODE) - 1); // initialize machine registers - uc_reg_write(handle, UC_ARM_REG_R0, &r0); - uc_reg_write(handle, UC_ARM_REG_R2, &r2); - uc_reg_write(handle, UC_ARM_REG_R3, &r3); + uc_reg_write(uc, UC_ARM_REG_R0, &r0); + uc_reg_write(uc, UC_ARM_REG_R2, &r2); + uc_reg_write(uc, UC_ARM_REG_R3, &r3); // tracing all basic blocks with customized callback - uc_hook_add(handle, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); // tracing one instruction at ADDRESS with customized callback - uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. - err = uc_emu_start(handle, ADDRESS, ADDRESS + sizeof(ARM_CODE) -1, UC_SECOND_SCALE * TIMEOUT, 0); + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(ARM_CODE) -1, UC_SECOND_SCALE * TIMEOUT, 0); if (err) { printf("Failed on uc_emu_start() with error returned: %u\n", err); } @@ -82,26 +82,26 @@ static void test_arm(void) // now print out some registers printf(">>> Emulation done. Below is the CPU context\n"); - uc_reg_read(handle, UC_ARM_REG_R0, &r0); - uc_reg_read(handle, UC_ARM_REG_R1, &r1); + uc_reg_read(uc, UC_ARM_REG_R0, &r0); + uc_reg_read(uc, UC_ARM_REG_R1, &r1); printf(">>> R0 = 0x%x\n", r0); printf(">>> R1 = 0x%x\n", r1); - uc_close(&handle); + uc_close(uc); } static void test_thumb(void) { - uch handle; + ucengine *uc; uc_err err; - uch trace1, trace2; + uchook trace1, trace2; int sp = 0x1234; // R0 register printf("Emulate THUMB code\n"); // Initialize emulator in ARM mode - err = uc_open(UC_ARCH_ARM, UC_MODE_THUMB, &handle); + err = uc_open(UC_ARCH_ARM, UC_MODE_THUMB, &uc); if (err) { printf("Failed on uc_open() with error returned: %u (%s)\n", err, uc_strerror(err)); @@ -109,23 +109,23 @@ static void test_thumb(void) } // map 2MB memory for this emulation - uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory - uc_mem_write(handle, ADDRESS, (uint8_t *)THUMB_CODE, sizeof(THUMB_CODE) - 1); + uc_mem_write(uc, ADDRESS, (uint8_t *)THUMB_CODE, sizeof(THUMB_CODE) - 1); // initialize machine registers - uc_reg_write(handle, UC_ARM_REG_SP, &sp); + uc_reg_write(uc, UC_ARM_REG_SP, &sp); // tracing all basic blocks with customized callback - uc_hook_add(handle, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); // tracing one instruction at ADDRESS with customized callback - uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. - err = uc_emu_start(handle, ADDRESS, ADDRESS + sizeof(THUMB_CODE) -1, UC_SECOND_SCALE * TIMEOUT, 0); + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(THUMB_CODE) -1, UC_SECOND_SCALE * TIMEOUT, 0); if (err) { printf("Failed on uc_emu_start() with error returned: %u\n", err); } @@ -133,10 +133,10 @@ static void test_thumb(void) // now print out some registers printf(">>> Emulation done. Below is the CPU context\n"); - uc_reg_read(handle, UC_ARM_REG_SP, &sp); + uc_reg_read(uc, UC_ARM_REG_SP, &sp); printf(">>> SP = 0x%x\n", sp); - uc_close(&handle); + uc_close(uc); } int main(int argc, char **argv, char **envp) diff --git a/samples/Makefile b/samples/Makefile index 1ebb891f..f6345ae8 100644 --- a/samples/Makefile +++ b/samples/Makefile @@ -97,6 +97,9 @@ endif ifneq (,$(findstring x86,$(UNICORN_ARCHS))) SOURCES += sample_x86.c SOURCES += shellcode.c +SOURCES += mem_unmap.c +SOURCES += mem_protect.c +SOURCES += mem_exec.c endif ifneq (,$(findstring m68k,$(UNICORN_ARCHS))) SOURCES += sample_m68k.c @@ -111,7 +114,8 @@ all: $(BINARY) clean: rm -rf *.o $(OBJS_ELF) $(BINARY) $(SAMPLEDIR)/*.exe $(SAMPLEDIR)/*.static $(OBJDIR)/lib$(LIBNAME)* $(OBJDIR)/$(LIBNAME)* rm -rf libunicorn*.so libunicorn*.lib libunicorn*.dylib unicorn*.dll unicorn*.lib - rm -rf sample_x86 sample_arm sample_arm64 sample_mips sample_sparc sample_ppc sample_m68k shellcode + rm -rf sample_x86 sample_arm sample_arm64 sample_mips sample_sparc sample_ppc sample_m68k \ + shellcode mem_unmap mem_protect mem_exec $(BINARY): $(OBJS) diff --git a/samples/mem_exec.c b/samples/mem_exec.c new file mode 100644 index 00000000..3b63012c --- /dev/null +++ b/samples/mem_exec.c @@ -0,0 +1,280 @@ +/* + Executable memory regions demo / unit test + + 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 +#include +#include +#include +#include +#include + +#include + +unsigned char PROGRAM[] = + "\xeb\x45\x5e\x81\xe6\x00\xf0\xff\xff\x40\x40\x40\x40\x40\x40\x40" + "\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40" + "\x40\x40\x40\x40\x40\x40\x40\x89\xf7\x81\xc7\x00\x00\x10\x00\xb9" + "\x4c\x00\x00\x00\x81\xff\x00\x00\x40\x00\x75\x01\xf4\xf3\xa4\x81" + "\xe7\x00\xf0\xff\xff\xff\xe7\xe8\xb6\xff\xff\xff"; + // total size: 76 bytes + +/* + bits 32 + + ; assumes r-x section at 0x100000 + ; assumes rw- section at 0x200000 + ; assumes r-- section at 0x300000 + ; also needs an initialized stack + +start: +jmp bottom +top: +pop esi +and esi, ~0xfff +times 30 inc eax +mov edi, esi +add edi, 0x100000 +mov ecx, end - start +rep movsb +and edi, ~0xfff +cmp edi, 0x400000 +jnz next_block +hlt +next_block: +jmp edi +bottom: +call top +end: + */ + +int test_num = 0; +uint32_t tests[] = { + 0x41414141, + 0x43434343, + 0x45454545 +}; + +static int log_num = 1; + +#define CODE_SECTION 0x100000 +#define CODE_SIZE 0x1000 + +// callback for tracing instruction +static void hook_code(ucengine *uc, uint64_t addr, uint32_t size, void *user_data) +{ + uint8_t opcode; + + if (uc_mem_read(uc, 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); + } + + // printf("ok %d - uc_mem_read for opcode at address 0x%" PRIx64 "\n", log_num++, addr); + switch (opcode) { + case 0xf4: //hlt + printf("# Handling HLT\n"); + if (uc_emu_stop(uc) != 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 + // printf("# Handling OTHER\n"); + break; + } +} + +// callback for tracing memory access (READ or WRITE) +static void hook_mem_write(ucengine *uc, 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); +} + +// callback for tracing invalid memory access (READ or WRITE) +static bool hook_mem_invalid(ucengine *uc, uc_mem_type type, + uint64_t addr, int size, int64_t value, void *user_data) +{ + switch(type) { + default: + printf("not ok %d - UC_HOOK_MEM_INVALID type: %d at 0x%" PRIx64 "\n", log_num++, type, addr); + return false; + case UC_MEM_EXEC_PROT: + printf("# Fetch from non-executable memory at 0x%"PRIx64 "\n", addr); + + //make page executable + if (uc_mem_protect(uc, addr & ~0xfffL, 0x1000, UC_PROT_READ | UC_PROT_EXEC) != UC_ERR_OK) { + printf("not ok %d - uc_mem_protect fail for address: 0x%" PRIx64 "\n", log_num++, addr); + } else { + printf("ok %d - uc_mem_protect success at 0x%" PRIx64 "\n", log_num++, addr); + } + return true; + case UC_MEM_WRITE_PROT: + printf("# write to non-writeable memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value); + + if (uc_mem_protect(uc, addr & ~0xfffL, 0x1000, UC_PROT_READ | UC_PROT_WRITE) != UC_ERR_OK) { + printf("not ok %d - uc_mem_protect fail during hook_mem_invalid callback, addr: 0x%" PRIx64 "\n", log_num++, addr); + } else { + printf("ok %d - uc_mem_protect success\n", log_num++); + } + return true; + } +} + +int main(int argc, char **argv, char **envp) +{ + ucengine *uc; + uchook trace1, trace2; + uc_err err; + uint32_t esp, eip; + int32_t buf1[1024], buf2[1024], readbuf[1024]; + int i; + + //don't really care about quality of randomness + srand(time(NULL)); + for (i = 0; i < 1024; i++) { + buf1[i] = rand(); + buf2[i] = rand(); + } + + printf("# Memory protect test\n"); + + // Initialize emulator in X86-32bit mode + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); + 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(uc, 0x100000, 0x1000, UC_PROT_READ | UC_PROT_EXEC); + uc_mem_map(uc, 0x1ff000, 0x2000, UC_PROT_READ | UC_PROT_WRITE); + uc_mem_map(uc, 0x300000, 0x2000, UC_PROT_READ); + uc_mem_map(uc, 0xf00000, 0x1000, UC_PROT_READ | UC_PROT_WRITE); + + esp = 0xf00000 + 0x1000; + + // Setup stack pointer + if (uc_reg_write(uc, UC_X86_REG_ESP, &esp)) { + printf("not ok %d - Failed to set esp. quit!\n", log_num++); + return 2; + } else { + printf("ok %d - ESP set\n", log_num++); + } + + // fill in sections that shouldn't get touched + if (uc_mem_write(uc, 0x1ff000, (uint8_t*)buf1, 4096)) { + printf("not ok %d - Failed to write random buffer 1 to memory, quit!\n", log_num++); + return 3; + } else { + printf("ok %d - Random buffer 1 written to memory\n", log_num++); + } + + if (uc_mem_write(uc, 0x301000, (uint8_t*)buf2, 4096)) { + printf("not ok %d - Failed to write random buffer 2 to memory, quit!\n", log_num++); + return 4; + } else { + printf("ok %d - Random buffer 2 written to memory\n", log_num++); + } + + // write machine code to be emulated to memory + if (uc_mem_write(uc, 0x100000, PROGRAM, sizeof(PROGRAM))) { + printf("not ok %d - Failed to write emulation code to memory, quit!\n", log_num++); + return 5; + } else { + printf("ok %d - Program written to memory\n", log_num++); + } + + if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { + printf("not ok %d - Failed to install UC_HOOK_CODE ucr\n", log_num++); + return 6; + } else { + printf("ok %d - UC_HOOK_CODE installed\n", log_num++); + } + + // intercept memory write events + if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { + printf("not ok %d - Failed to install UC_HOOK_MEM_WRITE ucr\n", log_num++); + return 7; + } else { + printf("ok %d - UC_HOOK_MEM_WRITE installed\n", log_num++); + } + + // intercept invalid memory events + if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL) != UC_ERR_OK) { + printf("not ok %d - Failed to install UC_HOOK_MEM_INVALID ucr\n", log_num++); + return 8; + } else { + printf("ok %d - UC_HOOK_MEM_INVALID installed\n", log_num++); + } + + // emulate machine code until told to stop by hook_code + printf("# BEGIN execution\n"); + err = uc_emu_start(uc, 0x100000, 0x400000, 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 9; + } else { + printf("ok %d - uc_emu_start complete\n", log_num++); + } + printf("# END execution\n"); + + // get ending EIP + if (uc_reg_read(uc, UC_X86_REG_EIP, &eip)) { + printf("not ok %d - Failed to read eip.\n", log_num++); + } else { + printf("ok %d - Ending EIP 0x%x\n", log_num++, eip); + } + + //make sure that random blocks didn't get nuked + // fill in sections that shouldn't get touched + if (uc_mem_read(uc, 0x1ff000, (uint8_t*)readbuf, 4096)) { + 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, 4096)) { + printf("not ok %d - Random buffer 1 contents are incorrect\n", log_num++); + } else { + printf("ok %d - Random buffer 1 contents are correct\n", log_num++); + } + } + + if (uc_mem_read(uc, 0x301000, (uint8_t*)readbuf, 4096)) { + printf("not ok %d - Failed to read random buffer 2 from memory\n", log_num++); + } else { + printf("ok %d - Random buffer 2 read from memory\n", log_num++); + if (memcmp(buf2, readbuf, 4096)) { + printf("not ok %d - Random buffer 2 contents are incorrect\n", log_num++); + } else { + printf("ok %d - Random buffer 2 contents are correct\n", log_num++); + } + } + + if (uc_close(uc) == 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; +} diff --git a/samples/mem_protect.c b/samples/mem_protect.c new file mode 100644 index 00000000..dfabd0fb --- /dev/null +++ b/samples/mem_protect.c @@ -0,0 +1,302 @@ +/* + uc_mem_protect demo / unit test + + 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 +#include +#include +#include +#include +#include + +#include + +unsigned char PROGRAM[] = + "\xc7\x05\x00\x00\x20\x00\x41\x41\x41\x41\x90\xc7\x05\x00\x00\x20" + "\x00\x42\x42\x42\x42\xc7\x05\x00\x00\x30\x00\x43\x43\x43\x43\x90" + "\xc7\x05\x00\x00\x30\x00\x44\x44\x44\x44\xc7\x05\x00\x00\x40\x00" + "\x45\x45\x45\x45\x90\xc7\x05\x00\x00\x40\x00\x46\x46\x46\x46\xc7" + "\x05\x00\xf8\x3f\x00\x47\x47\x47\x47\xc7\x05\x00\x18\x40\x00\x48" + "\x48\x48\x48\xf4"; + // total size: 84 bytes + +/* + bits 32 + + ; assumes code section at 0x100000 + ; assumes data section at 0x200000, initially rw + ; assumes data section at 0x300000, initially rw + ; assumes data section at 0x400000, initially rw + + ; with installed hooks unmaps or maps on each nop + + mov dword [0x200000], 0x41414141 + nop ; mark it RO + mov dword [0x200000], 0x42424242 + + mov dword [0x300000], 0x43434343 + nop ; mark it RO + mov dword [0x300000], 0x44444444 + + mov dword [0x400000], 0x45454545 + nop ; mark it RO + mov dword [0x400000], 0x46464646 + mov dword [0x3ff800], 0x47474747 ; make sure surrounding areas remained RW + mov dword [0x401800], 0x48484848 ; make sure surrounding areas remained RW + + hlt ; tell hook function we are done + */ + +int test_num = 0; +uint32_t tests[] = { + 0x41414141, + 0x43434343, + 0x45454545 +}; + +static int log_num = 1; + +#define CODE_SECTION 0x100000 +#define CODE_SIZE 0x1000 + +// callback for tracing instruction +static void hook_code(ucengine *uc, uint64_t addr, uint32_t size, void *user_data) +{ + uint8_t opcode; + uint32_t testval; + if (uc_mem_read(uc, 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); + } + printf("ok %d - uc_mem_read for opcode at address 0x%" PRIx64 "\n", log_num++, addr); + switch (opcode) { + case 0x90: //nop + printf("# Handling NOP\n"); + if (uc_mem_read(uc, 0x200000 + test_num * 0x100000, (uint8_t*)&testval, sizeof(testval)) != UC_ERR_OK) { + printf("not ok %d - uc_mem_read fail for address: 0x%x\n", log_num++, 0x200000 + test_num * 0x100000); + } else { + printf("ok %d - good uc_mem_read for address: 0x%x\n", log_num++, 0x200000 + test_num * 0x100000); + printf("# uc_mem_read for test %d\n", test_num); + + if (testval == tests[test_num]) { + printf("ok %d - passed test %d\n", log_num++, test_num); + } else { + printf("not ok %d - failed test %d\n", log_num++, test_num); + printf("# Expected: 0x%x\n",tests[test_num]); + printf("# Received: 0x%x\n", testval); + } + } + if (uc_mem_protect(uc, 0x200000 + test_num * 0x100000, 0x1000, UC_PROT_READ) != UC_ERR_OK) { + printf("not ok %d - uc_mem_protect fail during hook_code callback, addr: 0x%x\n", log_num++, 0x200000 + test_num * 0x100000); + } else { + printf("ok %d - uc_mem_protect success\n", log_num++); + } + test_num++; + break; + case 0xf4: //hlt + printf("# Handling HLT\n"); + if (uc_emu_stop(uc) != 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 + printf("# Handling OTHER\n"); + break; + } +} + +// callback for tracing memory access (READ or WRITE) +static void hook_mem_write(ucengine *uc, 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); +} + +// callback for tracing invalid memory access (READ or WRITE) +static bool hook_mem_invalid(ucengine *uc, uc_mem_type type, + uint64_t addr, int size, int64_t value, void *user_data) +{ + uint32_t testval; + switch(type) { + default: + printf("not ok %d - UC_HOOK_MEM_INVALID type: %d at 0x%" PRIx64 "\n", log_num++, type, addr); + return false; + case UC_MEM_WRITE_PROT: + printf("# write to non-writeable memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value); + + if (uc_mem_read(uc, addr, (uint8_t*)&testval, sizeof(testval)) != UC_ERR_OK) { + printf("not ok %d - uc_mem_read fail for address: 0x%" PRIx64 "\n", log_num++, addr); + } else { + printf("ok %d - uc_mem_read success after mem_protect at test %d\n", log_num++, test_num - 1); + } + + if (uc_mem_protect(uc, addr & ~0xfffL, 0x1000, UC_PROT_READ | UC_PROT_WRITE) != UC_ERR_OK) { + printf("not ok %d - uc_mem_protect fail during hook_mem_invalid callback, addr: 0x%" PRIx64 "\n", log_num++, addr); + } else { + printf("ok %d - uc_mem_protect success\n", log_num++); + } + return true; + } +} + +int main(int argc, char **argv, char **envp) +{ + ucengine *uc; + uchook trace1, trace2; + uc_err err; + uint32_t addr, testval; + int32_t buf1[1024], buf2[1024], readbuf[1024]; + int i; + + //don't really care about quality of randomness + srand(time(NULL)); + for (i = 0; i < 1024; i++) { + buf1[i] = rand(); + buf2[i] = rand(); + } + + printf("# Memory protect test\n"); + + // Initialize emulator in X86-32bit mode + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); + 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(uc, CODE_SECTION, CODE_SIZE, UC_PROT_READ | UC_PROT_EXEC); + uc_mem_map(uc, 0x200000, 0x1000, UC_PROT_READ | UC_PROT_WRITE); + uc_mem_map(uc, 0x300000, 0x1000, UC_PROT_READ | UC_PROT_WRITE); + uc_mem_map(uc, 0x3ff000, 0x3000, UC_PROT_READ | UC_PROT_WRITE); + + // fill in sections that shouldn't get touched + if (uc_mem_write(uc, 0x3ff000, (uint8_t*)buf1, 4096)) { + printf("not ok %d - Failed to write random buffer 1 to memory, quit!\n", log_num++); + return 2; + } else { + printf("ok %d - Random buffer 1 written to memory\n", log_num++); + } + + if (uc_mem_write(uc, 0x401000, (uint8_t*)buf2, 4096)) { + printf("not ok %d - Failed to write random buffer 2 to memory, quit!\n", log_num++); + return 3; + } else { + printf("ok %d - Random buffer 2 written to memory\n", log_num++); + } + + // write machine code to be emulated to memory + if (uc_mem_write(uc, CODE_SECTION, 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(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { + printf("not ok %d - Failed to install UC_HOOK_CODE ucr\n", log_num++); + return 5; + } else { + printf("ok %d - UC_HOOK_CODE installed\n", log_num++); + } + + // intercept memory write events + if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { + printf("not ok %d - Failed to install UC_HOOK_MEM_WRITE ucr\n", log_num++); + return 6; + } else { + printf("ok %d - UC_HOOK_MEM_WRITE installed\n", log_num++); + } + + // intercept invalid memory events + if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL) != UC_ERR_OK) { + printf("not ok %d - Failed to install UC_HOOK_MEM_INVALID ucr\n", log_num++); + return 7; + } else { + printf("ok %d - UC_HOOK_MEM_INVALID installed\n", log_num++); + } + + // emulate machine code until told to stop by hook_code + printf("# BEGIN execution\n"); + err = uc_emu_start(uc, CODE_SECTION, CODE_SECTION + CODE_SIZE, 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"); + + //read from the remapped memory + testval = 0x42424242; + for (addr = 0x200000; addr <= 0x400000; addr += 0x100000) { + uint32_t val; + if (uc_mem_read(uc, addr, (uint8_t*)&val, sizeof(val)) != UC_ERR_OK) { + printf("not ok %d - Failed uc_mem_read for address 0x%x\n", log_num++, addr); + } else { + printf("ok %d - Good uc_mem_read from 0x%x\n", log_num++, addr); + } + if (val != testval) { + printf("not ok %d - Read 0x%x, expected 0x%x\n", log_num++, val, testval); + } else { + printf("ok %d - Correct value retrieved\n", log_num++); + } + testval += 0x02020202; + } + + //account for the two mods made by the machine code + buf1[512] = 0x47474747; + buf2[512] = 0x48484848; + + //make sure that random blocks didn't get nuked + // fill in sections that shouldn't get touched + if (uc_mem_read(uc, 0x3ff000, (uint8_t*)readbuf, 4096)) { + 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, 4096)) { + printf("not ok %d - Random buffer 1 contents are incorrect\n", log_num++); + } else { + printf("ok %d - Random buffer 1 contents are correct\n", log_num++); + } + } + + if (uc_mem_read(uc, 0x401000, (uint8_t*)readbuf, 4096)) { + printf("not ok %d - Failed to read random buffer 2 from memory\n", log_num++); + } else { + printf("ok %d - Random buffer 2 read from memory\n", log_num++); + if (memcmp(buf2, readbuf, 4096)) { + printf("not ok %d - Random buffer 2 contents are incorrect\n", log_num++); + } else { + printf("ok %d - Random buffer 2 contents are correct\n", log_num++); + } + } + + if (uc_close(uc) == 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; +} diff --git a/samples/mem_unmap.c b/samples/mem_unmap.c new file mode 100644 index 00000000..0bf61911 --- /dev/null +++ b/samples/mem_unmap.c @@ -0,0 +1,293 @@ +/* + + uc_mem_unmap demo / unit test + + 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 +#include +#include +#include +#include +#include + +#include + +unsigned char PROGRAM[] = + "\xc7\x05\x00\x00\x20\x00\x41\x41\x41\x41\x90\xc7\x05\x00\x00\x20" + "\x00\x42\x42\x42\x42\xc7\x05\x00\x00\x30\x00\x43\x43\x43\x43\x90" + "\xc7\x05\x00\x00\x30\x00\x44\x44\x44\x44\xc7\x05\x00\x00\x40\x00" + "\x45\x45\x45\x45\x90\xc7\x05\x00\x00\x40\x00\x46\x46\x46\x46\xf4"; + // total size: 64 bytes + +/* + ; assumes code section at 0x100000 + ; assumes data section at 0x200000, initially rw + ; assumes data section at 0x300000, initially rw + ; assumes data section at 0x400000, initially rw + + ; with installed hooks unmaps or maps on each nop + + mov dword [0x200000], 0x41414141 + nop ; unmap it + mov dword [0x200000], 0x42424242 + + mov dword [0x300000], 0x43434343 + nop ; unmap it + mov dword [0x300000], 0x44444444 + + mov dword [0x400000], 0x45454545 + nop ; unmap it + mov dword [0x400000], 0x46464646 + + hlt ; tell hook function we are done + */ + +int test_num = 0; +uint32_t tests[] = { + 0x41414141, + 0x43434343, + 0x45454545 +}; + +static int log_num = 1; + +#define CODE_SECTION 0x100000 +#define CODE_SIZE 0x1000 + +// callback for tracing instruction +static void hook_code(ucengine *uc, uint64_t addr, uint32_t size, void *user_data) +{ + uint8_t opcode; + uint32_t testval; + if (uc_mem_read(uc, 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); + } + printf("ok %d - uc_mem_read for opcode at address 0x%" PRIx64 "\n", log_num++, addr); + switch (opcode) { + case 0x90: //nop + printf("# Handling NOP\n"); + if (uc_mem_read(uc, 0x200000 + test_num * 0x100000, (uint8_t*)&testval, sizeof(testval)) != UC_ERR_OK) { + printf("not ok %d - uc_mem_read fail for address: 0x%x\n", log_num++, 0x200000 + test_num * 0x100000); + } else { + printf("ok %d - good uc_mem_read for address: 0x%x\n", log_num++, 0x200000 + test_num * 0x100000); + printf("# uc_mem_read for test %d\n", test_num); + + if (testval == tests[test_num]) { + printf("ok %d - passed test %d\n", log_num++, test_num); + } else { + printf("not ok %d - failed test %d\n", log_num++, test_num); + printf("# Expected: 0x%x\n",tests[test_num]); + printf("# Received: 0x%x\n", testval); + } + } + if (uc_mem_unmap(uc, 0x200000 + test_num * 0x100000, 0x1000) != UC_ERR_OK) { + printf("not ok %d - uc_mem_unmap fail during hook_code callback, addr: 0x%x\n", log_num++, 0x200000 + test_num * 0x100000); + } else { + printf("ok %d - uc_mem_unmap success\n", log_num++); + } + test_num++; + break; + case 0xf4: //hlt + printf("# Handling HLT\n"); + if (uc_emu_stop(uc) != 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 + printf("# Handling OTHER\n"); + break; + } +} + +// callback for tracing memory access (READ or WRITE) +static void hook_mem_write(ucengine *uc, 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); +} + +// callback for tracing invalid memory access (READ or WRITE) +static bool hook_mem_invalid(ucengine *uc, uc_mem_type type, + uint64_t addr, int size, int64_t value, void *user_data) +{ + uint32_t testval; + switch(type) { + default: + printf("not ok %d - UC_HOOK_MEM_INVALID type: %d at 0x%" PRIx64 "\n", log_num++, type, addr); + return false; + case UC_MEM_WRITE: + printf("# write to invalid memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value); + + if (uc_mem_read(uc, addr, (uint8_t*)&testval, sizeof(testval)) != UC_ERR_OK) { + printf("ok %d - uc_mem_read fail for address: 0x%" PRIx64 "\n", log_num++, addr); + } else { + printf("not ok %d - uc_mem_read success after unmap at test %d\n", log_num++, test_num - 1); + } + + if (uc_mem_map(uc, addr & ~0xfffL, 0x1000, UC_PROT_READ | UC_PROT_WRITE) != UC_ERR_OK) { + printf("not ok %d - uc_mem_map fail during hook_mem_invalid callback, addr: 0x%" PRIx64 "\n", log_num++, addr); + } else { + printf("ok %d - uc_mem_map success\n", log_num++); + } + return true; + } +} + +int main(int argc, char **argv, char **envp) +{ + ucengine *uc; + uchook trace1, trace2; + uc_err err; + uint32_t addr, testval; + int32_t buf1[1024], buf2[1024], readbuf[1024]; + int i; + + //don't really care about quality of randomness + srand(time(NULL)); + for (i = 0; i < 1024; i++) { + buf1[i] = rand(); + buf2[i] = rand(); + } + + printf("# Memory unmapping test\n"); + + // Initialize emulator in X86-32bit mode + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); + 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(uc, CODE_SECTION, CODE_SIZE, UC_PROT_READ | UC_PROT_EXEC); + uc_mem_map(uc, 0x200000, 0x1000, UC_PROT_READ | UC_PROT_WRITE); + uc_mem_map(uc, 0x300000, 0x1000, UC_PROT_READ | UC_PROT_WRITE); + uc_mem_map(uc, 0x3ff000, 0x3000, UC_PROT_READ | UC_PROT_WRITE); + + // fill in sections that shouldn't get touched + if (uc_mem_write(uc, 0x3ff000, (uint8_t*)buf1, 4096)) { + printf("not ok %d - Failed to write random buffer 1 to memory, quit!\n", log_num++); + return 2; + } else { + printf("ok %d - Random buffer 1 written to memory\n", log_num++); + } + + if (uc_mem_write(uc, 0x401000, (uint8_t*)buf2, 4096)) { + printf("not ok %d - Failed to write random buffer 2 to memory, quit!\n", log_num++); + return 3; + } else { + printf("ok %d - Random buffer 2 written to memory\n", log_num++); + } + + // write machine code to be emulated to memory + if (uc_mem_write(uc, CODE_SECTION, 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(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { + printf("not ok %d - Failed to install UC_HOOK_CODE ucr\n", log_num++); + return 5; + } else { + printf("ok %d - UC_HOOK_CODE installed\n", log_num++); + } + + // intercept memory write events + if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { + printf("not ok %d - Failed to install UC_HOOK_MEM_WRITE ucr\n", log_num++); + return 6; + } else { + printf("ok %d - UC_HOOK_MEM_WRITE installed\n", log_num++); + } + + // intercept invalid memory events + if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL) != UC_ERR_OK) { + printf("not ok %d - Failed to install UC_HOOK_MEM_INVALID ucr\n", log_num++); + return 7; + } else { + printf("ok %d - UC_HOOK_MEM_INVALID installed\n", log_num++); + } + + // emulate machine code until told to stop by hook_code + printf("# BEGIN execution\n"); + err = uc_emu_start(uc, CODE_SECTION, CODE_SECTION + CODE_SIZE, 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"); + + //read from the remapped memory + testval = 0x42424242; + for (addr = 0x200000; addr <= 0x400000; addr += 0x100000) { + uint32_t val; + if (uc_mem_read(uc, addr, (uint8_t*)&val, sizeof(val)) != UC_ERR_OK) { + printf("not ok %d - Failed uc_mem_read for address 0x%x\n", log_num++, addr); + } else { + printf("ok %d - Good uc_mem_read from 0x%x\n", log_num++, addr); + } + if (val != testval) { + printf("not ok %d - Read 0x%x, expected 0x%x\n", log_num++, val, testval); + } else { + printf("ok %d - Correct value retrieved\n", log_num++); + } + testval += 0x02020202; + } + + //make sure that random blocks didn't get nuked + // fill in sections that shouldn't get touched + if (uc_mem_read(uc, 0x3ff000, (uint8_t*)readbuf, 4096)) { + 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, 4096)) { + printf("not ok %d - Random buffer 1 contents are incorrect\n", log_num++); + } else { + printf("ok %d - Random buffer 1 contents are correct\n", log_num++); + } + } + + if (uc_mem_read(uc, 0x401000, (uint8_t*)readbuf, 4096)) { + printf("not ok %d - Failed to read random buffer 2 from memory\n", log_num++); + } else { + printf("ok %d - Random buffer 2 read from memory\n", log_num++); + if (memcmp(buf2, readbuf, 4096)) { + printf("not ok %d - Random buffer 2 contents are incorrect\n", log_num++); + } else { + printf("ok %d - Random buffer 2 contents are correct\n", log_num++); + } + } + + if (uc_close(uc) == 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; +} diff --git a/samples/sample_arm.c b/samples/sample_arm.c index 173e8167..81ec691b 100644 --- a/samples/sample_arm.c +++ b/samples/sample_arm.c @@ -15,21 +15,21 @@ // memory address where emulation starts #define ADDRESS 0x10000 -static void hook_block(uch handle, uint64_t address, uint32_t size, void *user_data) +static void hook_block(ucengine *uc, uint64_t address, uint32_t size, void *user_data) { printf(">>> Tracing basic block at 0x%"PRIx64 ", block size = 0x%x\n", address, size); } -static void hook_code(uch handle, uint64_t address, uint32_t size, void *user_data) +static void hook_code(ucengine *uc, uint64_t address, uint32_t size, void *user_data) { printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); } static void test_arm(void) { - uch handle; + ucengine *uc; uc_err err; - uch trace1, trace2; + uchook trace1, trace2; int r0 = 0x1234; // R0 register int r2 = 0x6789; // R1 register @@ -39,7 +39,7 @@ static void test_arm(void) printf("Emulate ARM code\n"); // Initialize emulator in ARM mode - err = uc_open(UC_ARCH_ARM, UC_MODE_ARM, &handle); + err = uc_open(UC_ARCH_ARM, UC_MODE_ARM, &uc); if (err) { printf("Failed on uc_open() with error returned: %u (%s)\n", err, uc_strerror(err)); @@ -47,25 +47,25 @@ static void test_arm(void) } // map 2MB memory for this emulation - uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory - uc_mem_write(handle, ADDRESS, (uint8_t *)ARM_CODE, sizeof(ARM_CODE) - 1); + uc_mem_write(uc, ADDRESS, (uint8_t *)ARM_CODE, sizeof(ARM_CODE) - 1); // initialize machine registers - uc_reg_write(handle, UC_ARM_REG_R0, &r0); - uc_reg_write(handle, UC_ARM_REG_R2, &r2); - uc_reg_write(handle, UC_ARM_REG_R3, &r3); + uc_reg_write(uc, UC_ARM_REG_R0, &r0); + uc_reg_write(uc, UC_ARM_REG_R2, &r2); + uc_reg_write(uc, UC_ARM_REG_R3, &r3); // tracing all basic blocks with customized callback - uc_hook_add(handle, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); // tracing one instruction at ADDRESS with customized callback - uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. - err = uc_emu_start(handle, ADDRESS, ADDRESS + sizeof(ARM_CODE) -1, 0, 0); + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(ARM_CODE) -1, 0, 0); if (err) { printf("Failed on uc_emu_start() with error returned: %u\n", err); } @@ -73,26 +73,26 @@ static void test_arm(void) // now print out some registers printf(">>> Emulation done. Below is the CPU context\n"); - uc_reg_read(handle, UC_ARM_REG_R0, &r0); - uc_reg_read(handle, UC_ARM_REG_R1, &r1); + uc_reg_read(uc, UC_ARM_REG_R0, &r0); + uc_reg_read(uc, UC_ARM_REG_R1, &r1); printf(">>> R0 = 0x%x\n", r0); printf(">>> R1 = 0x%x\n", r1); - uc_close(&handle); + uc_close(uc); } static void test_thumb(void) { - uch handle; + ucengine *uc; uc_err err; - uch trace1, trace2; + uchook trace1, trace2; int sp = 0x1234; // R0 register printf("Emulate THUMB code\n"); // Initialize emulator in ARM mode - err = uc_open(UC_ARCH_ARM, UC_MODE_THUMB, &handle); + err = uc_open(UC_ARCH_ARM, UC_MODE_THUMB, &uc); if (err) { printf("Failed on uc_open() with error returned: %u (%s)\n", err, uc_strerror(err)); @@ -100,23 +100,23 @@ static void test_thumb(void) } // map 2MB memory for this emulation - uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory - uc_mem_write(handle, ADDRESS, (uint8_t *)THUMB_CODE, sizeof(THUMB_CODE) - 1); + uc_mem_write(uc, ADDRESS, (uint8_t *)THUMB_CODE, sizeof(THUMB_CODE) - 1); // initialize machine registers - uc_reg_write(handle, UC_ARM_REG_SP, &sp); + uc_reg_write(uc, UC_ARM_REG_SP, &sp); // tracing all basic blocks with customized callback - uc_hook_add(handle, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); // tracing one instruction at ADDRESS with customized callback - uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. - err = uc_emu_start(handle, ADDRESS, ADDRESS + sizeof(THUMB_CODE) -1, 0, 0); + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(THUMB_CODE) -1, 0, 0); if (err) { printf("Failed on uc_emu_start() with error returned: %u\n", err); } @@ -124,10 +124,10 @@ static void test_thumb(void) // now print out some registers printf(">>> Emulation done. Below is the CPU context\n"); - uc_reg_read(handle, UC_ARM_REG_SP, &sp); + uc_reg_read(uc, UC_ARM_REG_SP, &sp); printf(">>> SP = 0x%x\n", sp); - uc_close(&handle); + uc_close(uc); } int main(int argc, char **argv, char **envp) diff --git a/samples/sample_arm64.c b/samples/sample_arm64.c index b0d1608a..3541b2f6 100644 --- a/samples/sample_arm64.c +++ b/samples/sample_arm64.c @@ -14,21 +14,21 @@ // memory address where emulation starts #define ADDRESS 0x10000 -static void hook_block(uch handle, uint64_t address, uint32_t size, void *user_data) +static void hook_block(ucengine *uc, uint64_t address, uint32_t size, void *user_data) { printf(">>> Tracing basic block at 0x%"PRIx64 ", block size = 0x%x\n", address, size); } -static void hook_code(uch handle, uint64_t address, uint32_t size, void *user_data) +static void hook_code(ucengine *uc, uint64_t address, uint32_t size, void *user_data) { printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); } static void test_arm64(void) { - uch handle; + ucengine *uc; uc_err err; - uch trace1, trace2; + uchook trace1, trace2; int64_t x11 = 0x1234; // X11 register int64_t x13 = 0x6789; // X13 register @@ -37,7 +37,7 @@ static void test_arm64(void) printf("Emulate ARM64 code\n"); // Initialize emulator in ARM mode - err = uc_open(UC_ARCH_ARM64, UC_MODE_ARM, &handle); + err = uc_open(UC_ARCH_ARM64, UC_MODE_ARM, &uc); if (err) { printf("Failed on uc_open() with error returned: %u (%s)\n", err, uc_strerror(err)); @@ -45,25 +45,25 @@ static void test_arm64(void) } // map 2MB memory for this emulation - uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory - uc_mem_write(handle, ADDRESS, (uint8_t *)ARM_CODE, sizeof(ARM_CODE) - 1); + uc_mem_write(uc, ADDRESS, (uint8_t *)ARM_CODE, sizeof(ARM_CODE) - 1); // initialize machine registers - uc_reg_write(handle, UC_ARM64_REG_X11, &x11); - uc_reg_write(handle, UC_ARM64_REG_X13, &x13); - uc_reg_write(handle, UC_ARM64_REG_X15, &x15); + uc_reg_write(uc, UC_ARM64_REG_X11, &x11); + uc_reg_write(uc, UC_ARM64_REG_X13, &x13); + uc_reg_write(uc, UC_ARM64_REG_X15, &x15); // tracing all basic blocks with customized callback - uc_hook_add(handle, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); // tracing one instruction at ADDRESS with customized callback - uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. - err = uc_emu_start(handle, ADDRESS, ADDRESS + sizeof(ARM_CODE) -1, 0, 0); + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(ARM_CODE) -1, 0, 0); if (err) { printf("Failed on uc_emu_start() with error returned: %u\n", err); } @@ -71,10 +71,10 @@ static void test_arm64(void) // now print out some registers printf(">>> Emulation done. Below is the CPU context\n"); - uc_reg_read(handle, UC_ARM64_REG_X11, &x11); + uc_reg_read(uc, UC_ARM64_REG_X11, &x11); printf(">>> X11 = 0x%" PRIx64 "\n", x11); - uc_close(&handle); + uc_close(uc); } int main(int argc, char **argv, char **envp) diff --git a/samples/sample_m68k.c b/samples/sample_m68k.c index 82b06eb6..b8fef353 100644 --- a/samples/sample_m68k.c +++ b/samples/sample_m68k.c @@ -12,20 +12,20 @@ // memory address where emulation starts #define ADDRESS 0x10000 -static void hook_block(uch handle, uint64_t address, uint32_t size, void *user_data) +static void hook_block(ucengine *uc, uint64_t address, uint32_t size, void *user_data) { printf(">>> Tracing basic block at 0x%"PRIx64 ", block size = 0x%x\n", address, size); } -static void hook_code(uch handle, uint64_t address, uint32_t size, void *user_data) +static void hook_code(ucengine *uc, uint64_t address, uint32_t size, void *user_data) { printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); } static void test_m68k(void) { - uch handle; - uch trace1, trace2; + ucengine *uc; + uchook trace1, trace2; uc_err err; int d0 = 0x0000; // d0 data register @@ -52,7 +52,7 @@ static void test_m68k(void) printf("Emulate M68K code\n"); // Initialize emulator in M68K mode - err = uc_open(UC_ARCH_M68K, UC_MODE_BIG_ENDIAN, &handle); + err = uc_open(UC_ARCH_M68K, UC_MODE_BIG_ENDIAN, &uc); if (err) { printf("Failed on uc_open() with error returned: %u (%s)\n", err, uc_strerror(err)); @@ -60,42 +60,42 @@ static void test_m68k(void) } // map 2MB memory for this emulation - uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory - uc_mem_write(handle, ADDRESS, (uint8_t *)M68K_CODE, sizeof(M68K_CODE) - 1); + uc_mem_write(uc, ADDRESS, (uint8_t *)M68K_CODE, sizeof(M68K_CODE) - 1); // initialize machine registers - uc_reg_write(handle, UC_M68K_REG_D0, &d0); - uc_reg_write(handle, UC_M68K_REG_D1, &d1); - uc_reg_write(handle, UC_M68K_REG_D2, &d2); - uc_reg_write(handle, UC_M68K_REG_D3, &d3); - uc_reg_write(handle, UC_M68K_REG_D4, &d4); - uc_reg_write(handle, UC_M68K_REG_D5, &d5); - uc_reg_write(handle, UC_M68K_REG_D6, &d6); - uc_reg_write(handle, UC_M68K_REG_D7, &d7); + uc_reg_write(uc, UC_M68K_REG_D0, &d0); + uc_reg_write(uc, UC_M68K_REG_D1, &d1); + uc_reg_write(uc, UC_M68K_REG_D2, &d2); + uc_reg_write(uc, UC_M68K_REG_D3, &d3); + uc_reg_write(uc, UC_M68K_REG_D4, &d4); + uc_reg_write(uc, UC_M68K_REG_D5, &d5); + uc_reg_write(uc, UC_M68K_REG_D6, &d6); + uc_reg_write(uc, UC_M68K_REG_D7, &d7); - uc_reg_write(handle, UC_M68K_REG_A0, &a0); - uc_reg_write(handle, UC_M68K_REG_A1, &a1); - uc_reg_write(handle, UC_M68K_REG_A2, &a2); - uc_reg_write(handle, UC_M68K_REG_A3, &a3); - uc_reg_write(handle, UC_M68K_REG_A4, &a4); - uc_reg_write(handle, UC_M68K_REG_A5, &a5); - uc_reg_write(handle, UC_M68K_REG_A6, &a6); - uc_reg_write(handle, UC_M68K_REG_A7, &a7); + uc_reg_write(uc, UC_M68K_REG_A0, &a0); + uc_reg_write(uc, UC_M68K_REG_A1, &a1); + uc_reg_write(uc, UC_M68K_REG_A2, &a2); + uc_reg_write(uc, UC_M68K_REG_A3, &a3); + uc_reg_write(uc, UC_M68K_REG_A4, &a4); + uc_reg_write(uc, UC_M68K_REG_A5, &a5); + uc_reg_write(uc, UC_M68K_REG_A6, &a6); + uc_reg_write(uc, UC_M68K_REG_A7, &a7); - uc_reg_write(handle, UC_M68K_REG_PC, &pc); - uc_reg_write(handle, UC_M68K_REG_SR, &sr); + uc_reg_write(uc, UC_M68K_REG_PC, &pc); + uc_reg_write(uc, UC_M68K_REG_SR, &sr); // tracing all basic blocks with customized callback - uc_hook_add(handle, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); // tracing all instruction - uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. - err = uc_emu_start(handle, ADDRESS, ADDRESS + sizeof(M68K_CODE)-1, 0, 0); + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(M68K_CODE)-1, 0, 0); if (err) { printf("Failed on uc_emu_start() with error returned: %u\n", err); } @@ -103,26 +103,26 @@ static void test_m68k(void) // now print out some registers printf(">>> Emulation done. Below is the CPU context\n"); - uc_reg_read(handle, UC_M68K_REG_D0, &d0); - uc_reg_read(handle, UC_M68K_REG_D1, &d1); - uc_reg_read(handle, UC_M68K_REG_D2, &d2); - uc_reg_read(handle, UC_M68K_REG_D3, &d3); - uc_reg_read(handle, UC_M68K_REG_D4, &d4); - uc_reg_read(handle, UC_M68K_REG_D5, &d5); - uc_reg_read(handle, UC_M68K_REG_D6, &d6); - uc_reg_read(handle, UC_M68K_REG_D7, &d7); + uc_reg_read(uc, UC_M68K_REG_D0, &d0); + uc_reg_read(uc, UC_M68K_REG_D1, &d1); + uc_reg_read(uc, UC_M68K_REG_D2, &d2); + uc_reg_read(uc, UC_M68K_REG_D3, &d3); + uc_reg_read(uc, UC_M68K_REG_D4, &d4); + uc_reg_read(uc, UC_M68K_REG_D5, &d5); + uc_reg_read(uc, UC_M68K_REG_D6, &d6); + uc_reg_read(uc, UC_M68K_REG_D7, &d7); - uc_reg_read(handle, UC_M68K_REG_A0, &a0); - uc_reg_read(handle, UC_M68K_REG_A1, &a1); - uc_reg_read(handle, UC_M68K_REG_A2, &a2); - uc_reg_read(handle, UC_M68K_REG_A3, &a3); - uc_reg_read(handle, UC_M68K_REG_A4, &a4); - uc_reg_read(handle, UC_M68K_REG_A5, &a5); - uc_reg_read(handle, UC_M68K_REG_A6, &a6); - uc_reg_read(handle, UC_M68K_REG_A7, &a7); + uc_reg_read(uc, UC_M68K_REG_A0, &a0); + uc_reg_read(uc, UC_M68K_REG_A1, &a1); + uc_reg_read(uc, UC_M68K_REG_A2, &a2); + uc_reg_read(uc, UC_M68K_REG_A3, &a3); + uc_reg_read(uc, UC_M68K_REG_A4, &a4); + uc_reg_read(uc, UC_M68K_REG_A5, &a5); + uc_reg_read(uc, UC_M68K_REG_A6, &a6); + uc_reg_read(uc, UC_M68K_REG_A7, &a7); - uc_reg_read(handle, UC_M68K_REG_PC, &pc); - uc_reg_read(handle, UC_M68K_REG_SR, &sr); + uc_reg_read(uc, UC_M68K_REG_PC, &pc); + uc_reg_read(uc, UC_M68K_REG_SR, &sr); printf(">>> A0 = 0x%x\t\t>>> D0 = 0x%x\n", a0, d0); printf(">>> A1 = 0x%x\t\t>>> D1 = 0x%x\n", a1, d1); @@ -135,7 +135,7 @@ static void test_m68k(void) printf(">>> PC = 0x%x\n", pc); printf(">>> SR = 0x%x\n", sr); - uc_close(&handle); + uc_close(uc); } int main(int argc, char **argv, char **envp) diff --git a/samples/sample_mips.c b/samples/sample_mips.c index c9d00216..e604563c 100644 --- a/samples/sample_mips.c +++ b/samples/sample_mips.c @@ -15,28 +15,28 @@ // memory address where emulation starts #define ADDRESS 0x10000 -static void hook_block(uch handle, uint64_t address, uint32_t size, void *user_data) +static void hook_block(ucengine *uc, uint64_t address, uint32_t size, void *user_data) { printf(">>> Tracing basic block at 0x%"PRIx64 ", block size = 0x%x\n", address, size); } -static void hook_code(uch handle, uint64_t address, uint32_t size, void *user_data) +static void hook_code(ucengine *uc, uint64_t address, uint32_t size, void *user_data) { printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); } static void test_mips_eb(void) { - uch handle; + ucengine *uc; uc_err err; - uch trace1, trace2; + uchook trace1, trace2; int r1 = 0x6789; // R1 register printf("Emulate MIPS code (big-endian)\n"); // Initialize emulator in MIPS mode - err = uc_open(UC_ARCH_MIPS, UC_MODE_MIPS32 + UC_MODE_BIG_ENDIAN, &handle); + err = uc_open(UC_ARCH_MIPS, UC_MODE_MIPS32 + UC_MODE_BIG_ENDIAN, &uc); if (err) { printf("Failed on uc_open() with error returned: %u (%s)\n", err, uc_strerror(err)); @@ -44,23 +44,23 @@ static void test_mips_eb(void) } // map 2MB memory for this emulation - uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory - uc_mem_write(handle, ADDRESS, (uint8_t *)MIPS_CODE_EB, sizeof(MIPS_CODE_EB) - 1); + uc_mem_write(uc, ADDRESS, (uint8_t *)MIPS_CODE_EB, sizeof(MIPS_CODE_EB) - 1); // initialize machine registers - uc_reg_write(handle, UC_MIPS_REG_1, &r1); + uc_reg_write(uc, UC_MIPS_REG_1, &r1); // tracing all basic blocks with customized callback - uc_hook_add(handle, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); // tracing one instruction at ADDRESS with customized callback - uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. - err = uc_emu_start(handle, ADDRESS, ADDRESS + sizeof(MIPS_CODE_EB) - 1, 0, 0); + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(MIPS_CODE_EB) - 1, 0, 0); if (err) { printf("Failed on uc_emu_start() with error returned: %u (%s)\n", err, uc_strerror(err)); } @@ -68,17 +68,17 @@ static void test_mips_eb(void) // now print out some registers printf(">>> Emulation done. Below is the CPU context\n"); - uc_reg_read(handle, UC_MIPS_REG_1, &r1); + uc_reg_read(uc, UC_MIPS_REG_1, &r1); printf(">>> R1 = 0x%x\n", r1); - uc_close(&handle); + uc_close(uc); } static void test_mips_el(void) { - uch handle; + ucengine *uc; uc_err err; - uch trace1, trace2; + uchook trace1, trace2; int r1 = 0x6789; // R1 register @@ -86,7 +86,7 @@ static void test_mips_el(void) printf("Emulate MIPS code (little-endian)\n"); // Initialize emulator in MIPS mode - err = uc_open(UC_ARCH_MIPS, UC_MODE_MIPS32, &handle); + err = uc_open(UC_ARCH_MIPS, UC_MODE_MIPS32, &uc); if (err) { printf("Failed on uc_open() with error returned: %u (%s)\n", err, uc_strerror(err)); @@ -94,23 +94,23 @@ static void test_mips_el(void) } // map 2MB memory for this emulation - uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory - uc_mem_write(handle, ADDRESS, (uint8_t *)MIPS_CODE_EL, sizeof(MIPS_CODE_EL) - 1); + uc_mem_write(uc, ADDRESS, (uint8_t *)MIPS_CODE_EL, sizeof(MIPS_CODE_EL) - 1); // initialize machine registers - uc_reg_write(handle, UC_MIPS_REG_1, &r1); + uc_reg_write(uc, UC_MIPS_REG_1, &r1); // tracing all basic blocks with customized callback - uc_hook_add(handle, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); // tracing one instruction at ADDRESS with customized callback - uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. - err = uc_emu_start(handle, ADDRESS, ADDRESS + sizeof(MIPS_CODE_EL) - 1, 0, 0); + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(MIPS_CODE_EL) - 1, 0, 0); if (err) { printf("Failed on uc_emu_start() with error returned: %u (%s)\n", err, uc_strerror(err)); } @@ -118,10 +118,10 @@ static void test_mips_el(void) // now print out some registers printf(">>> Emulation done. Below is the CPU context\n"); - uc_reg_read(handle, UC_MIPS_REG_1, &r1); + uc_reg_read(uc, UC_MIPS_REG_1, &r1); printf(">>> R1 = 0x%x\n", r1); - uc_close(&handle); + uc_close(uc); } int main(int argc, char **argv, char **envp) diff --git a/samples/sample_sparc.c b/samples/sample_sparc.c index c7f2971a..540b7d36 100644 --- a/samples/sample_sparc.c +++ b/samples/sample_sparc.c @@ -15,21 +15,21 @@ // memory address where emulation starts #define ADDRESS 0x10000 -static void hook_block(uch handle, uint64_t address, uint32_t size, void *user_data) +static void hook_block(ucengine *uc, uint64_t address, uint32_t size, void *user_data) { printf(">>> Tracing basic block at 0x%"PRIx64 ", block size = 0x%x\n", address, size); } -static void hook_code(uch handle, uint64_t address, uint32_t size, void *user_data) +static void hook_code(ucengine *uc, uint64_t address, uint32_t size, void *user_data) { printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); } static void test_sparc(void) { - uch handle; + ucengine *uc; uc_err err; - uch trace1, trace2; + uchook trace1, trace2; int g1 = 0x1230; // G1 register int g2 = 0x6789; // G2 register @@ -38,7 +38,7 @@ static void test_sparc(void) printf("Emulate SPARC code\n"); // Initialize emulator in Sparc mode - err = uc_open(UC_ARCH_SPARC, UC_MODE_BIG_ENDIAN, &handle); + err = uc_open(UC_ARCH_SPARC, UC_MODE_BIG_ENDIAN, &uc); if (err) { printf("Failed on uc_open() with error returned: %u (%s)\n", err, uc_strerror(err)); @@ -46,25 +46,25 @@ static void test_sparc(void) } // map 2MB memory for this emulation - uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory - uc_mem_write(handle, ADDRESS, (uint8_t *)SPARC_CODE, sizeof(SPARC_CODE) - 1); + uc_mem_write(uc, ADDRESS, (uint8_t *)SPARC_CODE, sizeof(SPARC_CODE) - 1); // initialize machine registers - uc_reg_write(handle, UC_SPARC_REG_G1, &g1); - uc_reg_write(handle, UC_SPARC_REG_G2, &g2); - uc_reg_write(handle, UC_SPARC_REG_G3, &g3); + uc_reg_write(uc, UC_SPARC_REG_G1, &g1); + uc_reg_write(uc, UC_SPARC_REG_G2, &g2); + uc_reg_write(uc, UC_SPARC_REG_G3, &g3); // tracing all basic blocks with customized callback - uc_hook_add(handle, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); // tracing one instruction at ADDRESS with customized callback - uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. - err = uc_emu_start(handle, ADDRESS, ADDRESS + sizeof(SPARC_CODE) -1, 0, 0); + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(SPARC_CODE) - 1, 0, 0); if (err) { printf("Failed on uc_emu_start() with error returned: %u (%s)\n", err, uc_strerror(err)); @@ -73,10 +73,10 @@ static void test_sparc(void) // now print out some registers printf(">>> Emulation done. Below is the CPU context\n"); - uc_reg_read(handle, UC_SPARC_REG_G3, &g3); + uc_reg_read(uc, UC_SPARC_REG_G3, &g3); printf(">>> G3 = 0x%x\n", g3); - uc_close(&handle); + uc_close(uc); } int main(int argc, char **argv, char **envp) diff --git a/samples/sample_x86.c b/samples/sample_x86.c index 9133dc3a..aecad6b5 100644 --- a/samples/sample_x86.c +++ b/samples/sample_x86.c @@ -32,41 +32,41 @@ #define ADDRESS 0x1000000 // callback for tracing basic blocks -static void hook_block(uch handle, uint64_t address, uint32_t size, void *user_data) +static void hook_block(ucengine *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(uch handle, uint64_t address, uint32_t size, void *user_data) +static void hook_code(ucengine *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(handle, UC_X86_REG_EFLAGS, &eflags); + 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(handle); + // uc_emu_stop(uc); } // callback for tracing instruction -static void hook_code64(uch handle, uint64_t address, uint32_t size, void *user_data) +static void hook_code64(ucengine *uc, uint64_t address, uint32_t size, void *user_data) { uint64_t rip; - uc_reg_read(handle, UC_X86_REG_RIP, &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(handle); + // uc_emu_stop(uc); } // callback for tracing memory access (READ or WRITE) -static bool hook_mem_invalid(uch handle, uc_mem_type type, +static bool hook_mem_invalid(ucengine *uc, uc_mem_type type, uint64_t address, int size, int64_t value, void *user_data) { switch(type) { @@ -77,13 +77,13 @@ static bool hook_mem_invalid(uch handle, uc_mem_type type, 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(handle, 0xaaaa0000, 2 * 1024*1024, UC_PROT_ALL); + 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(uch handle, uc_mem_type type, +static void hook_mem64(ucengine *uc, uc_mem_type type, uint64_t address, int size, int64_t value, void *user_data) { switch(type) { @@ -101,11 +101,11 @@ static void hook_mem64(uch handle, uc_mem_type type, // callback for IN instruction (X86). // this returns the data read from the port -static uint32_t hook_in(uch handle, uint32_t port, int size, void *user_data) +static uint32_t hook_in(ucengine *uc, uint32_t port, int size, void *user_data) { uint32_t eip; - uc_reg_read(handle, UC_X86_REG_EIP, &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); @@ -126,12 +126,12 @@ static uint32_t hook_in(uch handle, uint32_t port, int size, void *user_data) } // callback for OUT instruction (X86). -static void hook_out(uch handle, uint32_t port, int size, uint32_t value, void *user_data) +static void hook_out(ucengine *uc, uint32_t port, int size, uint32_t value, void *user_data) { uint32_t tmp; uint32_t eip; - uc_reg_read(handle, UC_X86_REG_EIP, &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); @@ -140,13 +140,13 @@ static void hook_out(uch handle, uint32_t port, int size, uint32_t value, void * default: return; // should never reach this case 1: - uc_reg_read(handle, UC_X86_REG_AL, &tmp); + uc_reg_read(uc, UC_X86_REG_AL, &tmp); break; case 2: - uc_reg_read(handle, UC_X86_REG_AX, &tmp); + uc_reg_read(uc, UC_X86_REG_AX, &tmp); break; case 4: - uc_reg_read(handle, UC_X86_REG_EAX, &tmp); + uc_reg_read(uc, UC_X86_REG_EAX, &tmp); break; } @@ -154,24 +154,24 @@ static void hook_out(uch handle, uint32_t port, int size, uint32_t value, void * } // callback for SYSCALL instruction (X86). -static void hook_syscall(uch handle, void *user_data) +static void hook_syscall(ucengine *uc, void *user_data) { uint64_t rax; - uc_reg_read(handle, UC_X86_REG_RAX, &rax); + uc_reg_read(uc, UC_X86_REG_RAX, &rax); if (rax == 0x100) { rax = 0x200; - uc_reg_write(handle, UC_X86_REG_RAX, &rax); + 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) { - uch handle; + ucengine *uc; uc_err err; uint32_t tmp; - uch trace1, trace2; + uchook trace1, trace2; int r_ecx = 0x1234; // ECX register int r_edx = 0x7890; // EDX register @@ -179,33 +179,33 @@ static void test_i386(void) printf("Emulate i386 code\n"); // Initialize emulator in X86-32bit mode - err = uc_open(UC_ARCH_X86, UC_MODE_32, &handle); + 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(handle, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory - if (uc_mem_write(handle, ADDRESS, (uint8_t *)X86_CODE32, sizeof(X86_CODE32) - 1)) { + if (uc_mem_write(uc, ADDRESS, (uint8_t *)X86_CODE32, sizeof(X86_CODE32) - 1)) { printf("Failed to write emulation code to memory, quit!\n"); return; } // initialize machine registers - uc_reg_write(handle, UC_X86_REG_ECX, &r_ecx); - uc_reg_write(handle, UC_X86_REG_EDX, &r_edx); + 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(handle, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); // tracing all instruction by having @begin > @end - uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); // emulate machine code in infinite time - err = uc_emu_start(handle, ADDRESS, ADDRESS + sizeof(X86_CODE32) - 1, 0, 0); + 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)); @@ -214,54 +214,54 @@ static void test_i386(void) // now print out some registers printf(">>> Emulation done. Below is the CPU context\n"); - uc_reg_read(handle, UC_X86_REG_ECX, &r_ecx); - uc_reg_read(handle, UC_X86_REG_EDX, &r_edx); + 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(handle, ADDRESS, (uint8_t *)&tmp, 4)) + if (!uc_mem_read(uc, ADDRESS, (uint8_t *)&tmp, 4)) 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(&handle); + uc_close(uc); } static void test_i386_jump(void) { - uch handle; + ucengine *uc; uc_err err; - uch trace1, trace2; + uchook 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, &handle); + 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(handle, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory - if (uc_mem_write(handle, ADDRESS, (uint8_t *)X86_CODE32_JUMP, + if (uc_mem_write(uc, ADDRESS, (uint8_t *)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(handle, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); // tracing 1 instruction at ADDRESS - uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); // emulate machine code in infinite time - err = uc_emu_start(handle, ADDRESS, ADDRESS + sizeof(X86_CODE32_JUMP) - 1, 0, 0); + 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)); @@ -269,13 +269,13 @@ static void test_i386_jump(void) printf(">>> Emulation done. Below is the CPU context\n"); - uc_close(&handle); + uc_close(uc); } // emulate code that loop forever static void test_i386_loop(void) { - uch handle; + ucengine *uc; uc_err err; int r_ecx = 0x1234; // ECX register @@ -285,28 +285,28 @@ static void test_i386_loop(void) printf("Emulate i386 code that loop forever\n"); // Initialize emulator in X86-32bit mode - err = uc_open(UC_ARCH_X86, UC_MODE_32, &handle); + 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(handle, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory - if (uc_mem_write(handle, ADDRESS, (uint8_t *)X86_CODE32_LOOP, sizeof(X86_CODE32_LOOP) - 1)) { + if (uc_mem_write(uc, ADDRESS, (uint8_t *)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(handle, UC_X86_REG_ECX, &r_ecx); - uc_reg_write(handle, UC_X86_REG_EDX, &r_edx); + 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(handle, ADDRESS, ADDRESS + sizeof(X86_CODE32_LOOP) - 1, 2 * UC_SECOND_SCALE, 0); + 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)); @@ -315,20 +315,20 @@ static void test_i386_loop(void) // now print out some registers printf(">>> Emulation done. Below is the CPU context\n"); - uc_reg_read(handle, UC_X86_REG_ECX, &r_ecx); - uc_reg_read(handle, UC_X86_REG_EDX, &r_edx); + 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(&handle); + uc_close(uc); } // emulate code that read invalid memory static void test_i386_invalid_mem_read(void) { - uch handle; + ucengine *uc; uc_err err; - uch trace1, trace2; + uchook trace1, trace2; int r_ecx = 0x1234; // ECX register int r_edx = 0x7890; // EDX register @@ -337,33 +337,33 @@ static void test_i386_invalid_mem_read(void) 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, &handle); + 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(handle, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory - if (uc_mem_write(handle, ADDRESS, (uint8_t *)X86_CODE32_MEM_READ, sizeof(X86_CODE32_MEM_READ) - 1)) { + if (uc_mem_write(uc, ADDRESS, (uint8_t *)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(handle, UC_X86_REG_ECX, &r_ecx); - uc_reg_write(handle, UC_X86_REG_EDX, &r_edx); + 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(handle, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); // tracing all instruction by having @begin > @end - uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); // emulate machine code in infinite time - err = uc_emu_start(handle, ADDRESS, ADDRESS + sizeof(X86_CODE32_MEM_READ) - 1, 0, 0); + 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)); @@ -372,20 +372,20 @@ static void test_i386_invalid_mem_read(void) // now print out some registers printf(">>> Emulation done. Below is the CPU context\n"); - uc_reg_read(handle, UC_X86_REG_ECX, &r_ecx); - uc_reg_read(handle, UC_X86_REG_EDX, &r_edx); + 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(&handle); + uc_close(uc); } // emulate code that read invalid memory static void test_i386_invalid_mem_write(void) { - uch handle, evh; + ucengine *uc; uc_err err; - uch trace1, trace2; //, trace3; + uchook trace1, trace2, trace3; uint32_t tmp; int r_ecx = 0x1234; // ECX register @@ -395,36 +395,36 @@ static void test_i386_invalid_mem_write(void) 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, &handle); + 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(handle, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory - if (uc_mem_write(handle, ADDRESS, (uint8_t *)X86_CODE32_MEM_WRITE, sizeof(X86_CODE32_MEM_WRITE) - 1)) { + if (uc_mem_write(uc, ADDRESS, (uint8_t *)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(handle, UC_X86_REG_ECX, &r_ecx); - uc_reg_write(handle, UC_X86_REG_EDX, &r_edx); + 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(handle, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); // tracing all instruction by having @begin > @end - uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); // intercept invalid memory events - uc_hook_add(handle, &evh, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL); + uc_hook_add(uc, &trace3, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL); // emulate machine code in infinite time - err = uc_emu_start(handle, ADDRESS, ADDRESS + sizeof(X86_CODE32_MEM_WRITE) - 1, 0, 0); + 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)); @@ -433,31 +433,31 @@ static void test_i386_invalid_mem_write(void) // now print out some registers printf(">>> Emulation done. Below is the CPU context\n"); - uc_reg_read(handle, UC_X86_REG_ECX, &r_ecx); - uc_reg_read(handle, UC_X86_REG_EDX, &r_edx); + 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(handle, 0xaaaaaaaa, (uint8_t *)&tmp, 4)) + if (!uc_mem_read(uc, 0xaaaaaaaa, (uint8_t *)&tmp, 4)) printf(">>> Read 4 bytes from [0x%x] = 0x%x\n", 0xaaaaaaaa, tmp); else printf(">>> Failed to read 4 bytes from [0x%x]\n", 0xffffffaa); - if (!uc_mem_read(handle, 0xffffffaa, (uint8_t *)&tmp, 4)) + if (!uc_mem_read(uc, 0xffffffaa, (uint8_t *)&tmp, 4)) 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(&handle); + uc_close(uc); } // emulate code that jump to invalid memory static void test_i386_jump_invalid(void) { - uch handle; + ucengine *uc; uc_err err; - uch trace1, trace2; + uchook trace1, trace2; int r_ecx = 0x1234; // ECX register int r_edx = 0x7890; // EDX register @@ -466,33 +466,33 @@ static void test_i386_jump_invalid(void) 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, &handle); + 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(handle, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory - if (uc_mem_write(handle, ADDRESS, (uint8_t *)X86_CODE32_JMP_INVALID, sizeof(X86_CODE32_JMP_INVALID) - 1)) { + if (uc_mem_write(uc, ADDRESS, (uint8_t *)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(handle, UC_X86_REG_ECX, &r_ecx); - uc_reg_write(handle, UC_X86_REG_EDX, &r_edx); + 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(handle, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); // tracing all instructions by having @begin > @end - uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); // emulate machine code in infinite time - err = uc_emu_start(handle, ADDRESS, ADDRESS + sizeof(X86_CODE32_JMP_INVALID) - 1, 0, 0); + 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)); @@ -501,20 +501,19 @@ static void test_i386_jump_invalid(void) // now print out some registers printf(">>> Emulation done. Below is the CPU context\n"); - uc_reg_read(handle, UC_X86_REG_ECX, &r_ecx); - uc_reg_read(handle, UC_X86_REG_EDX, &r_edx); + 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(&handle); + uc_close(uc); } static void test_i386_inout(void) { - uch handle; + ucengine *uc; uc_err err; - uch trace1, trace2; - uch trace3, trace4; + uchook trace1, trace2, trace3, trace4; int r_eax = 0x1234; // EAX register int r_ecx = 0x6789; // ECX register @@ -523,38 +522,38 @@ static void test_i386_inout(void) printf("Emulate i386 code with IN/OUT instructions\n"); // Initialize emulator in X86-32bit mode - err = uc_open(UC_ARCH_X86, UC_MODE_32, &handle); + 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(handle, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory - if (uc_mem_write(handle, ADDRESS, (uint8_t *)X86_CODE32_INOUT, sizeof(X86_CODE32_INOUT) - 1)) { + if (uc_mem_write(uc, ADDRESS, (uint8_t *)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(handle, UC_X86_REG_EAX, &r_eax); - uc_reg_write(handle, UC_X86_REG_ECX, &r_ecx); + 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(handle, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); // tracing all instructions - uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); - // handle IN instruction - uc_hook_add(handle, &trace3, UC_HOOK_INSN, hook_in, NULL, UC_X86_INS_IN); - // handle OUT instruction - uc_hook_add(handle, &trace4, UC_HOOK_INSN, hook_out, NULL, UC_X86_INS_OUT); + // uc IN instruction + uc_hook_add(uc, &trace3, UC_HOOK_INSN, hook_in, NULL, UC_X86_INS_IN); + // uc OUT instruction + uc_hook_add(uc, &trace4, UC_HOOK_INSN, hook_out, NULL, UC_X86_INS_OUT); // emulate machine code in infinite time - err = uc_emu_start(handle, ADDRESS, ADDRESS + sizeof(X86_CODE32_INOUT) - 1, 0, 0); + 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)); @@ -563,19 +562,19 @@ static void test_i386_inout(void) // now print out some registers printf(">>> Emulation done. Below is the CPU context\n"); - uc_reg_read(handle, UC_X86_REG_EAX, &r_eax); - uc_reg_read(handle, UC_X86_REG_ECX, &r_ecx); + 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(&handle); + uc_close(uc); } static void test_x86_64(void) { - uch handle; + ucengine *uc; uc_err err; - uch trace1, trace2, trace3, trace4; + uchook trace1, trace2, trace3, trace4; int64_t rax = 0x71f3029efd49d41d; int64_t rbx = 0xd87b45277f133ddb; @@ -598,54 +597,54 @@ static void test_x86_64(void) printf("Emulate x86_64 code\n"); // Initialize emulator in X86-64bit mode - err = uc_open(UC_ARCH_X86, UC_MODE_64, &handle); + 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(handle, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory - if (uc_mem_write(handle, ADDRESS, (uint8_t *)X86_CODE64, sizeof(X86_CODE64) - 1)) { + if (uc_mem_write(uc, ADDRESS, (uint8_t *)X86_CODE64, sizeof(X86_CODE64) - 1)) { printf("Failed to write emulation code to memory, quit!\n"); return; } // initialize machine registers - uc_reg_write(handle, UC_X86_REG_RSP, &rsp); + uc_reg_write(uc, UC_X86_REG_RSP, &rsp); - uc_reg_write(handle, UC_X86_REG_RAX, &rax); - uc_reg_write(handle, UC_X86_REG_RBX, &rbx); - uc_reg_write(handle, UC_X86_REG_RCX, &rcx); - uc_reg_write(handle, UC_X86_REG_RDX, &rdx); - uc_reg_write(handle, UC_X86_REG_RSI, &rsi); - uc_reg_write(handle, UC_X86_REG_RDI, &rdi); - uc_reg_write(handle, UC_X86_REG_R8, &r8); - uc_reg_write(handle, UC_X86_REG_R9, &r9); - uc_reg_write(handle, UC_X86_REG_R10, &r10); - uc_reg_write(handle, UC_X86_REG_R11, &r11); - uc_reg_write(handle, UC_X86_REG_R12, &r12); - uc_reg_write(handle, UC_X86_REG_R13, &r13); - uc_reg_write(handle, UC_X86_REG_R14, &r14); - uc_reg_write(handle, UC_X86_REG_R15, &r15); + 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(handle, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); // tracing all instructions in the range [ADDRESS, ADDRESS+20] - uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code64, NULL, (uint64_t)ADDRESS, (uint64_t)(ADDRESS+20)); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code64, NULL, (uint64_t)ADDRESS, (uint64_t)(ADDRESS+20)); // tracing all memory WRITE access (with @begin > @end) - uc_hook_add(handle, &trace3, UC_HOOK_MEM_WRITE, hook_mem64, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace3, UC_HOOK_MEM_WRITE, hook_mem64, NULL, (uint64_t)1, (uint64_t)0); // tracing all memory READ access (with @begin > @end) - uc_hook_add(handle, &trace4, UC_HOOK_MEM_READ, hook_mem64, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace4, UC_HOOK_MEM_READ, hook_mem64, NULL, (uint64_t)1, (uint64_t)0); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. - err = uc_emu_start(handle, ADDRESS, ADDRESS + sizeof(X86_CODE64) - 1, 0, 0); + 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)); @@ -654,20 +653,20 @@ static void test_x86_64(void) // now print out some registers printf(">>> Emulation done. Below is the CPU context\n"); - uc_reg_read(handle, UC_X86_REG_RAX, &rax); - uc_reg_read(handle, UC_X86_REG_RBX, &rbx); - uc_reg_read(handle, UC_X86_REG_RCX, &rcx); - uc_reg_read(handle, UC_X86_REG_RDX, &rdx); - uc_reg_read(handle, UC_X86_REG_RSI, &rsi); - uc_reg_read(handle, UC_X86_REG_RDI, &rdi); - uc_reg_read(handle, UC_X86_REG_R8, &r8); - uc_reg_read(handle, UC_X86_REG_R9, &r9); - uc_reg_read(handle, UC_X86_REG_R10, &r10); - uc_reg_read(handle, UC_X86_REG_R11, &r11); - uc_reg_read(handle, UC_X86_REG_R12, &r12); - uc_reg_read(handle, UC_X86_REG_R13, &r13); - uc_reg_read(handle, UC_X86_REG_R14, &r14); - uc_reg_read(handle, UC_X86_REG_R15, &r15); + 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); @@ -684,13 +683,13 @@ static void test_x86_64(void) printf(">>> R14 = 0x%" PRIx64 "\n", r14); printf(">>> R15 = 0x%" PRIx64 "\n", r15); - uc_close(&handle); + uc_close(uc); } static void test_x86_64_syscall(void) { - uch handle; - uch trace1; + ucengine *uc; + uchook trace1; uc_err err; int64_t rax = 0x100; @@ -699,30 +698,30 @@ static void test_x86_64_syscall(void) printf("Emulate x86_64 code with 'syscall' instruction\n"); // Initialize emulator in X86-64bit mode - err = uc_open(UC_ARCH_X86, UC_MODE_64, &handle); + 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(handle, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory - if (uc_mem_write(handle, ADDRESS, (uint8_t *)X86_CODE64_SYSCALL, sizeof(X86_CODE64_SYSCALL) - 1)) { + if (uc_mem_write(uc, ADDRESS, (uint8_t *)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(handle, &trace1, UC_HOOK_INSN, hook_syscall, NULL, UC_X86_INS_SYSCALL); + uc_hook_add(uc, &trace1, UC_HOOK_INSN, hook_syscall, NULL, UC_X86_INS_SYSCALL); // initialize machine registers - uc_reg_write(handle, UC_X86_REG_RAX, &rax); + 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(handle, ADDRESS, ADDRESS + sizeof(X86_CODE64_SYSCALL) - 1, 0, 0); + 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)); @@ -731,16 +730,16 @@ static void test_x86_64_syscall(void) // now print out some registers printf(">>> Emulation done. Below is the CPU context\n"); - uc_reg_read(handle, UC_X86_REG_RAX, &rax); + uc_reg_read(uc, UC_X86_REG_RAX, &rax); printf(">>> RAX = 0x%" PRIx64 "\n", rax); - uc_close(&handle); + uc_close(uc); } static void test_x86_16(void) { - uch handle; + ucengine *uc; uc_err err; uint8_t tmp; @@ -751,29 +750,29 @@ static void test_x86_16(void) printf("Emulate x86 16-bit code\n"); // Initialize emulator in X86-16bit mode - err = uc_open(UC_ARCH_X86, UC_MODE_16, &handle); + 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(handle, 0, 8 * 1024, UC_PROT_ALL); + uc_mem_map(uc, 0, 8 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory - if (uc_mem_write(handle, 0, (uint8_t *)X86_CODE16, sizeof(X86_CODE64) - 1)) { + if (uc_mem_write(uc, 0, (uint8_t *)X86_CODE16, sizeof(X86_CODE64) - 1)) { printf("Failed to write emulation code to memory, quit!\n"); return; } // initialize machine registers - uc_reg_write(handle, UC_X86_REG_EAX, &eax); - uc_reg_write(handle, UC_X86_REG_EBX, &ebx); - uc_reg_write(handle, UC_X86_REG_ESI, &esi); + 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(handle, 0, sizeof(X86_CODE16) - 1, 0, 0); + 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)); @@ -783,12 +782,12 @@ static void test_x86_16(void) printf(">>> Emulation done. Below is the CPU context\n"); // read from memory - if (!uc_mem_read(handle, 11, &tmp, 1)) + 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(&handle); + uc_close(uc); } int main(int argc, char **argv, char **envp) diff --git a/samples/shellcode.c b/samples/shellcode.c index 36c71ab4..31f72ffc 100644 --- a/samples/shellcode.c +++ b/samples/shellcode.c @@ -20,18 +20,18 @@ #define MIN(a, b) (a < b? a : b) // callback for tracing instruction -static void hook_code(uch handle, uint64_t address, uint32_t size, void *user_data) +static void hook_code(ucengine *uc, uint64_t address, uint32_t size, void *user_data) { int r_eip; char tmp[16]; printf("Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); - uc_reg_read(handle, UC_X86_REG_EIP, &r_eip); + uc_reg_read(uc, UC_X86_REG_EIP, &r_eip); printf("*** EIP = %x ***: ", r_eip); size = MIN(sizeof(tmp), size); - if (!uc_mem_read(handle, address, (uint8_t *)tmp, size)) { + if (!uc_mem_read(uc, address, (uint8_t *)tmp, size)) { int i; for (i=0; i>> 0x%x: interrupt 0x%x, SYS_EXIT. quit!\n\n", r_eip, intno); - uc_emu_stop(handle); + uc_emu_stop(uc); break; case 4: // sys_write // ECX = buffer address - uc_reg_read(handle, UC_X86_REG_ECX, &r_ecx); + uc_reg_read(uc, UC_X86_REG_ECX, &r_ecx); // EDX = buffer size - uc_reg_read(handle, UC_X86_REG_EDX, &r_edx); + uc_reg_read(uc, UC_X86_REG_EDX, &r_edx); // read the buffer in size = MIN(sizeof(buffer)-1, r_edx); - if (!uc_mem_read(handle, r_ecx, buffer, size)) { + if (!uc_mem_read(uc, r_ecx, buffer, size)) { buffer[size] = '\0'; printf(">>> 0x%x: interrupt 0x%x, SYS_WRITE. buffer = 0x%x, size = %u, content = '%s'\n", r_eip, intno, r_ecx, r_edx, buffer); @@ -88,44 +88,44 @@ static void hook_intr(uch handle, uint32_t intno, void *user_data) static void test_i386(void) { - uch handle, evh; + ucengine *uc; uc_err err; - uch trace1; + uchook trace1, trace2; int r_esp = ADDRESS + 0x200000; // ESP register printf("Emulate i386 code\n"); // Initialize emulator in X86-32bit mode - err = uc_open(UC_ARCH_X86, UC_MODE_32, &handle); + 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(handle, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory - if (uc_mem_write(handle, ADDRESS, (uint8_t *)X86_CODE32_SELF, sizeof(X86_CODE32_SELF) - 1)) { + if (uc_mem_write(uc, ADDRESS, (uint8_t *)X86_CODE32_SELF, sizeof(X86_CODE32_SELF) - 1)) { printf("Failed to write emulation code to memory, quit!\n"); return; } // initialize machine registers - uc_reg_write(handle, UC_X86_REG_ESP, &r_esp); + uc_reg_write(uc, UC_X86_REG_ESP, &r_esp); // tracing all instructions by having @begin > @end - uc_hook_add(handle, &trace1, UC_HOOK_CODE, hook_code, NULL, 1, 0); + uc_hook_add(uc, &trace1, UC_HOOK_CODE, hook_code, NULL, 1, 0); // handle interrupt ourself - uc_hook_add(handle, &evh, UC_HOOK_INTR, hook_intr, NULL); + uc_hook_add(uc, &trace2, UC_HOOK_INTR, hook_intr, NULL); printf("\n>>> Start tracing this Linux code\n"); // emulate machine code in infinite time - // err = uc_emu_start(handle, ADDRESS, ADDRESS + sizeof(X86_CODE32_SELF), 0, 12); <--- emulate only 12 instructions - err = uc_emu_start(handle, ADDRESS, ADDRESS + sizeof(X86_CODE32_SELF) - 1, 0, 0); + // err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_SELF), 0, 12); <--- emulate only 12 instructions + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_SELF) - 1, 0, 0); if (err) { printf("Failed on uc_emu_start() with error returned %u: %s\n", err, uc_strerror(err)); @@ -133,7 +133,7 @@ static void test_i386(void) printf("\n>>> Emulation done.\n"); - uc_close(&handle); + uc_close(uc); } int main(int argc, char **argv, char **envp) diff --git a/uc.c b/uc.c index 6d93d0e7..210616bf 100644 --- a/uc.c +++ b/uc.c @@ -31,6 +31,7 @@ #include "qemu/include/hw/boards.h" + UNICORN_EXPORT unsigned int uc_version(unsigned int *major, unsigned int *minor) { @@ -44,15 +45,8 @@ unsigned int uc_version(unsigned int *major, unsigned int *minor) UNICORN_EXPORT -uc_err uc_errno(uch handle) +uc_err uc_errno(ucengine *uc) { - struct uc_struct *uc; - - if (!handle) - return UC_ERR_UCH; - - uc = (struct uc_struct *)(uintptr_t)handle; - return uc->errnum; } @@ -65,14 +59,12 @@ const char *uc_strerror(uc_err code) return "Unknown error code"; case UC_ERR_OK: return "OK (UC_ERR_OK)"; - case UC_ERR_OOM: - return "Out of memory (UC_ERR_OOM)"; + case UC_ERR_NOMEM: + return "No memory available or memory not present (UC_ERR_NOMEM)"; case UC_ERR_ARCH: return "Invalid/unsupported architecture(UC_ERR_ARCH)"; case UC_ERR_HANDLE: return "Invalid handle (UC_ERR_HANDLE)"; - case UC_ERR_UCH: - return "Invalid uch (UC_ERR_UCH)"; case UC_ERR_MODE: return "Invalid mode (UC_ERR_MODE)"; case UC_ERR_VERSION: @@ -89,10 +81,14 @@ const char *uc_strerror(uc_err code) return "Invalid hook type (UC_ERR_HOOK)"; case UC_ERR_MAP: return "Invalid memory mapping (UC_ERR_MAP)"; - case UC_ERR_MEM_WRITE_NW: - return "Write to non-writable (UC_ERR_MEM_WRITE_NW)"; - case UC_ERR_MEM_READ_NR: - return "Read from non-readable (UC_ERR_MEM_READ_NR)"; + case UC_ERR_WRITE_PROT: + return "Write to write-protected memory (UC_ERR_WRITE_PROT)"; + case UC_ERR_READ_PROT: + return "Read from non-readable memory (UC_ERR_READ_PROT)"; + case UC_ERR_EXEC_PROT: + return "Fetch from non-executable memory (UC_ERR_EXEC_PROT)"; + case UC_ERR_INVAL: + return "Invalid argumet (UC_ERR_INVAL)"; } } @@ -130,7 +126,7 @@ bool uc_arch_supported(uc_arch arch) UNICORN_EXPORT -uc_err uc_open(uc_arch arch, uc_mode mode, uch *handle) +uc_err uc_open(uc_arch arch, uc_mode mode, ucengine **result) { struct uc_struct *uc; @@ -138,7 +134,7 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uch *handle) uc = calloc(1, sizeof(*uc)); if (!uc) { // memory insufficient - return UC_ERR_OOM; + return UC_ERR_NOMEM; } uc->errnum = UC_ERR_OK; @@ -179,7 +175,6 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uch *handle) // verify mode if (mode != UC_MODE_ARM && mode != UC_MODE_THUMB) { - *handle = 0; free(uc); return UC_ERR_MODE; } @@ -229,38 +224,29 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uch *handle) } if (uc->init_arch == NULL) { - *handle = 0; return UC_ERR_ARCH; } machine_initialize(uc); - *handle = (uintptr_t)uc; + *result = uc; if (uc->reg_reset) - uc->reg_reset(*handle); + uc->reg_reset(uc); uc->hook_size = HOOK_SIZE; uc->hook_callbacks = calloc(1, sizeof(uc->hook_callbacks[0]) * HOOK_SIZE); return UC_ERR_OK; } else { - *handle = 0; return UC_ERR_ARCH; } } UNICORN_EXPORT -uc_err uc_close(uch *handle) +uc_err uc_close(ucengine *uc) { - struct uc_struct *uc; - - // invalid handle ? - if (*handle == 0) - return UC_ERR_UCH; - - uc = (struct uc_struct *)(*handle); if (uc->release) uc->release(uc->tcg_ctx); @@ -294,26 +280,15 @@ uc_err uc_close(uch *handle) memset(uc, 0, sizeof(*uc)); free(uc); - // invalidate this handle by ZERO out its value. - // this is to make sure it is unusable after uc_close() - *handle = 0; - return UC_ERR_OK; } UNICORN_EXPORT -uc_err uc_reg_read(uch handle, int regid, void *value) +uc_err uc_reg_read(ucengine *uc, int regid, void *value) { - struct uc_struct *uc; - - if (handle == 0) - // invalid handle - return UC_ERR_UCH; - - uc = (struct uc_struct *)handle; if (uc->reg_read) - uc->reg_read(handle, regid, value); + uc->reg_read(uc, regid, value); else return -1; // FIXME: need a proper uc_err @@ -322,17 +297,10 @@ uc_err uc_reg_read(uch handle, int regid, void *value) UNICORN_EXPORT -uc_err uc_reg_write(uch handle, int regid, const void *value) +uc_err uc_reg_write(ucengine *uc, int regid, const void *value) { - struct uc_struct *uc; - - if (handle == 0) - // invalid handle - return UC_ERR_UCH; - - uc = (struct uc_struct *)handle; if (uc->reg_write) - uc->reg_write(handle, regid, value); + uc->reg_write(uc, regid, value); else return -1; // FIXME: need a proper uc_err @@ -342,7 +310,7 @@ uc_err uc_reg_write(uch handle, int regid, const void *value) // check if a memory area is mapped // this is complicated because an area can overlap adjacent blocks -static bool check_mem_area(struct uc_struct *uc, uint64_t address, size_t size) +static bool check_mem_area(ucengine *uc, uint64_t address, size_t size) { size_t count = 0, len; @@ -361,14 +329,8 @@ static bool check_mem_area(struct uc_struct *uc, uint64_t address, size_t size) UNICORN_EXPORT -uc_err uc_mem_read(uch handle, uint64_t address, uint8_t *bytes, size_t size) +uc_err uc_mem_read(ucengine *uc, uint64_t address, uint8_t *bytes, size_t size) { - struct uc_struct *uc = (struct uc_struct *)(uintptr_t)handle; - - if (handle == 0) - // invalid handle - return UC_ERR_UCH; - if (!check_mem_area(uc, address, size)) return UC_ERR_MEM_READ; @@ -395,14 +357,8 @@ uc_err uc_mem_read(uch handle, uint64_t address, uint8_t *bytes, size_t size) } UNICORN_EXPORT -uc_err uc_mem_write(uch handle, uint64_t address, const uint8_t *bytes, size_t size) +uc_err uc_mem_write(ucengine *uc, uint64_t address, const uint8_t *bytes, size_t size) { - struct uc_struct *uc = (struct uc_struct *)(uintptr_t)handle; - - if (handle == 0) - // invalid handle - return UC_ERR_UCH; - if (!check_mem_area(uc, address, size)) return UC_ERR_MEM_WRITE; @@ -441,7 +397,7 @@ uc_err uc_mem_write(uch handle, uint64_t address, const uint8_t *bytes, size_t s #define TIMEOUT_STEP 2 // microseconds static void *_timeout_fn(void *arg) { - struct uc_struct *uc = (struct uc_struct *)arg; + struct uc_struct *uc = arg; int64_t current_time = get_clock(); do { @@ -454,30 +410,22 @@ static void *_timeout_fn(void *arg) // timeout before emulation is done? if (!uc->emulation_done) { // force emulation to stop - uc_emu_stop((uch)uc); + uc_emu_stop(uc); } return NULL; } -static void enable_emu_timer(uch handle, uint64_t timeout) +static void enable_emu_timer(ucengine *uc, uint64_t timeout) { - struct uc_struct *uc = (struct uc_struct *)handle; - uc->timeout = timeout; - qemu_thread_create(&uc->timer, "timeout", _timeout_fn, + qemu_thread_create(uc, &uc->timer, "timeout", _timeout_fn, uc, QEMU_THREAD_JOINABLE); } UNICORN_EXPORT -uc_err uc_emu_start(uch handle, uint64_t begin, uint64_t until, uint64_t timeout, size_t count) +uc_err uc_emu_start(ucengine* uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count) { - struct uc_struct* uc = (struct uc_struct *)handle; - - if (handle == 0) - // invalid handle - return UC_ERR_UCH; - // reset the counter uc->emu_counter = 0; uc->stop_request = false; @@ -490,7 +438,7 @@ uc_err uc_emu_start(uch handle, uint64_t begin, uint64_t until, uint64_t timeout break; case UC_ARCH_M68K: - uc_reg_write(handle, UC_M68K_REG_PC, &begin); + uc_reg_write(uc, UC_M68K_REG_PC, &begin); break; case UC_ARCH_X86: @@ -498,13 +446,13 @@ uc_err uc_emu_start(uch handle, uint64_t begin, uint64_t until, uint64_t timeout default: break; case UC_MODE_16: - uc_reg_write(handle, UC_X86_REG_IP, &begin); + uc_reg_write(uc, UC_X86_REG_IP, &begin); break; case UC_MODE_32: - uc_reg_write(handle, UC_X86_REG_EIP, &begin); + uc_reg_write(uc, UC_X86_REG_EIP, &begin); break; case UC_MODE_64: - uc_reg_write(handle, UC_X86_REG_RIP, &begin); + uc_reg_write(uc, UC_X86_REG_RIP, &begin); break; } break; @@ -515,23 +463,23 @@ uc_err uc_emu_start(uch handle, uint64_t begin, uint64_t until, uint64_t timeout break; case UC_MODE_THUMB: case UC_MODE_ARM: - uc_reg_write(handle, UC_ARM_REG_R15, &begin); + uc_reg_write(uc, UC_ARM_REG_R15, &begin); break; } break; case UC_ARCH_ARM64: - uc_reg_write(handle, UC_ARM64_REG_PC, &begin); + uc_reg_write(uc, UC_ARM64_REG_PC, &begin); break; case UC_ARCH_MIPS: // TODO: MIPS32/MIPS64/BIGENDIAN etc - uc_reg_write(handle, UC_MIPS_REG_PC, &begin); + uc_reg_write(uc, UC_MIPS_REG_PC, &begin); break; case UC_ARCH_SPARC: // TODO: Sparc/Sparc64 - uc_reg_write(handle, UC_SPARC_REG_PC, &begin); + uc_reg_write(uc, UC_SPARC_REG_PC, &begin); break; } @@ -544,7 +492,7 @@ uc_err uc_emu_start(uch handle, uint64_t begin, uint64_t until, uint64_t timeout uc->vm_start(uc); if (timeout) - enable_emu_timer(handle, timeout * 1000); // microseconds -> nanoseconds + enable_emu_timer(uc, timeout * 1000); // microseconds -> nanoseconds uc->pause_all_vcpus(uc); // emulation is done uc->emulation_done = true; @@ -559,14 +507,8 @@ uc_err uc_emu_start(uch handle, uint64_t begin, uint64_t until, uint64_t timeout UNICORN_EXPORT -uc_err uc_emu_stop(uch handle) +uc_err uc_emu_stop(ucengine *uc) { - struct uc_struct* uc = (struct uc_struct *)handle; - - if (handle == 0) - // invalid handle - return UC_ERR_UCH; - if (uc->emulation_done) return UC_ERR_OK; @@ -578,66 +520,62 @@ uc_err uc_emu_stop(uch handle) } -static int _hook_code(uch handle, int type, uint64_t begin, uint64_t end, - void *callback, void *user_data, uch *h2) +static int _hook_code(ucengine *uc, int type, uint64_t begin, uint64_t end, + void *callback, void *user_data, uchook *hh) { int i; - i = hook_add(handle, type, begin, end, callback, user_data); + i = hook_add(uc, type, begin, end, callback, user_data); if (i == 0) - return UC_ERR_OOM; // FIXME + return UC_ERR_NOMEM; // FIXME - *h2 = i; + *hh = i; return UC_ERR_OK; } -static uc_err _hook_mem_access(uch handle, uc_mem_type type, +static uc_err _hook_mem_access(ucengine *uc, uc_hook_t type, uint64_t begin, uint64_t end, - void *callback, void *user_data, uch *h2) + void *callback, void *user_data, uchook *hh) { int i; - i = hook_add(handle, type, begin, end, callback, user_data); + i = hook_add(uc, type, begin, end, callback, user_data); if (i == 0) - return UC_ERR_OOM; // FIXME + return UC_ERR_NOMEM; // FIXME - *h2 = i; + *hh = i; return UC_ERR_OK; } UNICORN_EXPORT -uc_err uc_mem_map(uch handle, uint64_t address, size_t size, uint32_t perms) +uc_err uc_mem_map(ucengine *uc, uint64_t address, size_t size, uint32_t perms) { MemoryRegion **regions; - struct uc_struct* uc = (struct uc_struct *)handle; - - if (handle == 0) - // invalid handle - return UC_ERR_UCH; if (size == 0) // invalid memory mapping - return UC_ERR_MAP; + return UC_ERR_INVAL; - // address must be aligned to 4KB - if ((address & (4*1024 - 1)) != 0) - return UC_ERR_MAP; + // address must be aligned to uc->target_page_size + if ((address & uc->target_page_align) != 0) + return UC_ERR_INVAL; - // size must be multiple of 4KB - if ((size & (4*1024 - 1)) != 0) - return UC_ERR_MAP; + // size must be multiple of uc->target_page_size + if ((size & uc->target_page_align) != 0) + return UC_ERR_INVAL; // check for only valid permissions - if ((perms & ~(UC_PROT_READ | UC_PROT_WRITE)) != 0) - return UC_ERR_MAP; + if ((perms & ~UC_PROT_ALL) != 0) + return UC_ERR_INVAL; if ((uc->mapped_block_count & (MEM_BLOCK_INCR - 1)) == 0) { //time to grow - regions = (MemoryRegion**)realloc(uc->mapped_blocks, sizeof(MemoryRegion*) * (uc->mapped_block_count + MEM_BLOCK_INCR)); + regions = (MemoryRegion**)realloc(uc->mapped_blocks, + sizeof(MemoryRegion*) * (uc->mapped_block_count + MEM_BLOCK_INCR)); if (regions == NULL) { - return UC_ERR_OOM; + return UC_ERR_NOMEM; } uc->mapped_blocks = regions; } @@ -647,6 +585,213 @@ uc_err uc_mem_map(uch handle, uint64_t address, size_t size, uint32_t perms) return UC_ERR_OK; } +// Create a backup copy of the indicated MemoryRegion. +// Generally used in prepartion for splitting a MemoryRegion. +static uint8_t *copy_region(struct uc_struct *uc, MemoryRegion *mr) +{ + uint8_t *block = (uint8_t *)malloc(int128_get64(mr->size)); + if (block != NULL) { + uc_err err = uc_mem_read(uc, mr->addr, block, int128_get64(mr->size)); + if (err != UC_ERR_OK) { + free(block); + block = NULL; + } + } + + return block; +} + +/* + Split the given MemoryRegion at the indicated address for the indicated size + this may result in the create of up to 3 spanning sections. If the delete + parameter is true, the no new section will be created to replace the indicate + range. This functions exists to support uc_mem_protect and uc_mem_unmap. + + This is a static function and callers have already done some preliminary + parameter validation. + + The do_delete argument indicates that we are being called to support + uc_mem_unmap. In this case we save some time by choosing NOT to remap + the areas that are intended to get unmapped + */ +// TODO: investigate whether qemu region manipulation functions already offered +// this capability +static bool split_region(struct uc_struct *uc, MemoryRegion *mr, uint64_t address, + size_t size, bool do_delete) +{ + uint8_t *backup; + uint32_t perms; + uint64_t begin, end, chunk_end; + size_t l_size, m_size, r_size; + + chunk_end = address + size; + + // if this region belongs to area [address, address+size], + // then there is no work to do. + if (address <= mr->addr && chunk_end >= mr->end) + return true; + + if (size == 0) + // trivial case + return true; + + if (address >= mr->end || chunk_end <= mr->addr) + // impossible case + return false; + + backup = copy_region(uc, mr); + if (backup == NULL) + return false; + + // save the essential information required for the split before mr gets deleted + perms = mr->perms; + begin = mr->addr; + end = mr->end; + + // unmap this region first, then do split it later + if (uc_mem_unmap(uc, mr->addr, int128_get64(mr->size)) != UC_ERR_OK) + goto error; + + /* overlapping cases + * |------mr------| + * case 1 |---size--| + * case 2 |--size--| + * case 3 |---size--| + */ + + // adjust some things + if (address < begin) + address = begin; + if (chunk_end > end) + chunk_end = end; + + // compute sub region sizes + l_size = (size_t)(address - begin); + r_size = (size_t)(end - chunk_end); + m_size = (size_t)(chunk_end - address); + + // If there are error in any of the below operations, things are too far gone + // at that point to recover. Could try to remap orignal region, but these smaller + // allocation just failed so no guarantee that we can recover the original + // allocation at this point + if (l_size > 0) { + if (uc_mem_map(uc, begin, l_size, perms) != UC_ERR_OK) + goto error; + if (uc_mem_write(uc, begin, backup, l_size) != UC_ERR_OK) + goto error; + } + + if (m_size > 0 && !do_delete) { + if (uc_mem_map(uc, address, m_size, perms) != UC_ERR_OK) + goto error; + if (uc_mem_write(uc, address, backup + l_size, m_size) != UC_ERR_OK) + goto error; + } + + if (r_size > 0) { + if (uc_mem_map(uc, chunk_end, r_size, perms) != UC_ERR_OK) + goto error; + if (uc_mem_write(uc, chunk_end, backup + l_size + m_size, r_size) != UC_ERR_OK) + goto error; + } + + return true; + +error: + free(backup); + return false; +} + +UNICORN_EXPORT +uc_err uc_mem_protect(struct uc_struct *uc, uint64_t address, size_t size, uint32_t perms) +{ + MemoryRegion *mr; + uint64_t addr = address; + size_t count, len; + + if (size == 0) + // trivial case, no change + return UC_ERR_OK; + + // address must be aligned to uc->target_page_size + if ((address & uc->target_page_align) != 0) + return UC_ERR_INVAL; + + // size must be multiple of uc->target_page_size + if ((size & uc->target_page_align) != 0) + return UC_ERR_INVAL; + + // check for only valid permissions + if ((perms & ~UC_PROT_ALL) != 0) + return UC_ERR_INVAL; + + // check that user's entire requested block is mapped + if (!check_mem_area(uc, address, size)) + return UC_ERR_NOMEM; + + // Now we know entire region is mapped, so change permissions + // We may need to split regions if this area spans adjacent regions + addr = address; + count = 0; + while(count < size) { + mr = memory_mapping(uc, addr); + len = MIN(size - count, mr->end - addr); + if (!split_region(uc, mr, addr, len, false)) + return UC_ERR_NOMEM; + + mr = memory_mapping(uc, addr); + mr->perms = perms; + uc->readonly_mem(mr, (perms & UC_PROT_WRITE) == 0); + + count += len; + addr += len; + } + return UC_ERR_OK; +} + +UNICORN_EXPORT +uc_err uc_mem_unmap(struct uc_struct *uc, uint64_t address, size_t size) +{ + MemoryRegion *mr; + uint64_t addr; + size_t count, len; + + if (size == 0) + // nothing to unmap + return UC_ERR_OK; + + // address must be aligned to uc->target_page_size + if ((address & uc->target_page_align) != 0) + return UC_ERR_INVAL; + + // size must be multiple of uc->target_page_size + if ((size & uc->target_page_align) != 0) + return UC_ERR_MAP; + + // check that user's entire requested block is mapped + if (!check_mem_area(uc, address, size)) + return UC_ERR_NOMEM; + + // Now we know entire region is mapped, so do the unmap + // We may need to split regions if this area spans adjacent regions + addr = address; + count = 0; + while(count < size) { + mr = memory_mapping(uc, addr); + len = MIN(size - count, mr->end - addr); + if (!split_region(uc, mr, addr, len, true)) + return UC_ERR_NOMEM; + // if we can retrieve the mapping, then no splitting took place + // so unmap here + mr = memory_mapping(uc, addr); + if (mr != NULL) + uc->memory_unmap(uc, mr); + count += len; + addr += len; + } + return UC_ERR_OK; +} + MemoryRegion *memory_mapping(struct uc_struct* uc, uint64_t address) { unsigned int i; @@ -661,7 +806,7 @@ MemoryRegion *memory_mapping(struct uc_struct* uc, uint64_t address) } static uc_err _hook_mem_invalid(struct uc_struct* uc, uc_cb_eventmem_t callback, - void *user_data, uch *evh) + void *user_data, uchook *evh) { size_t i; @@ -675,12 +820,12 @@ static uc_err _hook_mem_invalid(struct uc_struct* uc, uc_cb_eventmem_t callback, uc->hook_mem_idx = i; return UC_ERR_OK; } else - return UC_ERR_OOM; + return UC_ERR_NOMEM; } static uc_err _hook_intr(struct uc_struct* uc, void *callback, - void *user_data, uch *evh) + void *user_data, uchook *evh) { size_t i; @@ -694,12 +839,12 @@ static uc_err _hook_intr(struct uc_struct* uc, void *callback, uc->hook_intr_idx = i; return UC_ERR_OK; } else - return UC_ERR_OOM; + return UC_ERR_NOMEM; } static uc_err _hook_insn(struct uc_struct *uc, unsigned int insn_id, void *callback, - void *user_data, uch *evh) + void *user_data, uchook *evh) { size_t i; @@ -718,7 +863,7 @@ static uc_err _hook_insn(struct uc_struct *uc, unsigned int insn_id, void *callb uc->hook_out_idx = i; return UC_ERR_OK; } else - return UC_ERR_OOM; + return UC_ERR_NOMEM; case UC_X86_INS_IN: // FIXME: only one event handler at the same time i = hook_find_new(uc); @@ -729,7 +874,7 @@ static uc_err _hook_insn(struct uc_struct *uc, unsigned int insn_id, void *callb uc->hook_in_idx = i; return UC_ERR_OK; } else - return UC_ERR_OOM; + return UC_ERR_NOMEM; case UC_X86_INS_SYSCALL: case UC_X86_INS_SYSENTER: // FIXME: only one event handler at the same time @@ -741,7 +886,7 @@ static uc_err _hook_insn(struct uc_struct *uc, unsigned int insn_id, void *callb uc->hook_syscall_idx = i; return UC_ERR_OK; } else - return UC_ERR_OOM; + return UC_ERR_NOMEM; } break; } @@ -750,18 +895,13 @@ static uc_err _hook_insn(struct uc_struct *uc, unsigned int insn_id, void *callb } UNICORN_EXPORT -uc_err uc_hook_add(uch handle, uch *h2, uc_hook_t type, void *callback, void *user_data, ...) +uc_err uc_hook_add(ucengine *uc, uchook *hh, uc_hook_t type, void *callback, void *user_data, ...) { - struct uc_struct* uc = (struct uc_struct *)handle; va_list valist; int ret = UC_ERR_OK; int id; uint64_t begin, end; - if (handle == 0) - // invalid handle - return UC_ERR_UCH; - va_start(valist, user_data); switch(type) { @@ -769,38 +909,39 @@ uc_err uc_hook_add(uch handle, uch *h2, uc_hook_t type, void *callback, void *us ret = UC_ERR_HOOK; break; case UC_HOOK_INTR: - ret = _hook_intr(uc, callback, user_data, h2); + ret = _hook_intr(uc, callback, user_data, hh); break; case UC_HOOK_INSN: id = va_arg(valist, int); - ret = _hook_insn(uc, id, callback, user_data, h2); + ret = _hook_insn(uc, id, callback, user_data, hh); break; case UC_HOOK_CODE: begin = va_arg(valist, uint64_t); end = va_arg(valist, uint64_t); - ret = _hook_code(handle, UC_HOOK_CODE, begin, end, callback, user_data, h2); + ret = _hook_code(uc, UC_HOOK_CODE, begin, end, callback, user_data, hh); break; case UC_HOOK_BLOCK: begin = va_arg(valist, uint64_t); end = va_arg(valist, uint64_t); - ret = _hook_code(handle, UC_HOOK_BLOCK, begin, end, callback, user_data, h2); + ret = _hook_code(uc, UC_HOOK_BLOCK, begin, end, callback, user_data, hh); break; case UC_HOOK_MEM_INVALID: - ret = _hook_mem_invalid(uc, callback, user_data, h2); + ret = _hook_mem_invalid(uc, callback, user_data, hh); break; case UC_HOOK_MEM_READ: begin = va_arg(valist, uint64_t); end = va_arg(valist, uint64_t); - ret = _hook_mem_access(handle, UC_MEM_READ, begin, end, callback, user_data, h2); + ret = _hook_mem_access(uc, UC_HOOK_MEM_READ, begin, end, callback, user_data, hh); break; case UC_HOOK_MEM_WRITE: begin = va_arg(valist, uint64_t); end = va_arg(valist, uint64_t); - ret = _hook_mem_access(handle, UC_MEM_WRITE, begin, end, callback, user_data, h2); + ret = _hook_mem_access(uc, UC_HOOK_MEM_WRITE, begin, end, callback, user_data, hh); + break; case UC_HOOK_MEM_READ_WRITE: begin = va_arg(valist, uint64_t); end = va_arg(valist, uint64_t); - ret = _hook_mem_access(handle, UC_MEM_READ_WRITE, begin, end, callback, user_data, h2); + ret = _hook_mem_access(uc, UC_HOOK_MEM_READ_WRITE, begin, end, callback, user_data, hh); break; } @@ -810,17 +951,7 @@ uc_err uc_hook_add(uch handle, uch *h2, uc_hook_t type, void *callback, void *us } UNICORN_EXPORT -uc_err uc_hook_del(uch handle, uch *h2) +uc_err uc_hook_del(ucengine *uc, uchook hh) { - //struct uc_struct* uc = (struct uc_struct *)handle; - - if (handle == 0) - // invalid handle - return UC_ERR_UCH; - - if (*h2 == 0) - // invalid handle - return UC_ERR_HANDLE; - - return hook_del(handle, h2); + return hook_del(uc, hh); }