Site hosted by Angelfire.com: Build your free website today!

Pe File Format:Surgery Of The Executable

Ανατομία ενός εγκλήματος-The Sequel :)

by human_thought

ΕΚΘΕΣΗ ΓΙΑ ΤΟ 2ο PROJECT


Πραγματικά θεωρώ πως είναι ΕΞΑΙΡΕΤΙΚΑ χρήσιμο για ΚΑΘΕ cracker να γνωρίζει καλά το Portable 
Executable File Format.Οφείλω να επισημάνω ότι αυτά που θα λεχθούν σε αυτήν την έκθεση δεν είναι
εύκολα στην κατανόηση.Για κανένα λόγο όμως μην τα παρατήσετε.Σας διαβεβαιώνω πως προσωπικά,
όπως και οι περισσότεροι crackers,χρειάστηκα πολλές ώρες και καλή εξάσκηση για να καταλάβω
το pe file format,το επίσημο format των binary files των Windows.Οι γνώσεις αυτές έχουν 
σημαντικότατη εφαρμογή στον κλάδο του packing/unpacking,στο Import Table Rebuilding,σχεδόν
σε ότι μπορείτε να φανταστείτε.Ας ξεκινήσουμε λοιπόν...


Εργαλεία:  Hiew Editor

Δυσκολία:  Μέτριο

Συνοδευτικά αρχεία: ΕΔΩ και ΕΔΩ


  Υπάρχουν κάποια βοηθήματα στο internet που εξηγούν το PE file format,με το καλύτερο κατά την
γνώμη μου να είναι αυτό του Luevelsmeyer και φυσικά τα βοηθήματα του iczelion με win32asm
επεκτάσεις.Παρόλα αυτά δεν υπάρχει κάτι στα ελληνικά για όλα αυτά,εκτός από ενα βοήθημα
που είχα γράψει παλιότερα.Έτσι,προσπάθησα να κάνω κάτι λίγο πιο εύκολο στην κατανόηση 
χρησιμοποιώντας παραδείγματα.Ελπίζω να βοηθήσει κάποιους από εσάς.
  Στο πρώτο site της M.a.s.k. είχα γράψει ένα βοήθημα για το pe file format το οποίο θα 
αναφερθεί εδώ εξ ολοκλήρου.Παρόλα αυτά,έχω φτιάξει ένα συνοδευτικό αρχειάκι για την 
εξάσκησή σας μετά το θεωρητικό μάθημα.Ετοιμαστείτε,ξεκινάμε...

  Αρχικά,πρέπει να σας πω λίγα λόγια για το θέμα που θα αναπτύξω σε αυτό το βοήθημα.Θα μιλήσουμε,λοιπόν για το PE file format (Portable Executable File Format),που είναι αυτό που συναντάμε στα εκτελέσιμα των Windows,αλλά και στα 32bita Dll’s.Είναι το format που σχεδίασε δηλαδή η Microsoft,βασισμένη στο πρωθύστερο COFF (Common Object File Format).Ίσως κάποιοι από εσάς αναρωτιέστε τι χρειαζόμαστε τις γνώσεις γύρω από το PE file format.Βέβαια,αν έχει τύχει να κάνετε unpack,καταλαβαίνετε ότι όσο περισσότερες γνώσεις έχουμε γύρω από αυτό το θέμα,τόσο πιο εύκολα μπορούμε να αντιμετωπίσουμε ένα packed executable.Σε αυτό το βοήθημα,λοιπόν,θα αναλύσουμε το Official Crackme της M.a.s.k. για να δείτε έτσι πόσα πράγματα μπορείτε να μάθετε για ένα executable μόνο με την βοήθεια ενός hiew editor και κάποιων σημαντικών σημειώσεων.Ας ανοίξουμε,λοιπόν το official crackme της M.a.s.k.,με το Hiew Editor.Εδώ έρχεται η ώρα να ανοίξετε το txt αρχειάκι που σας παρείχα πιο πάνω.Κρατήστε το μπροστά σας κατά την διάρκεια της έκθεσης αυτής,ώστε να την κατανοήσετε πιο εύκολα.Ας ξεκινήσουμε,λοιπόν:




Στην αρχή κάθε εκτελέσιμου βλέπουμε το DOS MZ HEADER.Βρίσκεται πάντα στα πρώτα 2 bytes κάθε 
εκτελέσιμου,συγκεκριμένα στα bytes 00-01.Αμέσως μετά βρίσκεται το DOS-STUB,που στην 
πραγματικότητα είναι ένα εκτελέσιμο,που εκτελείται αν το λειτουργικό σύστημα δεν αναγνωρίζει το 
PE file format και εμφανίζει το εκάστοτε μήνυμα.Μετά το Dos Stub βρίσκεται το File Header,το 
Optional Header,τα Data Directories,τα Section Headers και αμέσως μετά βρίσκονται τα sections.
Ας πούμε τώρα αναλυτικότερα για τα κομμάτια αυτά του εκτελέσιμου.Πρέπει να αναφέρω εδώ ότι το 
IMAGE_NT_SIGNATURE,που είναι πάντα 0x00004550 είναι το E_LFANEW member του header του 
Dos Stub(PE).Παρακάτω,θα αναφέρω πώς να βρίσκετε κάθε στοιχείο παραθέτοντάς σας τις μετατοπίσεις 
αυτού από το πρώτο byte(P) του e_lfanew(PE ή 5045 όπως το βλέπετε).Το file header ξεκινά με 
μετατόπιση  e_lfanew + 4h.Στο παράδειγμά μας βλέπετε:

