Επόμενο Προηγούμενο Περιεχόμενα
Τι είναι το 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
Τι είναι;
Τα εκτελέσιμα αρχεία, όπως και όλα τα αρχεία, περιέχουν
μέσα τους επαναλήψεις που καθιστούν δυνατή τη συμπίεση
τους. Η συμπίεση στα εκτελέσιμα, εφόσον η αποσυμπίεση
μπορεί να εκτελεστεί αρκετά γρήγορα ώστε να μη γίνεται
αισθητή, είναι σίγουρα επιθυμητή. Τα αρχεία καταλαμβάνουν
λιγότερο χώρο και επίσης είναι πιο δύσκολο να ερευνηθούν
και να αλλαχτούν (βέβαια, για όσους κάνουμε 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
εκτελέσιμο μόνο στο δικό μας σύστημα και με τι ίδιες
ακριβώς βιβλιοθήκες, ίσως να τη γλιτώσουμε.
Επόμενο Προηγούμενο Περιεχόμενα