Tutorial for Unicorn

This short tutorial shows how the Unicorn API works and how easy it is to emulate binary code. There are more APIs than those used here, but these are all we need to get started.

NOTE: you can also find some hand-on tutorials about Unicorn from Avatao website.

1. Tutorial for C language

The following sample code presents how to emulate 32-bit code of X86 in C language.

 1 #include <unicorn/unicorn.h>
 2 
 3 // code to be emulated
 4 #define X86_CODE32 "\x41\x4a" // INC ecx; DEC edx
 5 
 6 // memory address where emulation starts
 7 #define ADDRESS 0x1000000
 8 
 9 int main(int argc, char **argv, char **envp)
10 {
11   uc_engine *uc;
12   uc_err err;
13   int r_ecx = 0x1234;     // ECX register
14   int r_edx = 0x7890;     // EDX register
15 
16   printf("Emulate i386 code\n");
17 
18   // Initialize emulator in X86-32bit mode
19   err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc);
20   if (err != UC_ERR_OK) {
21     printf("Failed on uc_open() with error returned: %u\n", err);
22     return -1;
23   }
24 
25   // map 2MB memory for this emulation
26   uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
27 
28   // write machine code to be emulated to memory
29   if (uc_mem_write(uc, ADDRESS, X86_CODE32, sizeof(X86_CODE32) - 1)) {
30     printf("Failed to write emulation code to memory, quit!\n");
31     return -1;
32   }
33 
34   // initialize machine registers
35   uc_reg_write(uc, UC_X86_REG_ECX, &r_ecx);
36   uc_reg_write(uc, UC_X86_REG_EDX, &r_edx);
37 
38   // emulate code in infinite time & unlimited instructions
39   err=uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32) - 1, 0, 0);
40   if (err) {
41     printf("Failed on uc_emu_start() with error returned %u: %s\n",
42       err, uc_strerror(err));
43   }
44 
45   // now print out some registers
46   printf("Emulation done. Below is the CPU context\n");
47 
48   uc_reg_read(uc, UC_X86_REG_ECX, &r_ecx);
49   uc_reg_read(uc, UC_X86_REG_EDX, &r_edx);
50   printf(">>> ECX = 0x%x\n", r_ecx);
51   printf(">>> EDX = 0x%x\n", r_edx);
52 
53   uc_close(uc);
54 
55   return 0;
56 }


To compile this file, we need a Makefile like below.

LDFLAGS += $(shell pkg-config --libs glib-2.0) -lpthread -lm -lunicorn

all: test
%: %.c
    $(CC) $(CFLAGS) $^ $(LDFLAGS) -o $@


Readers can get this sample code in this tarball file. Compile and run it as follows (demonstrated on Mac OS X).

$ make
cc  test1.c -L/usr/local/Cellar/glib/2.44.1/lib -L/usr/local/opt/gettext/lib -lglib-2.0 -lintl  -lpthread -lm -lunicorn -o test1

$ ./test1
Emulate i386 code
Emulation done. Below is the CPU context
>>> ECX = 0x1235
>>> EDX = 0x788f


The C sample is intuitive, but just in case, readers can find below the explanation for each line of test1.c.


2. Tutorial for Python language

The following code presents the same example as above, but in Python, to emulate 32-bit code of X86.

 1 from __future__ import print_function
 2 from unicorn import *
 3 from unicorn.x86_const import *
 4 
 5 # code to be emulated
 6 X86_CODE32 = b"\x41\x4a" # INC ecx; DEC edx
 7 
 8 # memory address where emulation starts
 9 ADDRESS = 0x1000000
10 
11 print("Emulate i386 code")
12 try:
13     # Initialize emulator in X86-32bit mode
14     mu = Uc(UC_ARCH_X86, UC_MODE_32)
15 
16     # map 2MB memory for this emulation
17     mu.mem_map(ADDRESS, 2 * 1024 * 1024)
18 
19     # write machine code to be emulated to memory
20     mu.mem_write(ADDRESS, X86_CODE32)
21 
22     # initialize machine registers
23     mu.reg_write(UC_X86_REG_ECX, 0x1234)
24     mu.reg_write(UC_X86_REG_EDX, 0x7890)
25 
26     # emulate code in infinite time & unlimited instructions
27     mu.emu_start(ADDRESS, ADDRESS + len(X86_CODE32))
28 
29     # now print out some registers
30     print("Emulation done. Below is the CPU context")
31 
32     r_ecx = mu.reg_read(UC_X86_REG_ECX)
33     r_edx = mu.reg_read(UC_X86_REG_EDX)
34     print(">>> ECX = 0x%x" %r_ecx)
35     print(">>> EDX = 0x%x" %r_edx)
36 
37 except UcError as e:
38     print("ERROR: %s" % e)


Readers can get this sample code here. Run it with Python as follows.

$ python test1.py

Emulate i386 code
Emulation done. Below is the CPU context
>>> ECX = 0x1235
>>> EDX = 0x788f


The Python sample is intuitive, but just in case, readers can find below the explanation for each line of test1.py.


3. More examples

This tutorial does not explain all the API of Unicorn yet.

Have fun! If you do use Unicorn for something cool, let us know so we can link to your products.