0   1   2   3   4

-------------------

50 45 00 00 4C 01

P   E   0   0   Machine Type

 

  Πρώτα πρώτα πρέπει να σας πω ότι δεν θα μιλήσουμε για το MZ-DOS Header,καθώς δεν έχει σχεδόν καμμία σημασία σε εμάς,αλλά σε περίπτωση που θέλετε να μάθετε ποια είναι τα μέλη αυτού,δείτε τα παρακάτω,παρμένα από μία έκθεση του +Mammon,ενός από τους μεγαλύτερους +Hcukers:

  

MZ Header

WORD e_magic;         // Magic number

WORD e_cblp;          // Bytes on last page of file

WORD e_cp;            // Pages in file

WORD e_crlc;          // Relocations

WORD e_cparhdr;       // Size of header in paragraphs

WORD e_minalloc;      // Minimum extra paragraphs needed

WORD e_maxalloc;      // Maximum extra paragraphs needed

WORD e_ss;            // Initial (relative) SS value

WORD e_sp;            // Initial SP value

WORD e_csum;          // Checksum

WORD e_ip;            // Initial IP value

WORD e_cs;            // Initial (relative) CS value

WORD e_lfarlc;        // File address of relocation table

WORD e_ovno;          // Overlay number

WORD e_res[4];        // Reserved words

WORD e_oemid;         // OEM identifier (for e_oeminfo)

WORD e_oeminfo;       // OEM information; e_oemid specific

WORD e_res2[10];      // Reserved words

DWORD   e_lfanew;    // File address of new exe header

 

FILE HEADER

 

  Βλέπουμε στο παράδειγμα αυτό ότι αν προχωρήσουμε 4 bytes μετά το "P"(50),θα βρεθούμε στο byte 4C,από όπου και ξεκινά το file header με το πρώτο μέλος αυτού,το Machine Type(2 δεκαεξαδικά ψηφία = 1 byte),που έχει μέγεθος 1 word.Το μέλος αυτό μπορεί να έχει διάφορες τιμές,αλλά δεν έχει μεγάλο ενδιαφέρον να αναφερθούν εδώ.Σε όσα εκτελέσιμα έχω δει,η τιμή αυτή είναι πάντα 014C.Αμέσως μετά,με μετατόπιση e_lfanew + 6h βρίσκεται το δεύτερο κατά σειρά μέλος του file header,το NumberOfSections,που έχει το μέγεθος μιας λέξης(Word).Στην περίπτωσή μας είναι 05 00,που μην ξεχνώντας το Little endian(ανάποδη σειρά bytes με λίγα λόγια),είναι 05.Τρίτο μέλος που ακολουθεί είναι το TimeDateStamp,με μετατόπιση e_lfanew + 8h,και τιμή 3C74DFC8 με μέγεθος DWORD(Double WORD),που δίνει την "ώρα" που δημιουργήθηκε το αρχείο.Ακολουθεί το PointerToSymbolTable,με μετατόπιση e_lfanew + Ch και έχει από όσο έχω δει πάντα την τιμή 00000000.Ακολουθεί το NumberOfSymbols,που έχει και αυτό την τιμή 00000000 με μετατόπιση e_lfanew + 10h(16 bytes δηλαδή ξεκινώντας από το 2ο byte του e_lfanew).Το έκτο μέλος του file header είναι το SizeOfOptionalHeader,που έχει το μέγεθος μιας λέξης,με μετατόπιση e_lfanew + 14h και στην περίπτωσή μας έχει την τιμή 00E0.Τέλος, βρίσκεται το μέλος Characteristics,με μετατόπιση e_lfanew + 16h,που αποτελείται από μια σειρά με flags και στο παράδειγμά μας έχει την τιμή 010F,που δυαδικά ερμηνεύεται σε 0000 0001 0000 1111.Ας αναλύσουμε λίγο τι σημαίνει το παρακάτω:

 

010F -> 0000 0001 0000 1111

 

  Μην ξεχνάμε ότι ξεκινάμε το μέτρημα από τα δεξιά με τον αριθμό 0 για το πρώτο bit.Οπότε:

 

* Το bit 0 έχει την τιμή 1.Αυτό σημαίνει ότι υπάρχει relocation information για το αρχείο αυτό. 

* Το bit 1 έχει την τιμή 1. Αυτό σημαίνει ότι το αρχείο είναι εκτελέσιμο και ΟΧΙ object file για παράδειγμα.

* Το bit 2 έχει την τιμή 1. Αυτό σημαίνει ότι το line number info είναι εμφανές.Δεν χρησιμοποιείται στα executables...

