Reverse Engineering σε περιβάλλον Linux, Μέρος 2: Χρήσιμες έως πολύ χρήσιμες πληροφορίες ΙΙ
Description: This is issue 34 of Magaz, the Hellenic LinuxMagazine
Keywords: magaz hellenic greek hellas greece hellug linux magazine

Magaz, The Greek Linux Magazine
Τεύχος #34
Περιληπτικά Περιεχόμενα Αναλυτικά Περιεχόμενα Mirrors Links Πληροφορίες Συντάκτες Αναζήτηση Επικοινωνία
> Επόμενο Προηγούμενο Περιεχόμενα ### 5. Χρήσιμες έως πολύ χρήσιμες πληροφορίες ΙΙ ### 5.1 Dead Listing και Εργαλεία #### Τι είναι το dead listing Dead listing είναι η παρουσίαση του κώδικα ενός εκτελέσιμου σε στατική μορφή. Κύριο πλεονέκτημα αυτού του τρόπου μελέτης του κώδικα είναι πως δίνει μια πιο ολοκληρωμένη άποψη για τη λειτουργία του, και, ανάλογα με την ποιότητα του disassembler, ένα πλήθος πληροφοριών (function calls, strings κτλ). Το βασικό μειονέκτημα είναι ότι δε μπορεί να μας δώσει χρήσιμα αποτελέσματα αν ο κώδικας αλλάζει κατά τη διάρκεια της εκτέλεσης (πχ self-modifying code, συμπιεσμένα/κρυπτογραφημένα εκτελέσιμα) ή αν υπάρχουν πολλά έμμεσα jmp και calls (πχ jmp [eax]), διότι δεν μπορούμε να ακολουθήσουμε (έστω και νοητικά) την πορεία της εκτέλεσης. Το καλύτερο που έχουμε να κάνουμε σε τέτοιες περιπτώσεις, είναι να φέρουμε το εκτελέσιμο σε μια μορφή που να μπορεί να διαβάσει ο disassembler, ώστε να εκμεταλλευτούμε τις ευκολίες που μας προσφέρει. Δυστυχώς, οι disassembly δυνατότητες του objdump δεν είναι αρκετά ικανοποιητικές (μη ξεχνάμε βέβαια πως το objdump δε σχεδιάστηκε για αυτό). Εκτός από ο γεγονός ότι δε φροντίζει να παρουσιάζει τα cross-references (πχ αν μια διεύθυνση μνήμης είναι στόχος μιας jump ή call εντολής), το disassembly του είναι γραμμικό και δε γίνεται καμία προσπάθεια να ακολουθηθεί η ροή του προγράμματος. Για παράδειγμα το παρακάτω κομμάτι κώδικα ο ΗΤEditor το κάνει disassemble σωστά...
>     8048080 !
>     ....... ! entrypoint:
>     ....... !   jmp     loc_8048083
>     8048082     db      86h
>     8048083 !
>     ....... ! loc_8048083:                    ;xref j8048080
>     ....... !   cmp     eax, ebx
>     8048085 !   ret
> ...ενώ το objdump δεν καταλαβαίνει ότι ο έλεγχος θα πάει στη διεύθυνση 0x8048083 και συνεχίζει το disassembly με το επόμενο byte (dummy byte), με αποτέλεσμα να αποσυγχρονιστεί το listing από εκεί και κάτω.
>     08048080 <_start>:
>      8048080:       eb 01                   jmp    8048083 <_start+0x3>
>      8048082:       86 39                   xchg   BYTE PTR [ecx],bh
>      8048084:       d8 c3                   fadd   %st,st(3)
> Μπορεί τα "κανονικά" προγράμματα να μην έχουν κώδικα αυτής της μορφής αλλά πρόκειται για μια πολύ κοινή τεχνική για προστασία έναντι των "χαζών" disassemblers. #### Εργαλεία Παρακάτω παρουσιάζονται συνοπτικά μερικοί disassemblers και το disassembly που παράγουν για το γνωστό :) πρόγραμμα.
>     #include <stdio.h>

