structure’s address is obtained, and might shed some light on the nature of
this data structure. I will be demonstrating all kinds of techniques for investi-
gating data structures in the reversing examples throughout this book.
The final instruction in this sequence is an IMUL(signed multiply) instruc-
tion. IMULhas several different forms, but when specified with two operands
as it is here, it means that the first operand is multiplied by the second, and
that the result is written into the first operand. This means that the value of
EDIwill be multiplied by the value of EBXand that the result will be written
back into EDI.
If you look at these three instructions as a whole, you can get a good idea of
their purpose. They basically take two different members of the same data
structure (whose address is taken from ECX), and multiply them. Also, because
IMULis used, you know that these members are signed integers, apparently
32-bits long. Not too bad for three lines of assembly language code!
For the final example, let’s have a look at what an average function call
sequence looks like in IA-32 assembly language.
push eax
push edi
push ebx
push esi
push dword ptr [esp+0x24]
call 0x10026eeb
This sequence pushes five values into the stack using the PUSHinstruction.
The first four values being pushed are all taken from registers. The fifth and
final value is taken from a memory address at ESPplus 0x24. In most cases,
this would be a stack address (ESPis the stack pointer), which would indicate
that this address is either a parameter that was passed to the current function
or a local variable. To accurately determine what this address represents, you
would need to look at the entire function and examine how it uses the stack. I
will be demonstrating techniques for doing this in Chapter 5.
A Primer on Compilers and Compilation
It would be safe to say that 99 percent of all modern software is implemented
using high-level languages and goes through some sort of compiler prior to
being shipped to customers. Therefore, it is also safe to say that most, if not all,
reversing situations you’ll ever encounter will include the challenge of deci-
phering the back-end output of one compiler or another.
Because of this, it can be helpful to develop a general understanding of com-
pilers and how they operate. You can consider this a sort of “know your
enemy” strategy, which will help you understand and cope with the difficul-
ties involved in deciphering compiler-generated code.
Low-Level Software 53