* Το bit 3 έχει την τιμή 1. Αυτό σημαίνει ότι δεν υπάρχει info για τα local symbols.Δεν χρησιμοποιείται στα executables...

* Το bit 4 έχει την τιμή 0. Αυτό σημαίνει ότι το O/S(Windows) δεν πρόκειται να δράσει "αυστηρά" στο εκτελέσιμο ώστε να διακόψει την λειτουργία του μέσω της RAM...

* Το bit 5 έχει την τιμή 0,αλλά από όσο ξέρω δεν έχει κανένα ρόλο στο αρχείο.

* Το bit 6 έχει την τιμή 0,που επίσης δεν πρέπει από όσο γνωρίζω να διαδραματίζει κάποιο ρόλο στο αρχείο.

* Το bit 7 έχει την τιμή 0,όπως και το bit 15. Αν και τα 2 ήταν 1,τότε θα σήμαινε ότι το αρχείο δεν έχει το τέλος που το σύστημα απαιτεί και χρειάζεται να το διορθώσει αλλάζοντας bytes ώστε να διαβάσει το αρχείο αυτό.Η τιμή αυτή είναι,όμως,αναξιόπιστη για τα εκτελέσιμα.

* Το bit 8 έχει την τιμή 1. Αυτό σημαίνει ότι ο επεξεργαστής του Η/Υ μας είναι 32bitos.

* Το bit 9 έχει την τιμή 0. Αυτό σημαίνει ότι δεν υπάρχει debugging info για το αρχείο.Είναι δηλαδή "released"...

* Το bit 10 έχει την τιμή 0. Αυτό σημαίνει ότι το αρχείο μπορεί να τρέξει και μέσω removable drive,όπως CD-Rom.Σε αντίθετη περίπτωση κάτι τέτοιο δεν είναι εφικτό και για να τρέξει το αρχείο αντιγράφεται πρώτα στο swapfile του δίσκου.

* Το bit 11 έχει την τιμή 0. Αυτό σημαίνει ότι το αρχείο μπορεί να τρέξει μέσω network.Σε αντίθετη περίπτωση συμβαίνει το παραπάνω.

* Το bit 12 έχει την τιμή 0. Αυτό σημαίνει ότι το αρχείο δεν είναι system file.

* Το bit 13 έχει την τιμή 0. Αυτό σημαίνει ότι το αρχείο δεν είναι DLL.

* Το bit 14 έχει την τιμή 0. Αυτό σημαίνει ότι το αρχείο είναι σχεδιασμένο να τρέχει σε multiprocessor systems.

 

OPTIONAL HEADER

 

  Μην σας ξεγελά το όνομα!Το Optional Header βρίσκεται σε κάθε valid pe binary file και μάλιστα αποτελεί και σημαντικότατο κομμάτι αυτού.Ας δούμε τώρα αναλυτικά τα κομμάτια από τα οποία αποτελείται το optional header:

 

* Το πρώτο μέλος του Optional Header είναι το "μαγικό" ‘Magic’ member,που αποτελείται από δύο Bytes και βρίσκεται αμέσως μετά τα characteristics του file header.Η τιμή του είναι πάντα 0x010b,δηλαδή 0B01,όπως το βλέπουμε από το hiew editor.

* Τα δύο επόμενα μέλη που ακολουθούν είναι ένα byte έκαστος και αυτά είναι τα: "MajorLinkerVersion" και "MinorLinkerVersion".Οι τιμές τους στο παράδειγμά μας είναι 05 και 00 αντίστοιχα.Οι μετατοπίσεις τους είναι:

e_lfanew + 1Ah και e_lfanew + 1Bh αντίστοιχα.

* Τα τρία επόμενα μέλη είναι τα: "SizeOfCode","SizeOfInitialisedData","SizeOfUninitialisedData" και είναι 4 bytes έκαστος.Οι τιμές τους στο παράδειγμά μας είναι:

 

SizeOfCode: 00024000

SizeOfInitialisedData: 00040600

SizeOfUninitialisedData: 00000000

 

* Το μέλος που ακολουθεί είναι εξαιρετικά σημαντικό.Είναι το "AddressOfEntryPoint" και έχει μέγεθος 4 bytes και όπως γνωρίζετε είναι το σημείο εκείνο από όπου ξεκινά η εκτέλεση του προγράμματος.Να μην ξεχνάμε βέβαια ότι είναι Relative Virtual Address(RVA) που σημαίνει ότι δεν είναι disk offset.Για να γίνει πρέπει να προστεθεί σε αυτό το image base(400000 στο παράδειγμά μας) ώστε RVA OF ENTRY POINT +IMAGE BASE = DISK OFFSET TO ENTRY POINT.Η μετατόπισή του είναι e_lfanew + 28h και η τιμή του 000079C0.

* Το αμέσως επόμενο μέλος είναι το "BaseOfCode" και αποτελείται από 4 bytes,ενώ έχει την μετατόπιση e_lfanew + 2Ch και τιμή 00001000 και είναι επίσης RVA.