>     int main(int argc, char **argv)
>     {
>         int num;

>         if (argc<2) {
>             printf("Usage: %s <number>\n",argv[0]);
>             exit(1);
>         }

>         num=alf(argv[1]);

>         if (num>10)
>             printf("Ok!\n");
>         else
>             printf("Failed!\n");

>         return 1;
>     }

>     int alf(char *s)
>     {
>         return atoi(s);
>     }
> #### IDA Ένα από τα καλύτερα εργαλεία για disassemby είναι ο IDA (Interactive DisAssembler). Υπάρχει μια freeware έκδοση που δουλεύει σε DOS, ενώ η εμπορική υπάρχει και για περιβάλλον Windows. Υποστηρίζει πλήθος αρχιτεκτονικών, εκτελέσιμων και compilers, ενώ περιέχει μια script γλώσσα για διάφορες αυτοματοποιήσεις. Στο linux μπορεί να εκτελεστεί μέσω wine. Το επίσημο site είναι http://www.datarescue.com, ενώ τη freeware εκδοση μπορείτε να τη βρείτε με μια αναζήτηση στο google.
>     .text:0804838C ; ??????????????? S U B R O U T I N E ???????????????????????????????????????
>     .text:0804838C
>     .text:0804838C ; Attributes: bp-based frame
>     .text:0804838C
>     .text:0804838C                 public main
>     .text:0804838C main            proc near               ; DATA XREF: _start+17 o
>     .text:0804838C
>     .text:0804838C var_4           = dword ptr -4
>     .text:0804838C arg_0           = dword ptr  8
>     .text:0804838C arg_4           = dword ptr  0Ch
>     .text:0804838C
>     .text:0804838C                 push    ebp
>     .text:0804838D                 mov     ebp, esp
>     .text:0804838F                 sub     esp, 8
>     .text:08048392                 and     esp, 0FFFFFFF0h
>     .text:08048395                 mov     eax, 0
>     .text:0804839A                 sub     esp, eax
>     .text:0804839C                 cmp     [ebp+arg_0], 1
>     .text:080483A0                 jg      short loc_80483C1
>     .text:080483A2                 sub     esp, 8
>     .text:080483A5                 mov     eax, [ebp+arg_4]
>     .text:080483A8                 push    dword ptr [eax]
>     .text:080483AA                 push    offset aUsageSNumber ; "Usage: %s <number>\n"
>     .text:080483AF                 call    _printf
>     .text:080483B4                 add     esp, 10h
>     .text:080483B7                 sub     esp, 0Ch
>     .text:080483BA                 push    1
>     .text:080483BC                 call    _exit
>     .text:080483C1
>     .text:080483C1 loc_80483C1:                            ; CODE XREF: main+14 j
>     .text:080483C1                 sub     esp, 0Ch
>     .text:080483C4                 mov     eax, [ebp+arg_4]
>     .text:080483C7                 add     eax, 4
>     .text:080483CA                 push    dword ptr [eax]
>     .text:080483CC                 call    alf
>     .text:080483D1                 add     esp, 10h
>     .text:080483D4                 mov     [ebp+var_4], eax
>     .text:080483D7                 cmp     [ebp+var_4], 0Ah
>     .text:080483DB                 jle     short loc_80483EF
>     .text:080483DD                 sub     esp, 0Ch
>     .text:080483E0                 push    offset aOk      ; "Ok!\n"
>     .text:080483E5                 call    _printf
>     .text:080483EA                 add     esp, 10h
>     .text:080483ED                 jmp     short loc_80483FF
>     .text:080483EF ; ---------------------------------------------------------------------------
>     .text:080483EF
>     .text:080483EF loc_80483EF:                            ; CODE XREF: main+4F j
>     .text:080483EF                 sub     esp, 0Ch
>     .text:080483F2                 push    offset aFailed  ; "Failed!\n"
>     .text:080483F7                 call    _printf
>     .text:080483FC                 add     esp, 10h
>     .text:080483FF
>     .text:080483FF loc_80483FF:                            ; CODE XREF: main+61 j
>     .text:080483FF                 mov     eax, 1
>     .text:08048404                 leave
>     .text:08048405                 retn
>     .text:08048405 main            endp
>     .text:08048405
>     .text:08048406
>     .text:08048406 ; ??????????????? S U B R O U T I N E ???????????????????????????????????????
>     .text:08048406
>     .text:08048406 ; Attributes: bp-based frame
>     .text:08048406
>     .text:08048406                 public alf
>     .text:08048406 alf             proc near               ; CODE XREF: main+40 p
>     .text:08048406
>     .text:08048406 arg_0           = dword ptr  8
>     .text:08048406
>     .text:08048406                 push    ebp
>     .text:08048407                 mov     ebp, esp
>     .text:08048409                 sub     esp, 8
>     .text:0804840C                 sub     esp, 0Ch
>     .text:0804840F                 push    [ebp+arg_0]
>     .text:08048412                 call    _atoi
>     .text:08048417                 add     esp, 10h
>     .text:0804841A                 leave
>     .text:0804841B                 retn
>     .text:0804841B alf             endp
>     .text:0804841B
>     .text:0804841C
> #### Bastard Disassembly Enviroment Στον κόσμο του open source τώρα, στο sourceforge θα βρείτε projects που υπόσχονται πολλά αλλά δυστυχώς είναι σε πρώιμο στάδιο. Ένα από αυτά είναι το Bastard Disassembly Enviroment. Πρακτικά πρόκειται για μια scripting γλώσσα και το αντίστοιχο interpreter shell. Site: http://bastard.sourceforge.net.
>     main:
>     0804838C 55                             push    ebp
>     0804838D 89 E5                          mov     ebp , esp
>     0804838F 83 EC 08                       sub     esp , 0x8
>     08048392 83 E4 F0                       and     esp , 0xF0
>     08048395 B8 00 00 00 00                 mov     eax , 0x0
>     0804839A 29 C4                          sub     esp , eax
>     0804839C 83 7D 08 01                    cmp     [ebp+0x08] , 0x1
>     080483A0 7F 1F                          jg      loc_080483C1  ;(0x80483C1 was +31) ;  xrefs: >080483C1[x]
>     080483A2 83 EC 08                       sub     esp , 0x8
>     080483A5 8B 45 0C                       mov     eax , [ebp+0x0C]
>     080483A8 FF 30                          push    [eax]
>     080483AA 68 64 84 04 08                 push    0x8048464
>     080483AF E8 F8 FE FF FF                 call    printf  ;(0x80482AC was -264) ;  xrefs: >080482AC[x]
>     080483B4 83 C4 10                       add     esp , 0x10
>     080483B7 83 EC 0C                       sub     esp , 0xC
>     080483BA 6A 01                          push    0x1
>     080483BC E8 FB FE FF FF                 call    exit  ;(0x80482BC was -261) ;  xrefs: >080482BC[x]
>     loc_080483C1:
>     080483C1 83 EC 0C                       sub     esp , 0xC  ;  xrefs: <080483A0[x]
>     080483C4 8B 45 0C                       mov     eax , [ebp+0x0C]
>     080483C7 83 C0 04                       add     eax , 0x4
>     080483CA FF 30                          push    [eax]
>     080483CC E8 35 00 00 00                 call    alf  ;(0x8048406 was +53) ;  xrefs: >08048406[x]
>     080483D1 83 C4 10                       add     esp , 0x10
>     080483D4 89 45 FC                       mov     [ebp-0x04] , eax
>     080483D7 83 7D FC 0A                    cmp     [ebp-0x04] , 0xA
>     080483DB 7E 12                          jle     loc_080483EF  ;(0x80483EF was +18) ;  xrefs: >080483EF[x]
>     080483DD 83 EC 0C                       sub     esp , 0xC
>     080483E0 68 78 84 04 08                 push    0x8048478
>     080483E5 E8 C2 FE FF FF                 call    printf  ;(0x80482AC was -318) ;  xrefs: >080482AC[x]
>     080483EA 83 C4 10                       add     esp , 0x10
>     080483ED EB 10                          jmp     loc_080483FF  ;(0x80483FF was +16) ;  xrefs: >080483FF[x]
>     loc_080483EF:
>     080483EF 83 EC 0C                       sub     esp , 0xC  ;  xrefs: <080483DB[x]
>     080483F2 68 7D 84 04 08                 push    0x804847D
>     080483F7 E8 B0 FE FF FF                 call    printf  ;(0x80482AC was -336) ;  xrefs: >080482AC[x]
>     080483FC 83 C4 10                       add     esp , 0x10
>     loc_080483FF:
>     080483FF B8 01 00 00 00                 mov     eax , 0x1  ;  xrefs: <080483ED[x]
>     08048404 C9                             leave
>     08048405 C3                             ret
>     alf:
>     08048406 55                             push    ebp   ;  xrefs: <080483CC[x]
>     08048407 89 E5                          mov     ebp , esp
>     08048409 83 EC 08                       sub     esp , 0x8
>     0804840C 83 EC 0C                       sub     esp , 0xC
>     0804840F FF 75 08                       push    [ebp+0x08]
>     08048412 E8 B5 FE FF FF                 call    atoi  ;(0x80482CC was -331) ;  xrefs: >080482CC[x]
>     08048417 83 C4 10                       add     esp , 0x10
>     0804841A C9                             leave
>     0804841B C3                             ret
> #### HT Editor Πρόκειται για ένα ιδιαίτερα χρήσιμο και καλοφτιαγμένο εργαλείο. Ο HT Editor είναι ένας editor με έμφαση στα εκτελέσιμα αρχεία. Τα file formats που υποστηρίζει είναι τα COFF, ELF, LE, NE, PE, MZ, και Java Class. Εκτός από τη δυνατότητα για εύκολη επεξεργασία των headers, sections, symbols κτλ των αρχείων, προσφέρει έναν αρκετά καλό disassembler. Το μόνο πρόβλημα που υπάρχει (στην έκδοση 0.7.3 τουλάχιστον), είναι ότι ο C++ demangler δεν υποστηρίζει ακόμα το gnu-V3 mangling, οπότε αν κάποιο πρόγραμμα έχει γίνει compile με g++ 3 τα σύμβολα θα είναι ακαταλαβίστικα. Site: http://hte.sourceforge.net.
>     ....... ! ;********************************************************
>     ....... ! ; function main (global)
>     ....... ! ;********************************************************
>     ....... ! main:                           ;xref o80482f3
>     ....... !   push    ebp
>     804838d !   mov     ebp, esp
>     804838f !   sub     esp, 8
>     8048392 !   and     esp, 0fffffff0h
>     8048395 !   mov     eax, 0
>     804839a !   sub     esp, eax
>     804839c !   cmp     dword ptr [ebp+8], 1
>     80483a0 !   jg      loc_80483c1
>     80483a2 !   sub     esp, 8
>     80483a5 !   mov     eax, [ebp+0ch]
>     80483a8 !   push    dword ptr [eax]
>     80483aa !   push    strz_Usage:__s__number___8048464
>     80483af !   call    printf@@GLIBC_2.0
>     80483b4 !   add     esp, 10h
>     80483b7 !   sub     esp, 0ch
>     80483ba !   push    1
>     80483bc !   call    exit@@GLIBC_2.0
>     80483c1 !
>     ....... ! loc_80483c1:                    ;xref j80483a0
>     ....... !   sub     esp, 0ch
>     80483c4 !   mov     eax, [ebp+0ch]
>     80483c7 !   add     eax, 4
>     80483ca !   push    dword ptr [eax]
>     80483cc !   call    alf
>     80483d1 !   add     esp, 10h
>     80483d4 !   mov     [ebp-4], eax
>     80483d4 !   mov     [ebp-4], eax
>     80483d7 !   cmp     dword ptr [ebp-4], 0ah
>     80483db !   jng     loc_80483ef
>     80483dd !   sub     esp, 0ch
>     80483e0 !   push    data_8048478
>     80483e5 !   call    printf@@GLIBC_2.0
>     80483ea !   add     esp, 10h
>     80483ed !   jmp     loc_80483ff
>     80483ef !
>     ....... ! loc_80483ef:                    ;xref j80483db
>     ....... !   sub     esp, 0ch
>     80483f2 !   push    strz_Failed___804847d
>     80483f7 !   call    printf@@GLIBC_2.0
>     80483fc !   add     esp, 10h
>     80483ff !
>     ....... ! loc_80483ff:                    ;xref j80483ed
>     ....... !   mov     eax, 1
>     8048404 !   leave
>     8048405 !   ret
>     8048406 !
>     ....... ! ;********************************************************
>     ....... ! ; function alf (global)
>     ....... ! ;********************************************************
>     ....... ! alf:                            ;xref c80483cc
>     ....... !   push    ebp
>     8048407 !   mov     ebp, esp
>     8048409 !   sub     esp, 8
>     804840c !   sub     esp, 0ch
>     804840f !   push    dword ptr [ebp+8]
>     8048412 !   call    atoi@@GLIBC_2.0
>     8048417 !   add     esp, 10h
>     804841a !   leave
>     804841b !   ret
> #### LDasm Το ldasm είναι ένα πρόγραμμα που χρησιμοποιεί και επεκτείνει την έξοδο του objdump. Χρησιμοποιεί perl/Tk για να δώσει ένα οπτικό αποτέλεσμα παρόμοιο με το W32Dasm που υπάρχει για Windows. Δυστυχώς, ο δημιουργός του το έχει παρατήσει και έτσι έχει ξεμείνει στην έκδοση 0.04.53 (!). Πάντως, έχει τις στοιχειώδεις δυνατότητες που χρειαζόμαστε, αν και αφού χρησιμοποιεί το objdump, έχει και τα ίδια αδύνατα σημεία. Site: http://Feedface.com/projects/ldasm.
>     Exported fn(): main
>     :0804838c 55                     push ebp
>     :0804838d 89e5                   mov  ebp, esp
>     :0804838f 83ec08                 sub  esp, 8
>     :08048392 83e4f0                 and  esp, -16
>     :08048395 b800000000             mov  eax, 0
>     :0804839a 29c4                   sub  esp, eax
>     :0804839c 837d0801               cmpl ptr [ebp+8], 1
>     :080483a0 7f1f                   jg   080483c1
>     :080483a2 83ec08                 sub  esp, 8
>     :080483a5 8b450c                 mov  eax, ptr [ebp]
>     :080483a8 ff30                   pushl (eax)

