Original kode (ligger i scripts/wait_for_change.c)
typedef struct _name_watch_t { char * file; int descriptor; struct _name_watch_t * next; } name_watch_t; name_watch_t * name_watch_alloc(char * file, int descriptor, name_watch_t * next) { name_watch_t * w = malloc(sizeof(name_watch_t)); w->file = file; w->descriptor = descriptor; w->next = next; return w; }
IDAs første decompilering
void *__fastcall name_watch_alloc(__int64 a1, int a2, __int64 a3) { __int64 v3; // ST08_8@1 void *result; // rax@1 v3 = a3; result = malloc(0x18uLL); *(_QWORD *)result = a1; *((_DWORD *)result + 2) = a2; *((_QWORD *)result + 2) = v3; return result; }
Efter lidt genskabelse af strukturer
name_watch_t *__fastcall name_watch_alloc(char *a1, int a2, name_watch_t *a3) { __int64 v3; // ST08_8@1 name_watch_t *result; // rax@1 v3 = (__int64)a3; result = (name_watch_t *)malloc(0x18uLL); result->file = (__int64)a1; result->descriptor = a2; result->next = v3; return result; }
$ strace ./breakme 2>&1 | tail -n 8 ptrace(PTRACE_TRACEME, 0, 0x1, 0) = -1 EPERM (Operation not permitted) fstat64(1, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xfffffffff772a000 write(1, "\nYou are debugging me, I don't l"..., 42 You are debugging me, I don't like it :( ) = 42 exit_group(1) = ? +++ exited with 1 +++
Kort introduktion eller genopfriskning.
i386 = CISC = helvedes mange instruktioner.
CPUens interne hukommelse
Bruges til betingede spring. Der er mange, men her er de vigtigste:
Hvad CPUen kan gøre. Igen, der er mange (CISC husker I nok), men vi kan klare os med meget få.
Kopierer data fra source til destination.
mov <dst>, <src> mov eax, 0x20 ;Register/Immediate mov ebx, eax ;Register/Register mov ecx, DWORD PTR [ebp+0x8] ;Register/Memory mov DWORD PTR [ebp-0x4], eax ;Memory/Register mov eax, DWORD PTR [eax] ;Register/Memory
movsx = move and sign extend
movzx = move and zero extend
push dekrementerer esp med fire og ligger data hvor esp peger.
pop kopierer data fra hvor esp peger til et register og inkrementerer esp med fire.
push 0x01020304 ;32 bit immediate push byte 0x1 ;8 bit immediate (samme som 'push 0x1' ;men kortere opcode) push eax ;Register pop ebp ;Register
inc ligger én til destinations registret.
dec trækker én fra destinations registret.
inc eax ;Register dec eax ;Register
add ligger source til destination.
sub trækker source fra destination.
add <dst>, <src> add eax, 100 ;Register/Immediate add eax, '0' ;Register/Immediate add eax, edx ;Register/Register add eax, DWORD PTR [edx] ;Register/Memory add [esp], edx ;Memory/Register sub <dst>, <src> sub eax, 100 ;Register/Immediate sub eax, '0' ;Register/Immediate sub eax, edx ;Register/Register sub eax, DWORD PTR [edx] ;Register/Memory sub [esp], edx ;Memory/Register
mul = Unsigned multiplication
edx og eax får henholdsvis de høje og lave 32 bit af unsigned multiplikation mellem eax og source.
imul = Signed multiplication.
mul ebx ; edx = (eax * ebx) >> 32 ; eax = (eax * ebx) & 0xffffffff imul ebx ; edx = (eax * ebx) >> 32 ; eax = (eax * ebx) & 0xffffffff imul eax, 10 ; eax = eax * 10 imul eax, ebx, 10 ; eax = ebx * 10 imul eax, [ebx] ; eax = eax * [ebx] imul eax, [ebx], 10 ; eax = [ebx] * 10
div = Unsigned division.
idiv = Signed division.
div ebx ; eax = edx:eax / ebx ; edx = edx:eax % ebx idiv ebx ; eax = edx:eax / ebx ; edx = edx:eax % ebx
Negér source.
neg eax ; eax = -eax
shl = logical shift left
shr = logical shift right
shl eax, 2 ; eax = eax << 2 shl eax, ebx ; eax = eax << ebx shr eax, 2 ; eax = eax >> 2 shr eax, ebx ; eax = eax >> ebx
sal = arithmetic shift left (ingen forskel fra shl)
sar = arithmetic shift right
sal eax, 2 ; eax = eax << 2 sal eax, ebx ; eax = eax << ebx sar eax, 2 ; eax = eax >> 2 ; mest betydende bit bliver shiftet ind sar eax, ebx ; eax = eax >> ebx ; mest betydende bit bliver shiftet ind
rol = rotate left
ror = rotate right
rol eax, 13 rol eax, ebx ror eax, ebx ror eax, 13
Bitvise and. Nulstil bits.
and eax 0x0000ff00 ;Isolér 8 bits ;Måske den grønne komponent i ARGB and eax, ebx
Bitwise or. Sæt bits.
or eax, 0x80000000 ;Sæt most significant bit
Bitwise exclusive or. Skift bits tilstand.
xor eax, eax ; Hurtigste og korteste måde at sætte eax = 0 xor eax, 1 ; Ændr least significant bit til modsat værdi ; af hvad den har nu
Bitwise not. Ændr værdi for alle bits.
not eax
Er som en bitwise and instruktion bortset fra at destinations registret ikke ændres.
Bruges ofte til at teste for lighed og ulighed.
test eax, eax ; Sæt ZF hvis eax == 0, SF hvis eax < 0 test eax, 16 ; Sæt ZF hvis EAX == 16
Er som en sub instruktion bortset fra at destinations registret ikke ændres.
Bruges ofte til at teste for større end og mindre end eller lighed/ulighed.
cmp eax, 10 ; Sæt ZF hvis eax == 10 ; Nulstil ZF og sæt SF = OF hvis eax > 10 ; Sæt SF != OF hvis eax < 10
Betingelsesløst spring enten relativt til instruktionen eller absolut.
jmp 47 ; Spring relativt jmp label ; Spring til "label" label: ; <---som er her jmp eax ; Spring til adressen i eax
Spring er en kilde til forvirring, for assembleren vil oversætte jmp short 0 til 0xeb 0xfe som betyder spring 2 tilbage. Det er fordi, vi som programmører ikke bør bekymre os om størrelsen på opcoder, så vi læser og skriver springene som relative til instruktionen selv, men maskinkoden springer relativt til instruktionen efter jmp instruktionen.
Spring baglæns angiver typisk afslutningen af et loop, mens spring fremad er typiske for if statements. IDA Pro er god til at visualisere dette.
De nærmest uendeligt mange (32 i hvert fald) betingede spring.
test eax, eax ;Sæt FLAGS ud fra EAX je nul ;Hvis ZF er sat så spring til 'nul' label ;eax is not nul ;Gør dette, hvis eax ikke er nul jmp end ;Spring over de næste instruktioner nul: ;eax is nul ;Gør dette, hvis eax ér nul end: ;Afslut
call pusher adresse på næste instruktion på stakken og springer så til en (relativ eller absolut) adresse.
ret popper adressen fra stakken ind i eip.
my_routine: ret call my_routine ; Relativt kald til my_routine call ebx ; Absolut kald til adressen i ebx call [ebx] ; Absolut kald til adressen som ; ligger i hukommelsen på adressen ; som ebx peger på
Load Effective Address = pointer aritmetik.
Ligner en læsning af hukommelse, men er bare en fancy mov instruktion.
struct Coordinate { int x; int y; }; struct Coordinate coords[128]; coords[15].y = 42;
mov ebx, coords ; Adressen på coords arrayet mov eax, 15 ; Index ind i arrayet lea eax, [ebx + 8 * eax + 4] ; Indlæs adressen på y koordinat elementet ; til eax registret mov [eax], 42 ; Skriv 42 til denne adresse
leave gør følgende:
mov esp, ebp pop ebp
Det giver mening senere.
En politik som (bl.a.) definerer følgende:
int arguments2(int a, int b, int c) { return a + b + c; } int arguments1() { return arguments2(7, 9, 13); }
00000500 <arguments2>: 500: push ebp 501: mov ebp,esp 503: mov edx,DWORD PTR [ebp+0x8] 506: mov eax,DWORD PTR [ebp+0xc] 509: add edx,eax 50b: mov eax,DWORD PTR [ebp+0x10] 50e: add eax,edx 510: pop ebp 511: ret 00000512 <arguments1>: 512: push ebp 513: mov ebp,esp 515: push 0xd 517: push 0x9 519: push 0x7 51b: call 51c <arguments1+0xa> 520: add esp,0xc 523: leave 524: ret
To metoder:
push 3 push 2 push 1 call subroutine add esp, 12
mov DWORD PTR [esp], 1 mov DWORD PTR [esp+4], 2 mov DWORD PTR [esp+8], 3 call subroutine
#include <string.h> void prologue_epilogue(int a, int b, int c) { int local1, local2; char string[32]; local1 = a + b * c; local2 = a * c + b; strcpy(string, "Hello, World!"); }
000004e0 <prologue_epilogue>: 4e0: push ebp 4e1: mov ebp,esp 4e3: sub esp,0x30 4e6: mov eax,DWORD PTR [ebp+0xc] 4e9: imul eax,DWORD PTR [ebp+0x10] 4ed: mov edx,eax 4ef: mov eax,DWORD PTR [ebp+0x8] 4f2: add eax,edx 4f4: mov DWORD PTR [ebp-0x4],eax 4f7: mov eax,DWORD PTR [ebp+0x8] 4fa: imul eax,DWORD PTR [ebp+0x10] 4fe: mov edx,eax 500: mov eax,DWORD PTR [ebp+0xc] 503: add eax,edx 505: mov DWORD PTR [ebp-0x8],eax 508: lea eax,[ebp-0x28] 50b: mov DWORD PTR [eax],0x6c6c6548 511: mov DWORD PTR [eax+0x4],0x57202c6f 518: mov DWORD PTR [eax+0x8],0x646c726f 51f: mov WORD PTR [eax+0xc],0x21 525: nop 526: leave 527: ret
000004e0 <prologue_epilogue>: eip -> 4e0: push ebp 4e1: mov ebp,esp 4e3: sub esp,0x30 4e6: mov eax,DWORD PTR [ebp+0xc] 4e9: imul eax,DWORD PTR [ebp+0x10] 4ed: mov edx,eax 4ef: mov eax,DWORD PTR [ebp+0x8] 4f2: add eax,edx 4f4: mov DWORD PTR [ebp-0x4],eax 4f7: mov eax,DWORD PTR [ebp+0x8] 4fa: imul eax,DWORD PTR [ebp+0x10] 4fe: mov edx,eax 500: mov eax,DWORD PTR [ebp+0xc] 503: add eax,edx 505: mov DWORD PTR [ebp-0x8],eax 508: lea eax,[ebp-0x28] 50b: mov DWORD PTR [eax],0x6c6c6548 511: mov DWORD PTR [eax+0x4],0x57202c6f 518: mov DWORD PTR [eax+0x8],0x646c726f 51f: mov WORD PTR [eax+0xc],0x21 525: nop 526: leave 527: ret
000004e0 <prologue_epilogue>: 4e0: push ebp eip -> 4e1: mov ebp,esp 4e3: sub esp,0x30 4e6: mov eax,DWORD PTR [ebp+0xc] 4e9: imul eax,DWORD PTR [ebp+0x10] 4ed: mov edx,eax 4ef: mov eax,DWORD PTR [ebp+0x8] 4f2: add eax,edx 4f4: mov DWORD PTR [ebp-0x4],eax 4f7: mov eax,DWORD PTR [ebp+0x8] 4fa: imul eax,DWORD PTR [ebp+0x10] 4fe: mov edx,eax 500: mov eax,DWORD PTR [ebp+0xc] 503: add eax,edx 505: mov DWORD PTR [ebp-0x8],eax 508: lea eax,[ebp-0x28] 50b: mov DWORD PTR [eax],0x6c6c6548 511: mov DWORD PTR [eax+0x4],0x57202c6f 518: mov DWORD PTR [eax+0x8],0x646c726f 51f: mov WORD PTR [eax+0xc],0x21 525: nop 526: leave 527: ret
000004e0 <prologue_epilogue>: 4e0: push ebp 4e1: mov ebp,esp eip -> 4e3: sub esp,0x30 4e6: mov eax,DWORD PTR [ebp+0xc] 4e9: imul eax,DWORD PTR [ebp+0x10] 4ed: mov edx,eax 4ef: mov eax,DWORD PTR [ebp+0x8] 4f2: add eax,edx 4f4: mov DWORD PTR [ebp-0x4],eax 4f7: mov eax,DWORD PTR [ebp+0x8] 4fa: imul eax,DWORD PTR [ebp+0x10] 4fe: mov edx,eax 500: mov eax,DWORD PTR [ebp+0xc] 503: add eax,edx 505: mov DWORD PTR [ebp-0x8],eax 508: lea eax,[ebp-0x28] 50b: mov DWORD PTR [eax],0x6c6c6548 511: mov DWORD PTR [eax+0x4],0x57202c6f 518: mov DWORD PTR [eax+0x8],0x646c726f 51f: mov WORD PTR [eax+0xc],0x21 525: nop 526: leave 527: ret
000004e0 <prologue_epilogue>: 4e0: push ebp 4e1: mov ebp,esp 4e3: sub esp,0x30 eip -> 4e6: mov eax,DWORD PTR [ebp+0xc] 4e9: imul eax,DWORD PTR [ebp+0x10] 4ed: mov edx,eax 4ef: mov eax,DWORD PTR [ebp+0x8] 4f2: add eax,edx 4f4: mov DWORD PTR [ebp-0x4],eax 4f7: mov eax,DWORD PTR [ebp+0x8] 4fa: imul eax,DWORD PTR [ebp+0x10] 4fe: mov edx,eax 500: mov eax,DWORD PTR [ebp+0xc] 503: add eax,edx 505: mov DWORD PTR [ebp-0x8],eax 508: lea eax,[ebp-0x28] 50b: mov DWORD PTR [eax],0x6c6c6548 511: mov DWORD PTR [eax+0x4],0x57202c6f 518: mov DWORD PTR [eax+0x8],0x646c726f 51f: mov WORD PTR [eax+0xc],0x21 525: nop 526: leave 527: ret
000004e0 <prologue_epilogue>: 4e0: push ebp 4e1: mov ebp,esp 4e3: sub esp,0x30 4e6: mov eax,DWORD PTR [ebp+0xc] 4e9: imul eax,DWORD PTR [ebp+0x10] 4ed: mov edx,eax 4ef: mov eax,DWORD PTR [ebp+0x8] 4f2: add eax,edx 4f4: mov DWORD PTR [ebp-0x4],eax 4f7: mov eax,DWORD PTR [ebp+0x8] 4fa: imul eax,DWORD PTR [ebp+0x10] 4fe: mov edx,eax 500: mov eax,DWORD PTR [ebp+0xc] 503: add eax,edx 505: mov DWORD PTR [ebp-0x8],eax 508: lea eax,[ebp-0x28] 50b: mov DWORD PTR [eax],0x6c6c6548 511: mov DWORD PTR [eax+0x4],0x57202c6f 518: mov DWORD PTR [eax+0x8],0x646c726f 51f: mov WORD PTR [eax+0xc],0x21 525: nop eip -> 526: leave 527: ret
000004e0 <prologue_epilogue>: 4e0: push ebp 4e1: mov ebp,esp 4e3: sub esp,0x30 4e6: mov eax,DWORD PTR [ebp+0xc] 4e9: imul eax,DWORD PTR [ebp+0x10] 4ed: mov edx,eax 4ef: mov eax,DWORD PTR [ebp+0x8] 4f2: add eax,edx 4f4: mov DWORD PTR [ebp-0x4],eax 4f7: mov eax,DWORD PTR [ebp+0x8] 4fa: imul eax,DWORD PTR [ebp+0x10] 4fe: mov edx,eax 500: mov eax,DWORD PTR [ebp+0xc] 503: add eax,edx 505: mov DWORD PTR [ebp-0x8],eax 508: lea eax,[ebp-0x28] 50b: mov DWORD PTR [eax],0x6c6c6548 511: mov DWORD PTR [eax+0x4],0x57202c6f 518: mov DWORD PTR [eax+0x8],0x646c726f 51f: mov WORD PTR [eax+0xc],0x21 525: nop 526: leave eip -> 527: ret
int condition_1(int number) { if (number > 0) { return 1; } else if (number < 0) { return -1; } else { return 0; } }
000004d0 <condition_1>: 4d0: push ebp 4d1: mov ebp,esp 4d3: cmp DWORD PTR [ebp+0x8],0x0 4d7: jle 4e0 <condition_1+0x10> 4d9: mov eax,0x1 4de: jmp 4f2 <condition_1+0x22> 4e0: cmp DWORD PTR [ebp+0x8],0x0 4e4: jns 4ed <condition_1+0x1d> 4e6: mov eax,0xffffffff 4eb: jmp 4f2 <condition_1+0x22> 4ed: mov eax,0x0 4f2: pop ebp 4f3: ret
…som svarer til:
int condition_1(int number) { register int ret; if (number <= 0) goto a; ret = 1; goto end; a: if (number > -1) goto b; ret = -1; goto end; b: ret = 0; end: return ret; }
int condition_2(int number) { if (number > 0 && number <= 10) { return 1; } return 0; }
000004d0 <condition_2>: 4d0: push ebp 4d1: mov ebp,esp 4d3: cmp DWORD PTR [ebp+0x8],0x0 4d7: jle 4e6 <condition_2+0x16> 4d9: cmp DWORD PTR [ebp+0x8],0xa 4dd: jg 4e6 <condition_2+0x16> 4df: mov eax,0x1 4e4: jmp 4eb <condition_2+0x1b> 4e6: mov eax,0x0 4eb: pop ebp 4ec: ret
…som svarer til:
int condition_2(int number) { register int ret; if (number <= 0) goto a; if (number > 10) goto a; ret = 1; goto end; a: ret = 0; end: return ret; }
int condition_3(int number) { if (number > 100 || number < -100) { return 1; } return 0; }
000004d0 <condition_3>: 4d0: push ebp 4d1: mov ebp,esp 4d3: cmp DWORD PTR [ebp+0x8],0x64 4d7: jg 4df <condition_3+0xf> 4d9: cmp DWORD PTR [ebp+0x8],0xffffff9c 4dd: jge 4e6 <condition_3+0x16> 4df: mov eax,0x1 4e4: jmp 4eb <condition_3+0x1b> 4e6: mov eax,0x0 4eb: pop ebp 4ec: ret
…som svarer til:
int condition_3(int number) { register int ret; if (number > 100) goto a; if (number >= -100) goto b; a: ret = 1; goto end; b: ret = 0; end: return ret; }
typedef enum { DO_STUFF, DO_OTHER_STUFF, DO_SOMETHING_ELSE } command_t; int condition_switch(command_t cmd) { switch (cmd) { case DO_STUFF: return 7; break; case DO_OTHER_STUFF: return 9; break; case DO_SOMETHING_ELSE: return 13; break; default: return -1; break; } }
000004e0 <condition_switch>: 4e0: push ebp 4e1: mov ebp,esp 4e3: mov eax,DWORD PTR [ebp+0x8] 4e6: cmp eax,0x1 4e9: je 4fe <condition_switch+0x1e> 4eb: cmp eax,0x1 4ee: jb 4f7 <condition_switch+0x17> 4f0: cmp eax,0x2 4f3: je 505 <condition_switch+0x25> 4f5: jmp 50c <condition_switch+0x2c> 4f7: mov eax,0x7 4fc: jmp 511 <condition_switch+0x31> 4fe: mov eax,0x9 503: jmp 511 <condition_switch+0x31> 505: mov eax,0xd 50a: jmp 511 <condition_switch+0x31> 50c: mov eax,0xffffffff 511: pop ebp 512: ret
int for_loop(int n) { int i, sum = 0; for (i = 0; i < n; i++) { sum += i; } return sum; }
000004d0 <for_loop>: 4d0: push ebp 4d1: mov ebp,esp 4d3: sub esp,0x10 4d6: mov DWORD PTR [ebp-0x8],0x0 4dd: mov DWORD PTR [ebp-0x4],0x0 4e4: jmp 4f0 <for_loop+0x20> 4e6: mov eax,DWORD PTR [ebp-0x4] 4e9: add DWORD PTR [ebp-0x8],eax 4ec: add DWORD PTR [ebp-0x4],0x1 4f0: mov eax,DWORD PTR [ebp-0x4] 4f3: cmp eax,DWORD PTR [ebp+0x8] 4f6: jl 4e6 <for_loop+0x16> 4f8: mov eax,DWORD PTR [ebp-0x8] 4fb: leave 4fc: ret
Skriv en serienummergenerator til ProsaCrackme.bin
Denne laver vi sammen og introducerer samtidig IDA Pro.
int while_loop(int n) { int i = 0, sum = 0; while (i < n) { sum += i++; } return sum; }
000004d0 <while_loop>: 4d0: push ebp 4d1: mov ebp,esp 4d3: sub esp,0x10 4d6: mov DWORD PTR [ebp-0x4],0x0 4dd: mov DWORD PTR [ebp-0x8],0x0 4e4: jmp 4f2 <while_loop+0x22> 4e6: mov eax,DWORD PTR [ebp-0x4] 4e9: lea edx,[eax+0x1] 4ec: mov DWORD PTR [ebp-0x4],edx 4ef: add DWORD PTR [ebp-0x8],eax 4f2: mov eax,DWORD PTR [ebp-0x4] 4f5: cmp eax,DWORD PTR [ebp+0x8] 4f8: jl 4e6 <while_loop+0x16> 4fa: mov eax,DWORD PTR [ebp-0x8] 4fd: leave 4fe: ret
int do_while_loop(int n) { int i = 0, sum = 0; do { sum += i; } while (++i < n); return sum; }
000004e0 <do_while_loop>: 4e0: push ebp 4e1: mov ebp,esp 4e3: sub esp,0x10 4e6: mov DWORD PTR [ebp-0x4],0x0 4ed: mov DWORD PTR [ebp-0x8],0x0 4f4: mov eax,DWORD PTR [ebp-0x4] 4f7: add DWORD PTR [ebp-0x8],eax 4fa: add DWORD PTR [ebp-0x4],0x1 4fe: mov eax,DWORD PTR [ebp-0x4] 501: cmp eax,DWORD PTR [ebp+0x8] 504: jl 4f4 <do_while_loop+0x14> 506: mov eax,DWORD PTR [ebp-0x8] 509: leave 50a: ret
#include <stddef.h> typedef struct _linked_list_t linked_list_t; struct _linked_list_t { linked_list_t * next; void * data; }; linked_list_t * linked_list_tail(linked_list_t * elem) { return elem == NULL || elem->next == NULL ? elem : linked_list_tail(elem->next); }
000004e0 <linked_list_tail>: 4e0: push ebp 4e1: mov ebp,esp 4e3: sub esp,0x8 4e6: cmp DWORD PTR [ebp+0x8],0x0 4ea: je 508 <linked_list_tail+0x28> 4ec: mov eax,DWORD PTR [ebp+0x8] 4ef: mov eax,DWORD PTR [eax] 4f1: test eax,eax 4f3: je 508 <linked_list_tail+0x28> 4f5: mov eax,DWORD PTR [ebp+0x8] 4f8: mov eax,DWORD PTR [eax] 4fa: sub esp,0xc 4fd: push eax 4fe: call 4ff <linked_list_tail+0x1f> 503: add esp,0x10 506: jmp 50b <linked_list_tail+0x2b> 508: mov eax,DWORD PTR [ebp+0x8] 50b: leave 50c: ret
int global[10]; void arrays() { int local[10]; int i; for (i = 0; i < 10; i++) { global[i] = i; } for (i = 0; i < 10; i++) { local[i] = i; } }
000004f0 <arrays>: 4f0: push ebp 4f1: mov ebp,esp 4f3: sub esp,0x30 4f6: mov DWORD PTR [ebp-0x4],0x0 4fd: jmp 510 <arrays+0x20> 4ff: mov eax,DWORD PTR [ebp-0x4] 502: mov edx,DWORD PTR [ebp-0x4] 505: mov DWORD PTR [eax*4+0x0],edx 50c: add DWORD PTR [ebp-0x4],0x1 510: cmp DWORD PTR [ebp-0x4],0x9 514: jle 4ff <arrays+0xf> 516: mov DWORD PTR [ebp-0x4],0x0 51d: jmp 52d <arrays+0x3d> 51f: mov eax,DWORD PTR [ebp-0x4] 522: mov edx,DWORD PTR [ebp-0x4] 525: mov DWORD PTR [ebp+eax*4-0x2c],edx 529: add DWORD PTR [ebp-0x4],0x1 52d: cmp DWORD PTR [ebp-0x4],0x9 531: jle 51f <arrays+0x2f> 533: nop 534: leave 535: ret
#include <malloc.h> typedef struct { /* Size in bytes * Packed index * Aligned index */ char first; /* 1 * 0 * 0 */ int second; /* 4 * 1 * 4 */ short third; /* 2 * 5 * 8 */ long long fourth;/* 8 * 7 * 12 */ } /* __attribute__((packed)) */ some_struct_t; some_struct_t global; void struct_global() { global.first = 10; global.second = 20; global.third = 30; global.fourth = 40; } void struct_stack() { some_struct_t stack; stack.first = 10; stack.second = 20; stack.third = 30; stack.fourth = 40; } void struct_heap() { some_struct_t * heap = malloc(sizeof(some_struct_t)); heap->first = 10; heap->second = 20; heap->third = 30; heap->fourth = 40; }
00000590 <struct_global>: 590: push ebp 591: mov ebp,esp 593: mov BYTE PTR ds:0x0,0xa 59a: mov DWORD PTR ds:0x4,0x14 5a4: mov WORD PTR ds:0x8,0x1e 5ad: mov DWORD PTR ds:0xc,0x28 5b7: mov DWORD PTR ds:0x10,0x0 5c1: nop 5c2: pop ebp 5c3: ret 000005c4 <struct_stack>: 5c4: push ebp 5c5: mov ebp,esp 5c7: sub esp,0x20 5ca: mov BYTE PTR [ebp-0x14],0xa 5ce: mov DWORD PTR [ebp-0x10],0x14 5d5: mov WORD PTR [ebp-0xc],0x1e 5db: mov DWORD PTR [ebp-0x8],0x28 5e2: mov DWORD PTR [ebp-0x4],0x0 5e9: nop 5ea: leave 5eb: ret 000005ec <struct_heap>: 5ec: push ebp 5ed: mov ebp,esp 5ef: sub esp,0x18 5f2: sub esp,0xc 5f5: push 0x14 5f7: call 5f8 <struct_heap+0xc> 5fc: add esp,0x10 5ff: mov DWORD PTR [ebp-0xc],eax 602: mov eax,DWORD PTR [ebp-0xc] 605: mov BYTE PTR [eax],0xa 608: mov eax,DWORD PTR [ebp-0xc] 60b: mov DWORD PTR [eax+0x4],0x14 612: mov eax,DWORD PTR [ebp-0xc] 615: mov WORD PTR [eax+0x8],0x1e 61b: mov eax,DWORD PTR [ebp-0xc] 61e: mov DWORD PTR [eax+0xc],0x28 625: mov DWORD PTR [eax+0x10],0x0 62c: nop 62d: leave 62e: ret
ProsaBomb.bin
Denne starter vi på sammen, derefter tager I resten på egen hånd eller i grupper.
#include <string.h> void strcpy_short() { char buffer[128]; strcpy(buffer, "Hello, World!"); } void strcpy_long() { char buffer[128]; /* 85 chars + nul terminator */ strcpy(buffer, "This is a much longer string " "so maybe it will be handled " "differently by the compiler?"); }
00000500 <strcpy_short>: 500: push ebp 501: mov ebp,esp 503: add esp,0xffffff80 506: lea eax,[ebp-0x80] 509: mov DWORD PTR [eax],0x6c6c6548 50f: mov DWORD PTR [eax+0x4],0x57202c6f 516: mov DWORD PTR [eax+0x8],0x646c726f 51d: mov WORD PTR [eax+0xc],0x21 523: nop 524: leave 525: ret 00000526 <strcpy_long>: 526: push ebp 527: mov ebp,esp 529: push edi 52a: push esi 52b: add esp,0xffffff80 52e: lea eax,[ebp-0x88] 534: mov edx,eax 536: mov eax,0x574 53b: mov ecx,0x15 540: mov edi,edx 542: mov esi,eax 544: rep movs DWORD PTR es:[edi],DWORD PTR ds:[esi] 546: mov eax,esi 548: mov edx,edi 54a: movzx ecx,WORD PTR [eax] 54d: mov WORD PTR [edx],cx 550: lea edx,[edx+0x2] 553: lea eax,[eax+0x2] 556: nop 557: sub esp,0xffffff80 55a: pop esi 55b: pop edi 55c: pop ebp 55d: ret
int multiply_by_eight(int num) { return num * 8; } int divide_by_eight(int num) { return num / 8; }
00000500 <multiply_by_eight>: 500: push ebp 501: mov ebp,esp 503: mov eax,DWORD PTR [ebp+0x8] 506: shl eax,0x3 509: pop ebp 50a: ret 0000050b <divide_by_eight>: 50b: push ebp 50c: mov ebp,esp 50e: mov eax,DWORD PTR [ebp+0x8] 511: lea edx,[eax+0x7] 514: test eax,eax 516: cmovs eax,edx 519: sar eax,0x3 51c: pop ebp 51d: ret
int mod_50(int num) { return num % 50; }
000004d0 <mod_50>: 4d0: push ebp 4d1: mov ebp,esp 4d3: mov ecx,DWORD PTR [ebp+0x8] 4d6: mov edx,0x51eb851f 4db: mov eax,ecx 4dd: imul edx 4df: sar edx,0x4 4e2: mov eax,ecx 4e4: sar eax,0x1f 4e7: sub edx,eax 4e9: mov eax,edx 4eb: imul eax,eax,0x32 4ee: sub ecx,eax 4f0: mov eax,ecx 4f2: pop ebp 4f3: ret
int meaning_of_life; void local_function() { meaning_of_life = 42; } void relocations() { local_function(); }
0000054b <local_function>: 54b: 55 push ebp 54c: 89 e5 mov ebp,esp 54e: c7 05 00 00 00 00 2a mov DWORD PTR ds:0x0,0x2a 555: 00 00 00 558: 5d pop ebp 559: c3 ret 0000055a <relocations>: 55a: 55 push ebp 55b: 89 e5 mov ebp,esp 55d: e8 fc ff ff ff call 55e <relocations+0x4> 562: 5d pop ebp 563: c3 ret
$ objdump -R examples/libpic.so | grep -E '(meaning_of_life)|(local_function)' 00000550 R_386_32 meaning_of_life 0000055e R_386_PC32 local_function
0000054b <local_function>: 54b: 55 push ebp 54c: 89 e5 mov ebp,esp 54e: c7 05 00 00 00 00 2a mov DWORD PTR ds:0x0,0x2a 555: 00 00 00 558: 5d pop ebp 559: c3 ret 0000055a <relocations>: 55a: 55 push ebp 55b: 89 e5 mov ebp,esp 55d: e8 fc ff ff ff call 55e <relocations+0x4> 562: 5d pop ebp 563: c3 ret
(gdb) disassemble relocations Dump of assembler code for function relocations: => 0xf7fd655a <+0>: push ebp 0xf7fd655b <+1>: mov ebp,esp 0xf7fd655d <+3>: call 0xf7fd654b <local_function> 0xf7fd6562 <+8>: pop ebp 0xf7fd6563 <+9>: ret End of assembler dump. (gdb) disassemble local_function Dump of assembler code for function local_function: 0xf7fd654b <+0>: push ebp 0xf7fd654c <+1>: mov ebp,esp 0xf7fd654e <+3>: mov DWORD PTR ds:0xf7fd801c,0x2a 0xf7fd6558 <+13>: pop ebp 0xf7fd6559 <+14>: ret End of assembler dump. (gdb)
#include <stdio.h> static int some_global = 42; int pic_function1() { return some_global; } int pic_function2() { return some_global; }
000003f0 <__x86.get_pc_thunk.bx>: 3f0: 8b 1c 24 mov ebx,DWORD PTR [esp] 3f3: c3 ret 0000051b <pic_function1>: 51b: 55 push ebp 51c: 89 e5 mov ebp,esp 51e: e8 24 00 00 00 call 547 <__x86.get_pc_thunk.cx> 523: 81 c1 dd 1a 00 00 add ecx,0x1add 529: 8b 81 18 00 00 00 mov eax,DWORD PTR [ecx+0x18] 52f: 5d pop ebp 530: c3 ret 00000531 <pic_function2>: 531: 55 push ebp 532: 89 e5 mov ebp,esp 534: e8 0e 00 00 00 call 547 <__x86.get_pc_thunk.cx> 539: 81 c1 c7 1a 00 00 add ecx,0x1ac7 53f: 8b 81 18 00 00 00 mov eax,DWORD PTR [ecx+0x18] 545: 5d pop ebp 546: c3 ret 00000547 <__x86.get_pc_thunk.cx>: 547: 8b 0c 24 mov ecx,DWORD PTR [esp] 54a: c3 ret
#include <unistd.h> int main(int argc, char *argv[]) { getpid(); return 0; }
Disassembly of section .plt: 080482e0 <getpid@plt-0x10>: 80482e0: ff 35 04 a0 04 08 push DWORD PTR ds:0x804a004 80482e6: ff 25 08 a0 04 08 jmp DWORD PTR ds:0x804a008 80482ec: 00 00 add BYTE PTR [eax],al ... 080482f0 <getpid@plt>: 80482f0: ff 25 0c a0 04 08 jmp DWORD PTR ds:0x804a00c 80482f6: 68 00 00 00 00 push 0x0 80482fb: e9 e0 ff ff ff jmp 80482e0 <_init+0x2c> 0804841d <main>: 804841d: 55 push ebp 804841e: 89 e5 mov ebp,esp 8048420: 83 e4 f0 and esp,0xfffffff0 8048423: e8 c8 fe ff ff call 80482f0 <getpid@plt> 8048428: b8 00 00 00 00 mov eax,0x0 804842d: c9 leave 804842e: c3 ret 804842f: 90 nop
$ objdump -R got_plt | grep 0804a00c
0804a00c R_386_JUMP_SLOT getpid
Disassembly of section .plt: 080482e0 <getpid@plt-0x10>: 80482e0: ff 35 04 a0 04 08 push DWORD PTR ds:0x804a004 80482e6: ff 25 08 a0 04 08 jmp DWORD PTR ds:0x804a008 80482ec: 00 00 add BYTE PTR [eax],al ... 080482f0 <getpid@plt>: 80482f0: ff 25 0c a0 04 08 jmp DWORD PTR ds:0x804a00c 80482f6: 68 00 00 00 00 push 0x0 80482fb: e9 e0 ff ff ff jmp 80482e0 <_init+0x2c> 0804841d <main>: 804841d: 55 push ebp 804841e: 89 e5 mov ebp,esp 8048420: 83 e4 f0 and esp,0xfffffff0 8048423: e8 c8 fe ff ff call 80482f0 <getpid@plt> 8048428: b8 00 00 00 00 mov eax,0x0 804842d: c9 leave 804842e: c3 ret 804842f: 90 nop
Gennemsku filformatet som ProsaFileFormat.bin benytter.
Denne laver vi også sammen.
Ekstraopgave…der er en memory leak. Kan I finde den?
if (ptrace(PTRACE_TRACEME, 0, 0, 0) == -1) { printf("Debugging not allowed!\n"); exit(-1); }
$ gdb -q ./breakme Reading symbols from ./breakme...Segmentation fault (core dumped) $
Første level i SmashTheStack IO er en ren reverser opgave:
Hvis nogen bliver færdig med bomben.
Kan findes i assignments/rivendel.zip
Ligger i papers
OpenSecurityTraining