* Ακολουθεί το μέλος ονόματι "BaseOfData",επίσης RVA και έχει την μετατόπιση e_lfanew + 30h και την τιμή 00025000,ενώ έχει το μέγεθος τεσσάρων bytes.

* Αργότερα βλέπουμε το μέλος "ImageBase",μεγέθους επίσης τεσσάρων bytes και αν προσθέσουμε την τιμή του(00400000) στο "BaseOfCode",βλέπουμε το disk offset από όπου ξεκινά η πρώτη εντολή του προγράμματος,στην περίπτωσή μας στο 00401000.Το μέλος αυτό έχει μετατόπιση e_lfanew + 34h.

* Τα δύο μέλη που ακολουθούν είναι τα "SectionAlignment" και "FileAlignment' αντίστοιχα και έχουν μεγέθη 4 bytes έκαστος.Οι μετατοπίσεις τους είναι e_lfanew + 38h και e_lfanew + 3Ch αντίστοιχα.Οι τιμές τους είναι 00001000 και 00000200 επίσης αντίστοιχα.

* Τα δύο επόμενα μέλη με μέγεθος 2 bytes έκαστος είναι τα "MajorOperatingSystemVersion" και "MinorOperatingSystemVersion" και έχουν τις τιμές 0004 και 0000 αντίστοιχα.Αλλά δεν είναι αξιόπιστες οι τιμές τους και δεν έχει σημασία να ξέρετε και τις μετατοπίσεις τους με βάση το e_lfanew member.

* Ακολουθούν δύο ακόμα όχι τόσο σημαντικά μέλη του optional header.Τα "MajorImageVersion" και "MinorImageVersion" με τιμές 0000 και 0000.Έχουν και τα δύο το μέγεθος 2 bytes.

* Άλλα δύο όχι και τόσο σημαντικά μέλη ακολουθούν.Τα "MajorSubSystemVersion" και "MinorSubSystemVersion' έχουν επίσης μέγεθος 2 bytes και τιμές 0004 και 0000 αντίστοιχα.

* Το επόμενο μέλος είναι το "Win32VersionValue" και σε σχεδόν σε όλα τα αρχεία από ότι ξέρω έχει τιμή 00000000,μέγεθος τεσσάρων bytes δηλαδή.

* Ακολουθεί ένα αρκετά σημαντικό μέλος.Το "SizeOfImage" έχει μέγεθος τεσσάρων bytes και στο παράδειγμά μας την τιμή 00068000.Το μέλος αυτό μας λέει πόση μνήμη θα χρειαστεί,σε bytes,για την εκτέλεση του προγράμματος.Έχει την μετατόπιση e_lfanew + 50h.

* Το επόμενο μέλος είναι το "SizeOfHeaders",που είναι επίσης σημαντικό,αφού δίνει το μέγεθος όλων των headers.Είναι επίσης το offset από την αρχή του αρχείου μέχρι το raw data του πρώτου section.Έχει στο παράδειγμά μας την τιμή 00000400,είναι δηλαδή 4 bytes και έχει μετατόπιση e_lfanew + 54h.

* Μετά βρίσκουμε το μέλος ονόματι "CheckSum" με μέγεθος 4 bytes και τιμή 00000000.Αυτό συμβαίνει επειδή το checksum χρησιμοποιείται μόνο στα WinNT και στο παράδειγμά μας είναι λογικά 0,αφού το crackme είναι για windows πλατφόρμες.

* Ακολουθεί το μέλος "SubSystem",μεγέθους 2 bytes,που δείχνει σε ποιο subsystem τρέχει το image file(executable).

Αν η τιμή του είναι:

 

0001 -> To αρχείο δεν χρειάζεται subsystem.Χρησιμοποιείται κυρίως στους drivers.

0002 -> Είναι Win32 Graphical binary

0003 -> Είναι Win32 Console binary

0005 -> Το binary είναι OS/2 binary

0007 -> Το binary χρησιμοποιεί Posix console subsystem

 

  Το δικό μας παράδειγμα έχει την τιμή 0002,άρα είναι win32 graphical binary.Έχει μετατόπιση e_lfanew + 5Ch.

* Ακολουθεί το μέλος "DLLCharacteristics",μεγέθους 2 bytes,που έχει φυσικά την τιμή 0000,αφού το αρχείο μας δεν είναι dll.

* Τα 4 επόμενα μέλη είναι τα:

 

 "SizeOfStackReserve","SizeOfStackCommit","SizeOfHeapReserve","SizeOfHeapCommit"

 

Είναι όλα τους μεγέθους 8 bytes και έχουν τις τιμές:

 

SizeOfStackReserve:  00100000

SizeOfStackCommit:  00001000

SizeOfHeapReserve:  00100000

SizeOfHeapCommit:  00001000

 

* Το επόμενο μέλος είναι το LoaderFlags,μεγέθους τεσσάρων bytes,που επίσης δεν έχει μεγάλη σημασία και στο παράδειγμά μας έχει την τιμή 00000000.