>     * Possible StringData Ref from Code Obj ->"Usage: %s <number>"
>                                      |
>     :080483aa 6864840408             push 8048464

>     * Reference To: GLIBC_2.0::printf
>                                      |
>     :080483af e8f8feffff             call 080482ac
>     :080483b4 83c410                 add  esp, 10
>     :080483b7 83ec0c                 sub  esp, c
>     :080483ba 6a01                   push 1

>     * Reference To: GLIBC_2.0::exit -.
>                                      |
>     :080483bc e8fbfeffff             call 080482bc

>     Referenced by a (U)nconditional or (C)onditional Jump at Address:
>     | :080483a0
>     |
>     :080483c1 83ec0c                 sub  esp, c
>     :080483c4 8b450c                 mov  eax, ptr [ebp]
>     :080483c7 83c004                 add  eax, 4
>     :080483ca ff30                   pushl (eax)

>     * Reference To: alf -------------.
>                                      |
>     :080483cc e835000000             call 08048406
>     :080483d1 83c410                 add  esp, 10
>     :080483d4 8945fc                 mov  ptr [ebp-4], eax
>     :080483d7 837dfc0a               cmpl ptr [ebp-4], a
>     :080483db 7e12                   jle  080483ef
>     :080483dd 83ec0c                 sub  esp, c

