Hvorfor?

  • Mange CTFer er udelukkende binary.
  • De fleste andre har bare mange binaries.
  • Du vil få bedre forståelse af software og bliver dermed en bedre programmør.
  • Du vil kunne rette i software i sin binære form.
  • Du vil (med lidt øvelse) kunne gennemskue IoT devices (hvorfor snakker dit køleskab med verden?)

Typiske reverser opgaver

  • Find sårbarheder i services (Defcon finals)
  • Snyd i spil (GITS Pwn Adventure)
  • Serienummer generatorer
  • Optimering
  • Fil/Netværks formater
  • Binary bomb

To metoder

  • Statisk analyse
  • Dynamisk analyse

Statisk analyse værktøjer - IDA Pro

Statisk analyse værktøjer - IDA Pro + decompiler

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;
}

Statisk analyse værktøjer - IDA Pro + decompiler

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;
}

Statisk analyse værktøjer - IDA Pro + decompiler

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;
}

Statisk analyse værktøjer - Ghidra

Statisk analyse værktøjer

Dynamisk analyse værktøjer - GDB + peda

Dynamisk analyse værktøjer - strace

$ 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 +++

Dynamisk analyse værktøjer - Wireshark

Introduktion til i386 assembly

Kort introduktion eller genopfriskning.

i386 = CISC = helvedes mange instruktioner.

i386 assembly - Registre

CPUens interne hukommelse

  • EAX (ax,ah,al): Accumulator (IO, multiplikation, division, syscall number, return value)
  • EBX (bx,bh,bl): Base (base pointer for memory access)
  • ECX (cx,ch,cl): Counter (looping and counting)
  • EDX (dx,dh,dl): Data (multiplikation, division, udviddelse af eax til 64 bit)
  • ESI : Source Index (memory reads)
  • EDI : Destination Index (memory writes)
  • EBP : Base Pointer (bunden af nuværende stack frame)
  • ESP : Stack Pointer (toppen af stakken, toppen af nuværende stack frame)
  • EIP : Instruction Pointer (peger på NÆSTE, ikke nuværende, instruktion)
  • FLAGS : En række boolske værdier (de vigtigste er beskrevet på næste slide)

i386 assembly - FLAGS

Bruges til betingede spring. Der er mange, men her er de vigtigste:

  • ZF : Zero flag (hvis resultat = 0)
  • CF : Carry flag (sat ved mente eller lån)
  • SF : Sign flag (MSB i resultat)
  • OF : Overflow flag (hvis resultat overflower fra positiv til negativ eller omvendt)

i386 assembly - Instruktioner

Hvad CPUen kan gøre. Igen, der er mange (CISC husker I nok), men vi kan klare os med meget få.

i386 assembly - mov

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

i386 assembly - push/pop

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

i386 assembly - inc/dec

inc ligger én til destinations registret.

dec trækker én fra destinations registret.

inc eax             ;Register
dec eax             ;Register

i386 assembly - add/sub

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

i386 assembly - mul/imul

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

i386 assembly - div/idiv

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

i386 assembly - neg

Negér source.

neg eax    ; eax = -eax

i386 assembly - shl/shr

shl = logical shift left

../images/shl.png

shr = logical shift right

../images/shr.png
shl eax, 2       ; eax = eax << 2
shl eax, ebx     ; eax = eax << ebx
shr eax, 2       ; eax = eax >> 2
shr eax, ebx     ; eax = eax >> ebx

i386 assembly - sal/sar

sal = arithmetic shift left (ingen forskel fra shl)

sar = arithmetic shift right

../images/sar.png
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

i386 assembly - ror/rol

rol = rotate left

../images/rol.png

ror = rotate right

../images/ror.png
rol eax, 13
rol eax, ebx

ror eax, ebx
ror eax, 13

i386 assembly - and

Bitvise and. Nulstil bits.

../images/and.png
and eax 0x0000ff00   ;Isolér 8 bits
                     ;Måske den grønne komponent i ARGB

and eax, ebx

i386 assembly - or

Bitwise or. Sæt bits.

../images/or.png
or eax, 0x80000000  ;Sæt most significant bit

i386 assembly - xor

Bitwise exclusive or. Skift bits tilstand.

../images/xor.png
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

i386 assembly - not

Bitwise not. Ændr værdi for alle bits.

not eax

i386 assembly - test

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

i386 assembly - cmp

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

