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 ST0, ST1, ST2, ST3, ST4, ST5, ST6, ST7 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)
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:
|
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:
|
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]
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
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
|
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);
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);