This commit continues the PR #111

- Allow to register handler separately for invalid memory access
- Add new memory events for hooking:
   - UC_MEM_READ_INVALID, UC_MEM_WRITE_INVALID, UC_MEM_FETCH_INVALID
   - UC_HOOK_MEM_READ_PROT, UC_HOOK_MEM_WRITE_PROT, UC_HOOK_MEM_FETCH_PROT
- Rename UC_ERR_EXEC_PROT to UC_ERR_FETCH_PROT
- Change API uc_hook_add() so event type @type can be combined from hooking types
This commit is contained in:
Nguyen Anh Quynh 2015-09-24 14:18:02 +08:00
parent e479f72403
commit 90eb8f2e72
21 changed files with 223 additions and 128 deletions

View File

@ -48,26 +48,33 @@ const (
ERR_MAP = 12
ERR_WRITE_PROT = 13
ERR_READ_PROT = 14
ERR_EXEC_PROT = 15
ERR_FETCH_PROT = 15
ERR_ARG = 16
ERR_READ_UNALIGNED = 17
ERR_WRITE_UNALIGNED = 18
ERR_FETCH_UNALIGNED = 19
MEM_READ = 16
MEM_WRITE = 17
MEM_READ_WRITE = 18
MEM_FETCH = 19
MEM_WRITE_PROT = 20
MEM_READ_PROT = 21
MEM_EXEC_PROT = 22
HOOK_INTR = 32
HOOK_INSN = 33
HOOK_CODE = 34
HOOK_BLOCK = 35
HOOK_MEM_INVALID = 36
HOOK_MEM_READ = 37
HOOK_MEM_WRITE = 38
HOOK_MEM_READ_WRITE = 39
MEM_FETCH = 18
MEM_READ_INVALID = 19
MEM_WRITE_INVALID = 20
MEM_FETCH_INVALID = 21
MEM_WRITE_PROT = 22
MEM_READ_PROT = 23
MEM_FETCH_PROT = 24
HOOK_INTR = 1
HOOK_INSN = 2
HOOK_CODE = 4
HOOK_BLOCK = 8
HOOK_MEM_READ_INVALID = 16
HOOK_MEM_WRITE_INVALID = 32
HOOK_MEM_FETCH_INVALID = 64
HOOK_MEM_READ_PROT = 128
HOOK_MEM_WRITE_PROT = 256
HOOK_MEM_FETCH_PROT = 512
HOOK_MEM_READ = 1024
HOOK_MEM_WRITE = 2048
HOOK_MEM_FETCH = 4096
PROT_NONE = 0
PROT_READ = 1

View File

@ -33,7 +33,7 @@ def hook_code(uc, address, size, user_data):
# callback for tracing invalid memory access (READ or WRITE)
def hook_mem_invalid(uc, access, address, size, value, user_data):
if access == UC_MEM_WRITE:
if access == UC_MEM_WRITE_INVALID:
print(">>> Missing memory is being WRITE at 0x%x, data size = %u, data value = 0x%x" \
%(address, size, value))
# map this memory in with 2MB in size
@ -231,7 +231,7 @@ def test_i386_invalid_mem_write():
#mu.hook_add(UC_HOOK_CODE, hook_code)
# intercept invalid memory events
mu.hook_add(UC_HOOK_MEM_INVALID, hook_mem_invalid)
mu.hook_add(UC_HOOK_MEM_READ_INVALID | UC_HOOK_MEM_WRITE_INVALID, hook_mem_invalid)
try:
# emulate machine code in infinite time
@ -349,7 +349,7 @@ def test_x86_64():
mu.hook_add(UC_HOOK_MEM_WRITE, hook_mem_access)
mu.hook_add(UC_HOOK_MEM_READ, hook_mem_access)
# actually you can also use READ_WRITE to trace all memory access
#mu.hook_add(UC_HOOK_MEM_READ_WRITE, hook_mem_access)
#mu.hook_add(UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE, hook_mem_access)
try:
# emulate machine code in infinite time

View File

@ -272,11 +272,13 @@ class Uc(object):
cb = ctypes.cast(UC_HOOK_CODE_CB(self._hookcode_cb), UC_HOOK_CODE_CB)
status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, cb, \
ctypes.cast(self._callback_count, ctypes.c_void_p), begin, end)
elif htype == UC_HOOK_MEM_INVALID:
elif htype & UC_HOOK_MEM_READ_INVALID or htype & UC_HOOK_MEM_WRITE_INVALID or \
htype & UC_HOOK_MEM_FETCH_INVALID or htype & UC_HOOK_MEM_READ_PROT or \
htype & UC_HOOK_MEM_WRITE_PROT or htype & UC_HOOK_MEM_FETCH_PROT:
cb = ctypes.cast(UC_HOOK_MEM_INVALID_CB(self._hook_mem_invalid_cb), UC_HOOK_MEM_INVALID_CB)
status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \
cb, ctypes.cast(self._callback_count, ctypes.c_void_p))
elif htype in (UC_HOOK_MEM_READ, UC_HOOK_MEM_WRITE, UC_HOOK_MEM_READ_WRITE):
elif htype in (UC_HOOK_MEM_READ, UC_HOOK_MEM_WRITE, UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE):
cb = ctypes.cast(UC_HOOK_MEM_ACCESS_CB(self._hook_mem_access_cb), UC_HOOK_MEM_ACCESS_CB)
status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \
cb, ctypes.cast(self._callback_count, ctypes.c_void_p))

