Expressions

Evaluation of expressions is done in two steps. First, OllyDbg compiles expression into the intermediate binary form. On the second step, it calculates its value. The evaluation is usually orders of magnitude faster than compilation.

Expressions may be roughly divided in two classes: those used to make a decision (for example, conditional breakpoints) and those used to display data. In the first case you need only one value. In the second case, user may want to see multiple values and expressions at once.


Basic elements

Expressions may include:
  • Byte registers AL, BL, CL, DL, AH, BH, CH, DH
  • Word registers AX, BX, CX, DX, SP, BP, SI, DI
  • Doubleword registers EAX, EBX, ECX, EDX, ESP, EBP, ESI, EDI
  • Segment registers CS, DS, ES, SS, FS, GS
  • FPU registers ST0ST1ST2ST3ST4ST5ST6ST7 or alternative forms ST, ST(0)ST(1)ST(2)ST(3)ST(4)ST(5)ST(6)ST(7)
  • Index pointer EIP
  • CPU flags EFL or alternative form FLAGS
  • Simple labels, like GetWindowTextA or userdefinedlabel1
  • Known constants, like WM_PAINT or ERROR_FILE_NOT_FOUND
  • Labels with prepended module name, like user32.GetWindowTextA
  • Immediate integer numbers, like ABCDEF01, 123, 0x123 (all hexadecimal) or 123. (decimal)
  • Immediate floating point numbers, like 123.456e-33
  • Immediate strings, like "String"
  • Parameters %A and %B
  • Thread identifier %THR (or alternative form %THREAD)
  • Ordinal number of the current thread %ORD (or alternative form %ORDINAL)
  • Contents of memory (requires square brackets [ ], see detailed description below)
Elements are processed in the listed order. Therefore AH is always interpreted as a 8-bit register and not as a hexadecimal constant 0Ah. For the same reason, label EBP can't be used in expressions (but mymodule.EBP would be OK). If there is a label named ABCD, ABCD will be interpreted as address of this label and not as the hexadecimal number 0x0000ABCD.

When OS creates new thread, this thread gets more or less random thread identifier. One can use expressions like %THREAD==0x00000172, but they will be meaningless in the next debugging session. To overcome this problem, at least partially, OllyDbg assigns each new thread its unique ordinal number. Main thread gets number 1, next thread created by the application has ordinal 2 etc. Temporary threads created by OS are not numbered (their ordinal is 0). If you want that breakpoint pauses application only in the main thread, you may set condition to %ORD==1.


Signed vs. unsigned data

By default, all integer variables and constants are unsigned. To interprete item as signed, prepend it with unary sign
('+' or '-') or with modifier SIGNED. To convert signed item to unsigned, use UNSIGNED. Examples:

Unsigned
Signed
0xFFFFFFFF +0xFFFFFFFF (-1.)
EAX +EAX
ECX SIGNED ECX
[DWORD 4F5024] [SIGNED DWORD 4F5024]

Floating-point items are always signed.


Contents of memory

To access memory, take address into the square brackets and optionally specify type and size of the item. OllyDbg supports following modifiers:

Modifier How the contents of memory is interpreted
BYTE Unsigned 8-bit integer
CHAR Signed 8-bit integer
WORD Unsigned 16-bit integer
SHORT Signed 16-bit integer
DWORD Unsigned 32-bit integer (default)
INT, LONG Signed 32-bit integer
FLOAT 32-bit floating-point number
DOUBLE 64-bit floating-point number
LONG DOUBLE 80-bit floating-point number
ASCII Address inside the brackets will be interpreted as a pointer to ASCII string, but numerical value of expression remains unchanged
UNICODE Address inside the brackets will be interpreted as a pointer to UNICODE string, but numerical value of expression remains unchanged

Syntax rules are relatively loose. The following five expressions have the same meaning:

[400000+EAX*32]
DWORD [400000+EAX*32]
[DWORD 32*EAX+400000]
DS:[DWORD 32*EAX+400000]
[DWORD DS:32*EAX+400000]


Multiple expressions

In the EMOD_MULTI evaluation mode, expression string may contain several subexpressions in the form text1=expr1,text2=expr2... Number of subexpressions is limited to NEXPR. Optional explanations (text1, text2) are pseudoidentifiers that comment subexpressions. If explanation is missing, OllyDbg creates one automatically. Example:

Expression compiled in EMOD_MULTI mode:

EAX,counter=ECX,[ESP],second=[ESP+4],third=[ESP+8]

Output of Eexpression() with specified index:

index=0: EAX = 12EBB8 (1239992.)
index=1: counter = 1BD9 (7129.)
index=2: [ESP] = 7C9011A7 (2089816487.)
index=3: second = 7
index=4: third = 1

Outermost memory bracket may contain repeat count, like [DWORD*10 EAX]. Modifier is obligatory, standalone repeat count *10 is treated as a syntax error. Repeat count tells OllyDbg to display the specified number of consecutive memory locations. Note that, according to OllyDbg syntax rules, constant 10 is hexadecimal. If you want decimal count, append a point: 
[DWORD*16. EAX]. Example:

Location [400000] contains
400000: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F

Expression Output
[BYTE*16. 400000] 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0A, 0B, 0C, 0D, 0E, 0F
[WORD*8 400000] 100, 302, 504, 706, 908, 0B0A, 0D0C, 0F0E
[DWORD*4 400000] 3020100, 7060504, 0B0A0908, 0F0E0D0C


String operations

Operations with strings are very limited. You may:
  • add or subtract integer to the string (C rules apply): [UNICODE EAX]+5
  • compare string with immediate string, ignoring case: [ASCII ESI]=="ABC". Comparison is limited to the length of the immediate string, so expression is true if ESI points to "ABCDE", "aBc" or "abc---" and false if ESI points to "AB" or "AABC"
  • compare pointer (doubleword) with immediate string, ignoring case, first assuming ASCII pointer and then UNICODE: ESI=="ABC"

API functions:

int Cexpression(wchar_t *expression,uchar *cexpr,int nexpr,int *explen,wchar_t *err,ulong mode);
int Exprcount(uchar *cexpr);
int Eexpression(t_result *result,wchar_t *expl,uchar *cexpr,int index,uchar *data,ulong base,ulong size,ulong threadid,ulong a,ulong b,ulong mode);
int Expression(t_result *result,wchar_t *expression,uchar *data,ulong base,ulong size,ulong threadid,ulong a,ulong b,ulong mode);
int Fastexpression(t_result *result,ulong addr,int type,ulong threadid);