Skip to content

Pharo bindings to the Unicorn machine code simulation library

License

Notifications You must be signed in to change notification settings

doste/pharo-unicorn

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

39 Commits
 
 
 
 
 
 
 
 

Repository files navigation

pharo-unicorn

Pharo bindings to the Unicorn library (https://www.unicorn-engine.org)

Basic Example

The following example shows the basic usage of the Unicorn binding, based on the original example from Unicorn's site in https://www.unicorn-engine.org/docs/tutorial.html. The example first creates an emulator and sets up 2MB of memory. It then writes two instructions on it that increase register ECX and decrease register EDX, and it initializes registers ECX and EDX with two values. Finally, it runs the programs and retrieves the modified values from the registers.

unicorn := Unicorn x86.
address := 16r1000000.
errorCode := unicorn mapMemoryOfSize: 2 * 1024 * 1024 atAddress: address withPermissions: UnicornConstants permissionAll.

x86_CODE32 := #[ 16r41 16r4a ]. "INC ecx; DEC edx".
errorCode := unicorn memoryAt: address write: x86_CODE32 size: x86_CODE32 size.

ecx := UcX86Registers ecx.
edx := UcX86Registers edx.

ecxValue := #[ 16r34 16r12 ].
edxValue := #[ 16r90 16r78 ].
unicorn register: ecx value write: ecxValue.
unicorn register: edx value write: edxValue.

errorCode := unicorn startAt: address until: address + x86_CODE32 size timeout: 0 count: 0.

unicorn register: ecx value readInto: ecxValue.
unicorn register: edx value readInto: edxValue.

Creating a Unicorn engine

Creating an engine requires providing an architecture and a mode to #architecture:mode: using the constants defined in UnicornConstants. Unicorn's class side defines some predefined constructors for common configurations:

engine := Unicorn arm.
engine := Unicorn arm64.

engine := Unicorn x86.
engine := Unicorn x8664

Manipulating Memory

Mapping memory

To setup a memory in the emulator, two different ways are supported: either to map a new chunk of memory of a certain size to an address:

unicorn mapMemoryOfSize: 2 * 1024 * 1024 atAddress: address withPermissions: UnicornConstants permissionAll

Or to map an existing piece of memory (typically a pharo byte array).

unicorn mapHostMemory: aByteArray atAddress: address withPermissions: UnicornConstants permissionAll

Permissions set what is doable with that chunk of mapped memory and are combinable by simple aritmethic (they are a bit mask).

Reading / Writing

Methods #memoryAt:write: and #memoryAt:readNext: allow to write a byte array or read into a byte array to/from the memory at an address.

Registers

Two main methods allow reading and writing from/to registers: #register:readInto: and #register:write:. Registers are represented by ids in the different *Registers enumerations (see for example UcX86Registers).

Emulation

A single method (#startAt:until:timeout:count:) allows to start the execution of a memory at a location. Three different stop conditions can be set: a final address, a timeout in microseconds or a number of instructions to execute.

About

Pharo bindings to the Unicorn machine code simulation library

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Smalltalk 100.0%