View File

@ -46,7 +46,7 @@ UC_ERR_INSN_INVALID = 11
UC_ERR_MAP = 12
UC_ERR_WRITE_PROT = 13
UC_ERR_READ_PROT = 14
UC_ERR_EXEC_PROT = 15
UC_ERR_FETCH_PROT = 15
UC_ERR_ARG = 16
UC_ERR_READ_UNALIGNED = 17
UC_ERR_WRITE_UNALIGNED = 18
@ -54,19 +54,25 @@ UC_ERR_FETCH_UNALIGNED = 19
UC_MEM_READ = 16
UC_MEM_WRITE = 17
UC_MEM_FETCH = 18
UC_MEM_WRITE_PROT = 19
UC_MEM_READ_PROT = 20
UC_MEM_FETCH_PROT = 21
UC_HOOK_INTR = 32
UC_HOOK_INSN = 33
UC_HOOK_CODE = 34
UC_HOOK_BLOCK = 35
UC_HOOK_MEM_INVALID_READ = 36
UC_HOOK_MEM_INVALID_WRITE = 37
UC_HOOK_MEM_INVALID_FETCH = 38
UC_HOOK_MEM_READ = 39
UC_HOOK_MEM_WRITE = 40
UC_HOOK_MEM_FETCH = 41
UC_MEM_READ_INVALID = 19
UC_MEM_WRITE_INVALID = 20
UC_MEM_FETCH_INVALID = 21
UC_MEM_WRITE_PROT = 22
UC_MEM_READ_PROT = 23
UC_MEM_FETCH_PROT = 24
UC_HOOK_INTR = 1
UC_HOOK_INSN = 2
UC_HOOK_CODE = 4
UC_HOOK_BLOCK = 8
UC_HOOK_MEM_READ_INVALID = 16
UC_HOOK_MEM_WRITE_INVALID = 32
UC_HOOK_MEM_FETCH_INVALID = 64
UC_HOOK_MEM_READ_PROT = 128
UC_HOOK_MEM_WRITE_PROT = 256
UC_HOOK_MEM_FETCH_PROT = 512
UC_HOOK_MEM_READ = 1024
UC_HOOK_MEM_WRITE = 2048
UC_HOOK_MEM_FETCH = 4096
UC_PROT_NONE = 0
UC_PROT_READ = 1

30
hook.c
View File

@ -73,7 +73,7 @@ size_t hook_add(struct uc_struct *uc, int type, uint64_t begin, uint64_t end, vo
if (begin > end)
uc->hook_write_idx = i;
break;
case UC_HOOK_MEM_READ_WRITE:
case UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE:
uc->hook_mem_read = true;
uc->hook_mem_write = true;
if (begin > end) {
@ -109,8 +109,28 @@ uc_err hook_del(struct uc_struct *uc, uc_hook hh)
uc->hook_write_idx = 0;
}
if (hh == uc->hook_mem_idx) {
uc->hook_mem_idx = 0;
if (hh == uc->hook_mem_read_idx) {
uc->hook_mem_read_idx = 0;
}
if (hh == uc->hook_mem_write_idx) {
uc->hook_mem_write_idx = 0;
}
if (hh == uc->hook_mem_fetch_idx) {
uc->hook_mem_fetch_idx = 0;
}
if (hh == uc->hook_mem_read_prot_idx) {
uc->hook_mem_read_prot_idx = 0;
}
if (hh == uc->hook_mem_write_prot_idx) {
uc->hook_mem_write_prot_idx = 0;
}
if (hh == uc->hook_mem_fetch_prot_idx) {
uc->hook_mem_fetch_prot_idx = 0;
}
if (hh == uc->hook_intr_idx) {
@ -176,13 +196,13 @@ static struct hook_struct *_hook_find(struct uc_struct *uc, int type, uint64_t a
}
break;
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].hook_type & UC_HOOK_MEM_READ) {
if (uc->hook_callbacks[i].begin <= address && address <= uc->hook_callbacks[i].end)
return &uc->hook_callbacks[i];
}
break;
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].hook_type & UC_HOOK_MEM_WRITE) {
if (uc->hook_callbacks[i].begin <= address && address <= uc->hook_callbacks[i].end)
return &uc->hook_callbacks[i];
}

