Skip to content

Convenience routines for working with the Unicorn emulator in Python

License

Notifications You must be signed in to change notification settings

engene163/ucutils

 
 

Repository files navigation

ucutils - Unicorn Emulator Utilities

ucutils provides helper utilities and abstractions for working with the Unicorn CPU emulator. It simplifies memory management, register access, and architecture-specific operations while supporting both x86 and x64 architectures. The library also includes Windows-specific utilities for emulating Windows structures and behaviors.

For more comprehensive Windows emulation including API hooking and system call emulation, consider using the Speakeasy project. ucutils focuses on providing low-level CPU emulation utilities rather than full system emulation.

Create the extended emulator instance:

emu = ucutils.emu.Emulator(unicorn.UC_ARCH_X86, unicorn.UC_MODE_64)

Map and access memory (typical Unicorn API):

emu.mem_map(0x0, 0x1000)
code = b"\x48\xC7\xC0\x01\x00\x00\x00"  # mov rax, 0x1
emu.mem_write(0x0, code)
emu.emu_start(0x0, len(code))

Easily access registers:

assert emu.rax == 0x1

And, easily allocate and access memory:

addr = emu.mem.alloc(0x1000)
emu.mem_write(addr, b"AAAA")
assert emu.mem[addr:addr+4] == b"AAAA"

Stack operations:

emu.push(0xAA)
assert emu.pop() == 0xAA

Emulation stepping:

emu.mem_map(0x0, 0x1000)
code = b"\x48\xC7\xC0\x01\x00\x00\x00\x48\xC7\xC3\x02\x00\x00\x00"  # mov rax,0x1; mov rbx,0x2
emu.mem_write(0x0, code)
emu.stepi()  # Execute first instruction
assert emu.pc == 0x7
assert emu.rax == 0x1

Checkpointing:

assert emu.rax == 0x0
assert emu.rbx == 0x0

with ucutils.checkpoint.checkpoint(emu):
    emu.rax = 0x1
    emu.rbx = 0x2

    emu.stepi()

    # changes will be reverted after the block,
    # including memory contents and registry context.

assert emu.rax == 0x0
assert emu.rbx == 0x0

Install TEB and PEB for Windows process emulation (useful for tracing shellcode), and then load a PE file:

ucutils.plat.win64.map_teb(emu)

pe = pefile.PE(data=b"MZ...")
ucutils.plat.win.load_dll(emu, {"filename": "payload.dll", "pe": pe})

# exports are added to emu.symbols
assert "payload.dll!ServiceMain" in emu.symbols

# LDR_ENTRY is registered in emulated memory,
# which is useful for (shellcode) payloads that manually resolve imports.

About

Convenience routines for working with the Unicorn emulator in Python

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Python 99.3%
  • Just 0.7%