* Ακολουθεί το "NumberOfRVA&Sizes",που δείχνει τον αριθμό των entries στα directories που ακολουθούν.Η τιμή του είναι αναξιόπιστη.Έχει μέγεθος τεσσάρων bytes και στο παράδειγμά μας την τιμή 00000010.Και τώρα ακολουθούν τα directory entries,που μας λένε για τα RVAs και Sizes κάποιων symbols,resources κ.α.Ας τα δούμε παρακάτω αναλυτικά:

 

DATA DIRECTORIES

 

  Τα Data Directories είναι πολύ σημαντικά για εμάς και ειδικότερα αυτό που μας δείχνει το RVA του Import Table.Αργότερα,ελπίζω σε κάποια έκθεση να σας περιγράψω πώς να κάνετε import table rebuilding,κάτι που πιστεύω ότι θα σας φανεί εξαιρετικά ευκολότερο αν διαβάσετε και καταλάβετε την έκθεση αυτή.Εξάλλου είναι πρόδρομος για το IT rebuilding,που αποτελεί και τον κύριο στόχο μας και μας χρειάζεται σαν τεχνική σε πολλά προγράμματα και εμπορικά παιχνίδια.Ας πούμε τώρα για το ποια directories ακολουθούν στο PE header,αμέσως μετά το μέλος "NumberOfRVA&Sizes",αφού σας πω ότι όλα τα παρακάτω μέλη έχουν μέγεθος τεσσάρων bytes έκαστος:

 

* IMAGE_DIRECTORY_ENTRY_EXPORT

  -----------------------------------------------------------

  Είναι το directory που βρίσκονται τα exported symbols και χρησιμοποιείται όπως ξέρουμε κυρίως για Dlls.Στο παράδειγμά μας έχει την τιμή 00000000.Ακολουθεί όπως είπαμε το μέγεθος σε bytes,που είναι φυσικά 00000000,όπως και το RVA του,αφού το εκτελέσιμό μας δεν έχει exported symbols.Οι μετατοπίσεις είναι e_lfanew + 78h για το RVA και e_lfanew + 7Ch για το Size.

 

* IMAGE_DIRECTORY_ENTRY_IMPORT

   -----------------------------------------------------------

  Είναι το directory των imported symbols και έχει την τιμή 00037000 ως RVA και μέγεθος 000000F0 bytes.Οι μετατοπίσεις είναι e_lfanew + 80h για το RVA και e_lfanew + 84h για το Size.

 

* IMAGE_DIRECTORY_ENTRY_RESOURCE

   ---------------------------------------------------------------

  Είναι το directory των resources και έχει RVA 0003A000 και μέγεθος 0002D4D4 bytes.Οι μετατοπίσεις είναι e_lfanew + 88h για το RVA και e_lfanew + 8Ch για το Size.

 

* IMAGE_DIRECTORY_ENTRY_EXCEPTION

   ----------------------------------------------------------------

  Είναι το exception directory που δεν έχει σημασία για εμάς.Έχει τις τιμές RVA 00000000 και μέγεθος 00000000 bytes,μέγεθος λογικό αν σκεφτεί κανείς ότι δεν υπάρχει exception directory J.Οι μετατοπίσεις είναι e_lfanew + 90h για το RVA και e_lfanew + 94h για το Size.

 

* IMAGE_DIRECTORY_ENTRY_SECURITY

   ---------------------------------------------------

  Είναι το security directory που επίσης δεν έχει σημασία για εμάς.Έχει τις τιμές RVA 00000000 και μέγεθος 00000000 bytes και μετατοπίσεις e_lfanew + 98h για το RVA και e_lfanew + 9Ch για το Size.

 

* IMAGE_DIRECTORY_ENTRY_BASERELOC

   ------------------------------------------------------

  Εδώ βρίσκεται το base relocation table και έχει τιμές RVA 00000000 και μέγεθος 00000000 bytes και μετατοπίσεις e_lfanew + A0h για το RVA και e_lfanew + A4h για το Size.

 

* IMAGE_DIRECTORY_ENTRY_DEBUG

   ---------------------------------------------------------

  Εδώ περιέχεται το γνωστό debug directory,που θα έλεγα ότι σπάνια βρίσκουμε σε κάποιο εκτελέσιμο,αφού τα περισσότερα γίνονται RELEASED από τους compilers και δεν περιέχουν debug info.Έχει τιμές RVA 00000000 και μέγεθος 00000000 bytes και μετατοπίσεις e_lfanew + A8h για το RVA και e_lfanew + ACh για το Size.

 

* IMAGE_DIRECTORY_ENTRY_COPYRIGHT

   ----------------------------------------------------------------

  Copyright notes...Δεν έχει ιδιαίτερη σημασία για εμάς.Έχει τιμές RVA 00000000 και μέγεθος 00000000 bytes και μετατοπίσεις e_lfanew + B0h για το RVA και e_lfanew + B4h για το Size.

 

* IMAGE_DIRECTORY_ENTRY_GLOBALPTR

   -----------------------------------------------------------------

  Εδώ βρίσκεται το Machine Value και δεν έχει σημασία σε εμάς.Έχει τιμές RVA 00000000 και μέγεθος 00000000 bytes και μετατοπίσεις e_lfanew + B8h για το RVA και e_lfanew + BCh για το Size.

 

