Merge branch 'master' into java_dev

This commit is contained in:
Chris Eagle 2015-09-03 20:30:31 -07:00
commit bae718274e
79 changed files with 2282 additions and 941 deletions

11
.gitignore vendored
View File

@ -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

View File

@ -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,7 +178,15 @@ 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

View File

@ -1,8 +1,12 @@
#include <unicorn/unicorn.h>
#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) {

View File

@ -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
}

View File

@ -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);

View File

@ -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
)

View File

@ -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

View File

@ -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

80
hook.c
View File

@ -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);
}

View File

@ -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.

View File

@ -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"

View File

@ -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
}

View File

@ -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 {

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -13,6 +13,7 @@ symbols = (
'phys_mem_clean',
'tb_cleanup',
'memory_map',
'memory_unmap',
'memory_free',
'helper_raise_exception',
'tcg_enabled',

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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:

View File

@ -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;
}

View File

@ -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);

View File

@ -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:

View File

@ -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);

View File

@ -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;

View File

@ -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)

View File

@ -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);

View File

@ -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;

View File

@ -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)

View File

@ -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);

View File

@ -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;

View File

@ -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)

View File

@ -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);

View File

@ -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)

View File

@ -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;
}

View File

@ -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);
}

View File

@ -16,6 +16,8 @@
#include <assert.h>
#include <limits.h>
#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();
}

View File

@ -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

View File

@ -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)

View File

@ -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);

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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)

View File

@ -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)

184
regress/rep_movsb.c Normal file
View File

@ -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 <inttypes.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unicorn/unicorn.h>
unsigned char PROGRAM[] =
"\xbe\x00\x00\x20\x00\xbf\x00\x10\x20\x00\xb9\x14\x00\x00\x00\xf3"
"\xa4\xf4";
// total size: 18 bytes
/*
bits 32
; assumes code section at 0x100000 r-x
; assumes data section at 0x200000-0x202000, rw-
mov esi, 0x200000
mov edi, 0x201000
mov ecx, 20
rep movsb
hlt
*/
static int log_num = 1;
// callback for tracing instruction
static void hook_code(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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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)

View File

@ -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)

280
samples/mem_exec.c Normal file
View File

@ -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 <inttypes.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unicorn/unicorn.h>
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;
}

302
samples/mem_protect.c Normal file
View File

@ -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 <inttypes.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unicorn/unicorn.h>
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;
}

293
samples/mem_unmap.c Normal file
View File

@ -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 <inttypes.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unicorn/unicorn.h>
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;
}

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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<size; i++) {
printf("%x ", ((uint8_t*)tmp)[i]);
@ -43,7 +43,7 @@ static void hook_code(uch handle, uint64_t address, uint32_t size, void *user_da
#define MIN(a, b) (a < b? a : b)
// callback for handling interrupt
// ref: http://syscalls.kernelgrok.com/
static void hook_intr(uch handle, uint32_t intno, void *user_data)
static void hook_intr(ucengine *uc, uint32_t intno, void *user_data)
{
int32_t r_eax, r_ecx, r_eip;
uint32_t r_edx, size;
@ -53,8 +53,8 @@ static void hook_intr(uch handle, uint32_t intno, void *user_data)
if (intno != 0x80)
return;
uc_reg_read(handle, UC_X86_REG_EAX, &r_eax);
uc_reg_read(handle, UC_X86_REG_EIP, &r_eip);
uc_reg_read(uc, UC_X86_REG_EAX, &r_eax);
uc_reg_read(uc, UC_X86_REG_EIP, &r_eip);
switch(r_eax) {
default:
@ -62,19 +62,19 @@ static void hook_intr(uch handle, uint32_t intno, void *user_data)
break;
case 1: // sys_exit
printf(">>> 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)

447
uc.c
View File

@ -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);
}