>     * Possible StringData Ref from Code Obj ->"Ok!"
>                                      |
>     :080483e0 6878840408             push 8048478

>     * Reference To: GLIBC_2.0::printf
>                                      |
>     :080483e5 e8c2feffff             call 080482ac
>     :080483ea 83c410                 add  esp, 10
>     :080483ed eb10                   jmp  080483ff

>     Referenced by a (U)nconditional or (C)onditional Jump at Address:
>     | :080483db
>     |
>     :080483ef 83ec0c                 sub  esp, c

>     * Possible StringData Ref from Code Obj ->"Failed!"
>                                      |
>     :080483f2 687d840408             push 804847d

>     * Reference To: GLIBC_2.0::printf
>                                      |
>     :080483f7 e8b0feffff             call 080482ac
>     :080483fc 83c410                 add  esp, 10

>     Referenced by a (U)nconditional or (C)onditional Jump at Address:
>     | :080483ed
>     |
>     :080483ff b801000000             mov  eax, 1
>     :08048404 c9                     leave
>     :08048405 c3                     ret

>     Referenced by a Call at Address:
>     | :080483cc
>     |
>     Exported fn(): alf
>     :08048406 55                     push ebp
>     :08048407 89e5                   mov  ebp, esp
>     :08048409 83ec08                 sub  esp, 8
>     :0804840c 83ec0c                 sub  esp, c
>     :0804840f ff7508                 pushl ptr [ebp+8]