* IMAGE_DIRECTORY_ENTRY_TLS

   ---------------------------------------------------

  Αν δεν κάνω λάθος εδώ βρίσκονται κάποιες δηλωμένες μεταβλητές στο πρόγραμμα,όπως είναι οι καθολικές μεταβλητές,στο TLS Table.Έχει τιμές RVA 00000000 και μέγεθος 00000000 bytes και μετατοπίσεις e_lfanew + C0h για το RVA και e_lfanew + C4h για το Size.

 

* IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG

   --------------------------------------------------------------------

  Εδώ είναι το directory του load configuration,του οποίου η δομή δεν μας ενδιαφέρει.Έχει τιμές RVA 00000000 και μέγεθος 00000000 bytes και μετατοπίσεις e_lfanew + C8h για το RVA και e_lfanew + CCh για το Size.

 

* IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT

   ------------------------------------------------------------------------

  Το bound import directory,όπως και το επόμενο μέλος έχει άμεση σχέση με το import table.Έχει τιμές RVA 00000000 και μέγεθος 00000000 bytes και μετατοπίσεις e_lfanew + D0h για το RVA και e_lfanew + D4h για το Size.

 

* IMAGE_DIRECTORY_ENTRY_IAT

   ---------------------------------------------------

  Εδώ βρίσκεται το Import Address Table.Έχει τιμές RVA 0003764C και μέγεθος 0000055C bytes και μετατοπίσεις e_lfanew + D8h για το RVA και e_lfanew + DCh για το Size.

  Εδώ τελειώνουν τα data directories και αρχίζουν τα section headers και αμέσως μετά ακολουθούν τα sections με το raw data αυτών.Ας δούμε τώρα μερικά πράγματα για τα section headers.

 

SECTION HEADERS

 

  Όπως σας έδειξα παραπάνω,στο file header,το εκτελέσιμό μας έχει 5 sections,που είναι τα εξής,μαζί με τα χαρακτηριστικά τους(Μην ανησυχείτε,θα σας δείξω πώς να βρίσκετε τις παρακάτω πληροφορίες):

 

Section      Virtual Size      Virtual Offset      Raw Size      Raw Offset      Characteristics     

=============================================================

.text           0023F63           00001000          00024000     00000400        60000020

 

 

  Μόλις είδατε τα χαρακτηριστικά του πρώτου section ονόματι .text.Πριν σας πω πώς να τα βρείτε στο editor,πρέπει να σας πληροφορήσω ότι πλέον δεν θα μιλάμε με σταθερές μετατοπίσεις βάσει του e_lfanew member,αφού δεν είναι σταθερές.Λοιπόν,το πρώτο πράγμα που βλέπετε σε ένα section είναι το όνομά του,που στο παράδειγμά μας ακολουθεί μετά από μία τελεία(.),που μπορεί να υπάρχει αλλά μπορεί και όχι.Το όνομα του πρώτου section είναι .text και νομίζω ότι είναι εξαιρετικά εμφανές.Το όνομα ενός section μπορεί να έχει μέχρι 8 γράμματα,και τελειώνει με ένα Zero(0)-terminator,εκτός αν έχει ακριβώς 8 γράμματα,οπότε δεν έχει terminator.Μετά το όνομα του section και το terminator ακολουθεί το "Virtual Size",που δείχνει το μέγεθος των περιεχομένων του εκτελέσιμου.Στο παράδειγμα μας βλέπουμε 633F0200,που αν το αντιστρέψουμε,όπως και πρέπει βρίσκουμε το "Virtual Size" που είναι 00023F63.To επόμενο μέλος του section header είναι το "Virtual Address",ή "Virtual Offset",που δείχνει το RVA στο οποίο φορτώνεται το section στην μνήμη του υπολογιστή μας.Όπως βλέπετε έχει την τιμή 00100000,που αντιστρέφοντας είναι 00001000.Ακολουθεί το "SizeOfRawData",που δείχνει το μέγεθος του section,που στο παράδειγμά μας είναι 00024000.Το "PointerToRawData" είναι το επόμενο μέλος και δείχνει το offset στο οποίο βρίσκεται το Data του Section,από την αρχή των offsets του αρχείου.Αν είναι 0,τότε το data του section δεν βρίσκεται στο αρχείο και κατά την διάρκεια εκτέλεσης θα είναι αυθαίρετο.Έχει τιμή 00040000,που αντιστρέφοντας είναι 00000400.Ακολουθούν τα μέλη:

"PointerToRelocations","PointerToLineNumbers",που έχουν μέγεθος τεσσάρων bytes και τιμές 00000000 και 00000000 και τα "NumberOfRelocations" και "NumberOfLineNumbers",μεγέθους δύο bytes και με τιμές 0000 και 0000 αντίστοιχα.Ενώ το σημαντικότερο κομμάτι έρχεται τώρα.Είναι το μέλος "Characteristics",που όπως πιθανότατα γνωρίζετε έχει μεγάλη σημασία στο packing/unpacking,όπως και σε άλλα ζητήματα.Έχει μέγεθος τεσσάρων bytes,δηλαδή 32 bits.Βλέπουμε ότι στο παράδειγμά μας έχει την τιμή 20000060,που πρέπει να αντιστρέψουμε  για να βρούμε την πραγματική τιμή 60000020.Πρέπει βέβαια να τα κάνουμε δυαδικά bits,για να βρούμε την τιμή:

 

