ESIL(7) Miscellaneous Information Manual ESIL(7)

ESIL - Evaluable Strings Intermediate Language

ESIL provides an abstract, stack-based format for representing CPU instruction semantics across various architectures, facilitating instruction emulation for analysis and debugging within the radare2 framework.

Evaluable Strings Intermediate Language (ESIL) adopts a Forth-like syntax, offering a method to describe and emulate the behavior of machine instructions in a platform-agnostic manner. It is particularly useful in reverse engineering, allowing for cross-architecture binary analysis and exploitation through radare2.

ESIL expressions use a series of operands and operations, manipulating values on an internal stack. These expressions are executed within an ESIL virtual machine (VM), enabling the simulation of CPU instructions' effects on registers and memory.

Uppercase words are special keywords that operate on the esil VM.

Lowercase words are register names that can be used for reading or writing through operations.

Words starting with $ represent internal variables of the VM that are readonly

Numbers can be in base 10 or hexadecimal.

The rest of keywords can be added or removed via esil or arch plugins, but this document describes all the common and standard ESIL commands. Note that the list of instructions is subject to change (will be reduced over time) for simplicity reasons.

Radare2's visual mode and various configuration options, such as `emu.str` and `asm.esil`, facilitate the inspection of ESIL evaluations alongside traditional disassembly. This dual view can greatly enhance understanding of binary behavior without requiring physical execution.

Radare2 leverages ESIL for detailed emulation of instruction execution, enabling users to step through instructions, inspect changes to registers and memory, and evaluate conditional logic in a controlled environment.

In the visual mode of radare2 you can emulate code doing single stepping, but it is also possible to debug the expressions using the `aev` command

ae: Evaluate an ESIL expression. Note that some expressions contain special characters that can be evaluated by the radare2 shell, so it's better to prefix the command with a single quote ' to skip that parsing.

"aev": Enter the interactive visual debugger to debug and emulate an esil expression.

"aes": ESIL Step: execute a single step in ESIL emulation.

"aeso": ESIL Step Over: perform a step over call instructions in ESIL emulation.

"aesu": ESIL Step Until: continue ESIL execution until a specified address is reached.

"ar": Show or modify ESIL registers.

The comma separated words in an ESIL expression can be grouped into different scopes:

internal flags
Prefixed with '$' they represent internal states of the esil vm and are used to perform conditional

comparison flags: $z, $c, $b, $p, $s, $o, $ds, $jt, $js

current address: $$

assignment
Pop the value and the destination from the stack

"=": strong assignment (update flags)

":=": weak assignment without updating flags

arithmetic and binary operations
Basic math operations like add, sub, mul, mod, div, shift, rotate, and, or

+ - / * %

"~" sign extend

"<<" shift left (see ">>" for shift right)

"<<<" rotate left (">>>" for rotate right

"<<<<" arithmetic shift left (">>>>" for asr)

"&" binary AND

"|" binary OR

"!" negate value ins tack

"L*": long multiplication

"*": multiplication

"^": xor

"~/": signed division

"%": mod

comparison

Comparison words update the internal flags and can be used to make conditional operations.

"<": smaller than

"<=": smaller or equal

"<=": bigger or equal

">": bigger than

"==": compare equality

control flow
Conditional expressions, loops

GOTO BREAK "?{" "}" "}{"

memory access
The memory access expressions contain the [] braces to read and =[] to write, address and value are popped from the stack, and size is defined between the brackets.

In order to simplify the VM and reduce the amount of keywords those combined operations may change in the future.

reading: [1] [2] [4] [8] [16]

writing: =[1] =[2] =[4] =[8] =[16]

combined: |=[2] +=[4] &=[4] --=[2]

special [*] =[*]

special
Represented as uppercase words, they are used to manipulate the internal esil stack, swaping, perform a cast, set flags and so on

STACK POP TODO CLEAR DUP NUM SWAP TRAP BITS SETJT SETJTS SETD

other (may use uppercase words)

"()": syscall "$": interrupt "#!": r2 command

floating point

NAN I2D U2D D2I D2F F2D F== F!= F< F<= F+ F- F* F/ -F CEIL FLOOR ROUND SQRT

Core operations in ESIL are designed to replicate basic CPU instructions' behavior, including arithmetic, logical, and control flow.

"=" Assignment: Transfers the value from the right operand to the left operand.

"+" Addition: Adds the two topmost values on the stack, pushing the result.

"-" Subtraction: Subtracts the top value from the second top value on the stack, pushing the result.

"*" Multiplication: Multiplies the two topmost values on the stack, pushing the result.

"/" Division: Divides the second top value by the top value on the stack, pushing the result.

"[]" Memory Access: Represents reading or writing to memory, with operation size being context-dependent.

"?{" Conditional Execution: If the top value of the stack is not zero, execute the following block of instructions.

"$" Special Flags and Operations: Accesses internal VM flags for conditions like carry, zero, and overflow or performs special operations like system calls.

"<<", ">>" Bit Shifts: Performs bitwise shift left or right operations.

"&", "|", "^" Bitwise Operations: Executes AND, OR, XOR on the two topmost stack values.

"!" Logical NOT: Inverts the top value on the stack.

ESIL uses internal flags to represent the outcome of operations, similar to how CPU flags work. These flags enable conditional execution and comparisons within the ESIL VM.

"$z" Zero Flag: Set if the result of an operation is zero. Used to perform equality checks.

"$c" Carry Flag: Set if an operation results in a carry out of the most significant bit. Useful for unsigned arithmetic operations.

"$s" Sign Flag: Set if the result of an operation is negative, indicating the sign in signed arithmetic.

"$o" Overflow Flag: Set if an arithmetic operation produces a result too large for the destination register, indicating overflow in signed arithmetic.

"$p" Parity Flag: Set if the number of set bits in the operation result is even. Rarely used in high-level analysis.

Flags are often used following comparison or arithmetic operations to guide conditional jumps and other control flow decisions, mimicking the behavior of physical CPUs.

Compares EAX and EBX, setting the zero flag (zf) in ESIL if they are equal.
cmp eax, ebx -> ebx,eax,==,$z,zf,:="

Adds 1 to EAX, demonstrating basic arithmetic.
add eax, 1 -> 1,eax,+=

Jumps to the label if the zero flag (zf) is set, illustrating conditional execution based on comparison results.
jz .label -> zf,?{,.label,eip,=,}

Code-wars like game implemented on top of ESIL, this is the implementation used in the r2con conference.

https://github.com/radareorg/r2wars

radare2(1),

https://www.radare.org/

pancake <pancake@nopcode.org>

March 16, 2024