Offensive Security & Reverse Engineering (OSRE) : Ali Hadi
Offensive Security & Reverse Engineering (OSRE) : Ali Hadi
Engineering (OSRE)
Ali Hadi
Intro. to x86 Assembly
“Crash Course”
Module #2
About this Lecture
The intent of this lecture is to expose you to the most
commonly generated assembly instructions, and the most
frequently dealt with architecture hardware.
@OpenSecurityTraining 4
What you're going to learn
#include <stdio.h>
int main()
{
printf(“Hello World!\n”);
return 0x1234;
}
@OpenSecurityTraining 5
Is the same as…
.text:00401730 main
.text:00401730 push ebp
.text:00401731 mov ebp, esp
.text:00401733 push offset aHelloWorld ; "Hello world\n"
.text:00401738 call ds:__imp__printf
.text:0040173E add esp, 4
.text:00401741 mov eax, 1234h
.text:00401746 pop ebp
.text:00401747 retn
Windows Visual C++ 2005, /GS (buffer overflow protection) option turned off
Disassembled with IDA Pro 4.9 Free Version
@OpenSecurityTraining 6
Is the same as…
08048374 <main>:
8048374: 8d 4c 24 04 lea 0x4(%esp),%ecx
8048378: 83 e4 f0 and $0xfffffff0,%esp
804837b: ff 71 fc pushl -0x4(%ecx)
804837e: 55 push %ebp
804837f: 89 e5 mov %esp,%ebp
8048381: 51 push %ecx
8048382: 83 ec 04 sub $0x4,%esp
8048385: c7 04 24 60 84 04 08 movl $0x8048460,(%esp)
804838c: e8 43 ff ff ff call 80482d4 <puts@plt>
8048391: b8 2a 00 00 00 mov $0x1234,%eax
8048396: 83 c4 04 add $0x4,%esp
8048399: 59 pop %ecx
804839a: 5d pop %ebp
804839b: 8d 61 fc lea -0x4(%ecx),%esp
804839e: c3 ret
804839f: 90 nop
Windows Visual C++ 2005, /GS (buffer overflow protection) option turned off
Optimize for minimum size (/O1) turned on
Disassembled with IDA Pro 4.9 Free Version
@OpenSecurityTraining 9
Instructions Needed
• By one measure, only 14 assembly instructions account for 90%
of code!
– http://www.blackhat.com/presentations/bh-usa-06/BH-US-06-Bilar.pdf
• Knowing about 20-30 (not counting variations) is good enough
that you will have the check the manual very infrequently
• You've already seen 11 instructions, just in the hello world
variations!
@OpenSecurityTraining 10
Refresher(s)
In C: char
short
int/long
double/long long
?->
long double?
@OpenSecurityTraining 12
Decimal, Binary, Hexidecimal
Decimal (base 10) Binary (base 2) Hex (base 16)
00 0000b 0x00
01 0001b 0x01
02 0010b 0x02
03 0011b 0x03
04 0100b 0x04
05 0101b 0x05
06 0110b 0x06
07 0111b 0x07
08 1000b 0x08
09 1001b 0x09
10 1010b 0x0A
11 1011b 0x0B
12 1100b 0x0C
13 1101b 0x0D
14 1110b 0x0E
15 1111b 0x0F
@OpenSecurityTraining 13
Negative Numbers
• “one's complement” = flip all bits. 0->1, 1->0
• “two's complement” = one's complement + 1
• Negative numbers are defined as the “two's complement” of the
positive number
@OpenSecurityTraining 14
Architecture(s)
@OpenSecurityTraining 16
Endian
• Endianness comes from Jonathan Swift's Gulliver's Travels. It
doesn't matter which way you eat your eggs :)
• Little Endian - 0x12345678 stored in RAM “little end” first.
The least significant byte of a word or larger is stored in the
lowest address. E.g. 0x78563412
– Intel is Little Endian
• Big Endian - 0x12345678 stored as is.
– Network traffic is Big Endian
– Most of the others you've heard of (PowerPC, ARM, SPARC, MIPS) is
either Big Endian by default or can be configured as either (Bi-
Endian)
@OpenSecurityTraining 17
Endianess Pictures
Big Endian Little Endian
High Memory
(Others) Addresses (Intel)
Register Register
00 0x5 00
FE ED FA CE FE ED FA CE
00 0x4 00
CE 0x3 FE
FA 0x2 ED
ED 0x1 FA
FE 0x0 CE
@OpenSecurityTraining 19
Register Conventions
• These are Intel's suggestions to compiler developers (and
assembly handcoders). Registers don't have to be used
these ways, but if you see them being used like this, you'll
know why.
• EAX - Stores function return values
• EBX - Base pointer to the data section
• ECX - Counter for string and loop operations
• EDX - I/O pointer
@OpenSecurityTraining 20
Registers Conventions – Cont.
• ESI - Source pointer for string operations
• EDI - Destination pointer for string operations
• ESP - Stack pointer
• EBP - Stack frame base pointer
• EIP - Pointer to next instruction to execute (“instruction
pointer”)
@OpenSecurityTraining 21
Registers Conventions – Cont.
• Caller-save registers - EAX, EDX, ECX
– If the caller has anything in the registers that it cares
about, the caller is in charge of saving the value before a
call to a subroutine, and restoring the value after the call
returns
– Put another way - the callee can (and is highly likely to)
modify values in caller-save registers
@OpenSecurityTraining 22
Registers Conventions – Cont.
• Callee-save registers - EBP, EBX, ESI, EDI
– If the callee needs to use more registers than are saved by
the caller, the callee is responsible for making sure the
values are stored/restored
– Put another way - the callee must be a good citizen and
not modify registers which the caller didn't save, unless
the callee itself saves and restores the existing values
@OpenSecurityTraining 23
Registers - 8/16/32 bit Addressing
http://www.sandpile.org/ia32/reg.htm @OpenSecurityTraining 24
Registers - 8/16/32 bit Addressing –
Cont.
http://www.sandpile.org/ia32/reg.htm
@OpenSecurityTraining 25
EFLAGS
• EFLAGS register holds many single bit flags.
• Remember the following for now:
– Zero Flag (ZF) - Set if the result of some instruction is zero;
cleared otherwise
– Sign Flag (SF) - Set equal to the most-significant bit of the
result, which is the sign bit of a signed integer. (0
indicates a positive value and 1 indicates a negative
value.)
@OpenSecurityTraining 26
1
Your first x86 instruction:
NOP
• NOP - No Operation! No registers, no values, no nothin'!
• Just there to pad/align bytes, or to delay time
• Bad guys use it to make simple exploits more reliable
– We’ll get to this later ☺
@OpenSecurityTraining 27
Extra! Extra!
Late-breaking NOP news!
• Amaze those who know x86 by citing this interesting bit of
trivia:
• “The one-byte NOP instruction is an alias mnemonic for the
XCHG (E)AX, (E)AX instruction.”
• XCHG instruction is not officially in this class. But if I hadn't
just told you what it does, I bet you would have guessed right
anyway.
@OpenSecurityTraining 28
The Stack
• The stack is a conceptual area of main memory (RAM) which
is designated by the OS when a program is started.
– Different OS start it at different addresses by convention
• A stack is a Last-In-First-Out (LIFO/FILO) data structure where
data is "pushed" on to the top of the stack and "popped" off
the top.
• By convention the stack grows toward lower memory
addresses.
• Adding something to the stack means the top of the stack is
now at a lower memory address.
@OpenSecurityTraining 29
The Stack – Cont.
• As already mentioned, ESP points to the top of the stack, the
lowest address which is being used
– While data will exist at addresses beyond the top of the stack, it is
considered undefined
• The stack keeps track of which functions were called before
the current one, it holds local variables and is frequently used
to pass arguments to the next function to be called.
• A firm understanding of what is happening on the stack is
*essential* to understanding a program's operation.
@OpenSecurityTraining 30
2
PUSH
Push Word, Dword, Qword onto the Stack
• For our purposes, it will always be a DWORD (4 bytes).
– Can either be an immediate (a numeric constant), or the value in a
register
• The push instruction automatically decrements the stack
pointer ESP by 4.
@OpenSecurityTraining 31
Registers Before Registers After
eax 0x00000003 eax 0x00000003
esp 0x0012FF8C push eax esp 0x0012FF88
0x0012FF80
undef undef
@OpenSecurityTraining 32
3
POP
Pop a Value from the Stack
• Take a DWORD off the stack, put it in a register, and increment
ESP by 4
@OpenSecurityTraining 33
Registers Before Registers After
eax 0xFFFFFFFF pop eax eax
esp
0x00000003
0x0012FF8C
esp 0x0012FF88
@OpenSecurityTraining 34
Calling Conventions
• How code calls a subroutine is compiler-dependent and
configurable. But there are a few conventions.
• We will only deal with the “cdecl” and “stdcall” conventions.
• More info at
– http://en.wikipedia.org/wiki/X86_calling_conventions
– http://www.programmersheaven.com/2/Calling-conventions
@OpenSecurityTraining 35
Calling Conventions - cdecl
• “C declaration” - most common calling convention
• Function parameters pushed onto stack right to left
• Saves the old stack frame pointer and sets up a new stack
frame
• EAX or EAX:EDX returns the result for primitive data types
• Caller is responsible for cleaning up the stack
@OpenSecurityTraining 36
Calling Conventions - stdcall
• Typically used by Microsoft C++ code (ex: Win32 API)
• Function parameters pushed onto stack right to left
• Saves the old stack frame pointer and sets up a new stack
frame
• EAX or EDX:EAX returns the result for primitive data types
• Callee responsible for cleaning up any stack parameters it
takes
@OpenSecurityTraining 37
4 CALL
Call Procedure
• CALL's job is to transfer control to a different function, in a
way that control can later be resumed where it left off
• First it pushes the address of the next instruction onto the
stack
– For use by RET for when the procedure is done
• Then it changes EIP to the address given in the instruction
• Destination address can be specified in multiple ways
– Absolute address
– Relative address (relative to the end of the instruction)
@OpenSecurityTraining 38
5
RET
Return from Procedure
Two forms
• Pop the top of the stack into EIP (remember pop
increments stack pointer)
– In this form, the instruction is just written as “ret”
– Typically used by cdecl functions
• Pop the top of the stack into EIP and add a constant number
of bytes to ESP
– In this form, the instruction is written as “ret 0x8”, or “ret 0x20”, etc
– Typically used by stdcall functions
@OpenSecurityTraining 40
General Stack Frame Operation
We are going to pretend that main() is the very first function being executed
in a program. This is what its stack looks like to start with (assuming it has
any local variables).
stack bottom
Local Variables
main() frame
undef
undef
…
stack top
@OpenSecurityTraining 41
Stack Frame Operation – Cont.
When main() decides to call a subroutine, main() becomes “the caller”. We will
assume main() has some registers it would like to remain the same, so it will save
them. We will also assume that the callee function takes some input arguments.
stack bottom
Local Variables
main() frame
Caller-Save Registers
undef
Arguments to Pass to Callee
undef
…
stack top
@OpenSecurityTraining 42
Stack Frame Operation – Cont.
When main() actually issues the CALL instruction, the return address gets saved
onto the stack, and because the next instruction after the call will be the beginning
of the called function, we consider the frame to have changed to the callee.
stack bottom
Local Variables
main() frame
Caller-Save Registers
undef
Arguments to Pass to Callee
Caller's saved return address undef
…
stack top
@OpenSecurityTraining 43
Stack Frame Operation – Cont.
When foo() starts, the frame pointer (EBP) still points to main()'s frame. So the
first thing it does is to save the old frame pointer on the stack and set the new
value to point to its own frame.
stack bottom
Local Variables
main() frame
Caller-Save Registers
foo()'s frame
Arguments to Pass to Callee
Caller's saved return address undef
Saved Frame Pointer …
stack top
@OpenSecurityTraining 44
Stack Frame Operation – Cont.
Next, we'll assume the the callee foo() would like to use all the registers, and
must therefore save the callee-save registers. Then it will allocate space for its
local variables.
stack bottom
Local Variables
main() frame
Caller-Save Registers
foo()'s frame
Arguments to Pass to Callee
Caller's saved return address undef
Saved Frame Pointer …
Callee-Save Registers stack top
Local Variables
@OpenSecurityTraining 45
Stack Frame Operation – Cont.
At this point, foo() decides it wants to call bar(). It is still the callee-of-
main(), but it will now be the caller-of-bar. So it saves any caller-save
registers that it needs to. It then puts the function arguments on the stack as
well.
stack bottom
Saved Frame Pointer
main() frame
Callee-Save Registers
foo()'s frame
Local Variables
Caller-Save Registers undef
Arguments to Pass to Callee …
stack top
@OpenSecurityTraining 46
General Stack Frame Layout
Every part of the stack frame is technically optional (that is, you can hand
code asm without following the conventions.)
But compilers generate code which uses portions if they are needed. Which
pieces are used can sometimes be manipulated with compiler options. (E.g.
omit frame pointers, changing calling convention to pass arguments in
registers, etc.)
stack bottom
Saved Frame Pointer
main() frame
Callee-Save Registers
foo()'s frame
Local Variables
Caller-Save Registers undef
Arguments to Pass to Callee …
stack top
@OpenSecurityTraining 47
Stack Frames are a Linked List!
The EBP in the current frame points at the saved EBP of the previous frame.
stack bottom
main() frame
foo()'s frame
bar()'s frame
…
stack top
@OpenSecurityTraining 48
Example1.c
//Example1 - using the stack sub:
//to call subroutines 00401000 push ebp
00401001 mov ebp,esp
//New instructions: 00401003 mov eax,0BEEFh
//push, pop, call, ret, mov 00401008 pop ebp
int sub(){ 00401009 ret
return 0xbeef; main:
00401010 push ebp
}
00401011 mov ebp,esp
int main(){ 00401013 call sub (401000h)
sub(); 00401018 mov eax,0F00Dh
return 0xf00d; 0040101D pop ebp
} 0040101E ret
sub:
0x0012FF6C 0x004012E8 ⌘
00401000 push ebp
00401001 mov ebp,esp
0x0012FF68 0x0012FFB8 ♍
00401003 mov eax,0BEEFh 0x0012FF64 undef
00401008 pop ebp
00401009 ret 0x0012FF60 undef
main:
00401010 push ebp ⌧ 0x0012FF5C undef
00401011 mov ebp,esp
00401013 call sub (401000h)
0x0012FF58 undef
00401018 mov eax,0F00Dh
0040101D pop ebp
0040101E ret
@OpenSecurityTraining 51
Example1.c 3
Key:
eax 0x003435C0 ⌘ ⌧ executed instruction,
ebp 0x0012FF68 ♍ ♍ modified value
esp 0x0012FF68 ⌘ start value
sub:
0x0012FF6C 0x004012E8 ⌘
00401000 push ebp ⌧
00401001 mov ebp,esp
0x0012FF68 0x0012FFB8
00401003 mov eax,0BEEFh
0x0012FF64 0x00401018
00401008 pop ebp
00401009 ret
0x0012FF60 0x0012FF68 ♍
main:
00401010 push ebp
0x0012FF5C undef
00401011 mov ebp,esp
00401013 call sub (401000h)
0x0012FF58 undef
00401018 mov eax,0F00Dh
0040101D pop ebp
0040101E ret
@OpenSecurityTraining 54
Example1.c 6
Key:
eax 0x003435C0 ⌘ ⌧ executed instruction,
ebp 0x0012FF60 ♍ ♍ modified value
esp 0x0012FF60 ⌘ start value
sub
push ebp
mov ebp, esp “Function-before-
main”'s frame
mov eax, 0BEEFh 0x0012FF6C 0x004012E8 ⌘
pop ebp
main's frame 0x0012FF68 0x0012FFB8
retn
(saved frame pointer
main and saved return address) 0x0012FF64
0x00401018
push ebp
mov ebp, esp sub's frame 0x0012FF60 0x0012FF68
call _sub (only saved frame pointer,
because it doesn't call 0x0012FF5C undef
mov eax, 0F00Dh
anything else, and doesn't
pop ebp have local variables) 0x0012FF58
undef
retn
@OpenSecurityTraining 56
Example1.c 7
Key:
eax 0x0000BEEF ⌧ executed instruction,
ebp 0x0012FF60 ♍ modified value
esp 0x0012FF60 ⌘ start value
@OpenSecurityTraining 57
Example1.c 8
Key:
eax 0x0000BEEF ⌧ executed instruction,
ebp 0x0012FF68 ♍ ♍ modified value
esp 0x0012FF64 ♍ ⌘ start value
@OpenSecurityTraining 58
Example1.c 9
Key:
eax 0x0000BEEF ⌧ executed instruction,
ebp 0x0012FF68 ♍ modified value
esp 0x0012FF68 ♍ ⌘ start value
@OpenSecurityTraining 59
Example1.c 9
Key:
eax 0x0000F00D ♍ ⌧ executed instruction,
ebp 0x0012FF68 ♍ modified value
esp 0x0012FF68 ⌘ start value
@OpenSecurityTraining 60
Example1.c 10
Key:
eax 0x0000F00D ⌧ executed instruction,
ebp 0x0012FFB8 ♍ ♍ modified value
esp 0x0012FF6C ♍ ⌘ start value
@OpenSecurityTraining 61
Example1.c 11
Key:
eax 0x0000F00D ⌧ executed instruction,
ebp 0x0012FFB8 ♍ modified value
esp 0x0012FF70 ♍ ⌘ start value
Execution would continue at the value ret removed from the stack: 0x004012E8
@OpenSecurityTraining 62
Example1 Notes
• sub() is deadcode - its return value is not used for anything,
and main always returns 0xF00D.
• If optimizations are turned on in the compiler, it would
remove sub()
• Also, because there are no input parameters to sub(), there is
no difference whether we compile as cdecl vs stdcall calling
conventions
@OpenSecurityTraining 63
"r/m32" Addressing Forms
• Anywhere you see an r/m32 it means it could be taking a
value either from a register or a memory address
• I'm just calling these “r/m32 forms” because anywhere you
see “r/m32” in the manual, the instruction can be a variation
of the forms in the next slide
@OpenSecurityTraining 66
8 9
ADD and SUB
• Adds or Subtracts, just as expected
• Destination operand can be r/m32 or register
• Source operand can be r/m32 or register or immediate
• No source and destination as r/m32s, because that could
allow for memory to memory transfer, which isn't allowed
on x86
• Evaluates the operation as if it were on signed AND unsigned
data, and sets flags as appropriate. Instructions modify OF,
SF, ZF, AF, PF, and CF flags
• add esp, 8
• sub eax, [ebx*2]
@OpenSecurityTraining 85
1
0 JMP
Jump
• Change EIP to the given address
• Main forms of the address
– Short relative (1 byte displacement from end of the instruction)
• “jmp 00401023” doesn’t have the number 00401023 anywhere in it, it’s
really “jmp 0x0E bytes forward”
• Some disassemblers will indicate this with a mnemonic by writing it as
“jmp short”
– Near relative (4byte displacement from current EIP)
– Absolute (hardcoded address in instruction)
– Absolute Indirect (address calculated with r/m32)
@OpenSecurityTraining 86
Example3.c
(Remain calm)
main:
00401010 push ebp
00401011 mov ebp,esp
00401013 sub esp,8
00401016 mov dword ptr [ebp-4],1
int main(){ 0040101D mov dword ptr [ebp-8],2
int a=1, b=2; 00401024 mov eax,dword ptr [ebp-4]
00401027 cmp eax,dword ptr [ebp-8]
if(a == b){ 0040102A jne 00401033
return 1; 0040102C mov eax,1
} 00401031 jmp 00401056
00401033 mov ecx,dword ptr [ebp-4]
if(a > b){
00401036 cmp ecx,dword ptr [ebp-8]
return 2; 00401039 jle 00401042
Jcc
} 0040103B mov eax,2
if(a < b){ 00401040 jmp 00401056
00401042 mov edx,dword ptr [ebp-4]
return 3; 00401045 cmp edx,dword ptr [ebp-8]
} 00401048 jge 00401051
return 0xdefea7; 0040104A mov eax,3
0040104F jmp 00401056
} 00401051 mov eax,0DEFEA7h
00401056 mov esp,ebp
00401058 pop ebp
00401059 ret
@OpenSecurityTraining 87
1
1 Jcc
Jump If Condition Is Met
• There are more than 4 pages of conditional jump types!
• Luckily a bunch of them are synonyms for each other.
• JNE == JNZ (Jump if not equal, Jump if not zero, both check if
the Zero Flag (ZF) == 0)
@OpenSecurityTraining 88
Notable Jcc Instructions
• JZ/JE: if ZF == 1
• JNZ/JNE: if ZF == 0
• JLE/JNG : if ZF == 1 or SF != OF
• JGE/JNL : if SF == OF
• JBE: if CF == 1 OR ZF == 1
• JB: if CF == 1
• Note: Don’t get hung up on memorizing which flags are set for
what. More often than not, you will be running code in a
debugger, not just reading it. In the debugger you can just
look at EFLAGS and/or watch whether it takes a jump.
@OpenSecurityTraining 89
Flag Setting
• Before you can do a conditional jump, you need something to
set the condition flags for you.
• Typically done with CMP, TEST, or whatever instructions are
already inline and happen to have flag-setting side-effects
@OpenSecurityTraining 90
1
2 CMP
Compare Two Operands
• “The comparison is performed by subtracting the second
operand from the first operand and then setting the status
flags in the same manner as the SUB instruction.”
• What’s the difference from just doing SUB? Difference is that
with SUB the result has to be stored somewhere. With CMP
the result is computed, the flags are set, but the result is
discarded. Thus this only sets flags and doesn’t mess up any of
your registers.
• Modifies CF, OF, SF, ZF, AF, and PF
• (implies that SUB modifies all those too)
@OpenSecurityTraining 91
1
3 TEST
Logical Compare
• “Computes the bit-wise logical AND of first operand (source 1
operand) and the second operand (source 2 operand) and
sets the SF, ZF, and PF status flags according to the result.”
• Like CMP - sets flags, and throws away the result
@OpenSecurityTraining 92
Example4.c
main:
00401010 push ebp
00401011 mov ebp,esp
#define MASK 0x100 00401013 push ecx
00401014 mov dword ptr [ebp-4],1301h
int main(){ 0040101B mov eax,dword ptr [ebp-4]
int a=0x1301; 0040101E and eax,100h
if(a & MASK){ jcc 00401023 je 0040102E
return 1; 00401025 mov eax,1
} 0040102A jmp 00401033 I actually
else{ 0040102C jmp 00401033 expected a
return 2; 0040102E mov eax,2 TEST,
} 00401033 mov esp,ebp because
} 00401035 pop ebp the result
00401036 ret isn't stored
Eventually found out why there
are 2 jmps!
(no optimization, so simple compiler rules) @OpenSecurityTraining 93
Refresher:
Boolean (”bitwise”) logic
0 0 0 0 0 0 0 0 0
0 1 0 0 1 1 0 1 1
1 0 0 1 0 1 1 0 1
1 1 1 1 1 1 1 1 0
Operands Result
NOT “~”
0 1
1 0
@OpenSecurityTraining 94
1
4 AND
Logical AND
• Destination operand can be r/m32 or register
• Source operand can be r/m32 or register or immediate (No
source and destination as r/m32s)
@OpenSecurityTraining 95
1
5 OR
Logical Inclusive OR
@OpenSecurityTraining 96
1
6 XOR
Logical Exclusive OR
• Destination operand can be r/m32 or register
• Source operand can be r/m32 or register or
immediate (No source and destination as r/m32s)
@OpenSecurityTraining 100
Book p. 225
1
9 SHR
Shift Logical Right
• Can be explicitly used with the C “>>” operator
• First operand (source and destination) operand is an r/m32
• Second operand is either cl (lowest byte of ecx), or a 1 byte immediate.
The 2nd operand is the number of places to shift.
• It divides the register by 2 for each place the value is shifted. More
efficient than a multiply instruction.
• Bits shifted off the right hand side are “shifted into” (set) the carry flag
(CF)
• For purposes of determining if the CF is set at the end, think of it as n
independent 1 bit shifts.
@OpenSecurityTraining 101
Example6.c
@OpenSecurityTraining 103
Back to Hello World
.text:00401730 main
.text:00401730 push ebp
.text:00401731 mov ebp, esp
.text:00401733 push offset aHelloWorld ; "Hello world\n“
.text:00401738 call ds:__imp__printf
.text:0040173E add esp, 4
.text:00401741 mov eax, 1234h
.text:00401746 pop ebp
.text:00401747 retn
Windows Visual C++ 2005, /GS (buffer overflow protection) option turned off
Disassembled with IDA Pro 4.9 Free Version
@OpenSecurityTraining 104
Instructions we now know(20)
• NOP
• PUSH/POP
• CALL/RET
• MOV/LEA
• ADD/SUB
• JMP/Jcc
• CMP/TEST
• AND/OR/XOR/NOT
• SHR/SHL
• LEAVE
@OpenSecurityTraining 105
Intel vs. AT&T Syntax
• Intel: Destination <- Source(s)
– Windows. Think algebra or C: y = 2x + 1;
– mov ebp, esp
– add esp, 0x14 ; (esp = esp + 0x14)
• AT&T: Source(s) -> Destination
– *nix/GNU. Think elementary school: 1 + 2 = 3
– mov %esp, %ebp
– add $0x14,%esp
– So registers get a % prefix and immediates get a $
• Important to know both, so you can read documents in either
format
– We will use Intel syntax
@OpenSecurityTraining 106
Intel vs AT&T Syntax – Cont.
• IMO the hardest-to-read difference is for r/m32 values
• For intel it’s expressed as
[base + index*scale + disp]
• For AT&T it’s expressed as
disp(base, index, scale)
• Examples:
– call DWORD PTR [ebx+esi*4-0xe8]
– call *-0xe8(%ebx,%esi,4)
@OpenSecurityTraining 108
SUMMARY
• Learned about the basic hardware registers and how they’re used
• Learned about how the stack is used
• Saw how C code translates to assembly
• Learned basic usage of compilers, disassemblers, and debuggers so that
assembly can easily be explored
• Learned about Intel vs AT&T asm syntax
@OpenSecurityTraining 109
References
• Open Security Training, Introductory Intel x86: (Architecture, Assembly,
Applications, & Alliteration) by Xeno Kovah,
http://www.opensecuritytraining.info/IntroX86.html
• Professional Assembly Language by Blum
@OpenSecurityTraining 110