0110 0000 0000 0000 0000 0000 0010 0000

 

  Αλλά τι σημαίνει όλο αυτό?Ας δούμε τι σημαίνει κάθε Bit ξεχωριστά,όπως κάναμε και παραπάνω(Τα bits που δεν αναφέρω δεν έχουν καμμία λειτουργία):

 

* Το bit 5 έχει τιμή 1.Αυτό σημαίνει ότι το section μας περιέχει executable code.Πολύ σημαντική τιμή αυτή,έτσι?Αλλάζοντας το byte αυτό και κάνοντάς το μηδέν(0),δηλώνουμε το section ως μη έχων executable code,που όπως πιθανότατα ξέρετε εμποδίζει το softice loader να "σπάσει" σε κάποιο εκτελέσιμο.Αν θέλετε αλλάξτε το για να δείτε ότι το εκτελέσιμο δεν θα σπάσει στον loader του softice.

* Το bit 6 έχει τιμή 0.Αυτό σημαίνει ότι το αρχείο μας δεν περιέχει initialised data,όπως σταθερές.

* Το bit 7 έχει τιμή 0.Αυτό σημαίνει ότι το αρχείο μας δεν περιέχει uninitialised data,όπως αδήλωτες μεταβλητές.

* Το bit 9 έχει τιμή 0.Αυτό σημαίνει ότι το section δεν περιέχει image data,όπως info από τον linker.

* Το bit 11 έχει τιμή 0.Αυτό σημαίνει ότι το data,αν υπήρχε,θα ήταν έξω από το εκτελέσιμο,όταν αυτό συνδέθηκε από τον linker.

* Το bit 12 έχει τιμή 0.Αυτό σημαίνει ότι το section δεν περιέχει "common block data",που είναι λειτουργίες σε ένα block of data.

* Το bit 15 έχει τιμή 0.Αυτό σημαίνει ότι το αρχείο δεν έχει far data,όπως far calls δηλαδή.

* Το bit 17 έχει τιμή 0.Το bit αυτό έχει πάλι σχέση με το data του section,αλλά η σημασία του είναι αβέβαιη και δεν έχει σημασία για εμάς.

* Το bit 18 έχει τιμή 0.Αυτό σημαίνει ότι το section μπορεί να μετακινηθεί στην μνήμη.

* Το bit 19 έχει τιμή 0.Αυτό σημαίνει ότι το section δεν χρειάζεται dumping πριν αρχίσει η εκτέλεση.Και πάλι,όμως,η σημασία του bit αυτού είναι αβέβαιη.

* Τα bit 20-23 έχουν τιμή 0.Αυτό δείχνει μία παράταξη κάποιων αντικειμένων σε ένα library file,που όμως πάλι δεν έχει σημασία για εμάς και από όσο ξέρω είναι συνήθως μηδεν(0).

* Το bit 24 έχει τιμή 0.Αυτό σημαίνει ότι το section δεν έχει extended relocations.

* Το bit 25 έχει τιμή 0.Αυτό σημαίνει ότι το section data χρειάζεται κατά την διάρκεια της εκτέλεσης του αρχείου.Στο παράδειγμά μας το bit θα ήταν αναγκαστικά μηδέν(0),αφού το section μας δεν έχει data.

* Το bit 26 έχει τιμή 0.Αυτό σημαίνει ότι το section data μπορεί να βρεθεί στην μνήμη cache,που δεν έχει πάλι σημασία εδώ για τον ίδιο λόγο.

* Το bit 27 έχει τιμή 0.Αυτό σημαίνει ότι το section data θα μπορούσε να δεχθεί paging out,που γίνεται συνήθως σε dll files.

* Το bit 28 έχει τιμή 0.Αυτό σημαίνει ότι το data του section,αν υπήρχε,θα μπορούσε να "μοιρασθεί" σε κάθε instance του image αυτού,όπως κάποιο dll.

* Το bit 29 έχει τιμή 1.Αυτό σημαίνει ότι η διαδικασία έχει "execute" πρόσβαση στην μνήμη του section.

* Το bit 30 έχει τιμή 1.Αυτό σημαίνει ότι η διαδικασία έχει "read" πρόσβαση στην μνήμη του section.

* Το bit 31 έχει τιμή 0.Αυτό σημαίνει ότι η διαδικασία ΔΕΝ έχει "write" πρόσβαση στην μνήμη του section.

 

  Εδώ τελείωσαν τα χαρακτηριστικά του ".text" section.Νομίζω ότι τώρα άνετα μπορείτε να βρείτε τα χαρακτηριστικά των άλλων sections.Μετά από όλα τα section headers,ακολουθούν τα sections raw data,το περιεχόμενο δηλαδή των sections.


  Όλες αυτές οι πληροφορίες μπορούν άνετα να χρησιμοποιηθούν για την δημιουργία ενός PE Viewer 
