Unicorn

The Unicorn API exposes a lightweight CPU + memory emulation layer to AngelScript. It supports two modes:

  • Local emulation (uc_create) — fully sandboxed memory you map/write yourself.

  • Process-backed emulation (uc_create_process) — unmapped reads/fetches can be paged-in from a proc_t target, enabling “emulate code that reads target memory”.


Notes (Important)

  • Always call uc_close(handle) when done.

  • You should use uc_setup_stack for setting up stack.

  • If you modify code bytes at the same address and re-run, call uc_flush_code(handle) (TB cache flush) or run the updated code at a different address.

  • Memory addresses are Unicorn virtual addresses:

    • Low “sandbox” memory (e.g. 0x1000 / 0x2000) is local/emulator-owned.

    • Real target VAs (user-mode addresses) are process-backed when running in process mode.


Constants

Memory Protection Flags

Copy

const uint32 UC_PROT_READ
const uint32 UC_PROT_WRITE
const uint32 UC_PROT_EXEC
const uint32 UC_PROT_ALL

Use these with uc_mem_map.


Register IDs (x86_64)

Register IDs are exposed as global const int values, for example:

Copy


Hook Types

  • UC_HOOK_CODE — Hook every instruction executed.

  • UC_HOOK_MEM_UNMAPPED — Hook unmapped memory access (read/write/fetch).


Engine Handles

Create (Local)

Copy

Creates a new Unicorn context (local emulation). Returns a handle, or 0 on failure.


Create (Process-backed)

Copy

Creates a Unicorn context that can page-in unmapped reads/fetches from proc. Use allow_writes=false for safe read-only emulation.

A synthetic TEB is created with the real PEB address written at offset 0x60. For correct and stable emulation, you should override the FS and GS base registers to point to a real TEB instance.

Returns a handle, or 0 on failure.


Close

Copy

Destroys the Unicorn context and releases all internal resources.


Memory

Map Memory

Copy

Maps a memory region in the emulator.

  • addr must be page-aligned.

  • size must be page-aligned (or a multiple of page size).

Returns true on success.


Write Memory

Copy

Writes bytes into emulator memory at addr.


Read Memory

Copy

Reads bytes from emulator memory at addr into data.

In process-backed mode, this may succeed if the page was already paged-in (or if your integration supports paging-in for external reads).


Registers

Write 64-bit Register

Copy


Read 64-bit Register

Copy


Write 128-bit Register (XMM)

Copy

data must be exactly 16 bytes.


Read 128-bit Register (XMM)

Copy

Returns exactly 16 bytes in data.


Write 256-bit Register (YMM)

Copy

data must be exactly 32 bytes.


Read 256-bit Register (YMM)

Copy

Returns exactly 32 bytes in data.


Execution

Copy

Maps a stack region, sets RSP, pushes a return address, and maps a STOP page.

Use this before running any code that can execute ret.

Returns true on success.

If uc_setup_stack is not used in process mode, the emulator may attempt to read stack memory from the remote process instead of the emulated address space.


Start Emulation

Copy

Starts emulation at begin.

  • end — stop address (use a STOP page if your code returns)

  • timeout — microseconds (0 = unlimited)

  • count — instruction limit (0 = unlimited)

Returns UC_ERR_OK on success. Error Codesarrow-up-right


Flush Translated Code Cache

Copy

Flushes Unicorn’s internal translation cache (TB cache). Call this after modifying code bytes at an address you will execute again.

Returns true on success.


Callback Signature

Hook callbacks receive:

  • uc — Unicorn handle (same value as the handle you created)

  • addr — address of the instruction or faulting memory access

Return value:

  • true — continue emulation

  • false — stop emulation (recommended to also call uc_emu_stop)

Add Hook

Registers a hook callback on the Unicorn context.

  • handle — Unicorn context handle

  • type — hook type constant (UC_HOOK_CODE, UC_HOOK_MEM_UNMAPPED)

  • cb — callback function handle

Returns true on success, false on failure.

Stop Emulation (from hook)

Stops emulation immediately. Intended for use inside hook callbacks to halt execution cleanly.


Notes (Hooks)

  • Hooks run during uc_start(...) execution.

  • Keep hook callbacks lightweight (they can fire very frequently, especially UC_HOOK_CODE).

  • If you stop execution from a hook, prefer:

    • uc_emu_stop(handle) and return false from the hook.


Examples

Example 1 — Read Notepad ImageBaseAddress via PEB (GS:[0x60])

This example:

  • References notepad.exe

  • Creates a process-backed Unicorn context

  • Reads PEB->ImageBaseAddress via:

    • mov rax, gs:[0x60] (PEB)

    • mov rax, [rax+0x10] (ImageBaseAddress)

    • ret (lands on STOP)

Copy


Example 2 — Patch Code In-Place + Flush Cache

This example shows why uc_flush_code exists. We run two different code blobs at the same address:

  • Run 1: mov rax, gs:[0x60]; ret (returns PEB)

  • Patch code in place

  • Flush translation cache

  • Run 2: mov rax, [abs64]; ret (returns ImageBase)

Copy


Example 3 — Local Sandbox Emulation (No Process)

This runs a tiny code snippet in a fully local emulator memory map.

Copy

Last updated