i386 assembly - jmp

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.

i386 assembly - je/jz/jne/jnz

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

i386 assembly - call/ret

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å

i386 assembly - lea

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

i386 assembly - leave

leave gør følgende:

mov esp, ebp
pop ebp

Det giver mening senere.

Reversing - Calling conventions

En politik som (bl.a.) definerer følgende:

  • Hvordan parametre leveres til subroutine kald
  • Hvem der skal rydde parametre af stakken (hvis den bruges til parametre)
  • Hvordan retur værdier leveres til kalderen
  • Hvilke registre, som skal bibeholde deres værdi gennem subroutine kald

Reversing - Calling conventions - cdecl

  • Parametre til subroutiner leveres (generelt) på stakken, første argument øverst
  • Den kaldende funktion rydder selv stakken op
  • Returværdien leveres (generelt) i eax registeret
  • Alle registre undtagen eax, ecx og edx skal bibeholde deres værdi under subroutine kald

Reversing - Argumenter og returværdi

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

Reversing - Argumenter til funktionskald

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

Reversing - Function prologue/epilogue

#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

Reversing - Function prologue/epilogue - Inden push ebp

../images/prologue_epilogue_01.png
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

Reversing - Function prologue/epilogue - Efter push ebp

../images/prologue_epilogue_02.png
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

Reversing - Function prologue/epilogue - Efter mov ebp, esp

../images/prologue_epilogue_03.png
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

Reversing - Function prologue/epilogue - Efter sub esp, 0x30

../images/prologue_epilogue_04.png
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

Reversing - Function prologue/epilogue - Inden leave

../images/prologue_epilogue_04.png
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

Reversing - Function prologue/epilogue - Efter leave

../images/prologue_epilogue_05.png
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

Reversing - Betingelser - if

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;
}

Reversing - Betingelser - if

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;
}

Reversing - Betingelser - if

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;
}

Reversing - Betingelser - switch

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

Reversing - Loops - for

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

Reversing - Main metodens stak

../images/main_stack_frame.png

Reversing - Første opgave

Skriv en serienummergenerator til ProsaCrackme.bin

Denne laver vi sammen og introducerer samtidig IDA Pro.

Reversing - Loops - while

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

Reversing - Loops - do while

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

Reversing - Pointers

#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

Reversing - Arrays

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

Reversing - Structures

#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

Reversing - Tredje opgave

ProsaBomb.bin

Denne starter vi på sammen, derefter tager I resten på egen hånd eller i grupper.

Reversing - Intrinsics

#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

Reversing - Optimeringer

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

Reversing - Optimeringer

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

Reversing - Position Independent Code - Relocations

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

Reversing - Position Independent Code - Relocations

$ 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

Reversing - Position Independent Code - Relocations

(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)

Reversing - Position Independent Code - PIC

#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

Reversing - Position Independent Code - GOT/PLT

#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

Reversing - Position Independent Code - GOT/PLT

$ 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

Reversing - Position Independent Code - GOT/PLT

../images/got_plt_01.png

Reversing - Position Independent Code - GOT/PLT

../images/got_plt_02.png

Reversing - Anden opgave

Gennemsku filformatet som ProsaFileFormat.bin benytter.

Denne laver vi også sammen.

Ekstraopgave…der er en memory leak. Kan I finde den?

Reversing - Anti debugging - Debug dig selv

if (ptrace(PTRACE_TRACEME, 0, 0, 0) == -1) {
    printf("Debugging not allowed!\n");
    exit(-1);
}

Reversing - Anti debugging - Crash værktøjerne

$ gdb -q ./breakme
Reading symbols from ./breakme...Segmentation fault (core dumped)
$

Reversing - Fjerde opgave

Første level i SmashTheStack IO er en ren reverser opgave:

Reversing - Femte opgave

Hvis nogen bliver færdig med bomben.

Kan findes i assignments/rivendel.zip

Selvstudie - Bøger

../images/reversing-secrets_of_reverse_engineering.jpg

Selvstudie - Bøger

../images/practical_reverse_engineering.jpg

Selvstudie - Bøger

../images/the_ida_pro_book.jpg

Selvstudie - Bøger

../images/re_for_beginners.png

Ligger i papers

Selvstudie - Bøger

../images/reverse_engineering_code_with_ida_pro.jpg
../images/bad_review.png

Selvstudie - Video

Selvstudie - Opgaver