Emulation
Understanding the distinction between static analysis and dynamic analysis is crucial in reverse engineering. radare2 uses two different kind of instruction information to perform static analysis:
- OpType, Instruction Family plus other static details
- ESIL expression associated
Radare2 employs its own intermediate language and virtual machine, known as ESIL, for partial emulation (or imprecise full emulation).
Radare2's ESIL supports partial emulation across all platforms by evaluating those expressions.
Use Cases
There are many use cases for ESIL in radare2, not just bare code emulation:
- Resolve indirect branches
- Determine the likelity of a branch
- Search memory addresses matching complex nested conditionals
- Find out computed pointer references (
aae
or/re
) - Execution of a function portion
- Simulate behaviour of syscalls and imports
- r2wars (let's play!)
To view the ESIL representation of your program, use the ao~esil
command or enable the asm.esil
configuration variable. This will let you verify how the code is uplifted from assembly to ESIL and understand better how that works internally.
[0x00001660]> pdf
. (fcn) fcn.00001660 40
| fcn.00001660 ();
| ; CALL XREF from 0x00001713 (entry2.fini)
| 0x00001660 lea rdi, obj.__progname ; 0x207220
| 0x00001667 push rbp
| 0x00001668 lea rax, obj.__progname ; 0x207220
| 0x0000166f cmp rax, rdi
| 0x00001672 mov rbp, rsp
| .-< 0x00001675 je 0x1690
| | 0x00001677 mov rax, qword [reloc._ITM_deregisterTMCloneTable] ; [0x206fd8:8]=0
| | 0x0000167e test rax, rax
|.--< 0x00001681 je 0x1690
||| 0x00001683 pop rbp
||| 0x00001684 jmp rax
|``-> 0x00001690 pop rbp
` 0x00001691 ret
[0x00001660]> e asm.esil=true
[0x00001660]> pdf
. (fcn) fcn.00001660 40
| fcn.00001660 ();
| ; CALL XREF from 0x00001713 (entry2.fini)
| 0x00001660 0x205bb9,rip,+,rdi,=
| 0x00001667 rbp,8,rsp,-=,rsp,=[8]
| 0x00001668 0x205bb1,rip,+,rax,=
| 0x0000166f rdi,rax,==,$z,zf,=,$b64,cf,=,$p,pf,=,$s,sf,=,$o,of,=
| 0x00001672 rsp,rbp,=
| .-< 0x00001675 zf,?{,5776,rip,=,}
| | 0x00001677 0x20595a,rip,+,[8],rax,=
| | 0x0000167e 0,rax,rax,&,==,$z,zf,=,$p,pf,=,$s,sf,=,$0,cf,=,$0,of,=
|.--< 0x00001681 zf,?{,5776,rip,=,}
||| 0x00001683 rsp,[8],rbp,=,8,rsp,+=
||| 0x00001684 rax,rip,=
|``-> 0x00001690 rsp,[8],rbp,=,8,rsp,+=
` 0x00001691 rsp,[8],rip,=,8,rsp,+=
Commands
To manually set up imprecise ESIL emulation, run the following sequence of commands:
aei
to initialize the ESIL VMaeim
to initialize ESIL VM memory (stack)aeip
to set the initial ESIL VM IP (instruction pointer)- a sequence of
aer
commands to set the initial register values.
While performing emulation, please remember that the ESIL VM cannot emulate external calls system calls, nor SIMD instructions. Thus, the most common scenario is to emulate only a small chunk of code like encryption, decryption, unpacking, or a calculation.
After successfully setting up the ESIL VM, we can interact with it like a normal debugging session. The command interface for the ESIL VM is almost identical to the debugging interface:
aes
to step (ors
key in visual mode)aesi
to step over function callsaesu <address>
to step until some specified addressaesue <ESIL expression>
to step until some specified ESIL expression is metaec
to continue until break (Ctrl-C). This one is rarely used due to the omnipresence of external calls
In visual mode, all of the debugging hotkeys will also work in ESIL emulation mode.
In addition to normal emulation, it's also possible to record and replay sessions:
aets
to list all current ESIL R&R sessionsaets+
to create a new oneaesb
to step back in the current ESIL R&R session
You can read more about this operation mode in the Reverse Debugging chapter.
Options
The emulation can be triggered at analysis, runtime or at will with full manual control, in other words, the user can decide what and how to use ESIL.
To change some of the behaviours of the emulation engine in radare2 you can use the following options:
[0x00000000]> e??esil.
- esil.addr.size: maximum address size in accessed by the ESIL VM
- esil.breakoninvalid: break esil execution when instruction is invalid
- esil.dfg.mapinfo: use mapinfo for esil dfg
- esil.dfg.maps: set ro maps for esil dfg
- esil.exectrap: trap when executing code in non-executable memory
- esil.fillstack: initialize ESIL stack with (random, debruijn, sequence, zeros, ...)
- esil.gotolimit: maximum number of gotos per ESIL expression
- esil.iotrap: invalid read or writes produce a trap exception
- esil.maxsteps: If !=0 defines the maximum amount of steps to perform on aesu/aec/..
- esil.mdev.range: specify a range of memory to be handled by cmd.esil.mdev
- esil.nonull: prevent memory read, memory write at null pointer
- esil.prestep: step before esil evaluation in
de
commands - esil.romem: set memory as read-only for ESIL
- esil.stack.addr: set stack address in ESIL VM
- esil.stack.depth: number of elements that can be pushed on the esilstack
- esil.stack.pattern: specify fill pattern to initialize the stack (0, w, d, i)
- esil.stack.size: set stack size in ESIL VM
- esil.stats: statistics from ESIL emulation stored in sdb
- esil.timeout: a timeout (in seconds) for when we should give up emulating
- esil.verbose: show ESIL verbose level (0, 1, 2)
Problems
There are several situations where emulation will not work as expected or solve your problems. It is important to understand those situations to avoid undesired surprises and know how to workaround them.
- Path explossion (too many execution or unknown paths to follow)
- Incorrect stack size or contents (aeim)
- Thread local storage (custom segments or memory layouts) not defined
- Unimplemented instructions (Use ahe to set analysis hints)
- Undefined behaviour (analy
- Custom Ops (requires esil plugins)
- Don't go into Syscall / Imports implementations