>     * Reference To: GLIBC_2.0::atoi -.
>                                      |
>     :08048412 e8b5feffff             call 080482cc
>     :08048417 83c410                 add  esp, 10
>     :0804841a c9                     leave
>     :0804841b c3                     ret
### 5.2 Packed Executables - Συμπιεσμένα Εκτελέσιμα #### Τι είναι; Τα εκτελέσιμα αρχεία, όπως και όλα τα αρχεία, περιέχουν μέσα τους επαναλήψεις που καθιστούν δυνατή τη συμπίεση τους. Η συμπίεση στα εκτελέσιμα, εφόσον η αποσυμπίεση μπορεί να εκτελεστεί αρκετά γρήγορα ώστε να μη γίνεται αισθητή, είναι σίγουρα επιθυμητή. Τα αρχεία καταλαμβάνουν λιγότερο χώρο και επίσης είναι πιο δύσκολο να ερευνηθούν και να αλλαχτούν (βέβαια, για όσους κάνουμε RCE αυτό είναι μεγάλο πρόβλημα). Μάλιστα, πολλά προγράμματα συμπίεσης εκτελέσιμων εφαρμόζουν και άλλες τεχνικές, όπως κρυπτογράφηση και CRC ελέγχους. Είναι σαφές πως δε βολεύει απλώς να συμπιεστεί το αρχείο με κάποια παραδοσιακή μέθοδο (πχ με το gzip). Αυτό συμβαίνει, διότι εκτός από το ότι το εκτελέσιμο δεν είναι πια εκτελέσιμο (η κατάσταση διορθώνεται με χρήση scripts για αυτόματη αποσυμπίεση, το utility gzexe λειτουργεί έτσι), χάνεται η προστασία από το RCE, αφού τελικά το εκτελέσιμο θα βρεθεί στην αρχική του μορφή πριν εκτελεστεί. Για αυτό, έχουν αναπτυχθεί διάφορες άλλες τεχνικές για συμπίεση προγραμμάτων. #### Βασικές Τεχνικές packing Καταρχάς θα δούμε την απλή packing τεχνική που αναφέραμε στην εισαγωγή . Η βασική της λειτουργία φαίνεται στο παρακάτω σχήμα: Ο packer συμπιέζει όλο το εκτελέσιμο και δημιουργεί ένα καινούργιο που περιλαμβάνει τα συμπιεσμένα δεδομένα και τον κώδικα αποσυμπίεσης. Ο κώδικα αποσυμπιέζει τα συμπιεσμένα δεδομένα (αρχικό εκτελέσιμο), τα σώζει σε ένα προσωρινό αρχείο, και μετά το εκτελεί συνήθως με exec(). Η αδυναμία του βρίσκεται στο γεγονός πως εμφανίζεται το αυθεντικό εκτελέσιμο στο δίσκο, και επομένως δεν παρέχει ιδιαίτερη προστασία. Το θετικό στοιχείο του είναι η απλότητα. Μια πιo εξελιγμένη τεχνική : Εδώ τα πράγματα είναι πιο ενδιαφέροντα. Δε συμπιέζεται όλο το εκτελέσιμο αλλά μόνο τα segments του. Το καινούργιο εκτελέσιμο περιέχει τα συμπιεσμένα δεδομένα και τον κώδικα για το unpacking (κατά προτίμηση μετά τα δεδομένα). Κατά την εκτέλεση φορτώνονται τα συμπιεσμένα segments στη μνήμη, με τέτοιο τρόπο, ώστε όταν αποσυμπιεστούν να έχουν τις αρχικές διευθύνσεις τους. Επίσης, ο unpacker πρέπει να κάνει και κάτι άλλο που δεν είναι φανερό με την πρώτη ματιά. Αν το αυθεντικό εκτελέσιμο χρησιμοποιούσε shared objects (βιβλιοθήκες), τότε μέσα στο αρχείο υπήρχαν οι πληροφορίες, ώστε ο dynamic linker να τα φορτώσει. Όμως το συμπιεσμένο εκτελέσιμο έχει διαφορετικές πληροφορίες και έτσι τα shared objects δε φορτώνονται. Θα πρέπει ο unpacker να επωμιστεί αυτό το βάρος και επιπλέον να διορθώσει τις αναφορές στα εξωτερικά σύμβολα. Αυτό γίνεται με χρήση των συναρτήσεων dlopen() και dlsym() που χρησιμοποιούνται για να φορτώνουν shared objects στο run-time (δείτε manpages). Ο unpacker, αφού ολοκληρώσει όλες τις εργασίες του, θα μεταφέρει τον έλεγχο στο OEP (original entry point) και έτσι θα αρχίσει το κυρίως πρόγραμμα. #### Βασικές Τεχνικές Unpacking Στην πιο απλή περίπτωση, όπου ο unpacker αποσυμπιέζει το αρχικό αρχείο στο δίσκο και το εκτελεί από εκεί, τα πράγματα είναι εύκολα. Αρκεί να βρούμε ποιο προσωρινό αρχείο χρησιμοποιείται και τελειώσαμε. Το /proc filesystem είναι ιδιαίτερα χρήσιμο, όπως θα φανεί και στο hands-on παράδειγμα που ακολουθεί. Αν ο packer είναι εξελιγμένος, τότε θα πρέπει να φερθούμε και εμείς πιο έξυπνα. Η μέθοδος αυτή είναι σχετικά επίπονη αλλά μπορεί να εφαρμοστεί ακόμα και στις πιο δύσκολες περιπτώσεις. Σκοπός είναι να κάνουμε dump από τη μνήμη την εικόνα του εκτελέσιμου σε ένα αρχείο. Αυτό, βέβαια, δε θα είναι το πλήρες, αυθεντικό αρχείο αλλά συχνά είναι ότι καλύτερο μπορούμε να κάνουμε. Εξάλλου, μετά μπορούμε να κάνουμε διάφορες επεμβάσεις για να το "βελτιώσουμε". Η διαδικασία αποτελείται από τα παρακάτω βήματα: Ανάκτηση του OEP (original entry point) : Εδώ προσπαθούμε να εντοπίσουμε τη διεύθυνση της πρώτης εντολής του αυθεντικού προγράμματος στην εικόνα του εκτελέσιμου μετά την αποσυμπίεση. Αυτό το βήμα είναι που απαιτεί την περισσότερη εμπειρία. Σημάδια πως τελειώνει ο κώδικας του unpacker και περνάμε στο αρχικό εκτελέσιμο είναι: Unconditional jump ( άμεσο πχ jmp 0x8048954 ή έμμεσο πχ jmp eax ) σε κάποια "μακρινή" διεύθυνση. Αλλαγή του ύφους του προγράμματος. Οι unpackers είναι συνήθως γραμμένοι σε assembly με το χέρι και το στυλ τους διαφέρει από τον κώδικα που έχει παραχθεί από compilers. Χρήση των popa/popad (pop all registers). Επειδή η unpackers αλλοιώνουν το context της διεργασίας (πχ τιμές των registers) τους σώζουν όλους πριν αρχίσουν (με pusha/pushad) και τους επαναφέρουν πριν περάσουν τον έλεγχο στο αρχικό πρόγραμμα. Dump της εικόνας (image) του εκτελέσιμου σε ένα αρχείο : Κάνουμε dump την εικόνα του εκτελέσιμου, όπως είναι αυτή, ακριβώς πριν περάσει ο έλεγχος στο αυθεντικό εκτελέσιμο. Για αυτό χρειαζόμαστε το OEP που μας δινει το προηγούμενο βήμα. Αφου, λοιπόν, το έχουμε, αναγκάζουμε τη διεργασία να εκτελεστεί μέχρι το OEP (έτσι είμαστε σίγουροι πως όλα είναι unpacked όπως πρέπει) και τότε κάνουμε dump την εικόνα του εκτελέσιμου. Μπορούμε να χρησιμοποιήσουμε την εντολή dump του gdb. Η σύνταξη της είναι dump memory <file> <start> <stop>. Για να αποφασίσουμε ποιες διευθύνσεις θα κάνουμε dump μπορούμε να συμβουλευτούμε το map από το /proc/<pid>/. Για τα εκτελέσιμα στο linux, αρκούν συνήθως τα δύο πρώτα segments που είναι το code και data segment αντίστοιχα . Διόρθωση του ELF Header : Διορθώνουμε τον ELF Header του dumped αρχείου, ώστε να μπορεί να εξεταστεί και να εκτελεστεί. Συγκεκριμένα θέτουμε το entry point του εκτελέσιμου στο OEP, διορθώνουμε τα στοιχεία των segments και αναδημιουργούμε το DYNAMIC segment. Το τελευταίο είναι αρκετά επίπονο και όχι απαραίτητο αν απλώς θέλουμε να εξετάσουμε τον κώδικα (dissasembly). Αν δε γίνει αυτή η διόρθωση, τότε οι διευθύνσεις των συναρτήσεων των shared objects θα έχουν παντα τις τιμές που είχαν την στιγμή που κάναμε dump, διότι ο dynamic linker δε θα ενεργοποιηθεί. Αν χρησιμοποιούμε το dumped εκτελέσιμο μόνο στο δικό μας σύστημα και με τι ίδιες ακριβώς βιβλιοθήκες, ίσως να τη γλιτώσουμε. Επόμενο Προηγούμενο Περιεχόμενα