Assembly language crash course (Intel x86 Architecture)
The goal of this assembly language crash course is to help you have a quick overview of the assembly language, and transition from a higher-level language to a lower-level one (in this case, it’s assembly). Therefore, it is imperative that you already possess a programming background in order to be understand my explanations or references later on.
A good habit to have when learning assembly language is to convert these low level codes into that of a high level language to better understand the flow, logic and code.
Now, on to the actual assembly language. There are 3 main components that you should take note of when you first begin learning. Namely – Registers, Flags, and the Code itself.
Registers are like global variables which can hold 4 bytes (32 bits). Registers can be used for anything – for calculation, for copying of data, … There are however, standards or common usage for each register though. There are 8 of these registers – namely,
Eax, Ecx, Ebx, Edx – General purpose registers
Esi, Edi – Index register
Ebp – Pointer to base of current stack frame
Esp – Pointer to the top of the stack
Flags are well, flags … also known as EFLAGS (x86 system) or RFLAGS (x64 system). Like your normal programming flags, they are binary values – either 0 or 1 and are used to signify that an event has happened, which can can be used as part of your code’s decision-making logic.
Zero Flag (ZF) – If an operation has a result of 0, the ZF is set to 1. This flag is checked by conditional jump opcodes(the equivalent of ‘if’, ‘else’, ‘switch’ ..)
Overflow Flag (OF) – indicate when an arithmetic overflow happened in an operation
Sign Flag (SF) – indicate whether the last mathematical operation resulted in a value in which the most significant bit was set. Or if you interpret the result as two’s complement, the negative flag will be set if the result was negative.
Codes are as you guessed it – codes. One line of assembly code is usually made up of two components – an opcode and operand. An opcode is usually the prefix (or the code at the start of the line) and operand is everything else. Take a look at the example below (It’s alright if you don’t understand it yet)
mov eax, edx // mov is the opcode, eax & edx are operands.
sub ebx, edi// sub is the opcode, ebx & edi are operands
Now that you know what Registers, Flags, and Codes are, you will now need to know how assembly does its stuff – calculations, copying of data, calling a function and so on. There will be 3 parts to this.
- Data manipulation (calculation, copying of data..)
mov eax, edx // edx = eax; move the value from edx into eax
sub eax, edx // eax = eax – edx; // subtract edx with eax, result is in eax
add eax, edx // eax= eax + edx; // add edx with eax, result is in eax
note that while i used registers ‘eax’ and ‘edx’ above, they can also be replaced with a hard coded value. For example,
mov eax, 5
sub eax, 9
add eax, A // note : a constant value is usually denoted in hex
- Comparing of values
Now that you know how to do simple calculations in assembly, let’s move on to comparing of values in assembly. This is where the Zero Flag that I have mentioned earlier will come into use.
cmp eax, edx // if ( eax==edx ) ZF = 1;
On the surface it may be just comparing values, but underneath it, it does a subtraction of eax and edx. So if eax-edx == 0, the ZF is set to 1. The result of the subtraction is not stored anywhere.
test eax, eax // if ( eax==0 ) ZF = 1;
For the ‘test’ opcode, it does not do a subtraction, it instead does a bitwise AND. If the result of the bitwise AND operation is 0, the ZF is set to 1. In code it would look like if( (eax AND eax) == 0 ) ZF=1;
- Function calls & conditional jumps
Now that you know how CMP and TEST works, all that is left are the basic conditional jumps & calls
JMP location // unconditional jump – Jump regardless of what happens
JZ location // ‘jump if zero flag set’ – condition ZF=1
JNZ location // ‘jump if not zero flag set’ – condition ZF=0
JLE location // ‘jump if less than or equal’ – condition ZF = 1 or SF <> OF
JG location // ‘jump if greater’ – condition ZF = 0 and SF = OF
CALL location // nothing special. same as normal programming calls like foobar();
Now that you have a basic grasp of the assembly language, next thing you should do is to practise it ! Be it through programming or using assembly to reverse engineer – practise makes perfect.