View File

@ -152,7 +152,13 @@ struct uc_struct {
bool hook_block, hook_insn, hook_mem_read, hook_mem_write;
uint64_t block_addr; // save the last block address we hooked
// indexes to event callbacks
int hook_mem_idx; // for handling invalid memory access
int hook_mem_read_idx; // for handling invalid memory read access on unmapped memory
int hook_mem_write_idx; // for handling invalid memory write access on unmapped memory
int hook_mem_fetch_idx; // for handling invalid memory fetch access on unmapped memory
int hook_mem_read_prot_idx; // for handling invalid memory read access on read-protected memory
int hook_mem_write_prot_idx; // for handling invalid memory write access on write-protected memory
int hook_mem_fetch_prot_idx; // for handling invalid memory fetch access on non-executable memory
int hook_intr_idx; // for handling interrupt
int hook_out_idx; // for handling OUT instruction (X86)
int hook_in_idx; // for handling IN instruction (X86)

View File

@ -120,7 +120,7 @@ typedef enum uc_err {
UC_ERR_MAP, // Invalid memory mapping: uc_mem_map()
UC_ERR_WRITE_PROT, // Quit emulation due to UC_MEM_WRITE_PROT violation: uc_emu_start()
UC_ERR_READ_PROT, // Quit emulation due to UC_MEM_READ_PROT violation: uc_emu_start()
UC_ERR_EXEC_PROT, // Quit emulation due to UC_MEM_EXEC_PROT violation: uc_emu_start()
UC_ERR_FETCH_PROT, // Quit emulation due to UC_MEM_FETCH_PROT violation: uc_emu_start()
UC_ERR_ARG, // Inavalid argument provided to uc_xxx function (See specific function API)
UC_ERR_READ_UNALIGNED, // Unaligned read
UC_ERR_WRITE_UNALIGNED, // Unaligned write
@ -153,9 +153,12 @@ typedef void (*uc_cb_insn_out_t)(uc_engine *uc, uint32_t port, int size, uint32_
// All type of memory accesses for UC_HOOK_MEM_*
typedef enum uc_mem_type {
UC_MEM_READ = 16, // Unmapped memory is read from
UC_MEM_WRITE, // Unmapped memory is written to
UC_MEM_FETCH, // Unmapped memory is fetched
UC_MEM_READ = 16, // Memory is read from
UC_MEM_WRITE, // Memory is written to
UC_MEM_FETCH, // Memory is fetched
UC_MEM_READ_INVALID, // Unmapped memory is read from
UC_MEM_WRITE_INVALID, // Unmapped memory is written to
UC_MEM_FETCH_INVALID, // Unmapped memory is fetched
UC_MEM_WRITE_PROT, // Write to write protected, but mapped, memory
UC_MEM_READ_PROT, // Read from read protected, but mapped, memory
UC_MEM_FETCH_PROT, // Fetch from non-executable, but mapped, memory
@ -163,16 +166,19 @@ typedef enum uc_mem_type {
// All type of hooks for uc_hook_add() API.
typedef enum uc_hook_type {
UC_HOOK_INTR = 32, // Hook all interrupt events
UC_HOOK_INSN, // Hook a particular instruction
UC_HOOK_CODE, // Hook a range of code
UC_HOOK_BLOCK, // Hook basic blocks
UC_HOOK_MEM_READ_INVALID, // Hook for invalid memory read events
UC_HOOK_MEM_WRITE_INVALID, // Hook for invalid memory write events
UC_HOOK_MEM_FETCH_INVALID, // Hook for invalid memory fetch for execution events
UC_HOOK_MEM_READ, // Hook all memory read events.
UC_HOOK_MEM_WRITE, // Hook all memory write events.
UC_HOOK_MEM_FETCH, // Hook all memory fetch for execution events
UC_HOOK_INTR = 1 << 0, // Hook all interrupt events
UC_HOOK_INSN = 1 << 1, // Hook a particular instruction
UC_HOOK_CODE = 1 << 2, // Hook a range of code
UC_HOOK_BLOCK = 1 << 3, // Hook basic blocks
UC_HOOK_MEM_READ_INVALID = 1 << 4, // Hook for invalid memory read events
UC_HOOK_MEM_WRITE_INVALID = 1 << 5, // Hook for invalid memory write events
UC_HOOK_MEM_FETCH_INVALID = 1 << 6, // Hook for invalid memory fetch for execution events
UC_HOOK_MEM_READ_PROT = 1 << 7, // Hook for memory read on read-protected memory
UC_HOOK_MEM_WRITE_PROT = 1 << 8, // Hook for memory write on write-protected memory
UC_HOOK_MEM_FETCH_PROT = 1 << 9, // Hook for memory fetch on non-executable memory
UC_HOOK_MEM_READ = 1 << 10, // Hook memory read events.
UC_HOOK_MEM_WRITE = 1 << 11, // Hook memory write events.
UC_HOOK_MEM_FETCH = 1 << 12, // Hook memory fetch for execution events
} uc_hook_type;
// Callback function for hooking memory (UC_HOOK_MEM_*)
@ -381,7 +387,7 @@ uc_err uc_emu_stop(uc_engine *uc);
for detailed error).
*/
UNICORN_EXPORT
uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, uc_hook_type type, void *callback, void *user_data, ...);
uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, void *user_data, ...);
/*
Unregister (remove) a hook callback.

View File

@ -300,7 +300,7 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env1, target_ulong addr)
(addr & TARGET_PAGE_MASK))) {
cpu_ldub_code(env1, addr);
//check for NX related error from softmmu
if (env1->invalid_error == UC_ERR_EXEC_PROT) {
if (env1->invalid_error == UC_ERR_FETCH_PROT) {
env1->invalid_error = UC_ERR_CODE_INVALID;
return -1;
}

View File

@ -177,7 +177,7 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx,
target_ulong tlb_addr = env->tlb_table[mmu_idx][index].ADDR_READ;
uintptr_t haddr;
DATA_TYPE res;
int mem_access, error_code;
int error_code;
struct uc_struct *uc = env->uc;
MemoryRegion *mr = memory_mapping(uc, addr);
@ -185,15 +185,16 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx,
// memory can be unmapped while reading or fetching
if (mr == NULL) {
#if defined(SOFTMMU_CODE_ACCESS)
mem_access = UC_MEM_FETCH;
error_code = UC_ERR_FETCH_INVALID;
if (uc->hook_mem_fetch_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_fetch_idx].callback)(
uc, UC_MEM_FETCH_INVALID, addr, DATA_SIZE, 0,
uc->hook_callbacks[uc->hook_mem_fetch_idx].user_data)) {
#else
mem_access = UC_MEM_READ;
error_code = UC_ERR_READ_INVALID;
if (uc->hook_mem_read_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_read_idx].callback)(
uc, UC_MEM_READ_INVALID, addr, DATA_SIZE, 0,
uc->hook_callbacks[uc->hook_mem_read_idx].user_data)) {
#endif
if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)(
uc, mem_access, addr, DATA_SIZE, 0,
uc->hook_callbacks[uc->hook_mem_idx].user_data)) {
env->invalid_error = UC_ERR_OK;
mr = memory_mapping(uc, addr); // FIXME: what if mr is still NULL at this time?
} else {
@ -208,13 +209,13 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx,
#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)) {
if (uc->hook_mem_fetch_prot_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_fetch_prot_idx].callback)(
uc, UC_MEM_FETCH_PROT, addr, DATA_SIZE, 0,
uc->hook_callbacks[uc->hook_mem_fetch_prot_idx].user_data)) {
env->invalid_error = UC_ERR_OK;
} else {
env->invalid_addr = addr;
env->invalid_error = UC_ERR_EXEC_PROT;
env->invalid_error = UC_ERR_FETCH_PROT;
// printf("***** Invalid fetch (non-executable) at " TARGET_FMT_lx "\n", addr);
cpu_exit(uc->current_cpu);
return 0;
@ -233,9 +234,9 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx,
// Unicorn: callback on non-readable memory
if (READ_ACCESS_TYPE == MMU_DATA_LOAD && mr != NULL && !(mr->perms & UC_PROT_READ)) { //non-readable
if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)(
if (uc->hook_mem_read_prot_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_read_prot_idx].callback)(
uc, UC_MEM_READ_PROT, addr, DATA_SIZE, 0,
uc->hook_callbacks[uc->hook_mem_idx].user_data)) {
uc->hook_callbacks[uc->hook_mem_read_prot_idx].user_data)) {
env->invalid_error = UC_ERR_OK;
}
else {
@ -367,7 +368,7 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx,
target_ulong tlb_addr = env->tlb_table[mmu_idx][index].ADDR_READ;
uintptr_t haddr;
DATA_TYPE res;
int mem_access, error_code;
int error_code;
struct uc_struct *uc = env->uc;
MemoryRegion *mr = memory_mapping(uc, addr);
@ -375,15 +376,16 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx,
// memory can be unmapped while reading or fetching
if (mr == NULL) {
#if defined(SOFTMMU_CODE_ACCESS)
mem_access = UC_MEM_FETCH;
error_code = UC_ERR_FETCH_INVALID;
if (uc->hook_mem_fetch_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_fetch_idx].callback)(
uc, UC_MEM_FETCH_INVALID, addr, DATA_SIZE, 0,
uc->hook_callbacks[uc->hook_mem_fetch_idx].user_data)) {
#else
mem_access = UC_MEM_READ;
error_code = UC_ERR_READ_INVALID;
if (uc->hook_mem_read_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_read_idx].callback)(
uc, UC_MEM_READ_INVALID, addr, DATA_SIZE, 0,
uc->hook_callbacks[uc->hook_mem_read_idx].user_data)) {
#endif
if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)(
uc, mem_access, addr, DATA_SIZE, 0,
uc->hook_callbacks[uc->hook_mem_idx].user_data)) {
env->invalid_error = UC_ERR_OK;
mr = memory_mapping(uc, addr); // FIXME: what if mr is still NULL at this time?
} else {
@ -398,13 +400,13 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx,
#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)) {
if (uc->hook_mem_fetch_prot_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_fetch_prot_idx].callback)(
uc, UC_MEM_FETCH_PROT, addr, DATA_SIZE, 0,
uc->hook_callbacks[uc->hook_mem_fetch_prot_idx].user_data)) {
env->invalid_error = UC_ERR_OK;
} else {
env->invalid_addr = addr;
env->invalid_error = UC_ERR_EXEC_PROT;
env->invalid_error = UC_ERR_FETCH_PROT;
// printf("***** Invalid fetch (non-executable) at " TARGET_FMT_lx "\n", addr);
cpu_exit(uc->current_cpu);
return 0;
@ -423,9 +425,9 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx,
// Unicorn: callback on non-readable memory
if (READ_ACCESS_TYPE == MMU_DATA_LOAD && mr != NULL && !(mr->perms & UC_PROT_READ)) { //non-readable
if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)(
if (uc->hook_mem_read_prot_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_read_prot_idx].callback)(
uc, UC_MEM_READ_PROT, addr, DATA_SIZE, 0,
uc->hook_callbacks[uc->hook_mem_idx].user_data)) {
uc->hook_callbacks[uc->hook_mem_read_prot_idx].user_data)) {
env->invalid_error = UC_ERR_OK;
} else {
env->invalid_addr = addr;
@ -608,10 +610,10 @@ 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)(
uc, UC_MEM_WRITE, addr, DATA_SIZE, (int64_t)val,
uc->hook_callbacks[uc->hook_mem_idx].user_data)) {
if (uc->hook_mem_write_idx && mr == NULL) {
if (!((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_write_idx].callback)(
uc, UC_MEM_WRITE_INVALID, addr, DATA_SIZE, (int64_t)val,
uc->hook_callbacks[uc->hook_mem_write_idx].user_data)) {
// save error & quit
env->invalid_addr = addr;
env->invalid_error = UC_ERR_WRITE_INVALID;
@ -620,14 +622,15 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val,
return;
} else {
env->invalid_error = UC_ERR_OK;
mr = memory_mapping(uc, addr); // FIXME: what if mr is still NULL at this time?
}
}
// 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)(
if (uc->hook_mem_write_prot_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_write_prot_idx].callback)(
uc, UC_MEM_WRITE_PROT, addr, DATA_SIZE, (int64_t)val,
uc->hook_callbacks[uc->hook_mem_idx].user_data)) {
uc->hook_callbacks[uc->hook_mem_write_prot_idx].user_data)) {
env->invalid_error = UC_ERR_OK;
}
else {
@ -754,10 +757,10 @@ 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)(
uc, UC_MEM_WRITE, addr, DATA_SIZE, (int64_t)val,
uc->hook_callbacks[uc->hook_mem_idx].user_data)) {
if (uc->hook_mem_write_idx && mr == NULL) {
if (!((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_write_idx].callback)(
uc, UC_MEM_WRITE_INVALID, addr, DATA_SIZE, (int64_t)val,
uc->hook_callbacks[uc->hook_mem_write_idx].user_data)) {
// save error & quit
env->invalid_addr = addr;
env->invalid_error = UC_ERR_WRITE_INVALID;
@ -766,14 +769,15 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val,
return;
} else {
env->invalid_error = UC_ERR_OK;
mr = memory_mapping(uc, addr); // FIXME: what if mr is still NULL at this time?
}
}
// 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)(
if (uc->hook_mem_write_prot_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_write_prot_idx].callback)(
uc, UC_MEM_WRITE_PROT, addr, DATA_SIZE, (int64_t)val,
uc->hook_callbacks[uc->hook_mem_idx].user_data)) {
uc->hook_callbacks[uc->hook_mem_write_prot_idx].user_data)) {
env->invalid_error = UC_ERR_OK;
}
else {

View File

@ -79,13 +79,13 @@ static bool hook_mem_invalid(uc_engine *uc, uc_mem_type type,
default:
printf("not ok - UC_HOOK_MEM_INVALID type: %d at 0x%" PRIx64 "\n", type, addr);
return false;
case UC_MEM_READ:
case UC_MEM_READ_INVALID:
printf("not ok - Read from invalid memory at 0x%"PRIx64 ", data size = %u\n", addr, size);
return false;
case UC_MEM_WRITE:
case UC_MEM_WRITE_INVALID:
printf("not ok - Write to invalid memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value);
return false;
case UC_MEM_EXEC_PROT:
case UC_MEM_FETCH_PROT:
printf("not ok - Fetch from non-executable memory at 0x%"PRIx64 "\n", addr);
return false;
case UC_MEM_WRITE_PROT:
@ -147,7 +147,9 @@ static void do_nx_demo(bool cause_fault)
// intercept code and invalid memory events
if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK ||
uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL) != UC_ERR_OK) {
uc_hook_add(uc, &trace1,
UC_HOOK_MEM_READ_INVALID | UC_HOOK_MEM_WRITE_INVALID | UC_HOOK_MEM_FETCH_INVALID | UC_HOOK_MEM_FETCH_PROT | UC_HOOK_MEM_WRITE_PROT | UC_HOOK_MEM_READ_PROT,
hook_mem_invalid, NULL) != UC_ERR_OK) {
printf("not ok - Failed to install hooks\n");
return;
}
@ -226,7 +228,9 @@ static void do_perms_demo(bool change_perms)
// intercept code and invalid memory events
if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK ||
uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL) != UC_ERR_OK) {
uc_hook_add(uc, &trace1,
UC_HOOK_MEM_READ_INVALID | UC_HOOK_MEM_WRITE_INVALID | UC_HOOK_MEM_FETCH_INVALID | UC_HOOK_MEM_FETCH_PROT | UC_HOOK_MEM_WRITE_PROT | UC_HOOK_MEM_READ_PROT,
hook_mem_invalid, NULL) != UC_ERR_OK) {
printf("not ok - Failed to install hooks\n");
return;
}
@ -302,7 +306,9 @@ static void do_unmap_demo(bool do_unmap)
// intercept code and invalid memory events
if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK ||
uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL) != UC_ERR_OK) {
uc_hook_add(uc, &trace1,
UC_HOOK_MEM_READ_INVALID | UC_HOOK_MEM_WRITE_INVALID | UC_HOOK_MEM_FETCH_INVALID | UC_HOOK_MEM_FETCH_PROT | UC_HOOK_MEM_WRITE_PROT | UC_HOOK_MEM_READ_PROT,
hook_mem_invalid, NULL) != UC_ERR_OK) {
printf("not ok - Failed to install hooks\n");
return;
}

View File

@ -73,7 +73,7 @@ static bool hook_mem_invalid(uc_engine *uc, uc_mem_type type,
default:
// return false to indicate we want to stop emulation
return false;
case UC_MEM_WRITE:
case UC_MEM_WRITE_INVALID:
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
@ -421,7 +421,7 @@ static void test_i386_invalid_mem_write(void)
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0);
// intercept invalid memory events
uc_hook_add(uc, &trace3, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL);
uc_hook_add(uc, &trace3, UC_HOOK_MEM_READ_INVALID | UC_HOOK_MEM_WRITE_INVALID, hook_mem_invalid, NULL);
// emulate machine code in infinite time
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_MEM_WRITE) - 1, 0, 0);

View File

@ -1,5 +1,5 @@
CFLAGS += -I../include
LDFLAGS += ../libunicorn.a $(shell pkg-config --libs glib-2.0) -lpthread -lm
LDFLAGS += ../../libunicorn.a $(shell pkg-config --libs glib-2.0) -lpthread -lm
TESTS = map_crash map_write
TESTS += sigill sigill2

View File

@ -116,9 +116,9 @@ static bool hook_mem_invalid(uc_engine *uc, uc_mem_type type,
{
switch(type) {
default:
printf("not ok %d - UC_HOOK_MEM_INVALID type: %d at 0x%" PRIx64 "\n", log_num++, type, addr);
printf("not ok %d - memory invalid type: %d at 0x%" PRIx64 "\n", log_num++, type, addr);
return false;
case UC_MEM_EXEC_PROT:
case UC_MEM_FETCH_PROT:
printf("# Fetch from non-executable memory at 0x%"PRIx64 "\n", addr);
//make page executable
@ -221,11 +221,11 @@ int main(int argc, char **argv, char **envp)
}
// 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++);
if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE_PROT | UC_HOOK_MEM_FETCH_PROT, hook_mem_invalid, NULL) != UC_ERR_OK) {
printf("not ok %d - Failed to install memory invalid handler\n", log_num++);
return 8;
} else {
printf("ok %d - UC_HOOK_MEM_INVALID installed\n", log_num++);
printf("ok %d - memory invalid handler installed\n", log_num++);
}
// emulate machine code until told to stop by hook_code

View File

@ -138,7 +138,7 @@ static bool hook_mem_invalid(uc_engine *uc, uc_mem_type type,
uint32_t testval;
switch(type) {
default:
printf("not ok %d - UC_HOOK_MEM_INVALID type: %d at 0x%" PRIx64 "\n", log_num++, type, addr);
printf("not ok %d - memory 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);
@ -229,11 +229,11 @@ int main(int argc, char **argv, char **envp)
}
// 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++);
if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE_PROT, hook_mem_invalid, NULL) != UC_ERR_OK) {
printf("not ok %d - Failed to install memory invalid handler\n", log_num++);
return 7;
} else {
printf("ok %d - UC_HOOK_MEM_INVALID installed\n", log_num++);
printf("ok %d - memory invalid handler installed\n", log_num++);
}
// emulate machine code until told to stop by hook_code

View File

@ -133,7 +133,7 @@ static bool hook_mem_invalid(uc_engine *uc, uc_mem_type type,
uint32_t testval;
switch(type) {
default:
printf("not ok %d - UC_HOOK_MEM_INVALID type: %d at 0x%" PRIx64 "\n", log_num++, type, addr);
printf("not ok %d - memory 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);
@ -224,11 +224,11 @@ int main(int argc, char **argv, char **envp)
}
// 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++);
if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE_INVALID, hook_mem_invalid, NULL) != UC_ERR_OK) {
printf("not ok %d - Failed to install memory invalid handler\n", log_num++);
return 7;
} else {
printf("ok %d - UC_HOOK_MEM_INVALID installed\n", log_num++);
printf("ok %d - memory invalid handler installed\n", log_num++);
}
// emulate machine code until told to stop by hook_code

View File

@ -86,7 +86,7 @@ int main(int argc, char **argv, char **envp)
//uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)0x400000, (uint64_t)0x400fff);
// intercept invalid memory events
uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL);
uc_hook_add(uc, &trace1, UC_MEM_READ_PROT, hook_mem_invalid, NULL);
// emulate machine code in infinite time
printf("BEGIN execution\n");

View File

@ -24,7 +24,7 @@ class RegWriteSignExt(regress.RegressTest):
# jmp ebx
mu.mem_write(0x10000000, b'\xff\xe3')
mu.hook_add(unicorn.UC_HOOK_MEM_INVALID, hook_mem_invalid)
mu.hook_add(unicorn.UC_HOOK_MEM_FETCH_INVALID | unicorn.UC_HOOK_MEM_FETCH_PROT, hook_mem_invalid)
mu.emu_start(0x10000000, 0x10000000 + 2, count=1)
if __name__ == '__main__':

13
tests/regress/regress.sh Executable file
View File

@ -0,0 +1,13 @@
#!/bin/sh
./map_crash map_write
./sigill sigill2
./block_test
./ro_mem_test nr_mem_test
./timeout_segfault
./rep_movsb
./mem_unmap
./mem_protect
./mem_exec

View File

@ -142,7 +142,7 @@ int main(int argc, char **argv, char **envp)
//uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)0x400000, (uint64_t)0x400fff);
// intercept invalid memory events
uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL);
uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE_INVALID | UC_HOOK_MEM_WRITE_PROT, hook_mem_invalid, NULL);
// emulate machine code in infinite time
printf("BEGIN execution - 1\n");

View File

@ -11,7 +11,7 @@ all: ${ALL_TESTS}
.PHONY: clean
clean:
rm ${ALL_TESTS}
rm -rf ${ALL_TESTS}
.PHONY: test
test: export LD_LIBRARY_PATH=../../

47
uc.c
View File

@ -87,8 +87,8 @@ const char *uc_strerror(uc_err code)
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_FETCH_PROT:
return "Fetch from non-executable memory (UC_ERR_FETCH_PROT)";
case UC_ERR_ARG:
return "Invalid argumet (UC_ERR_ARG)";
@ -830,7 +830,7 @@ MemoryRegion *memory_mapping(struct uc_struct* uc, uint64_t address)
return NULL;
}
static uc_err _hook_mem_invalid(struct uc_struct* uc, uc_cb_eventmem_t callback,
static uc_err _hook_mem_invalid(struct uc_struct* uc, int type, uc_cb_eventmem_t callback,
void *user_data, uc_hook *evh)
{
size_t i;
@ -842,7 +842,18 @@ static uc_err _hook_mem_invalid(struct uc_struct* uc, uc_cb_eventmem_t callback,
uc->hook_callbacks[i].callback = callback;
uc->hook_callbacks[i].user_data = user_data;
*evh = i;
uc->hook_mem_idx = i;
if (type & UC_HOOK_MEM_READ_INVALID)
uc->hook_mem_read_idx = i;
if (type & UC_HOOK_MEM_READ_PROT)
uc->hook_mem_read_prot_idx = i;
if (type & UC_HOOK_MEM_WRITE_INVALID)
uc->hook_mem_write_idx = i;
if (type & UC_HOOK_MEM_WRITE_PROT)
uc->hook_mem_write_prot_idx = i;
if (type & UC_HOOK_MEM_FETCH_INVALID)
uc->hook_mem_fetch_idx = i;
if (type & UC_HOOK_MEM_FETCH_PROT)
uc->hook_mem_fetch_prot_idx = i;
return UC_ERR_OK;
} else
return UC_ERR_NOMEM;
@ -920,7 +931,7 @@ static uc_err _hook_insn(struct uc_struct *uc, unsigned int insn_id, void *callb
}
UNICORN_EXPORT
uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, uc_hook_type type, void *callback, void *user_data, ...)
uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, void *user_data, ...)
{
va_list valist;
int ret = UC_ERR_OK;
@ -929,9 +940,26 @@ uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, uc_hook_type type, void *callback
va_start(valist, user_data);
if (type & UC_HOOK_MEM_READ_INVALID)
ret = _hook_mem_invalid(uc, UC_HOOK_MEM_READ_INVALID, callback, user_data, hh);
if (type & UC_HOOK_MEM_WRITE_INVALID)
ret = _hook_mem_invalid(uc, UC_HOOK_MEM_WRITE_INVALID, callback, user_data, hh);
if (type & UC_HOOK_MEM_FETCH_INVALID)
ret = _hook_mem_invalid(uc, UC_HOOK_MEM_FETCH_INVALID, callback, user_data, hh);
if (type & UC_HOOK_MEM_READ_PROT)
ret = _hook_mem_invalid(uc, UC_HOOK_MEM_READ_PROT, callback, user_data, hh);
if (type & UC_HOOK_MEM_WRITE_PROT)
ret = _hook_mem_invalid(uc, UC_HOOK_MEM_WRITE_PROT, callback, user_data, hh);
if (type & UC_HOOK_MEM_FETCH_PROT)
ret = _hook_mem_invalid(uc, UC_HOOK_MEM_FETCH_PROT, callback, user_data, hh);
switch(type) {
default:
ret = UC_ERR_HOOK;
break;
case UC_HOOK_INTR:
ret = _hook_intr(uc, callback, user_data, hh);
@ -950,9 +978,6 @@ uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, uc_hook_type type, void *callback
end = va_arg(valist, uint64_t);
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, hh);
break;
case UC_HOOK_MEM_READ:
begin = va_arg(valist, uint64_t);
end = va_arg(valist, uint64_t);
@ -963,10 +988,10 @@ uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, uc_hook_type type, void *callback
end = va_arg(valist, uint64_t);
ret = _hook_mem_access(uc, UC_HOOK_MEM_WRITE, begin, end, callback, user_data, hh);
break;
case UC_HOOK_MEM_READ_WRITE:
case UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE:
begin = va_arg(valist, uint64_t);
end = va_arg(valist, uint64_t);
ret = _hook_mem_access(uc, UC_HOOK_MEM_READ_WRITE, begin, end, callback, user_data, hh);
ret = _hook_mem_access(uc, UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE, begin, end, callback, user_data, hh);
break;
}