sicurezza informatica - lasersecurity.di.unimi.it/sicurezza1314/slides/lezione2.pdf · stack •...
TRANSCRIPT
Sicurezza Informatica
Lez. 2 Assembler (II parte)
A.A. 2013/2014 Sicurezza Informatica © Danilo Bruschi
Stack
• Many CPU’s have built-in support for a stack A stack is a Last-In First-Out (LIFO) list
• The stack is an area of memory that is organized in this fashion. The PUSH instruction adds data to the stack and the POP instruction removes data
• The data removed is always the last data added • The ESP register contains the address of the data that would be
removed from the stack. This data is said to be at the top of the stack • The processor references the SS register automatically for all stack
operations. Also, the CALL, RET, PUSH, POP, ENTER, and LEAVE instructions all perform operations on the current stack.
• Data can only be added in double word units. That is, one can not push a single byte on the stack
A.A. 2013/2014 Sicurezza Informatica © Danilo Bruschi
Runtime Stack
• Managed by the CPU, using two registers • SS (stack segment) • ESP (stack pointer) *
* SP in Real-address mode
00000006 ESP00001000
Offset
00000FF8
00000FF4
00000FF0
00000FFC
PUSH
• The PUSH instruction inserts a double word on the stack by subtracting 4 from ESP and then stores the double word at [ESP]
!
• The 80x86 also provides a PUSHA instruction that pushes the values of EAX, EBX, ECX, EDX, ESI, EDI and EBP registers (not in this order)
pushl src ! à !subl $4,%esp!! ! ! ! !movl src,(%esp)!
A.A. 2013/2014 Sicurezza Informatica © Danilo Bruschi
PUSH Operation (1 of 2) • A 32-bit push operation decrements the stack pointer
by 4 and copies a value into the location pointed to by the stack pointer.
00000006 00000006
ESP
00001000
00000FFC
00000FF8
00000FF4
00000FF0
000000A5
ESP00001000
BEFORE
00000FFC
00000FF8
00000FF4
00000FF0
AFTER
PUSH Operation (2 of 2) • This is the same stack, after pushing two more
integers:
00000006
ESP
00001000
Offset
00000FFC
00000FF8
00000FF4
00000FF0
000000A5
00000001
00000002
The stack grows downward. The area below ESP is always available (unless the stack has overflowed).
POP
• The POP instruction reads the double word at [ESP] and then adds 4 to ESP
• The popa instruction, recovers the original values of the registers saved by the pusha!
A.A. 2013/2014 Sicurezza Informatica © Danilo Bruschi
!popl dest ! à movl (%esp),dest!! ! ! ! addl $4,%esp!
POP Operation • Copies value at stack[ESP] into a register or variable. • Adds n to ESP, where n is either 2 or 4.
• depends on the operand receiving the data
BEFORE AFTER
00000006
000000A5
00000001
00000002 ESP
00000006
000000A5
00000001 ESP
00001000
00000FFC
00000FF8
00000FF4
00000FF0
00001000
00000FFC
00000FF8
00000FF4
00000FF0
Esercizio
• Scrivere un programma in assembler che inverte il contenuto di una stringa data.
• Esempio: • Data la stringa: Hello World! • Stampa la stringa: !dlroW olleH
A.A. 2013/2014 Sicurezza Informatica © Danilo Bruschi
Function call
• Calling and returning • How does caller function jump to callee function? • How does callee function jump back to the right place in caller
function? • Passing parameters
• How does caller function pass parameters to callee function? • Storing local variables
• Where does callee function store its local variables? • Handling registers
• How do caller and callee functions use same registers without interference?
• Returning a value • How does callee function send return value back to caller function?
A.A. 2013/2014 Sicurezza Informatica © Danilo Bruschi
Calling and returning
• How does caller function jump to callee function? • I.e., Jump to the address of the callee’s first instruction
• How does the callee function jump back to the right place in caller function?
• Jump to the instruction immediately following the most-recently-executed call instruction
A.A. 2013/2014 Sicurezza Informatica © Danilo Bruschi
CALL/RET
• The 80x86 provides two instructions that use the stack to make calling subprograms quick and easy. The CALL instruction makes an unconditional jump to a subprogram and pushes the address of the next instruction on the stack.
• The RET instruction pops off an address and jumps to that address.
• When using these instructions, it is very important that one manage the stack correctly so that the right number is popped off by the RET instruction
A.A. 2013/2014 Sicurezza Informatica © Danilo Bruschi
Implementation of Call
• call subprogram1 becomes:!pushl %eip!jmp subprogram1 !!!!!ESP à!
A.A. 2013/2014 Sicurezza Informatica © Danilo Bruschi
Saved EIP!
Implementation of ret
• ret becomes:!• pop %eip!
• ESP à!
A.A. 2013/2014 Sicurezza Informatica © Danilo Bruschi
Saved EIP!
Passing Parameters
• How does caller function pass parameters to callee function?
• Attempted solution: Pass parameters in registers • Problem: Cannot handle nested function calls • Also: How to pass parameters that are longer than 4 bytes?
• Caller pushes parameters before executing the call instruction
• Parameters are pushed in the reverse order • Push the nth parameter first • Push 1° parameter last
A.A. 2013/2014 Sicurezza Informatica © Danilo Bruschi
Parameter
A.A. 2013/2014 Sicurezza Informatica © Danilo Bruschi
Parameter n!
Parameter …!
Parameter 1!ESP before à call
Parameter
A.A. 2013/2014 Sicurezza Informatica © Danilo Bruschi
Parameter n!
Parameter …!
Parameter 1!
Saved EIP!ESP after à call
Callee addresses params relative to ESP: Param 1 as 4(%esp)
Parameter
• After returning to the caller, the caller pops the parameters from the stack !… ! ! ! !sub:!# Push parameters ! !…!pushl $5 ! ! !movl 4(%esp),var1!pushl $4 ! ! !movl 8(%esp),var2!pushl $3 ! ! !movl 12(%esp), var3!call sub ! ! !…!# Pop parameters ! !ret!addl $12, %esp!
A.A. 2013/2014 Sicurezza Informatica © Danilo Bruschi
%ebp
• As callee executes, ESP may change • E.g., preparing to call another function
• It can be very error prone to use ESP when referencing parameters. To solve this problem, the 80386 supplies another register to use: EBP. This register’s only purpose is to reference data on the stack
• Use EBP as fixed reference point to access params
A.A. 2013/2014 Sicurezza Informatica © Danilo Bruschi
Using EBP (prolog)
• A subprogram before overwriting ebp first save the old value of EBP on the stack and then set EBP to be equal to ESP. This allows ESP to change as data is pushed or popped off the stack without modifying EBP
pushl %ebp!! !movl !%esp, %ebp!! !(sub !Local_bytes, %esp)!
• Regardless of ESP, the subprogram can reference param 1 as 8(%ebp), param 2 as 12(%ebp), etc.
A.A. 2013/2014 Sicurezza Informatica © Danilo Bruschi
Using ebp (epilog)
• Before returning, callee must restore ESP and EBP to their old values executing the epilog
movl %ebp, %esp!popl %ebp!ret!
A.A. 2013/2014 Sicurezza Informatica © Danilo Bruschi
Enter/Leave
• The ENTER instruction performs the prologue code and the LEAVE performs the epilogue
• The ENTER instruction takes two immediate operands. • For the C calling convention, the second operand is always 0.
The first operand is the number bytes needed by local variables. The LEAVE instruction has no operands
A.A. 2013/2014 Sicurezza Informatica © Danilo Bruschi
Epilogo
A.A. 2013/2014 Sicurezza Informatica © Danilo Bruschi
Parameter n!
Parameter …!
Parameter 1!
Saved EIP!
Old EBP!Ebp à
Esp à
movl %ebp, %esp popl %ebp ret
à
Epilogo
A.A. 2013/2014 Sicurezza Informatica © Danilo Bruschi
Parameter n!
Parameter …!
Parameter 1!
Saved EIP!
Old EBP!Esp = Ebp à movl %ebp, %esp popl %ebp ret
à
Epilogo
A.A. 2013/2014 Sicurezza Informatica © Danilo Bruschi
Parameter n!
Parameter …!
Parameter 1!
Saved EIP!Esp à movl %ebp, %esp popl %ebp ret
à
Ebp à
Epilogo
A.A. 2013/2014 Sicurezza Informatica © Danilo Bruschi
Parameter n!
Parameter …!
Parameter 1!Esp à
movl %ebp, %esp popl %ebp ret à
Ebp à
Storing local variables • Where does callee function store its local variables? • Local variables:
• Short-lived, so don’t need a permanent location in Memory • Size known in advance, so don’t need to allocate on the
heap
• The function just uses the top of the stack • Local variables of the callee are allocated on the
stack by moving the stack pointer • subl $8,%esp #allocate memory for 2 integers!
• Reference local variables as negative offsets relative to EBP!
A.A. 2013/2014 Sicurezza Informatica © Danilo Bruschi
Registers Handling
• How do caller and callee functions use same registers without interference?
• Callee may use a register that the caller also is using • Solution: save the registers on the stack
• Someone must save old register contents • Someone must later restore the register contents
• Define a convention for who saves and restores which registers
A.A. 2013/2014 Sicurezza Informatica © Danilo Bruschi
Registers handling
• Caller-save registers EAX, EBX, ECX … (when necessary…) • Saves on stack before call • Restores from stack after call
• Callee-save registers EAX, EBX, ECX … (when necessary) • Saves on stack after prolog • Restores from stack before epilog
A.A. 2013/2014 Sicurezza Informatica © Danilo Bruschi
Stack Frame
• Any active function has its own stack frame • Stack frame contains:
• Return address (Saved EIP) • Old EBP • Saved register values • Local variables • Parameters to be passed to callee function
• ESP points to top (low memory) of current stack frame
• EBP points to bottom (high memory) of current stack frame
A.A. 2013/2014 Sicurezza Informatica © Danilo Bruschi
Esempio: stack.c
A.A. 2013/2014 Sicurezza Informatica © Danilo Bruschi
#include <stdio.h>!int main() {!
!int x = foo( 10 );!!printf( "the value of x = %d\n", x );!!return 0;!!}!
int foo( int i ) {!!int ii = i + i;!!int iii = bar( ii );!!int iiii = iii;!!return iiii;!!}!
int bar( int j ) {!!int jj = j + j;!!return jj;!!}!
Compiliamo con il comando gcc –S stack.c - o stack.s!
Lo stack che ci aspettiamo
jj
Ret. Addr. foo
j
iiii
iii ii
Ret. Addr. main
i
x
ESP à
bar
foo
main A.A. 2013/2014 Sicurezza Informatica © Danilo Bruschi
Saved EBP
Saved EBP
Assembler: main
A.A. 2013/2014 Sicurezza Informatica © Danilo Bruschi
.file "stack.c"! .section .rodata!.LC0:! .string "the value of x = %d\n"! .text!.globl main! .type main, @function!main:! leal 4(%esp), %ecx! andl $-16, %esp! pushl -4(%ecx)! pushl %ebp! movl %esp, %ebp! pushl %ecx! subl $36, %esp! movl $10, (%esp)! call foo! movl %eax, -8(%ebp)! movl -8(%ebp), %eax! movl %eax, 4(%esp)! movl $.LC0, (%esp)! call printf! movl $0, %eax! addl $36, %esp! popl %ecx! popl %ebp!
Assembler : foo
A.A. 2013/2014 Sicurezza Informatica © Danilo Bruschi
.globl foo! .type foo, @function!foo:! pushl %ebp! movl %esp, %ebp! subl $24, %esp! movl 8(%ebp), %eax! addl %eax, %eax! movl %eax, -12(%ebp)! movl -12(%ebp), %eax! movl %eax, (%esp)! call bar! movl %eax, -8(%ebp)! movl -8(%ebp), %eax! movl %eax, -4(%ebp)! movl -4(%ebp), %eax! leave! ret! .size foo, .-foo!
Assembler: foo
A.A. 2013/2014 Sicurezza Informatica © Danilo Bruschi
.globl bar! .type bar, @function!bar:! pushl %ebp! movl %esp, %ebp! subl $16, %esp! movl 8(%ebp), %eax! addl %eax, %eax! movl %eax, -4(%ebp)! movl -4(%ebp), %eax! leave! ret! .size bar, .-bar!
Compilazione ottimizzata
Non Ottimizzata
.globl bar! .type bar, @function!bar:! pushl %ebp! movl %esp, %ebp! subl $16, %esp! movl 8(%ebp), %eax! addl %eax, %eax! movl %eax, -4(%ebp)! movl -4(%ebp), %eax! leave! ret! .
Ottimizzata
.globl bar! .type bar,@function!bar:! pushl %ebp! movl %esp, %ebp! movl 8(%ebp), %eax! addl %eax, %eax! popl %ebp! ret! !
A.A. 2013/2014 Sicurezza Informatica © Danilo Bruschi
Compilazione ottimizzata
Non Ottimizzata .globl foo! .type foo, @function!foo:!
pushl %ebp! movl %esp, %ebp! subl $24, %esp! movl 8(%ebp), %eax! addl %eax, %eax! movl %eax, -12(%ebp)!
movl -12(%ebp), %eax! movl %eax, (%esp)! call bar! movl %eax, -8(%ebp)! movl -8(%ebp), %eax! movl %eax, -4(%ebp)!
movl -4(%ebp), %eax! leave! ret!
Ottimizzata .globl foo! .type foo, @function!foo:! pushl %ebp! movl %esp, %ebp! subl $4, %esp! movl 8(%ebp), %eax! addl %eax, %eax! movl %eax, (%esp)! call bar! leave! ret!
A.A. 2013/2014 Sicurezza Informatica © Danilo Bruschi
Esercizio
• Risolvere i seguenti esercizi e descrivere quali sono i principi di funzionamento della soluzione adottata
A.A. 2013/2014 Sicurezza Informatica © Danilo Bruschi
A.A. 2013/2014 Sicurezza Informatica © Danilo Bruschi
Esercizio 1
/* stack1-stdin.c *! * specially crafted to feed your brain by gera
InsecureProgramming */!!#include <stdio.h>!!int main() {!!int cookie;!!char buf[80];!
!!printf("buf: %08x cookie: %08x\n", &buf, &cookie);!!gets(buf);!
!!if (cookie == 0x41424344)!! !printf("you win!\n");!
}!
A.A. 2013/2014 Sicurezza Informatica © Danilo Bruschi
Esercizio 2
/* stack2-stdin.c *! * specially crafted to feed your brain by gera */!!#include <stdio.h>!!int main() {!!int cookie;!!char buf[80];!
!!printf("buf: %08x cookie: %08x\n", &buf, &cookie);!!gets(buf);!
!!if (cookie == 0x01020305)!
! !printf("you win!\n");!}!