ή ενός PE Editor.Πως μπορεί να γίνει κάτι τέτοιο?Όπως είδαμε όλα τα χαρακτηριστικά ενός αρχείου 
βρίσκονται ως μία σχετική απόσταση από τo "PE".Έτσι μπορούμε να πάρουμε τα χαρακτηριστικά
κάθε valid pe.Πολύ σημαντικό κομμάτι αποτελεί το import table ενός αρχείου,το οποίο δεν θα 
περιγράψω εγώ σε αυτήν την έκθεση,καθώς σύντομα θα το δείτε σε μία έκθεση του Black Shadow.
  Προς το παρόν,ανοίξτε το messagebox.exe που είναι ένα από τα 2 συνοδευτικά αρχεία και 
προσπαθήστε να βρείτε το image base.Είναι "400000h",και βρίσκεται πάντα στην μετατόπιση 
e_lfanew + 34h.Το image base είναι πρακτικά η διεύθυνση στην οποία φορτώνεται το εκτελέσιμο.
Βρίσκοντας το Entry Point,που είναι 1000h,μπορούμε πλεόν να δούμε ότι το code section του 
αρχείου μας ξεκινά στο 401000h.Πόσο μέγεθος έχει το .text section(που έχει τον κώδικα του
προγράμματος)? 200h bytes όπως θα βλέπετε και εσείς.Τι σημαίνει αυτό?Ξεκινώντας από το
401000h που φορτώνεται το πρόγραμμα στην μνήμη,ο κώδικας τελειώνει στην διεύθυνση 
401200h.Και που βρίσκεται το text section μέσα στο εκτελέσιμο?Στο Raw offset 400h,που 
τελειώνει 200h bytes μετά όπου και αρχίζει το .rdata,στο raw offset 600h και virtual offset
(2000h).Συνεπώς το .rdata φορτώνεται στο 402000h.Αν το .text section ενός αρχείου έχει
characteristics που δεν δείχνουν ότι το section είναι "executable as code",τότε αυτό
δεν μπορεί να σπάσει στο Softice loader και δεν φαίνεται ο κώδικάς του  στο windasm.
Δοκιμάστε το.Αλλάξτε τα characteristics του .text σε C0000040h και δείτε την διαφορά.
Γιατί συμβαίνει αυτό?Το softice δεν σπάει γιατί δεν μπορεί να θέσει breakpoint σε κάτι
που "μοιάζει" να είναι data και ο windasm δεν αναλύει κάτι που μοιάζει με data.Αντίθετα,
το IDA δεν κολλάει σε τέτοια tricks.Χρειάζεται μεγαλύτερη μαεστρία για να μπερδευτεί
το έξοχο IDA...
  Ξεκινήστε λοιπόν την εξάσκηση! Δημιουργήστε κάτι με ένα αρχείο.Μόνο έτσι θα μάθετε
την δομή του.Ξέρετε τι είναι ένα CRC Check? Σημαίνει Cyclic Redundancy Code Check,
και μπορεί να ελέγξει αν το πρόγραμμα έχει δεχθεί patch ή όχι.Πως? Η σκέψη είναι απλή.
Κάθε byte σε ένα αρχείο έχει μία τιμή.Αν τα προσθέσετε όλα μεταξύ τους θα πάρετε μία
άλλη τιμή.Αν,όμως,αλλάξει αυτή η τιμή,τότε το αρχείο έχει δεχθεί αλλαγές.Καιρός να 
πείτε στον cracker να σταματήσει να παίζει με τα αρχεία σας :) Πως γίνεται ένα CRC 
Check? Βασικά υπάρχει CRC16 και CRC32 που έχουν συγκεκριμένους αλγόριθμους
που οδηγούνται από πίνακες(table driven with CRC table values).Αλλά δεν χρειάζεται
να χρησιμοποιήσετε αυτόν τον αλγόριθμο.Φτιάξτε έναν δικό σας,όπως έχω κάνει στο
προηγούμενο project,για το cd check crackme μου.Μπορείτε να φτιάξετε και ένα 
πρόγραμμα που θα ελέγχει αν τα αρχεία σας έχουν δεχθεί αλλαγές.
  Κάντε το !!! Και στείλτε το μας ! Θα το δημοσιεύσουμε.Βοηθήστε εμάς για να 
βοηθήσουμε και εμείς εσάς...


Ευχαριστώ για την προσοχή σας.Τα ξαναλέμε σύντομα...

 


ΠΡΟΣΟΧΗ

Φυσικά δεν χρειάζεται καν να σας θυμίσω πως το βοήθημα αυτό είναι αυστηρά 
για εκπαιδευτικούς σκοπούς και για την οποιαδήποτε λάθος χρήση τους ο 
δημιουργός του δεν φέρει καμμία ευθύνη.Αν θέλετε έτοιμα cracks υπάρχουν
πολλά άλλα μέρη στο internet,εδώ παρέχουμε μόνο γνώση.

 

BACK HOME