---
description: This is unofficial document of Unicorn Engine authored by Tomori Nao (@K_atc). Have fun :)
---
Unicorn Engine Reference (Unofficial)
====
Author: [Tomori Nao (@K_atc)](https://twitter.com/K_atc)
Unicorn Engine: http://www.unicorn-engine.org/
Installation
----
```shell
sudo apt-get install libglib2.0-dev # install the dependency
git clone https://github.com/unicorn-engine/unicorn.git
cd unicorn
./make.sh; sudo ./make.sh install # compile & install the core
```
Include Header
-----
Following include statement is required in your C program:
```cpp
#include <unicorn/unicorn.h>
```
Compilation
----
```shell
gcc -o sample sample.c -lunicorn -lpthread
```
Tutorials & Samples
----
* Official: [Programming with C & Python languages – Unicorn – The ultimate CPU emulator](http://www.unicorn-engine.org/docs/tutorial.html)
* Official: [samples/sample_x86.c](https://github.com/unicorn-engine/unicorn/blob/master/samples/sample_x86.c)
HOOK Constants
----
UC_HOOK_CODE
: hooks (each) code
UC_HOOK_BLOCK
: hooks (each) block
UC_HOOK_INSN
: hooks instructions (including syscall)
UC_HOOK_INTR
: hooks signals (interrupts, not syscall)
API Summary
----
All API are defined in `uc.c`.
Constants are defined in `include/unicorn/unicorn.h`.
```clike
K_atc% cat uc.c | grep -A1 UNICORN_EXPORT | perl -pe 's/(--\n|UNICORN_EXPORT\n)//'
unsigned int uc_version(unsigned int *major, unsigned int *minor)
uc_err uc_errno(uc_engine *uc)
const char *uc_strerror(uc_err code)
bool uc_arch_supported(uc_arch arch)
uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result)
uc_err uc_close(uc_engine *uc)
uc_err uc_reg_read_batch(uc_engine *uc, int *ids, void **vals, int count)
uc_err uc_reg_write_batch(uc_engine *uc, int *ids, void *const *vals, int count)
uc_err uc_reg_read(uc_engine *uc, int regid, void *value)
uc_err uc_reg_write(uc_engine *uc, int regid, const void *value)
uc_err uc_mem_read(uc_engine *uc, uint64_t address, void *_bytes, size_t size)
uc_err uc_mem_write(uc_engine *uc, uint64_t address, const void *_bytes, size_t size)
uc_err uc_emu_start(uc_engine* uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count)
uc_err uc_emu_stop(uc_engine *uc)
uc_err uc_mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t perms)
uc_err uc_mem_map_ptr(uc_engine *uc, uint64_t address, size_t size, uint32_t perms, void *ptr)
uc_err uc_mem_protect(struct uc_struct *uc, uint64_t address, size_t size, uint32_t perms)
uc_err uc_mem_unmap(struct uc_struct *uc, uint64_t address, size_t size)
uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback,
uc_err uc_hook_del(uc_engine *uc, uc_hook hh)
uint32_t uc_mem_regions(uc_engine *uc, uc_mem_region **regions, uint32_t *count)
uc_err uc_query(uc_engine *uc, uc_query_type type, size_t *result)
uc_err uc_context_alloc(uc_engine *uc, uc_context **context)
uc_err uc_free(void *mem)
uc_err uc_context_save(uc_engine *uc, uc_context *context)
uc_err uc_context_restore(uc_engine *uc, uc_context *context)
```
API
----
### uc_strerror
translates error no to human-readable format
```clike
uc_err err;
err = uc_xxx(...);
printf("uc_xxx() err: %s\n", uc_strerror(err));
```
### uc_open
creates instance of `uc_engine *`.
```clike
uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result)
```
usage:
```clike
err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc);
if (err != UC_ERR_OK) {
printf("Failed on uc_open() with error returned: %u\n", err);
return -1;
}
```
**NOTE**: Do not forget change UC_ARCH and UC_MODE to suitable value.
### uc_hook_add
```clike
uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback,
void *user_data, uint64_t begin, uint64_t end, ...)
```
uc
: handle returned by uc_open(); `unicorn_engine *`
hh
: reference of `uc_hook`; that is, define `uc_hook uh` and `uc_hook_add(uc, &uh, ...)`
type
: UC_HOOK_XXX
callback
: hook (user defined function to be called)
user_data
: null pointer or a pointer to user defined data comes here.
begin
: start memory address where hook is enabled. If `begin > end` is true, the `hh` hook passes address range check (see `HOOK_BOUND_CHECK` definition).
end
: end memory address where hook is enabled
insn
: **if `type` is UC_HOOK_INSN:** UC_ARCH_INS_XXX (ARCH is arch name and XXX is instrucation name; for example, UC_X86_INS_SYSCALL)
... (extra args)
: **if type is UC_HOOK_INTR:** extra args are not required
#### example
example from `tests/regress/sigill.c`:
```clike
#include <unicorn/unicorn.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define UC_BUG_WRITE_SIZE 128
#define UC_BUG_WRITE_ADDR 0x1000 // fix this by change this to 0x2000
int got_sigill = 0;
void _interrupt(uc_engine *uc, uint32_t intno, void *user_data)
{
if (intno == 6) {
uc_emu_stop(uc);
got_sigill = 1;
}
}
int main()
{
int size;
uint8_t *buf;
uc_engine *uc;
uc_hook uh_trap;
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;
buf = malloc (size);
if (!buf) {
fprintf (stderr, "Cannot allocate\n");
return 1;
}
memset (buf, 0, size);
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(uc, &uh_trap, UC_HOOK_INTR, _interrupt, NULL, 1, 0);
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;
}
```
### uc_mem_map
```clike
uc_err uc_mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t perms)
```
uc
: `uc_engine *`
address
: start address of memory block
size
: size of memory block; MUST be 4 KB (4 * 1024) aligned (size=1,2,... will cause fail)
perms
: > Permissions for the newly mapped region.
This must be some combination of UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC, or this will return with UC_ERR_ARG error.
### uc_emu_start
```clike
uc_err uc_emu_start(uc_engine* uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count)
```
uc
: `uc_engine *`
begin
: emulation start from this address
until
: emulation stops at this address
timeout
: emulation timeout
count
: limits of executed code counter. If `count <= 0` is *true*, then counting is disabled (see below).
from `uc.c`:
```
uc->emu_count = count;
// remove count hook if counting isn't necessary
if (count <= 0 && uc->count_hook != 0) {
uc_hook_del(uc, uc->count_hook);
uc->count_hook = 0;
}
```
### uc_reg_read
**NOTE**: If UC_MODE is 32-bit and `regid` is 64-bit register, `value` is 0 and `uc_reg_read` returns NO error (`UC_ERROK`).
```clike
uc_err uc_reg_read(uc_engine *uc, int regid, void *value)
```
### uc_mem_read
```clike
uc_err uc_mem_read(uc_engine *uc, uint64_t address, void *_bytes, size_t size)
```
uc
: a pointer to instance of unicorn engine
address
: read memory address
_bytes
: read value (content of memory comes here)
size
: read bytes size
returns
: `UC_ERR_OK` if read count is equals to `size`.
`UC_ERR_READ_UNMAPPED` if this memory access overwraps unmapped memory region.
### uc_context_alloc
```clike
/*
Allocate a region that can be used with uc_context_{save,restore} to perform
quick save/rollback of the CPU context, which includes registers and some
internal metadata. Contexts may not be shared across engine instances with
differing arches or modes.
*/
UNICORN_EXPORT
uc_err uc_context_alloc(uc_engine *uc, uc_context **context);
```
uc
: handle returned from uc_open()
context
: pointer to a uc_engine*. This will be updated with the pointer to the new context on successful return of this function.
Later, this allocated memory must be freed with uc_free().
### uc_context_save
```clike
uc_err uc_context_save(uc_engine *uc, uc_context *context)
{
struct uc_context *_context = context;
memcpy(_context->data, uc->cpu->env_ptr, _context->size);
return UC_ERR_OK;
}
```
### uc_context_restore
```clike
uc_err uc_context_restore(uc_engine *uc, uc_context *context)
{
struct uc_context *_context = context;
memcpy(uc->cpu->env_ptr, _context->data, _context->size);
return UC_ERR_OK;
}
```
Constants
----
### UC_HOOK list
```clike
// All type of hooks for uc_hook_add() API.
typedef enum uc_hook_type {
// Hook all interrupt/syscall events
UC_HOOK_INTR = 1 << 0,
// Hook a particular instruction - only a very small subset of instructions supported here
UC_HOOK_INSN = 1 << 1,
// Hook a range of code
UC_HOOK_CODE = 1 << 2,
// Hook basic blocks
UC_HOOK_BLOCK = 1 << 3,
// Hook for memory read on unmapped memory
UC_HOOK_MEM_READ_UNMAPPED = 1 << 4,
// Hook for invalid memory write events
UC_HOOK_MEM_WRITE_UNMAPPED = 1 << 5,
// Hook for invalid memory fetch for execution events
UC_HOOK_MEM_FETCH_UNMAPPED = 1 << 6,
// Hook for memory read on read-protected memory
UC_HOOK_MEM_READ_PROT = 1 << 7,
// Hook for memory write on write-protected memory
UC_HOOK_MEM_WRITE_PROT = 1 << 8,
// Hook for memory fetch on non-executable memory
UC_HOOK_MEM_FETCH_PROT = 1 << 9,
// Hook memory read events.
UC_HOOK_MEM_READ = 1 << 10,
// Hook memory write events.
UC_HOOK_MEM_WRITE = 1 << 11,
// Hook memory fetch for execution events
UC_HOOK_MEM_FETCH = 1 << 12,
// Hook memory read events, but only successful access.
// The callback will be triggered after successful read.
UC_HOOK_MEM_READ_AFTER = 1 << 13,
} uc_hook_type;
// Hook type for all events of unmapped memory access
#define UC_HOOK_MEM_UNMAPPED (UC_HOOK_MEM_READ_UNMAPPED + UC_HOOK_MEM_WRITE_UNMAPPED + UC_HOOK_MEM_FETCH_UNMAPPED)
// Hook type for all events of illegal protected memory access
#define UC_HOOK_MEM_PROT (UC_HOOK_MEM_READ_PROT + UC_HOOK_MEM_WRITE_PROT + UC_HOOK_MEM_FETCH_PROT)
// Hook type for all events of illegal read memory access
#define UC_HOOK_MEM_READ_INVALID (UC_HOOK_MEM_READ_PROT + UC_HOOK_MEM_READ_UNMAPPED)
// Hook type for all events of illegal write memory access
#define UC_HOOK_MEM_WRITE_INVALID (UC_HOOK_MEM_WRITE_PROT + UC_HOOK_MEM_WRITE_UNMAPPED)
// Hook type for all events of illegal fetch memory access
#define UC_HOOK_MEM_FETCH_INVALID (UC_HOOK_MEM_FETCH_PROT + UC_HOOK_MEM_FETCH_UNMAPPED)
// Hook type for all events of illegal memory access
#define UC_HOOK_MEM_INVALID (UC_HOOK_MEM_UNMAPPED + UC_HOOK_MEM_PROT)
// Hook type for all events of valid memory access
// NOTE: UC_HOOK_MEM_READ is triggered before UC_HOOK_MEM_READ_PROT and UC_HOOK_MEM_READ_UNMAPPED, so
// this hook may technically trigger on some invalid reads.
#define UC_HOOK_MEM_VALID (UC_HOOK_MEM_READ + UC_HOOK_MEM_WRITE + UC_HOOK_MEM_FETCH)
```
### UC_ARCH
```clike
// Architecture type
typedef enum uc_arch {
UC_ARCH_ARM = 1, // ARM architecture (including Thumb, Thumb-2)
UC_ARCH_ARM64, // ARM-64, also called AArch64
UC_ARCH_MIPS, // Mips architecture
UC_ARCH_X86, // X86 architecture (including x86 & x86-64)
UC_ARCH_PPC, // PowerPC architecture (currently unsupported)
UC_ARCH_SPARC, // Sparc architecture
UC_ARCH_M68K, // M68K architecture
UC_ARCH_MAX,
} uc_arch;
```
### UC_MODE
```clike
// Mode type
typedef enum uc_mode {
UC_MODE_LITTLE_ENDIAN = 0, // little-endian mode (default mode)
UC_MODE_BIG_ENDIAN = 1 << 30, // big-endian mode
// arm / arm64
UC_MODE_ARM = 0, // ARM mode
UC_MODE_THUMB = 1 << 4, // THUMB mode (including Thumb-2)
UC_MODE_MCLASS = 1 << 5, // ARM's Cortex-M series (currently unsupported)
UC_MODE_V8 = 1 << 6, // ARMv8 A32 encodings for ARM (currently unsupported)
// mips
UC_MODE_MICRO = 1 << 4, // MicroMips mode (currently unsupported)
UC_MODE_MIPS3 = 1 << 5, // Mips III ISA (currently unsupported)
UC_MODE_MIPS32R6 = 1 << 6, // Mips32r6 ISA (currently unsupported)
UC_MODE_MIPS32 = 1 << 2, // Mips32 ISA
UC_MODE_MIPS64 = 1 << 3, // Mips64 ISA
// x86 / x64
UC_MODE_16 = 1 << 1, // 16-bit mode
UC_MODE_32 = 1 << 2, // 32-bit mode
UC_MODE_64 = 1 << 3, // 64-bit mode
// ppc
UC_MODE_PPC32 = 1 << 2, // 32-bit mode (currently unsupported)
UC_MODE_PPC64 = 1 << 3, // 64-bit mode (currently unsupported)
UC_MODE_QPX = 1 << 4, // Quad Processing eXtensions mode (currently unsupported)
// sparc
UC_MODE_SPARC32 = 1 << 2, // 32-bit mode
UC_MODE_SPARC64 = 1 << 3, // 64-bit mode
UC_MODE_V9 = 1 << 4, // SparcV9 mode (currently unsupported)
// m68k
} uc_mode;
:
```
### UC_X86
see `include/unicorn/x86.h`
#### UC_X86_INS
```clike
UC_X86_INS_SYSCALL//> X86 instructions
typedef enum uc_x86_insn {
UC_X86_INS_INVALID = 0,
UC_X86_INS_AAA,
UC_X86_INS_AAD,
UC_X86_INS_AAM,
UC_X86_INS_AAS,
UC_X86_INS_FABS,
UC_X86_INS_ADC,
UC_X86_INS_ADCX,
UC_X86_INS_ADD,
UC_X86_INS_ADDPD,
UC_X86_INS_ADDPS,
UC_X86_INS_ADDSD
```
### uc_x86_reg
in `include/unicorn/x86.h`:
```clike
//> X86 registers
typedef enum uc_x86_reg {
UC_X86_REG_INVALID = 0,
UC_X86_REG_AH, UC_X86_REG_AL, UC_X86_REG_AX, UC_X86_REG_BH, UC_X86_REG_BL,
UC_X86_REG_BP, UC_X86_REG_BPL, UC_X86_REG_BX, UC_X86_REG_CH, UC_X86_REG_CL,
UC_X86_REG_CS, UC_X86_REG_CX, UC_X86_REG_DH, UC_X86_REG_DI, UC_X86_REG_DIL,
UC_X86_REG_DL, UC_X86_REG_DS, UC_X86_REG_DX, UC_X86_REG_EAX, UC_X86_REG_EBP,
UC_X86_REG_EBX, UC_X86_REG_ECX, UC_X86_REG_EDI, UC_X86_REG_EDX, UC_X86_REG_EFLAGS,
UC_X86_REG_EIP, UC_X86_REG_EIZ, UC_X86_REG_ES, UC_X86_REG_ESI, UC_X86_REG_ESP,
UC_X86_REG_FPSW, UC_X86_REG_FS, UC_X86_REG_GS, UC_X86_REG_IP, UC_X86_REG_RAX,
UC_X86_REG_RBP, UC_X86_REG_RBX, UC_X86_REG_RCX, UC_X86_REG_RDI, UC_X86_REG_RDX,
UC_X86_REG_RIP, UC_X86_REG_RIZ, UC_X86_REG_RSI, UC_X86_REG_RSP, UC_X86_REG_SI,
UC_X86_REG_SIL, UC_X86_REG_SP, UC_X86_REG_SPL, UC_X86_REG_SS, UC_X86_REG_CR0,
UC_X86_REG_CR1, UC_X86_REG_CR2, UC_X86_REG_CR3, UC_X86_REG_CR4, UC_X86_REG_CR5,
UC_X86_REG_CR6, UC_X86_REG_CR7, UC_X86_REG_CR8, UC_X86_REG_CR9, UC_X86_REG_CR10,
UC_X86_REG_CR11, UC_X86_REG_CR12, UC_X86_REG_CR13, UC_X86_REG_CR14, UC_X86_REG_CR15,
UC_X86_REG_DR0, UC_X86_REG_DR1, UC_X86_REG_DR2, UC_X86_REG_DR3, UC_X86_REG_DR4,
UC_X86_REG_DR5, UC_X86_REG_DR6, UC_X86_REG_DR7, UC_X86_REG_DR8, UC_X86_REG_DR9,
UC_X86_REG_DR10, UC_X86_REG_DR11, UC_X86_REG_DR12, UC_X86_REG_DR13, UC_X86_REG_DR14,
UC_X86_REG_DR15, UC_X86_REG_FP0, UC_X86_REG_FP1, UC_X86_REG_FP2, UC_X86_REG_FP3,
UC_X86_REG_FP4, UC_X86_REG_FP5, UC_X86_REG_FP6, UC_X86_REG_FP7,
UC_X86_REG_K0, UC_X86_REG_K1, UC_X86_REG_K2, UC_X86_REG_K3, UC_X86_REG_K4,
UC_X86_REG_K5, UC_X86_REG_K6, UC_X86_REG_K7, UC_X86_REG_MM0, UC_X86_REG_MM1,
UC_X86_REG_MM2, UC_X86_REG_MM3, UC_X86_REG_MM4, UC_X86_REG_MM5, UC_X86_REG_MM6,
UC_X86_REG_MM7, UC_X86_REG_R8, UC_X86_REG_R9, UC_X86_REG_R10, UC_X86_REG_R11,
UC_X86_REG_R12, UC_X86_REG_R13, UC_X86_REG_R14, UC_X86_REG_R15,
UC_X86_REG_ST0, UC_X86_REG_ST1, UC_X86_REG_ST2, UC_X86_REG_ST3,
UC_X86_REG_ST4, UC_X86_REG_ST5, UC_X86_REG_ST6, UC_X86_REG_ST7,
UC_X86_REG_XMM0, UC_X86_REG_XMM1, UC_X86_REG_XMM2, UC_X86_REG_XMM3, UC_X86_REG_XMM4,
UC_X86_REG_XMM5, UC_X86_REG_XMM6, UC_X86_REG_XMM7, UC_X86_REG_XMM8, UC_X86_REG_XMM9,
UC_X86_REG_XMM10, UC_X86_REG_XMM11, UC_X86_REG_XMM12, UC_X86_REG_XMM13, UC_X86_REG_XMM14,
UC_X86_REG_XMM15, UC_X86_REG_XMM16, UC_X86_REG_XMM17, UC_X86_REG_XMM18, UC_X86_REG_XMM19,
UC_X86_REG_XMM20, UC_X86_REG_XMM21, UC_X86_REG_XMM22, UC_X86_REG_XMM23, UC_X86_REG_XMM24,
UC_X86_REG_XMM25, UC_X86_REG_XMM26, UC_X86_REG_XMM27, UC_X86_REG_XMM28, UC_X86_REG_XMM29,
UC_X86_REG_XMM30, UC_X86_REG_XMM31, UC_X86_REG_YMM0, UC_X86_REG_YMM1, UC_X86_REG_YMM2,
UC_X86_REG_YMM3, UC_X86_REG_YMM4, UC_X86_REG_YMM5, UC_X86_REG_YMM6, UC_X86_REG_YMM7,
UC_X86_REG_YMM8, UC_X86_REG_YMM9, UC_X86_REG_YMM10, UC_X86_REG_YMM11, UC_X86_REG_YMM12,
UC_X86_REG_YMM13, UC_X86_REG_YMM14, UC_X86_REG_YMM15, UC_X86_REG_YMM16, UC_X86_REG_YMM17,
UC_X86_REG_YMM18, UC_X86_REG_YMM19, UC_X86_REG_YMM20, UC_X86_REG_YMM21, UC_X86_REG_YMM22,
UC_X86_REG_YMM23, UC_X86_REG_YMM24, UC_X86_REG_YMM25, UC_X86_REG_YMM26, UC_X86_REG_YMM27,
UC_X86_REG_YMM28, UC_X86_REG_YMM29, UC_X86_REG_YMM30, UC_X86_REG_YMM31, UC_X86_REG_ZMM0,
UC_X86_REG_ZMM1, UC_X86_REG_ZMM2, UC_X86_REG_ZMM3, UC_X86_REG_ZMM4, UC_X86_REG_ZMM5,
UC_X86_REG_ZMM6, UC_X86_REG_ZMM7, UC_X86_REG_ZMM8, UC_X86_REG_ZMM9, UC_X86_REG_ZMM10,
UC_X86_REG_ZMM11, UC_X86_REG_ZMM12, UC_X86_REG_ZMM13, UC_X86_REG_ZMM14, UC_X86_REG_ZMM15,
UC_X86_REG_ZMM16, UC_X86_REG_ZMM17, UC_X86_REG_ZMM18, UC_X86_REG_ZMM19, UC_X86_REG_ZMM20,
UC_X86_REG_ZMM21, UC_X86_REG_ZMM22, UC_X86_REG_ZMM23, UC_X86_REG_ZMM24, UC_X86_REG_ZMM25,
UC_X86_REG_ZMM26, UC_X86_REG_ZMM27, UC_X86_REG_ZMM28, UC_X86_REG_ZMM29, UC_X86_REG_ZMM30,
UC_X86_REG_ZMM31, UC_X86_REG_R8B, UC_X86_REG_R9B, UC_X86_REG_R10B, UC_X86_REG_R11B,
UC_X86_REG_R12B, UC_X86_REG_R13B, UC_X86_REG_R14B, UC_X86_REG_R15B, UC_X86_REG_R8D,
UC_X86_REG_R9D, UC_X86_REG_R10D, UC_X86_REG_R11D, UC_X86_REG_R12D, UC_X86_REG_R13D,
UC_X86_REG_R14D, UC_X86_REG_R15D, UC_X86_REG_R8W, UC_X86_REG_R9W, UC_X86_REG_R10W,
UC_X86_REG_R11W, UC_X86_REG_R12W, UC_X86_REG_R13W, UC_X86_REG_R14W, UC_X86_REG_R15W,
UC_X86_REG_IDTR, UC_X86_REG_GDTR, UC_X86_REG_LDTR, UC_X86_REG_TR, UC_X86_REG_FPCW,
UC_X86_REG_FPTAG,
UC_X86_REG_MSR, // Model-Specific Register
UC_X86_REG_ENDING // <-- mark the end of the list of registers
} uc_x86_reg;
```
Internals
----
### uc_hook
```
include/unicorn/unicorn.h
32:typedef size_t uc_hook;
```
`include/uc_priv.h`
```clike
struct hook {
int type; // UC_HOOK_*
int insn; // instruction for HOOK_INSN
int refs; // reference count to free hook stored in multiple lists
uint64_t begin, end; // only trigger if PC or memory access is in this address (depends on hook type)
void *callback; // a uc_cb_* type
void *user_data;
};
// if statement to check hook bounds
#define HOOK_BOUND_CHECK(hh, addr) \
((((addr) >= (hh)->begin && (addr) <= (hh)->end) \
|| (hh)->begin > (hh)->end))
```
```clike
// Metadata stub for the variable-size cpu context used with uc_context_*()
struct uc_context {
size_t size;
char data[0];
};
```
in `include/unicorn/unicorn.h`:
```clike
uc_err// These are values returned by uc_errno()
typedef enum uc_err {
UC_ERR_OK = 0, // No error: everything was fine
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_MODE, // Invalid/unsupported mode: uc_open()
UC_ERR_VERSION, // Unsupported version (bindings)
UC_ERR_READ_UNMAPPED, // Quit emulation due to READ on unmapped memory: uc_emu_start()
UC_ERR_WRITE_UNMAPPED, // Quit emulation due to WRITE on unmapped memory: uc_emu_start()
UC_ERR_FETCH_UNMAPPED, // Quit emulation due to FETCH on unmapped memory: uc_emu_start()
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_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_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
UC_ERR_FETCH_UNALIGNED, // Unaligned fetch
UC_ERR_HOOK_EXIST, // hook for this event already existed
UC_ERR_RESOURCE, // Insufficient resource: uc_emu_start()
UC_ERR_EXCEPTION // Unhandled CPU exception
} uc_err;
```
Usefull Macro
----
Copy and paste them into your header file. They will ease troublesome.
### error check
```
static uc_err _uc_err_check(uc_err err, const char* expr)
{
if (err) {
fprintf(stderr, "Failed on %s with error: %s\n", expr, uc_strerror(err)); exit(1);
}
else {
// fprintf(stderr, "Succeeded on %s\n", expr);
}
return err;
}
#define UC_ERR_CHECK(x) _uc_err_check(x, #x)
```
#### usage
```clike
UC_ERR_CHECK(uc_open(UC_ARCH_X86, UC_MODE_64, &uc));
uint64_t rax = 0x114514;
UC_ERR_CHECK(uc_reg_write(uc, UC_X86_REG_RAX, &rax));
```