+++
title = 'Reverse Engineering σε περιβάλλον Linux, Μέρος 2'
date = '2003-09-01T00:00:00Z'
description = ''
author = 'Φραντζής Αλέξανδρος (aka Alf) alf82 at freemail dot gr'
issue = ['Magaz 34']
issue_weight = 5
+++

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

*To άρθρο αυτό είναι το τρίτο της σειράς \"Reverse Engineering σε περιβάλλον Linux\". Σκοπός της σειράς είναι να εξοικοιώσει τους αναγνώστες με τις βασικές
τεχνικές του Reverse Enineering, με έμφαση στο πως αυτές μπορούν να εφαρμοστούν στο Linux, και να τους προσφέρει πιο βαθιές γνώσεις για τη λειτουργία του
συστήματος τους. Στο συγκεκριμένο άρθρο θα ασχοληθούμε κυρίως με τη διαδικασία της εκτέλεσης των προγραμμάτων και τις πληροφορίες που μπορούμε να αποκομίσουμε
από αυτά.*

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

**1. Εισαγωγή**
--------------------------------------

**2. Διαδικασία Δημιουργίας και Φόρτωσης Εκτελέσιμου**
-----------------------------------------------------------------------------

-   [2.1 Εισαγωγή](#ss2.1)
-   [2.2 Η πορεία ενός bit: Από την πηγαίο κώδικα στο τελικό εκτελέσιμο](#ss2.2)
-   [2.3 Το φόρτωμα του προγράμματος](#ss2.3)
-   [2.4 Relocation - Εναλλακτικοί τρόποι για τη διόρθωση των αναφορών στο dynamic linking.](#ss2.4)

**3. Το ELF**
------------------------------------

-   [3.1 Τι είναι το ELF;](#ss3.1)
-   [3.2 Βασική δομή του ELF](#ss3.2)
-   [3.3 Ο ELF Header](#ss3.3)
-   [3.4 Τα ELF Sections](#ss3.4)
-   [3.5 Τα ELF Segments](#ss3.5)
-   [3.6 Εκτέλεση ενός ELF executable και dynamic linking](#ss3.6)
-   [3.7 Εργαλεία για το ELF](#ss3.7)

**4. Το /proc filesystem**
-------------------------------------------------

-   [4.1 Τι είναι το /proc filesystem](#ss4.1)
-   [4.2 Γενικές πληροφορίες για το σύστημα](#ss4.2)
-   [4.3 Πληροφορίες για μια διεργασία](#ss4.3)

**5. Χρήσιμες έως πολύ χρήσιμες πληροφορίες ΙΙ**
-----------------------------------------------------------------------

-   [5.1 Dead Listing και Εργαλεία](#ss5.1)
-   [5.2 Packed Executables - Συμπιεσμένα Εκτελέσιμα](#ss5.2)

**6. Hands-on Παράδειγμα - Υπό πίεση**
-------------------------------------------------------------

-   [6.1 Πράξη 1η](#ss6.1)
-   [6.2 Επιστροφή σε Κανονικές Συνθήκες πίεσης και θερμοκρασίας.](#ss6.2)
-   [6.3 Σταματώντας τον χρόνο](#ss6.3)
-   [6.4 To patch](#ss6.4)
-   [6.5 Ασκήσεις για το σπίτι :)](#ss6.5)

**7. Πρόκληση**
--------------------------------------

-   [7.1 Προηγούμενη Πρόκληση (\#1) - Λύση και Hall Of Fame](#ss7.1)
-   [7.2 Πρόκληση \#2](#ss7.2)


### [1. Εισαγωγή]{#s1}

Καλωσήρθατε στο τρίτο άρθρο (η μέτρηση αρχίζει από το 0) για Reverse Code Engineering σε Linux!

Στο μέρος 2 θα ασχοληθούμε με το πως λειτουργούν τα εκτελέσιμα αρχεία γενικά, ενώ στο 3ο μέρος θα μιλήσουμε συγκεκριμένα για τα ELF αρχεία. Για την καλύτερη
κατανόηση των προηγούμενων σας προτείνω να δημιουργήσετε δικά σας μικρά προγράμματα και να δείτε πως ο compiler και ο linker τα μεταμορφώνουν στο τελικό
εκτελέσιμο.

Στο μέρος 4 θα ρίξουμε μια σύντομη ματιά στα άδυτα του /proc filesystem και στο 5 θα αναφερθούμε σε δύο πολύ σημαντικά θέματα: το dead-listing και τα packed
εκτελέσιμα.

Το μέρος 6 περιέχει το hands on παράδειγμα αυτού του μήνα, όπου θα συναντήσουμε τη Σταχτοπούτα και τη C++ σε όλο της το μεγαλείο :) Εδώ θα εφαρμόσουμε πολλά από
όσα ειπώθηκαν στα προηγούμενα μέρη.

Τέλος, όπως πάντα, υπάρχει η λύση του προηγούμενης πρόκλησης, μαζί με το hall of fame και μια καινούργια (και αρκετά διαφορετική από τις προηγούμενες) πρόκληση!

Να σημειωθεί πως όλα τα εκτελέσιμα έχουν δημιουργηθεί με gcc 3.2.2 και επομένως μπορεί να υπάρχουν προβλήματα αν εκτελεστούν σε σύστημα με παλιά έκδοση του gcc
(πχ 2.95). Ειδικά στην περίπτωση των C++ προγραμμάτων αυτό είναι σίγουρο, διότι έχει αλλάξει ριζικά το Application Binary Interface (ABI).

Μη διστάσετε να επικοινωνήσετε μαζί μου για οποιαδήποτε διόρθωση, διευκρίνηση ή σχόλιο.

Επίσης είμαι ανοιχτός σε ιδέες για το τι θα θέλατε να περιέχουν τα επόμενα άρθρα (αν υπάρξουν, βέβαια).


### [2. Διαδικασία Δημιουργίας και Φόρτωσης Εκτελέσιμου]{#s2}

### [2.1 Εισαγωγή]{#ss2.1}

Η δημιουργία ενός εκτελέσιμου είναι μια από τις πιο βασικές διαδικασίες σε οποιοδήποτε υπολογιστικό σύστημα. Την εποχή του 1950-1960 τα πράγματα ήταν σχετικά
\"απλά\". Ο προγραμματιστής έγραφε τον αλγόριθμο σε μνημονική γλώσσα assembly και τον μετέφραζε με το χέρι σε γλώσσα μηχανής. Ύστερα τον περνούσε με κάποιο
τρόπο (βύσματα, διάτρητες κάρτες) στο σύστημα και προσευχόταν όλα να πάνε καλά!

Η πρώτη προσπάθεια αυτοματοποίησης ήρθε με την δημιουργία των assemblers. Τώρα πια ο ίδιος ο υπολογιστής έκανε την κουραστική δουλειά της μετάφρασης από
assembly σε γλώσσα μηχανής. Οι (τεμπέληδες :) )προγραμματιστές, όμως, δεν αρκέστηκαν σε αυτό. Ανέπτυξαν γλώσσες υψηλού επιπέδου και δημιούργησαν compilers οι
οποίοι τις μετέφραζαν σε γλώσσα assembly. Οι assemblers που ήδη υπήρχαν ολοκλήρωναν τη διαδικασία αλλά τα πράγματα δε σταμάτησαν ούτε εδώ! Ακολούθησε η χρυσή
εποχή του δομημένου προγραμματισμού και των modules. Αποφασίστηκε ότι ήταν σοφό να επαναχρησιμοποιείται ο κώδικας που υπήρχε ήδη και έτσι έπρεπε να βρεθεί ένας
τρόπος να μπορούν να συνενώνονται κομμάτια κώδικα (σε δυαδική μορφή) που βρίσκονταν σε διαφορετικά αρχεία.

### [2.2 Η πορεία ενός bit: Από την πηγαίο κώδικα στο τελικό εκτελέσιμο]{#ss2.2}

Υπάρχουν τρία βασικά είδη object αρχείων:

-   Relocatable Object File: Περιέχουν δεδομένα και κώδικα και είναι κατάλληλα για τη δημιουργία executable ή shared object αρχείων με τη διαδικασία του linking
    (Κατάληξη: \".o\", \".obj\" )
-   Executable Object File: Αρχεία κατάλληλα για εκτέλεση (Κατάληξη: στα Unix συστήματα συνήθως καμία, \".bin\", \".exe\")
-   Shared Object File: Μπορούν να γίνουν link με άλλα Shared Object ή Relocatable Object Files για να δημιουργήσουν Executable Files Επιπλέον μπορούν να
    συνδεθούν δυναμικά με το εκτελέσιμο κατά τη διάρκεια της φόρτωσης του. (Κατάληξη: \".so\", \".dll\") ????

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

![](/34/img/linking.png)

Το παραπάνω πρόγραμμα αποτελείται από δύο modules (Relocatable Object File 1 και 2). Επιπλέον, χρησιμοποιεί δύο \"βιβλιοθήκες\" (Shared Object File 1 και 2). Η
πρώτη συνδέεται στατικά στο πρόγραμμα μας, δηλαδή ο κώδικας της συγχωνεύεται στο τελικό object αρχείο. Η δεύτερη συνδέεται δυναμικά. Στην περίπτωση αυτή, στο
στάδιο του linking δε γίνεται συγχώνευση κώδικα, αλλά εισάγονται πληροφορίες ώστε όταν φορτωθεί το πρόγραμμα ο dynamic linker να μπορέσει να βρει τις
διευθύνσεις των συναρτήσεων και των δεδομένων.

### [2.3 Το φόρτωμα του προγράμματος]{#ss2.3}

Όταν ζητάμε από το λειτουργικό να εκτελέσει ένα πρόγραμμα, γίνονται πολλά περισσότερα από όσα φαίνονται εκ πρώτης όψεως. Σε γενικές γραμμές ακολουθούνται τα
εξής βήματα (για τα ELF εκτελέσιμα τα πράγματα διαφέρουν λίγο):

1.  Αρχικά το λειτουργικό διαβάζει τον header του εκτελέσιμου για να πάρει απαραίτητες πληροφορίες, όπως:
    -   Αν όντως πρόκειται για εκτελέσιμο που μπορεί να τρέξει στον υπολογιστή.
    -   Πόση μνήμη απαιτεί και τι ιδιότητες έχει κάθε τμήμα (segment) του εκτελέσιμου ( πχ read-only, executable κτλ).
    -   Ποια shared objects απαιτεί το εκτελέσιμο.
2.  Το λειτουργικό αποδίδει στη διεργασία τη μνήμη που χρειάζεται και φορτώνει τα διάφορα τμήματα στη μνήμη.
3.  O dynamic linker φορτώνει στο address space της διεργασίας τις βιβλιοθήκες που χρειάζεται.
4.  Γίνεται relocation στο εκτελέσιμο και τις βιβλιοθήκες. Ως μέρος της διαδικασίας του relocation, διορθώνονται οι αναφορές σε συναρτήσεις/δεδομένα των
    βιβλιοθηκών που φορτώθηκαν. Αυτό είναι το θέμα του επόμενου τμήματος.
5.  Τέλος, ο έλεγχος μεταφέρεται στο entry point του προγράμματος. Αυτό αποτελεί τη διεύθυνση της πρώτης εντολής που πρόκειται να εκτελεστεί.

### [2.4 Relocation - Εναλλακτικοί τρόποι για τη διόρθωση των αναφορών στο dynamic linking.]{#ss2.4}

Το relocation (επανατοποθέτηση) είναι η διαδικασία κατά την οποία γίνονται διορθώσεις στην εικόνα ενός προγράμματος επειδή αυτή μπορεί να τοποθετηθεί στη μνήμη
σε κάποιο αυθαίρετο σημείο. Αυτό συμβαίνει πάντα για τα shared objects ενώ για τα εκτελέσιμα γίνεται σε πολύ μικρότερο βαθμό. Λόγω της εικονικής μνήμης,
μπορούμε να φορτώνουμε το εκτελέσιμο πάντα στο ίδιο σημείο. Για τα shared objects, από την άλλη, δε γίνεται να υποθέσουμε πως δε θα υπάρχει σύγκρουση, διότι
πρέπει να μπορούν να συνυπάρχουν με οποιοδήποτε άλλο shared object.

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

H χρήση των shared objects για dynamic linking προσφέρει πολλά πλεονεκτήματα σε σχέση με το static linking. Μερικά από αυτά είναι η μείωση του μεγέθους των
εκτελέσιμων, οι αυξημένες δυνατότητες για επαναχρησιμοποίηση κώδικα και η δυνατότητα επέκτασης των εφαρμογών (πχ plug-ins). Όλα αυτά όμως έρχονται με ένα
(μικρό, ομολογουμένως) τίμημα. Επειδή οι βιβλιοθήκες φορτώνονται σε κάποιο αυθαίρετο σημείο της εικονικής μνήμης της διεργασίας, οι διευθύνσεις των
συναρτήσεων/δεδομένων τους δεν είναι γνωστές από πριν. Έτσι οι κλήσεις/αναφορές σε αυτά δεν είναι ολοκληρωμένες στο εκτελέσιμο.

Υπάρχουν διάφοροι τρόποι για να αντιμετωπιστεί το πρόβλημα αυτό. Έτσι οι κλήσεις σε συναρτήσεις βιβλιοθηκών μπορεί να έχουν μια από τις παρακάτω μορφές (και όχι
μόνο, αυτές είναι οι πιο βασικές):

1.  call 0x???????? : Για τη διόρθωση, πρέπει σε κάθε κλήση της συνάρτησης ο dynamic linker να αλλάξει την τιμή στην πραγματική διεύθυνση της συνάρτησης. πχ
    call 0x40001000. Το πρόβλημα είναι πως αν η συνάρτηση καλείται σε 100 διαφορετικά σημεία, πρέπει καταρχάς το εκτελέσιμο να περιέχει πληροφορίες για όλα αυτά
    τα σημεία και ο dynamic linker είναι αναγκασμένος να κάνει 100 διορθώσεις.

    ![](/34/img/dynamic1.png)

2.  call \[func1\_offset\] : στη διεύθυνση μνήμης func1\_offset (που είναι καθορισμένη από πριν) ο dynamic linker τοποθετεί τη διεύθυνση της επιθυμητής
    συνάρτησης. Όλες οι κλήσεις προς αυτή τη συνάρτηση διαβάζουν τη διεύθυνση από τη συγκεκριμένη θέση μνήμης και την καλούν έμμεσα (indirect call). Έτσι
    αποφεύγονται οι πολλαπλές διορθώσεις, με ένα μικρό κόστος στην ταχύτητα εκτέλεσης. Τα PE (Portable Executable) format που χρησιμοποιούν τα MS Windows
    στηρίζεται σε αυτό το μοντέλο.

    ![](/34/img/dynamic2.png)

3.  call jmp\_func : στη διεύθυνση jmp\_func βρίσκεται μια εντολή jmp \[func\_offset\]. Στη διεύθυνση func\_offset ο dynamic linker τοποθετεί τη διεύθυνση της
    επιθυμητής συνάρτησης. Γιατί όλη αυτή η ταλαιπωρία; Ο μηχανισμός αυτός προσφέρει τη δυνατότητα οι διορθώσεις να γίνονται κατά τη διάρκεια της εκτέλεσης του
    προγράμματος, όταν υπάρχει ανάγκη, και όχι απαραίτητα όλες μαζί κατά τη φόρτωση του προγράμματος. Το ELF χρησιμοποιεί μια παραλλαγή του μοντέλου αυτού και
    θα το εξετάσουμε αναλυτικότερα παρακάτω.

    ![](/34/img/dynamic3.png)


### [3. Το ELF]{#s3}

### [3.1 Τι είναι το ELF;]{#ss3.1}

Το Εxecutable and Linking Format (ELF) αποτελεί το format που χρησιμοποιεί το linux για τα object αρχεία του. Υποστηρίζει μια πληθώρα αρχιτεκτονικών και για
αυτό είναι ιδανικό για ένα multi-platform λειτουργικό όπως το linux. Παρακάτω θα γίνει μια περιγραφή των βασικών στοιχείων του ELF. Για μια πιο αναλυτική
περιγραφή ανατρέξτε στο standard (pdf): [ELF 1.1](http://www.nondot.org/sabre/os/files/Executables/ELF.pdf), [ELF
1.2](http://x86.ddj.com/ftp/manuals/tools/elf.pdf)

Αυτό το ELF δεν έχει καμία σχέση με τον Tolkien :)

### [3.2 Βασική δομή του ELF]{#ss3.2}

Τα βασικά συστατικά που απαρτίζουν κάθε ELF object αρχείο είναι:

-   O ELF header
-   Το Program Header Table (optional στα Relocatable Object Files)
-   Τα sections και τα segments. Τα segments αποτελούνται από ένα ή παραπάνω sections.
-   To Section Header Table (optional στα Executable Object Files)

Σχηματικά:

![](/34/img/elf_views.png)

Τα δύο views αποτελούν διαφορετικούς τρόπους με τους οποίους το σύστημα βλέπει ένα ELF object αρχείο. Το πρώτο (linking view) χρησιμοποιείται όταν το αρχείο
πρόκειται να συνδεθεί για την παραγωγή εκτελέσιμου. Η δομική μονάδα εδώ είναι το section. Το δεύτερο (execution view) χρησιμοποιείται κατά τη φόρτωση-εκτέλεση
ενός εκτελέσιμου. Ο loader δε \"βλέπει\" πια sections αλλά φορτώνει στη μνήμη ολόκληρα segments (ομάδες από sections).

### [3.3 Ο ELF Header]{#ss3.3}

![](/34/img/elf_header.png)

Ο ELF Header περιέχει βασικές πληροφορίες για το object αρχείο. To πρώτο του κομμάτι (16 bytes) είναι το ELF Identification. Αυτό εκτός από τον \"μαγικό
αριθμό\" (υπογραφή) του ELF καθορίζει

-   **File Class**: Aν το εκτελέσιμο είναι 32-bit ή 64-bit (πάνε τα 16-bit, πόσο μάλλον τα 8-bit!).
-   **Data Encoding**: Aν τα δεδομένα είναι σε LSB (little-endian) ή MSB (big-endian) μορφή.
-   **Header Ver \#**: Την έκδοση του ELF Header.

Ακολουθούν 9 padding bytes και ύστερα αρχίζει ο κυρίως header.

-   **Object File Type** : Το είδος του object file (relocatable, executable, shared object).
-   **Required Architecture** : Η αρχιτεκτονική στην οποία πρέπει να είναι στηριγμένος ο επεξεργαστής ώστε να μπορεί να λειτουργήσει το πρόγραμμα (Intel 80386,
    SPARC, MIPS RS3000 κτλ)
-   **Object File Version \#** : H εκδοση του ELF.
-   **Process Entry point** : H εικονική διεύθυνση της πρώτης εντολής του προγράμματος η οποία θα εκτελεστεί.
-   **Program Header Table Offset** : To offset του PHT στο object αρχείο.
-   **Section Header Table Offset** : To offset του SHT στο object αρχείο.
-   **Processor Specific Flags** : Σημαίες που αφορούν σε ιδιότητες του εκάστοτε επεξεργαστή.
-   **ELF Header Size** : To μέγεθος του ELF Header σε bytes.
-   **PHT Entry Size** : Το μέγεθος μιας καταχώρησης στο Program Header Table.
-   **Number of PHT entries** : Ο αριθμός των καταχωρήσεων στο Program Header Table σε bytes.
-   **SHT Entry Size** : Το μέγεθος μιας καταχώρησης στο Section Header Table σε bytes .
-   **Number of SHT entries** : Ο αριθμός των καταχωρήσεων στο Section Header Table.
-   **Section Name String Table SHT Index** : Το index στο SHT που καθορίζει ποιο section περιέχει το string table με τα ονόματα των sections.

### [3.4 Τα ELF Sections]{#ss3.4}

Το section είναι ένα τμήμα του object αρχείου το οποίο περιέχει συγκεκριμένες και ομογενείς πληροφορίες. Για παράδειγμα, ένα section μπορεί να περιέχει τον
κώδικα του προγράμματος, ένα άλλο τα δεδομένα, ένα τρίτο το string table κτλ. Τα sections ενός ELF αρχείου καθορίζονται στο Section Header Table. Αν και είναι
προαιρετικός στο executable object αρχεία, πάντα περιλαμβάνεται (από όσο έχω δει). Το Section Header Table αποτελείται από μια σειρά από περιγραφείς, καθένας
από τους οποίους μας δίνει πληροφορίες για ένα section:

![](/34/img/elf_section.png)

Οι πληροφορίες που μας παρέχει η παραπάνω δομή είναι:

-   **Section Name String Table Index** : To offset του ονόματος του section στο string table.
-   **Section Type** : Το είδος του section (πχ program-defined, symbol table, dynamic linking info).
-   **Section Flags** : Σημαίες που καθορίζουν διάφορα χαρακτηριστικά του section (πχ allocation (αν το section φορτώνεται στη μνήμη κατα την εκτέλεση), write,
    execute).
-   **Section Virtual Address** : Η εικονική διεύθυνση στην οποία θα φορτωθεί το section στη μνήμη ή 0 αν δεν φορτώνεται.
-   **Section File Offset** : Το offset στο οποίο αρχίζει το section στο object αρχείο.
-   **Section Size** : Το μέγεθος του section σε bytes
-   **Section Header Table Index Link** : Κάποια sections χρειάζονται πληροφορίες από κάποιο άλλο section. To πεδίο καθορίζει το index του απαραίτητου section
    στο section header table. Χαρακτηριστικό παράδειγμα είναι τα sections που περιέχουν πληροφορίες για το dynamic linking. Σε αυτά, το πεδίο καθορίζει σε ποιo
    string table section βρίσκονται τα ονόματα του εξωτερικών συμβόλων.
-   **Additional Section Info** : Επιπλέον πληροφορίες, η σημασία των οποίων εξαρτάται από το είδος του section.
-   **Section Address Alignment** : Καθορίζει σε τι όρια πρέπει να φορτωθεί το section.
-   **Fixed-Size Entry Size** : Αν το section αποτελείται από κάποιον πίνακα στον οποίο κάθε καταχώρηση έχει σταθερό μέγεθος, το πεδίο αυτό δίνει το μέγεθος της
    κάθε καταχώρησης (πχ το symbol table section)

Υπάρχουν κάποια sections τα οποία κατά σύμβαση περιέχουν συγκεκριμένες πληροφορίες. Μια πλήρης λίστα μπορεί να βρεθεί στο standard. Τα πιο σημαντικά και κοινά
είναι:

-   **.text** : Περιέχει τον εκτελέσιμο κώδικα του προγράμματος.
-   **.data** : Περιέχει τα αρχικοποιημένα δεδομένα του προγράμματος (πχ global μεταβλητές στις οποίες έχουμε δώσει αρχική τιμή).
-   **.bss** : Περιέχει μη αρχικοποιημένα δεδομένα του προγράμματος (πχ global μεταβλητές στις οποίες δεν έχουμε δώσει αρχική τιμή). Το section αυτό δεν
    καταλαμβάνει χώρο στο αρχείο αλλά δημιουργείται μόνο στη μνήμη, όπου όλα τα bytes του μηδενίζονται.
-   **.dynamic** : Περιέχει πληροφορίες απαραίτητες για το dynamic linking.
-   **.strtab** : Περιέχει strings που χρησιμοποιούνται κυριώς από το symbol table.
-   **.dynstr** : Περιέχει τα strings σχετικά με το dynamic linking.
-   **.shstrtab** : Περιέχει τα strings των ονομάτων των sections.
-   **.symtab** : Περιέχει τo symbol table για το αρχείο.
-   **.dynsym** : Περιέχει τo symbol table για τα σύμβολα που χρειάζονται για το dynamic linking.
-   **.plt** : Περιέχει τo procedure linkage table. Θα ασχοληθούμε με αυτό αργότερα.
-   **.interp** : Περιέχει το path του interpreter που θα φορτώσει το εκτελέσιμο.

#### String Table Section

Τα τρία sections .strtab, .dynstr και .shstrtab περιέχουν strings τα οποία χρησιμοποιούνται από κάποια άλλα sections. Η δομή τους είναι αρκετά απλή: Το πρώτο
byte του section είναι \'\\0\' και από εκεί και πέρα ακολουθεί μια σειρά από null-terminated strings. Τα strings καθορίζονται από το offset τους από την αρχή
του section.

![](/34/img/elf_string.png)

Για το παραπάνω table έχουμε:

           index/offset       String
                 1            "alf"
                 2              "lf"
                 5             "tx"
                        κτλ

### [3.5 Τα ELF Segments]{#ss3.5}

Τα segments αποτελούνται από ένα ή περισσότερα sections τα οποία κατά τη φόρτωση του εκτελέσιμου/shared object αρχείου έχουν κοινές ιδιότητες. Για κάθε segment
υπάρχει μια καταχώρηση στο Program Header Table:

![](/34/img/elf_segment.png)

-   **Segment Type** : To είδος του segment και των πληροφοριών που περιέχει (πχ loadable(θα φορτωθεί στη μνήμη), dynamic linking info)
-   **Segment File offset** : Το offset της αρχής του segment στο αρχείο.
-   **Segment Virtual Address** : Η εικονική διεύθυνση στην οποία θα φορτωθεί το segment στη μνήμη.
-   **Segment Physical Address** : Η φυσική διεύθυνση μνήμη στην οποία θα φορτωθεί το segment. Προφανώς τα περισσότερα συστήματα αγνοούν αυτό το πεδίο.
-   **Segment File Image Size** : To μέγεθος που καταλαμβάνει το segment στο αρχείο.
-   **Segment Memory Image Size** : To μέγεθος που θα καταλαμβάνει το segment στη μνήμη (\>=Segment File Image Size)
-   **Segment Flags** : Σημαίες που καθορίζουν ιδιότητες του segment.
-   **Segment Alignment** : Καθορίζει σε τι όρια πρέπει να φορτωθεί το segment.

### [3.6 Εκτέλεση ενός ELF executable και dynamic linking]{#ss3.6}

#### Φόρτωση - Εκτέλεση

Σε γενικές γραμμές ακολουθούνται τα εξής βήματα:

1.  Αρχικά το λειτουργικό (μέσω του syscall exec()) διαβάζει τον header του εκτελέσιμου για να πάρει απαραίτητες πληροφορίες όπως:
    -   Αν όντως πρόκειται για εκτελέσιμο που μπορεί να τρέξει στον υπολογιστή
    -   Πόση μνήμη απαιτεί και τι ιδιότητες έχει κάθε τμήμα (segment) του εκτελέσιμου ( πχ read-only, executable κτλ)
2.  To λειτουργικό ελέγχει στο Program Header Table αν το εκτελέσιμο περιέχει ένα segment τύπου PT\_INTERP (το οποίο περιέχει μόνο ένα section, το .interp).\
    Αν δεν υπάρχει τότε:
    -   Το λειτουργικό αποδίδει στη διεργασία τη μνήμη που χρειάζεται και φορτώνει τα διάφορα τμήματα στη μνήμη.
    -   Γίνεται relocation (επανατοποθέτηση) αν χρειάζεται.
    -   Τέλος, ο έλεγχος μεταφέρεται στο entry point του προγράμματος.

    Αν υπάρχει (συνήθως υπάρχει):
    -   Διαβάζει από το segment το path του interpreter και φορτώνει τον interpreter στη μνήμη.
    -   Το λειτουργικό είτε φορτώνει το εκτελέσιμο στη μνήμη και \"περνάει\" τη διεύθυνση του στον interpreter, είτε \"περνάει\" στον interpreter έναν file
        descriptor για το αρχείο του εκτελέσιμου και τον αφήνει να κάνει τη δουλειά. Σε κάθε περίπτωση, **ο έλεγχος περνάει στον interpreter**.
    -   O interpreter, αν είναι ο dynamic linker ld.so (κατά 99% είναι αυτός), φορτώνει στο address space της διεργασίας τις βιβλιοθήκες που χρειάζεται το
        εκτελέσιμο.
    -   Γίνεται relocation στο εκτελέσιμο και στις βιβλιοθήκες. Ως μέρος του relocation, διορθώνονται, αν είναι ανάγκη, οι αναφορές σε συναρτήσεις/δεδομένα των
        βιβλιοθηκών που φορτώθηκαν. Στο ELF αυτό μπορεί να γίνει και στο run-time.
    -   Δίνεται η δυνατότητα σε κάθε shared object να εκτελέσει κάποιο κώδικα αρχικοποίησης.
    -   Τέλος, ο έλεγχος μεταφέρεται στο entry point του εκτελέσιμου.

#### Το dynamic linking στο ELF

Τα sections τα οποία σχετίζονται με το dynamic linking σε ένα εκτελέσιμο είναι τα εξής:

**.dynamic**

Αυτό περιέχει πληροφορίες για το ποια shared object είναι απαραίτητα για την εκτέλεση, τη διεύθυνση του relocation table, τη διεύθυνση του symbol table που
περιέχει τα εξωτερικά σύμβολα κτλ. Ο dynamic linker διαβάζει τα πεδία αυτά, φορτώνει (και επανατοποθετεί) τις βιβλιοθήκες και προσπαθεί να \"επιλύσει\"
(resolve) τις αναφορές στα εξωτερικά σύμβολα. Με άλλα λόγια, βρίσκει τις διευθύνσεις των συμβόλων και τις διορθώνει στο εκτελέσιμο. Πρέπει να σημειωθεί πως οι
βιβλιοθήκες που φορτώνει ο dynamic linker μπορεί και αυτές να απαιτούν άλλες βιβλιοθήκες, οπότε η όλη διαδικασία επαναλαμβάνεται αναδρομικά. Βέβαια, κάθε
βιβλιοθήκη φορτώνεται μόνο μια φορά, άσχετα από το αν χρησιμοποιείται από πολλά ELF objects.

**.got (Global Offset Table)**

Το section αυτό (αφού φορτωθεί το πρόγραμμα) περιλαμβάνει τις διευθύνσεις των συμβόλων που είναι πιθανό να αλλάξουν από το relocation. Στα εκτελέσιμα περιέχει
μόνο τις διευθύνσεις των εξωτερικών συμβόλων (dynamically linked), ενώ για τα shared object περιλαμβάνει τις διευθύνσεις όλων των συμβόλων (εσωτερικών και
εξωτερικών). Αυτό συμβαίνει αφού σίγουρα το shared object θα επανατοποθετηθεί. Οι πρώτες τρεις καταχωρίσεις έχουν ειδική σημασία. Η πρώτη (offset 0) περιέχει τη
διεύθυνση του .dynamic section. Η τρίτη περιλαμβάνει τη διεύθυνση του dynamic linker. Η τύχη της δεύτερης αγνοείται προς το παρόν.

**.plt (Procedure Linkage Table)**

    Αυτό έχει τη μορφή:
    plt_start:
            push got_start+4
            jmp [got_start+8]
            ...
    jmp_func1:
            jmp [func1_offset]
            push relocation_offset1
            jmp plt_start
     
    jmp_func2:
            ...

Το func1\_offset είναι μια διεύθυνση μέσα στο .got section που τελικά (μετά το relocation) θα περιέχει τη διεύθυνση της συνάρτησης func1. To relocation\_offset1
είναι ένα offset που καθορίζει μια καταχώρηση στο relocation table. H καταχώρηση αυτή θα έχει ως offset αλλαγής (η διεύθυνση στην οποία θα γίνει η διόρθωση) το
func1\_offset.

Αρχικά, η διεύθυνση func1\_offset περιέχει τη διεύθυνση της επόμενης εντολής από την jmp \[func1\_offset\]. Έτσι, ο έλεγχος πάει στην push relocation\_offset1
και μετά, μέσω της jmp plt\_start, στο push got\_start+4, jmp \[got\_start+8\].

Το got\_start+8 είναι η τρίτη καταχώρηση στο .got section και όπως είπαμε περιλαμβάνει τη διεύθυνση του dynamic linker. Έτσι, ο έλεγχος περνάει στο dynamic
linker με δύο παραμέτρους (got\_start+4, relocation\_offset1). Με αυτές τις πληροφορίες ο dynamic linker μπορεί να βρει τη διεύθυνση της ζητούμενης συνάρτησης
και να την τοποθετήσει στη func1\_offset. Την επόμενη φορά που θα κληθεί η jmp\_func1, η εντολή jmp \[func1\_offset\] θα οδηγήσει στην πραγματική συνάρτηση
func1 (και όχι στο αμέσως επόμενο push).

Είναι φανερό πως αυτή η διαδικασία δεν είναι απαραίτητο να γίνει στο φόρτωμα του προγράμματος αλλά την πρώτη φορά που θα χρειαστεί να κληθεί η func1. Αυτή είναι
η default συμπεριφορά και ονομάζεται lazy binding. Μπορούμε να την αλλάξουμε δίνοντας στη enviroment μεταβλητή LD\_BIND\_NOW μία μη null τιμή.

### [3.7 Εργαλεία για το ELF]{#ss3.7}

Η δομή του ELF καθιστά αρκετά επίπονη και χρονοβόρα την απευθείας εξαγωγή πληροφοριών από ένα object αρχείο. Ευτυχώς για εμάς, υπάρχει μια πληθώρα εργαλείων που
μπορούν να μας διευκολύνουν.

Το πιο κοινό ίσως εργαλείο (αλλά σίγουρα όχι το καλύτερο) είναι το **objdump**. Το objdump είναι μέρος των binutils και μπορεί να μας δώσει σχεδόν όλες τις
πληροφορίες που περιέχει ένα ELF object αρχείο. Η επιλογή των πληροφοριών που θα απεικονιστούν γίνεται με διάφορα flags. Βασικά flags είναι το **-x** το οποίο
δείχνει *σχεδόν* όλες τις πληροφορίες (**εκτός από αυτές που σχετίζονται με δυναμικά σύμβολα**), το **-Τ** που δείχνει τα δυναμικά σύμβολα, το **-d** που κάνει
disassemble τον κώδικα, το **-M** με το οποίο ρυθμίζουμε τον disassembler (πχ **-M intel** για intel σύνταξη) και το **-C** που ενεργοποιεί το demangling. Το
κύριο μειονέκτημα του objdump είναι στον τομέα του disassembly. Το listing που παράγεται έχει ελάχιστες πληροφορίες, ειδικά αν δεν υπάρχουν σύμβολα. Παρέα με το
objdump (στα binutils) έρχονται το readelf και το nm. Η αλήθεια είναι πως δεν είναι και πολύ χρήσιμα, αφού το objdump κάνει ότι τα προηγούμενα δύο μαζί και
ακόμα παραπάνω.

Ένα σαφώς πιο εξελιγμένο εργαλείο είναι το **ELFsh** (Site: <http://elfsh.devhell.org>). Πρόκειται για μια scripting γλώσσα που μας επιτρέπει να διαχειριστούμε
ένα ELF αρχείο. Οι δυνατότητές του ποικίλουν από μια απλή απεικόνιση των πληροφοριών του header, μέχρι και συγχώνευση δύο object αρχείων! Η \"ψυχή\" του
προγράμματος βρίσκεται σε μια καλοσχεδιασμένη βιβλιοθήκη (libelfsh) και έτσι μπορεί να χρησιμοποιηθεί σε οποιαδήποτε άλλη εφαρμογή.

Μια πιο εύχρηστη λύση είναι o **HT Editor** (Site: <http://hte.sourceforge.net>). Παρέχει πλήρη διαχείριση του object αρχείου και έναν αρκετά καλό disassembler.
Θα αναφερθούμε λίγο περισσότερο σε αυτόν στο κομμάτι για το [dead-listing](05_rce3-5.html#dead-listing).


### [4. Το /proc filesystem]{#s4}

### [4.1 Τι είναι το /proc filesystem]{#ss4.1}

To /proc είναι ένα εικονικό σύστημα αρχείων το οποίο μας δίνει τη δυνατότητα να πάρουμε πληροφορίες από τις δομές δεδομένων του πυρήνα. Είναι εικονικό με την
έννοια ότι τα αρχεία που βλέπουμε δεν έχουν κάποια φυσική υπόσταση (πχ δεν βρίσκονται σε κάποια συσκευή). Τα περισσότερα αρχεία μπορούν να ανοιχτούν μόνο για
ανάγνωση. Με ένα \"man proc\" θα λάβετε ότι πληροφορίες για το /proc θέλετε και δε θέλετε να μάθετε :)

### [4.2 Γενικές πληροφορίες για το σύστημα]{#ss4.2}

Στο βασικό κατάλογο /proc υπάρχει ένα πλήθος από αρχεία και καταλόγους. Κάποια από αυτά περιέχουν ολόκληρες δομές πληροφοριών, ενώ άλλα απλώς την τιμή μιας
συγκεκριμένης μεταβλητής του πυρήνα. Τα περισσότερα αρχεία έχουν ονόματα που αυτοεξηγούνται. Κάποια κύρια είναι:

-   **/proc/\<num\> (directory)** : Οι κατάλογοι που το όνομα τους είναι ένας αριθμός, περιέχουν πληροφορίες για τη διεργασία με τον συγκεκριμένο process id. Θα
    τους εξετάσουμε αναλυτικά σε λίγο.
-   **/proc/self (directory)** : Symbolic link στον κατάλογο που περιέχει πληροφορίες για την τρέχουσα διεργασία
-   **/proc/ide (directory)** : Πληροφορίες για τις συσκευές που είναι συνδεδεμένες στο ide bus.
-   **/proc/sys (directory)** : Πλήθος πληροφοριών για το σύστημα και τον πυρήνα.
-   **/proc/cpuinfo** : Πληροφορίες για τον επεξεργαστή μας και τα bugs του :)
-   **/proc/filesystems** : Λίστα από τα filesystem που υποστηρίζει ο πυρήνας.
-   **/proc/meminfo** : Πληροφορίες για τη χρήση της μνήμης στο σύστημα σας.
-   **/proc/modules** : Ποια modules είναι φορτωμένα στον πυρήνα. Αυτό χρησιμοποιεί και η *lsmod*.
-   **/proc/interrupts** : Από ποιες συσκευές πηγάζουν τα hardware interrupts.
-   **/proc/partitions** : Λίστα με όλα τα partitions στον υπολογιστή (άσχετα αν είναι mounted η όχι).
-   **/proc/mounts** : Λίστα με όλα τα mounted directories. (link στο self/mounts)

### [4.3 Πληροφορίες για μια διεργασία]{#ss4.3}

Αν και το /proc filesystem περιέχει τεράστιο όγκο πληροφοριών, αυτές που είναι πραγματικά χρήσιμες για κάποιον που επιδίδεται στο RCE είναι οι πληροφορίες περί
διεργασιών. Αυτές βρίσκονται στον κατάλογο με αριθμό (όνομα) το pid της διεργασίας. Ο κατάλογος περιέχει:

-   **/cwd (directory link)**: link στον τρέχον κατάλογο της διεργασίας (current working directory).

-   **/fd (directory)** : Περιέχει links στα ανοικτά αρχεία της διεργασίας. Πχ το link για το αρχείο με file descriptor 2 είναι fd/2.

-   **/root (directory link)**: link στο root directory του filesystem στο οποίο εκτελείται η διεργασία (συνήθως \"/\" ).

-   **cmdline** : Η πλήρης γραμμή εντολής με την οποία κλήθηκε η διεργασία.

-   **environ** : Λίστα με τις enviroment variables που βλέπει η διεργασία.

-   **exe (link)** : link στο εκτελέσιμο από το οποίο δημιουργήθηκε η διεργασία.

-   **maps** : Το memory map της διεργασίας. Για παράδειγμα για την εντολή less:

        Virtual Address   Perm  Offset  Device  INode        Path
        08048000-08060000 r-xp 00000000 03:07 1457441    /usr/bin/less
        08060000-08061000 rw-p 00018000 03:07 1457441    /usr/bin/less
        08061000-0806a000 rwxp 00000000 00:00 0
        40000000-40014000 r-xp 00000000 03:07 615324     /lib/ld-2.3.1.so
        40014000-40015000 rw-p 00014000 03:07 615324     /lib/ld-2.3.1.so
        40026000-40059000 r-xp 00000000 03:07 615315     /lib/libncurses.so.5.3
        40059000-40062000 rw-p 00032000 03:07 615315     /lib/libncurses.so.5.3
        40062000-40063000 rw-p 00000000 00:00 0
        40063000-4018d000 r-xp 00000000 03:07 615327     /lib/libc-2.3.1.so
        4018d000-40192000 rw-p 0012a000 03:07 615327     /lib/libc-2.3.1.so
        40192000-40196000 rw-p 00000000 00:00 0
        40196000-40396000 r--p 00000000 03:07 745906     /usr/lib/locale/locale-archive
        40396000-403c9000 r--p 00507000 03:07 745906     /usr/lib/locale/locale-archive
        bfffc000-c0000000 rwxp ffffd000 00:00 0

    Η πρώτη στήλη και η δεύτερη δίνουν το πεδίο εικονικών διευθύνσεων που καταλαμβάνει το segment και τα διακαιώματα του, αντίστοιχα. Η τρίτη είναι το offset
    στο οποίο βρίσκεται το segment στο αρχείο από το οποίο φορτώθηκε. Οι υπόλοιπες στήλες δίνουν το device major:minor number, το ΙNode και το πλήρες path του
    αρχείο αυτού.

    Παρατηρήστε πως όλα τα shared object φορτώνονται στη διεύθυνση 0x40000000 και πάνω. Επιπλέον το τελευταίο segment περιέχει το σωρό. Το γεγονός ότι από
    default είναι executable (-x- flag) είναι η ρίζα του κακού για τα buffer overflow exploits.

-   **mem** : Η ίδια η μνήμη της διεργασίας. Διαβάζοντας και γράφοντας στο αρχείο αυτό, προσπελαύνουμε κατευθείαν τη μνήμη της διεργασίας. Προφανώς πρέπει να
    έχουμε τα κατάλληλα δικαιώματα.

-   **mounts** : Λίστα με όλα τα mounted directories. (link στο self/mounts)

-   **stat** : Η κατάσταση της διεργασίας (αλά *ps*).

-   **statm** : Πληροφορίες για την κατάσταση της μνήμης.

-   **status** : Πληροφορίες από τα δύο παραπάνω αρχεία σε πιο ευανάγνωστη μορφή.

Οι πιο χρήσιμες (για RCE) από τις παραπάνω πληροφορίες είναι αυτές που δίνονται από τα **fd/**, **map**, **cmdline** και **exe**. Ειδικά το τελευταίο έχει μια
ενδιαφέρουσα χρήση. Ακόμα και αν διαγράψουμε το εκτελέσιμο αρχείο μιας διεργασίας ενώ εκτελείται, μπορούμε να έχουμε πρόσβαση σε αυτό μέσω του **exe**!


### [5. Χρήσιμες έως πολύ χρήσιμες πληροφορίες ΙΙ]{#s5}

### []{#dead-listing} [5.1 Dead Listing και Εργαλεία]{#ss5.1}

#### Τι είναι το dead listing

Dead listing είναι η παρουσίαση του κώδικα ενός εκτελέσιμου σε στατική μορφή. Κύριο πλεονέκτημα αυτού του τρόπου μελέτης του κώδικα είναι πως δίνει μια πιο
ολοκληρωμένη άποψη για τη λειτουργία του, και, ανάλογα με την ποιότητα του disassembler, ένα πλήθος πληροφοριών (function calls, strings κτλ). Το βασικό
μειονέκτημα είναι ότι δε μπορεί να μας δώσει χρήσιμα αποτελέσματα αν ο κώδικας αλλάζει κατά τη διάρκεια της εκτέλεσης (πχ self-modifying code,
συμπιεσμένα/κρυπτογραφημένα εκτελέσιμα) ή αν υπάρχουν πολλά έμμεσα jmp και calls (πχ jmp \[eax\]), διότι δεν μπορούμε να ακολουθήσουμε (έστω και νοητικά) την
πορεία της εκτέλεσης. Το καλύτερο που έχουμε να κάνουμε σε τέτοιες περιπτώσεις, είναι να φέρουμε το εκτελέσιμο σε μια μορφή που να μπορεί να διαβάσει ο
disassembler, ώστε να εκμεταλλευτούμε τις ευκολίες που μας προσφέρει.

[]{#objdump-weakness} Δυστυχώς, οι 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, έχει και τα ίδια [αδύνατα σημεία](#objdump-weakness). 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

### []{#packing}[5.2 Packed Executables - Συμπιεσμένα Εκτελέσιμα]{#ss5.2}

#### Τι είναι;

Τα εκτελέσιμα αρχεία, όπως και όλα τα αρχεία, περιέχουν μέσα τους επαναλήψεις που καθιστούν δυνατή τη συμπίεση τους. Η συμπίεση στα εκτελέσιμα, εφόσον η
αποσυμπίεση μπορεί να εκτελεστεί αρκετά γρήγορα ώστε να μη γίνεται αισθητή, είναι σίγουρα επιθυμητή. Τα αρχεία καταλαμβάνουν λιγότερο χώρο και επίσης είναι πιο
δύσκολο να ερευνηθούν και να αλλαχτούν (βέβαια, για όσους κάνουμε RCE αυτό είναι μεγάλο πρόβλημα). Μάλιστα, πολλά προγράμματα συμπίεσης εκτελέσιμων εφαρμόζουν
και άλλες τεχνικές, όπως κρυπτογράφηση και CRC ελέγχους. Είναι σαφές πως δε βολεύει απλώς να συμπιεστεί το αρχείο με κάποια παραδοσιακή μέθοδο (πχ με το gzip).
Αυτό συμβαίνει, διότι εκτός από το ότι το εκτελέσιμο δεν είναι πια εκτελέσιμο (η κατάσταση διορθώνεται με χρήση scripts για αυτόματη αποσυμπίεση, το utility
gzexe λειτουργεί έτσι), χάνεται η προστασία από το RCE, αφού τελικά το εκτελέσιμο θα βρεθεί στην αρχική του μορφή πριν εκτελεστεί. Για αυτό, έχουν αναπτυχθεί
διάφορες άλλες τεχνικές για συμπίεση προγραμμάτων.

#### Βασικές Τεχνικές packing

Καταρχάς θα δούμε την απλή packing τεχνική που αναφέραμε στην εισαγωγή . Η βασική της λειτουργία φαίνεται στο παρακάτω σχήμα:

![](/34/img/unpacking1.png)

Ο packer συμπιέζει **όλο το εκτελέσιμο** και δημιουργεί ένα καινούργιο που περιλαμβάνει τα συμπιεσμένα δεδομένα και τον κώδικα αποσυμπίεσης. Ο κώδικα
αποσυμπιέζει τα συμπιεσμένα δεδομένα (αρχικό εκτελέσιμο), τα σώζει σε ένα προσωρινό αρχείο, και μετά το εκτελεί συνήθως με exec(). Η αδυναμία του βρίσκεται στο
γεγονός πως εμφανίζεται το αυθεντικό εκτελέσιμο στο δίσκο, και επομένως δεν παρέχει ιδιαίτερη προστασία. Το θετικό στοιχείο του είναι η απλότητα.

Μια πιo εξελιγμένη τεχνική :

![](/34/img/unpacking2.png)

Εδώ τα πράγματα είναι πιο ενδιαφέροντα. Δε συμπιέζεται όλο το εκτελέσιμο αλλά μόνο τα segments του. Το καινούργιο εκτελέσιμο περιέχει τα συμπιεσμένα δεδομένα
και τον κώδικα για το unpacking (κατά προτίμηση μετά τα δεδομένα).

![](/34/img/unpacking3.png)

Κατά την εκτέλεση φορτώνονται τα συμπιεσμένα 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 από τη μνήμη την εικόνα του εκτελέσιμου σε ένα αρχείο. Αυτό, βέβαια, δε θα είναι το πλήρες, αυθεντικό
αρχείο αλλά συχνά είναι ότι καλύτερο μπορούμε να κάνουμε. Εξάλλου, μετά μπορούμε να κάνουμε διάφορες επεμβάσεις για να το \"βελτιώσουμε\".

Η διαδικασία αποτελείται από τα παρακάτω βήματα:

1.  **Ανάκτηση του OEP (original entry point)** : Εδώ προσπαθούμε να εντοπίσουμε τη διεύθυνση της πρώτης εντολής του αυθεντικού προγράμματος στην εικόνα του
    εκτελέσιμου μετά την αποσυμπίεση. Αυτό το βήμα είναι που απαιτεί την περισσότερη εμπειρία. Σημάδια πως τελειώνει ο κώδικας του unpacker και περνάμε στο
    αρχικό εκτελέσιμο είναι:
    -   Unconditional jump ( άμεσο πχ jmp 0x8048954 ή έμμεσο πχ jmp eax ) σε κάποια \"μακρινή\" διεύθυνση.
    -   Αλλαγή του ύφους του προγράμματος. Οι unpackers είναι συνήθως γραμμένοι σε assembly με το χέρι και το στυλ τους διαφέρει από τον κώδικα που έχει
        παραχθεί από compilers.
    -   Χρήση των popa/popad (pop all registers). Επειδή η unpackers αλλοιώνουν το context της διεργασίας (πχ τιμές των registers) τους σώζουν όλους πριν
        αρχίσουν (με pusha/pushad) και τους επαναφέρουν πριν περάσουν τον έλεγχο στο αρχικό πρόγραμμα.
2.  **Dump της εικόνας (image) του εκτελέσιμου σε ένα αρχείο** : Κάνουμε dump την εικόνα του εκτελέσιμου, όπως είναι αυτή, ακριβώς πριν περάσει ο έλεγχος στο
    αυθεντικό εκτελέσιμο. Για αυτό χρειαζόμαστε το OEP που μας δινει το προηγούμενο βήμα. Αφου, λοιπόν, το έχουμε, αναγκάζουμε τη διεργασία να εκτελεστεί μέχρι
    το OEP (έτσι είμαστε σίγουροι πως όλα είναι unpacked όπως πρέπει) και τότε κάνουμε dump την εικόνα του εκτελέσιμου. Μπορούμε να χρησιμοποιήσουμε την εντολή
    **dump** του gdb. Η σύνταξη της είναι **dump memory \<file\> \<start\> \<stop\>**. Για να αποφασίσουμε ποιες διευθύνσεις θα κάνουμε dump μπορούμε να
    συμβουλευτούμε το map από το /proc/\<pid\>/. Για τα εκτελέσιμα στο linux, αρκούν συνήθως τα δύο πρώτα segments που είναι το code και data segment αντίστοιχα
    .
3.  **Διόρθωση του ELF Header** : Διορθώνουμε τον ELF Header του dumped αρχείου, ώστε να μπορεί να εξεταστεί και να εκτελεστεί. Συγκεκριμένα θέτουμε το entry
    point του εκτελέσιμου στο OEP, διορθώνουμε τα στοιχεία των segments και αναδημιουργούμε το DYNAMIC segment. Το τελευταίο είναι αρκετά επίπονο και όχι
    απαραίτητο αν απλώς θέλουμε να εξετάσουμε τον κώδικα (dissasembly). Αν δε γίνει αυτή η διόρθωση, τότε οι διευθύνσεις των συναρτήσεων των shared objects θα
    έχουν παντα τις τιμές που είχαν την στιγμή που κάναμε dump, διότι ο dynamic linker δε θα ενεργοποιηθεί. Αν χρησιμοποιούμε το dumped εκτελέσιμο μόνο στο δικό
    μας σύστημα και με τι ίδιες **ακριβώς** βιβλιοθήκες, ίσως να τη γλιτώσουμε.


### [6. Hands-on Παράδειγμα - Υπό πίεση]{#s6}

### [6.1 Πράξη 1η]{#ss6.1}

Αυτή τη φορά θα ασχοληθούμε με το demo του εκπληκτικού προγράμματος για πράξεις μη αρνητικών ακεραίων: [rce2-files/hands-on.gz](rce2-files/hands-on.gz). Το demo
θα σταματήσει να λειτουργεί μετά από κάποιο χρονικό διάστημα. Αυτό το είδος της προστασίας ονομάζεται Cinderella (Σταχτοπούτα) protection, διότι όπως και στο
γνωστό παραμύθι, όταν παρέλθει κάποιο χρονικό διάστημα η άμαξα/πρόγραμμα θα γίνει κολοκύθα :) Για να δούμε\...

>     bash$ ./hands-on
>     Ready> 1+3
>     Result: 4
>     Ready> 4*5
>     Result: 20
>     Ready> 25/5
>     Result: 5
>     Ready>

Αν πάμε την ημερομηνία του συστήματος μερικές μέρες μπροστά\...

>     ./hands-on
>     Not ready> 3+4
>     Result: 11
>     Not ready> 6*6
>     Result: 108
>     Not ready> 2/3
>     Result: -1
>     Not ready>

Χμμ, το πρόγραμμα όντως σταμάτησε να λειτουργεί (σωστά τουλάχιστον). Αν επιστρέψουμε στην αρχική ημερομηνία και εκτελέσουμε το πρόγραμμα θα δούμε ότι λειτουργεί
κανονικά. Όποιος έφτιαξε την προστασία μάλλον δεν το έκανε πολύ καλά :) Πάντως είναι εκνευριστικό να πρέπει να γυρνάμε το ρολόι πίσω όποτε θέλουμε να
εκτελέσουμε αυτή την *εκπληκτική* εφαρμογή. Θα πρέπει να κάνουμε κάτι καλύτερο!

Ας δούμε τι μπορούμε να μάθουμε για το πρόγραμμα\...\
[listing1](rce2-files/listing1.txt)\
Ουακ! Τι είναι όλα αυτά;

Τα ακατανόητα ονόματα είναι σύμβολα της C++ σε μπλεγμένη (mangled) μορφή. Υποτίθεται πως το ltrace έχει μια επιλογή (-C) για να κάνει demangling αλλά σε εμένα
δε βελτίωσε την κατάσταση. Ευτυχώς υπάρχει ένα πρόγραμμα, το **c++filt**, το οποίο αποκωδικοποιεί τα ονόματα των c++ συμβόλων.\
[listing2](rce2-files/listing2.txt)\
Αν δεν είστε μυημένοι στους μυστικούς συμβολισμούς της STL (Standard Template Library) της C++, τα παραπάνω ίσως να σας φαίνονται τόσο ακατανόητα όσο και τα
mangled σύμβολα. Η αλήθεια είναι, όμως, ότι περιέχουν σημαντικές πληροφορίες. Για παράδειγμα, οι περισσότερες γραμμές που αρχίζουν με std::basic\_ostream είναι
κλήσεις στη συνάρτηση operator\<\<() η οποία είναι υπεύθυνη για την υπερφόρτωση του τελεστή \<\<. Αν έχετε ασχοληθεί στοιχειωδώς με C++ σίγουρα θα έχετε δει το
cout\<\<\"Hello World\". Στην πραγματικότητα αυτό είναι μια κλήση operator\<\<(cout, \"Hello World\") η οποία γράφει δεδομένα στο stream της κονσόλας. Oι
κλήσεις στο παραπάνω listing δεν είναι τίποτα άλλο από τέτοιου είδους κλήσεις. Παρομοίως, οι γραμμές που αρχίζουν με std::basic\_istream είναι κλήσεις στη
συνάρτηση operator\>\>() η οποία διαβάζει δεδομένα από κάποιο stream (πχ πληκτρολόγιο).

Ξεφεύγοντας λίγο από τη C++, άξιες προσοχής είναι οι κλήσεις στην **time(NULL)** που επιστρέφει την τρέχουσα ώρα και επίσης στη stat (\_\_xstat) που επιστρέφει
πληροφορίες για κάποιο αρχείο (το \"hands-on\" στην περίπτωση αυτή). Παρατηρήστε, επίσης, ότι στο πρόγραμμα οι κλήσεις αρχίζουν να επαναλαμβάνονται: η
\[08048be0\] time(NULL) καλείται στην αρχή και ξανακαλείται από το ίδιο σημείο αργότερα. Επίσης, αμέσως μετά και τις δύο αυτές time() (0x08048be0), υπάρχει η
ίδια ακολουθία ostream\..., istream\..., string\... . Υπαρχεί μεγάλη πιθανότητα αυτό να είναι το σημείο στο οποίο εμφανίζεται το prompt (ostream), εισάγουμε την
αριθμητική παράσταση (istream) και αυτή αποθηκεύεται (string). Αλλά αρκετά με τις υποθέσεις. Ας δούμε τι άλλο μπρούμε να μάθουμε για το εκτελέσιμο:

>     bash$ objdump -x ./hands-on
>     /hands-on:     file format elf32-i386
>     ./hands-on
>     architecture: i386, flags 0x00000102:
>     EXEC_P, D_PAGED
>     start address 0x08048080
>
>     Program Header:
>         LOAD off    0x00000000 vaddr 0x08048000 paddr 0x08048000 align 2**12
>              filesz 0x000005b8 memsz 0x000005b8 flags r-x
>         LOAD off    0x000005b8 vaddr 0x080495b8 paddr 0x080495b8 align 2**12
>              filesz 0x0000002c memsz 0x0000002c flags rw-
>
>     Sections:
>     Idx Name          Size      VMA       LMA       File off  Algn
>     SYMBOL TABLE:
>     no symbols

\...όχι και πολλά πράγματα. Μάλιστα, κάτι ύποπτο συμβαίνει! Ενώ γνωρίζουμε ότι το εκτελέσιμο καλεί δυναμικά συναρτήσεις βιβλιοθηκών (από το ltrace) δεν υπάρχει
DYNAMIC segment. Εκτός των άλλων, δεν υπάρχουν καθόλου sections, γεγονός παράξενο (βέβαια δεν είναι απαραίτητο να υπάρχουν στο εκτελέσιμο αλλά είναι
συνηθισμένο).

Συνεχίζοντας να μαζεύουμε πληροφορίες:

>     bash$ file hands-on
>     hands-on: ELF 32-bit LSB executable, Intel 80386, version 1, statically linkedfile: corrupted section header size.
>     bash$ strings hands-on
>     Linux
>     SlQf
>     UPXδ
>     δψRQθώ
>     $Info: This file is packed with the UPX executable packer http://upx.sf.net $
>     $Id: UPX 1.24 Copyright (C) 1996-2002 the UPX Team. All Rights Reserved. $
>     UWVSQRό
>     ...
>     ...

Τώρα όλα βγάζουν νόημα\... Το εκτελέσιμο έχει συμπιεστεί με το πρόγραμμα UPX! Στην περίπτωση που θέλουμε απλώς να εργαστούμε με κάποιον debugger αυτό δε μας
ενοχλεί ιδιαίτερα, αρκεί κάθε φορά να προσπερνάμε τον κώδικα της αποσυμπίεσης και να ασχολούμαστε με το πραγματικό εκτελέσιμο. Το πρόβλημα είναι στη περίπτωση
του dead-listing. Θα μπορούσαμε να το αγνοήσουμε, όμως, όπως έχουμε αναφέρει, οι ευκολίες που προσφέρει είναι ανεκτίμητες. Οπότε, στο επόμενο κομμάτι θα κάνουμε
ότι μπορούμε για να φέρουμε το εκτελέσιμο όσο πιο κοντά γίνεται στην αυθεντική του μορφή.

### [6.2 Επιστροφή σε Κανονικές Συνθήκες πίεσης και θερμοκρασίας.]{#ss6.2}

(ΣΗΜΕΙΩΣΗ: Αν δεν έχετε διαβάσει τις πληροφορίες για το packing, [τώρα είναι μια καλή στιγμή να το κάνετε](05_rce3-5.html#packing))

Πως όμως θα δούμε το αρχικό εκτελέσιμο; Αυτό μπορεί να επιτευχθεί ως εξής:

**1. Ο εύκολος τρόπος**

Μπορούμε να πάμε στη σελίδα του UPX <http://upx.sourceforge.net>, να το κατεβάσουμε και να αποσυμπιέσουμε το εκτελέσιμο. Αν και είναι απλή μέθοδος, δεν έχει
καμία γενικότητα. Για παράδειγμα, δε μπορεί να εφαρμοστεί στην περίπτωση που η συμπίεση/κρυπτογράφηση έχει γίνει με κάποιο custom αλγόριθμο ή ακόμα και με άλλη
έκδοση του ίδιου προγράμματος.

**2. Ο καλύτερος τρόπος**

Χρησιμοποιώντας το strace (κάτι που αμελήσαμε να κάνουμε πριν):

>     bash$ strace -ohands-on.st  hands-on
>     Ready> 
>     ^C
>     bash$ cat -n hands-on.st
>          1  execve("./hands-on", ["hands-on"], [/* 48 vars */]) = 0
>          2  getpid()                                = 690
>          3  open("/proc/690/exe", O_RDONLY)         = 3
>          4  lseek(3, 1508, SEEK_SET)                = 1508
>          5  read(3, "0e\300\177\314\30\0\0\314\30\0\0", 12) = 12
>          6  gettimeofday({1062315999, 908816}, NULL) = 0
>          7  unlink("/tmp/upxCOXBQXPAAVS")           = -1 ENOENT (No such file or directory)
>          8  open("/tmp/upxCOXBQXPAAVS", O_WRONLY|O_CREAT|O_EXCL, 0700) = 4
>          9  ftruncate(4, 6348)                      = 0
>         10  old_mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40000000
>         11  read(3, "\314\30\0\0b\f\0\0", 8)        = 8
>         12  read(3, "\177?d\371\177ELF\1\0\2\0\3\0\r\30\211\4\377o\263\335\010"..., 3170) = 3170
>         13  write(4, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\2\0\3\0\1\0\0\0\30\211"..., 6348) = 6348
>         14  read(3, "\0\0\0\0UPX!", 8)              = 8
>         15  munmap(0x40000000, 12288)               = 0
>         16  close(4)                                = 0
>         17  close(3)                                = 0
>         18  open("/tmp/upxCOXBQXPAAVS", O_RDONLY)   = 3
>         19  access("/proc/690/fd/3", R_OK|X_OK)     = 0
>         20  unlink("/tmp/upxCOXBQXPAAVS")           = 0
>         21  fcntl(3, F_SETFD, FD_CLOEXEC)           = 0
>         22  execve("/proc/690/fd/3", ["hands-on"], [/* 48 vars */]) = 0
>             ...

Λοιπόν, για να δούμε τι συμβαίνει.

**1**: Εκτελείται το hands-on.

**2-5**: Το πρόγραμμα μαθαίνει το pid του και ανοίγει το ίδιο το αρχείο του μέσω του /proc filesystem (θα μπορούσε να έχει χρησιμοποιήσει το /proc/self άλλα
ίσως δεν το έκανε για λόγους συμβατότητας). Ύστερα διαβάζει 12 bytes από το offset 1508 στο αρχείο.

**6-9**: Διαβάζεται η ώρα του συστήματος, γίνεται μια προσπάθεια να διαγραφεί το αρχείο \"/tmp/upxCOXBQXPAAVS\" το οποίο δεν υπάρχει και δημιουργείται εκ νέου
με δικαιώματα 0700 = -rwx\-\-\-\-\--. Τέλος, το μέγεθος του αρχείου καθορίζεται στα 6348 bytes. Η δημιουργία του αρχείου με δικαίωμα εκτέλεσης ελπίζω να σας
προβλημάτισε. Παρεπιπτόντως, παρατηρήστε οτι οι δύο τελευταίες τετράδες bytes από τα 12 bytes που διαβάστηκαν στη γραμμή 5 αντιστοιχούν στο 6348 αν τις
θεωρήσουμε ακέραιους των 4 bytes (διαβασμένα LSB first).

**10-15**: Αρχικά γίνονται map 12288 bytes. Μετά διαβάζονται 8 bytes από αρχικό αρχείο (hands-on) (συνεχίζοντας από εκεί που είχε μείνει μετά τα 12 bytes). Αν
ερμηνευτούν ως ακέραιοι των 4-bytes είναι οι τιμές 6348 και 3170. Ύστερα διαβάζονται από το αρχικό αρχείο 3170 bytes (τι σύμπτωση!) και γράφονται στο καινούργιο
(\"/tmp/upxCOXBQXPAAVS\") 6348 bytes. Παρατηρήστε πως η αρχή των δεδομένων που γράφονται είναι ένας ELF header. Τέλος, διαβάζονται άλλα 8 bytes (μοιάζουν με end
of data signature) και γίνονται unmap αυτά που είχαν γίνει map πιο πριν.

**16-22**: Κλείνουν τα δύο αρχεία και ανοίγει πάλι το \"/tmp/upxCOXBQXPAAVS\" με δικαιώματα μόνο ανάγνωσης αυτή τη φορά. Μετά ελέγχεται αν η τρέχουσα διεργασία
έχει δικαιώματα ανάγνωσης (R\_OK) και εκτέλεσης (X\_OK) για το αρχείο και αμέσως μετά αυτό διαγράφεται. Η διαγραφή αυτή όμως είναι τυπική διότι η τρέχουσα
διεργασία έχει ήδη ένα file handle (3), οπότε αν και το αρχείο δεν υπάρχει πια ως μέρος του filesystem τα δεδομένα του δεν έχουν χαθεί. Με τη fcntl() που
ακολουθεί, καθορίζεται ότι σε περίπτωση που κληθεί η exec() για την αντικατάσταση της διεργασίας με κάποια καινούργια, η καινούργια *δε* θα λάβει τον file
descriptor 3. Αυτό ονομάζεται close-on-exec. Τέλος, εκτελείται το αρχείο.

Ελπίζω ύστερα από τα παραπάνω, η γενική λειτουργία του UPX να έχει γίνει φανερή. Με απλά λόγια, όταν ένα πρόγραμμα συμπιεσμένο με UPX εκτελείται, το αυθεντικό
αρχείο αποσυμπιέζεται σε ένα προσωρινό αρχείο στον κατάλογο \"/tmp\" και ο έλεγχος περνάει σε αυτό. Το αποσυμπιεσμένο αρχείο \"διαγράφεται\" αλλά τα δεδομένα
του υφίστανται μέχρι να τελειώσει η εκτέλεση.

Τώρα τίθεται το ερώτημα: πως θα έχουμε πρόσβαση στο αποσυμπιεσμένο εκτελέσιμο; Και από το πουθενά ακούγεται ένας υπερκοσμικός ψίθυρος: **/proc/\<pid\>/exe**!

Πράγματι :

>     bash$  ./hands-on &
>     [1] 804
>     Ready> bash$ cat /proc/804/exe > ./hands-on-unpacked
>
>     [1]+  Stopped                 ./hands-on
>     bash$ %1
>     ./hands-on
>     ^C
>     bash$ objdump -x ./hands-on-unpacked
>
>     ./hands-on-unpacked:     file format elf32-i386
>     ./hands-on-unpacked
>     architecture: i386, flags 0x00000112:
>     EXEC_P, HAS_SYMS, D_PAGED
>     start address 0x08048918
>
>     Program Header:
>         PHDR off    0x00000034 vaddr 0x08048034 paddr 0x08048034 align 2**2
>              filesz 0x000000e0 memsz 0x000000e0 flags r-x
>       INTERP off    0x00000114 vaddr 0x08048114 paddr 0x08048114 align 2**0
>              filesz 0x00000013 memsz 0x00000013 flags r--
>         LOAD off    0x00000000 vaddr 0x08048000 paddr 0x08048000 align 2**12
>              filesz 0x00001050 memsz 0x00001050 flags r-x
>         LOAD off    0x00001050 vaddr 0x0804a050 paddr 0x0804a050 align 2**12
>              filesz 0x000002f4 memsz 0x00000430 flags rw-
>      DYNAMIC off    0x000011f8 vaddr 0x0804a1f8 paddr 0x0804a1f8 align 2**2
>              filesz 0x000000e0 memsz 0x000000e0 flags rw-
>         NOTE off    0x00000128 vaddr 0x08048128 paddr 0x08048128 align 2**2
>              filesz 0x00000020 memsz 0x00000020 flags r--
>     EH_FRAME off    0x00001014 vaddr 0x08049014 paddr 0x08049014 align 2**2
>              filesz 0x0000003c memsz 0x0000003c flags r--
>
>     Dynamic Section:
>       NEEDED      libstdc++.so.5
>       NEEDED      libm.so.6
>       NEEDED      libgcc_s.so.1
>
>         ...
>     bash$ ./hands-on-unpacked
>     Ready>
>     ^C

Αυτό ήταν, τώρα πια έχουμε το εκτελέσιμο στην αυθεντική του μορφή!

### [6.3 Σταματώντας τον χρόνο]{#ss6.3}

Αφού αποσυμπιέσαμε ο εκτελέσιμο, ήρθε η ώρα να δούμε πως μπορούμε να απενεργοποιήσουμε την προστασία. Αυτή τη φορά αντί για τον GDB θα χρησιμοποιήσουμε την
dead-listing προσέγγιση με τον HTEditor. Φορτώνοντας το πρόγραμμα στο ht εμφανίζεται μπροστά μας ένα γραφικό περιβάλλον σε ncurses. Με το F6/Space εμφανίζεται
το παράθυρο επιλογής mode, και εμείς επιλέγουμε το mode elf/image. Τώρα πια βλέπουμε το listing αρχίζοντας από το entry point. Με τα βελάκια μπορούμε να
κινηθούμε στις διάφορες διευθύνσεις/σύμβολα και με το πλήκτρο enter το listing μετακινείται στο σημείο όπου αναφέρεται η τρέχουσα επιλογή. Αρχικά έχουμε:

>     8048918 !                                                                                                                
>     ....... ! ;******************************************************************                                            
>     ....... ! ;  end of section <.plt>                                                                                       
>     ....... ! ;******************************************************************                                            
>     ....... !                                                                                                                
>     ....... ! ;******************************************************************                                            
>     ....... ! ;  section 13 <.text>                                                                                          
>     ....... ! ;  virtual address  08048918  virtual size   00000678                                                          
>     ....... ! ;  file offset      00000918  file size      00000678                                                          
>     ....... ! ;******************************************************************                                            
>     ....... !                                                                                                                
>     ....... ! ;****************************                                                                                  
>     ....... ! ;  executable entry point                                                                                      
>     ....... ! ;****************************                                                                                  
>     ....... ! entrypoint:                                                                                                    
>     ....... !   xor     ebp, ebp                                                                                             
>     804891a !   pop     esi                                                                                                  
>     804891b !   mov     ecx, esp                                                                                             
>     804891d !   and     esp, 0fffffff0h                                                                                      
>     8048920 !   push    eax                                                                                                  
>     8048921 !   push    esp                                                                                                  
>     8048922 !   push    edx                                                                                                  
>     8048923 !   push    offset_8048f90                                                                                       
>     8048928 !   push    offset_80487e0                                                                                       
>     804892d !   push    ecx                                                                                                  
>     804892e !   push    esi                                                                                                  
>     804892f !   push    offset_80489c8                                                                                       
>     8048934 !   call    __libc_start_main                                                                                    
>     8048939 !   hlt                                                                                                          
>     804893a !   nop                                                                                                          
>     804893b !   nop                                                                                                          
>     804893c !

Έτσι, αν επιλέξουμε το offset\_80489c8 και πατήσουμε enter, το listing θα αρχίζει από τη διεύθυνση 0x80489c8 η οποία είναι και η διεύθυνση της main.

Κάνοντας μερικές \"βόλτες\" στη main παρατηρούμε ότι τα πράγματα δεν είναι και πολύ κατατοπιστικά. Αυτό οφείλεται εν μέρει στα optimizations του g++ αλλά και
την ίδια τη C++ ως γλώσσα. Θα μπορούσαμε να κυκλοφορούμε σαν την άδικη κατάρα στο listing ψάχνοντας για οτιδήποτε ενδιαφέρον αλλά σίγουρα μπορούμε να σκεφτούμε
κάτι καλύτερο. Ας καταστρώσουμε, λοιπόν, κάποιο σχέδιο. Σκοπός μας είναι, καταρχάς, να εντοπίσουμε σε ποιο σημείο (ή σημεία) γίνεται ο έλεγχος για το αν έχουμε
ξεπεράσει το επιτρεπτό χρονικό όριο. Αυτό συχνά είναι και το πιο δύσκολο κομμάτι σε μια προσπάθεια RCE, το να εντοπίσουμε και να ξεχωρίσουμε μέσα στις χιλιάδες
εντολές αυτές που μας ενδιαφέρουν.

Ένας καλός τρόπος να το πετύχουμε αυτό είναι να δούμε πως η εσωτερική αλλαγή/έλεγχος επηρεάζει εξωτερικά (προς το χρήστη) το πρόγραμμα και να ψάξουμε για το
σημείο στον κώδικα που γίνεται αυτή η εξωτερική αλλαγή. Επειδή η προηγούμενη περίοδος είναι κάπως ασαφής ας κάνουμε τα πράγματα πιο συγκεκριμένα. Αυτό που μας
ενδιαφέρει είναι να εντοπίσουμε που γίνεται ο χρονικός έλεγχος. Επειδή αυτό είναι κάπως δύσκολο, ας αναλογιστούμε πως το αποτέλεσμα του χρονικού ελέγχου (αλλαγή
της εσωτερικής κατάστασης) επηρεάζει τη συμπεριφορά του προγράμματος. Είδαμε στην αρχή πως, όταν δεν έχει λήξει η demo περίοδος, το πρόγραμμα εμφανίζει το
prompt \"Ready\>\" ενώ όταν έχει λήξει το \"Not Ready\>\". Ας ψάξουμε λοιπόν μήπως βρούμε κάποιο από αυτά τα strings. Με το F7 εμφανίζεται το παράθυρο
αναζήτησης όπου αν βάλουμε \"Ready\>\" θα βρεθούμε στο εξής

>
>     8048fb1     db      00h ; ' '                                                                                            
>     8048fb2     db      02h ; ' '                                                                                            
>     8048fb3     db      00h ; ' '                                                                                            
>     8048fb4                                                                                                                  
>     .......   strz_Not_ready___8048fb4:       ;xref o8048bf3                                                                 
>     .......     db      "Not ready> \0"                                                                                      
>     8048fc0                                                                                                                  
>     .......   strz_Result:__8048fc0:          ;xref o8048c25                                                                 
>     .......     db      "Result: \0"                                                                                         
>     8048fc9                                                                                                                  
>     .......   strz_Ready___8048fc9:           ;xref o8048c8f                                                                 
>     .......     db      "Ready> \0"                                                                                          
>     8048fd1     db      33h ; '3'                                                                                            
>     8048fd2     db      42h ; 'B'                                                                                            
>     8048fd3     db      75h ; 'u'                                                                                            
>     8048fd4     db      6ch ; 'l'                                                                                            
>     8048fd5     db      00h ; ' '                                                                                            
>     8048fd6     db      33h ; '3'                                                                                            
>     8048fd7     db      44h ; 'D'                                                                                            
>     8048fd8     db      69h ; 'i'                                                                                            
>     8048fd9     db      76h ; 'v'                                                                                            
>     8048fda     db      00h ; ' '

Ο disassembler έχει βρει τα strings και μάλιστα τους έχει δώσει και όνομα (πχ strz\_Ready\_\_\_8048fc9). To xref o8048c8f σημαίνει ότι αυτό το σύμβολο/διεύθυνση
έχει \"αναφερθεί\"/χρησιμοποιηθεί στη διεύθυνση 0x8048c8f ως offset σε κάποια εντολή. Ας πάμε εκεί λοιπόν :

>
>     ....... ! loc_8048c84:                    ;xref j8048c20                                                                 
>     ....... !   lea     esp, [ebp-0ch]                                                                                       
>     8048c87 !   pop     ebx                                                                                                  
>     8048c88 !   pop     esi                                                                                                  
>     8048c89 !   pop     edi                                                                                                  
>     8048c8a !   leave                                                                                                        
>     8048c8b !   ret                                                                                                          
>     8048c8c !                                                                                                                
>     ....... ! loc_8048c8c:                    ;xref j8048bea                                                                 
>     ....... !   sub     esp, 8                                                                                               
>     8048c8f !   push    strz_Ready___8048fc9                                                                                 
>     8048c94 !   jmp     loc_8048bf8                                                                                          
>     8048c99     nop                                                                                                          
>     8048c9a     nop                                                                                                          
>     8048c9b     nop

Παρατηρούμε ότι το offset του string χρησιμοποιήθηκε στην push. Σημειώστε τη διεύθυνση του τελικού jmp και ότι ο μόνος τρόπος για να φτάσουμε σε αυτό το κομμάτι
κώδικα είναι μέσω ενός jump που βρίσκεται στη διεύθυνση 0x8048bea (το xref μας έδωσε αυτές τις πληροφορίες). Δε μένει τίποτα παρά να πάμε εκεί να δούμε:

>
>     8048bd4 !                                                                                                                
>     ....... ! loc_8048bd4:                    ;xref j8048c73                                                                 
>     ....... !   sub     esp, 0ch                                                                                             
>     8048bd7 !   mov     ebx, [edi]                                                                                           
>     8048bd9 !   push    0                                                                                                    
>     8048bdb !   call    time                                                                                                 
>     8048be0 !   mov     edx, [ebx+8]                                                                                         
>     8048be3 !   add     edx, [ebx]                                                                                           
>     8048be5 !   add     esp, 10h                                                                                             
>     8048be8 !   cmp     eax, edx                                                                                             
>     8048bea !   jng     loc_8048c8c     <------   Αυτό το jump μας ενδιαφέρει                                                          
>     8048bf0 !   sub     esp, 8                                                                                               
>     8048bf3 !   push    strz_Not_ready___8048fb4                                                                             
>     8048bf8 !                                                                                                                
>     ....... ! loc_8048bf8:                    ;xref j8048c94                                                                 
>     ....... !   push    _ZSt4cout                                                                                            
>     8048bfd !   call    _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc                                              
>     8048c02 !   pop     ebx                                                                                                  
>     8048c03 !   pop     esi                                                                                                  
>     8048c04 !   push    dword ptr [ebp-10h]                                                                                  
>     8048c07 !   push    _ZSt3cin                                                                                             
>     8048c0c !   call    _ZStrsIcSt11char_traitsIcESaIcEERSt13basic_istreamIT_T0_ES7_RSbIS4_S5_T1_E                           
>     8048c11 !   mov     [esp], edi                                                                                           
>     8048c14 !   call    sub_8048c9c                                                                                          
>     8048c19 !   add     esp, 10h                                                                                             
>     8048c1c !   test    eax, eax                                                                                             
>     8048c1e !   mov     ebx, eax                                                                                             
>     8048c20 !   jz      loc_8048c84                                                                                          
>     8048c22 !   sub     esp, 8                                                                                               
>     8048c25 !   push    strz_Result:__8048fc0                                                                                
>     8048c2a !   push    _ZSt4cout                                                                                            
>     8048c2f !   call    _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc                                              
>     8048c34 !   mov     esi, eax

Κάτι μου λέει πως φτάνουμε στη λύση του μυστηρίου! Το jump ψάχνουμε είναι ακριβώς μετά από μια σύγκριση του eax με τον edx. Από το listing βλέπουμε πως ο eax
περιέχει την τιμή επιστροφής της κλήσης της συνάρτησης time(0) (\@0x8048bdb). Αυτή επιστρέφει την τρέχουσα ώρα σε δευτερόλεπτα, μετρημένη από τις 1/1/1970 (το
λεγόμενο Epoch). Η τιμή στον edx προκύπτει από την πρόσθεση δύο τιμών που βρίσκονται στις διευθύνσεις ebx και ebx+8. Αν η τωρινή ώρα είναι μικρότερη από το
άθροισμα, τότε το πρόγραμμα κάνει άλμα, κάνει push \"Ready\>\" και γυρίζει στη διεύθυνση 0x8048bf8. Αντίθετα, αν η τρέχουσα ώρα είναι μεγαλύτερη ή ίση από το
άθροισμα, το άλμα δεν εκτελείται, γίνεται push \"Not Ready\>\" και φτάνουμε πάλι στη διεύθυνση 0x8048bf8. Μου φαίνεται ότι είναι πια ξεκάθαρο πως το άθροισμα
που παράγεται ( \[ebx\] + \[ebx+8\] ) αποτελεί τη χρονική στιγμή πέρα από την οποία λήγει το demo.

Στη διεύθυνση 0x8048bf8 γίνεται push το σύμβολο cout και καλείται η συνάρτηση \_ZStlsISt11char\_traitsIcEERSt13basic\_ostreamIcT\_ES5\_PKc. Χμμ, όχι και πολύ
ξεκάθαρα πράγματα. Ας το κάνουμε demangle manually με το c++filt\
[listing3.txt](rce2-files/listing3.txt)\
Όλη η προηγούμενη ακολουθία μας λέει πως καλείται η συνάρτηση για τον overloaded τελεστή \<\<, με αριστερή πλευρά ένα αντικείμενο τύπου *basic\_ostream* (output
stream) και δεξιά *const char \**. Με απλά λόγια, η εντολή που εκτελέστηκε ήταν η std::cout\<\<\"Ready\>\" ή std::cout\<\<\"Not Ready\>\".

Λίγο πιο κάτω (έχω αποπλέξει τα σύμβολα με το c++filt):\
[listing4.txt](rce2-files/listing4.txt)\
Το οποίο μεταφράζεται σε std::cin\>\>string1, όπου string1 ένα αντικείμενο τύπου *std::string*. Σε αυτό το string μπορούμε να υποθέσουμε πως αποθηκεύεται η
έκφραση που εισάγουμε.

Ας αφήσουμε την ανάλυση του listing για λίγο και ας αναλογιστούμε πως μπορούμε να πειράξουμε το εκτελέσιμο ώστε να ξεπεράσουμε το χρονικό έλεγχο. Η πιο απλή
λύση είναι να αντικαταστήσουμε το jng στη διεύθυνση 0x8048bea με ένα jmp στη διεύθυνση 0x8048c8. Το πρόβλημα με αυτή την προσέγγιση είναι ότι αντιμετωπίζουμε το
αποτέλεσμα και όχι την αιτία. Θα πρέπει σε κάθε σημείο που γίνεται ένα τέτοιος έλεγχος να αλλάξουμε το άλμα. Εμείς βρήκαμε ένα τέτοιο σημείο αλλά πιθανότατα
υπάρχει τουλάχιστον ακόμα ένα. Θυμηθείτε πως όταν το πρόγραμμα είχε λήξει, εκτός από το prompt \"Not Ready\>\", κάτι δεν πήγαινε καλά και με τις πράξεις. Στο
σημείο που αναλύσαμε εμείς, ο έλεγχος φαίνεται να επηρεάζει μόνο το prompt, οπότε θα πρέπει να υπάρχει και κάποιο άλλο checkpoint. Σε ένα πλήρες πρόγραμμα τα
σημεία ελέγχου μπορεί να είναι εκατοντάδες και σίγουρα δεν είναι πρακτικό να τα αλλάξουμε όλα. Η πιο σωστή λύση είναι να βρούμε σε ποιο σημείο αρχικοποιούνται
οι μεταβλητές που περιέχουν τις πληροφορίες για τη λήξη του χρόνου και να τις \"πειράξουμε\" εκεί. Ας αρχίσουμε λοιπόν\...

Επιστρέφοντας στο listing λίγο πιο πάνω από εκεί που είχαμε μείνει:

>     8048bc0 !                                                                                                                
>     ....... ! ;-----------------------                                                                                       
>     ....... ! ;  S U B R O U T I N E                                                                                         
>     ....... ! ;-----------------------                                                                                       
>     ....... ! sub_8048bc0:                    ;xref c8048a7d                                                                 
>     ....... !   push    ebp                                                                                                  
>     8048bc1 !   mov     ebp, esp                                                                                             
>     8048bc3 !   push    edi                                                                                                  
>     8048bc4 !   push    esi                                                                                                  
>     8048bc5 !   push    ebx                                                                                                  
>     8048bc6 !   sub     esp, 0ch                                                                                             
>     8048bc9 !   mov     edi, [ebp+8]                                                                                         
>     8048bcc !   lea     eax, [edi+4]                                                                                         
>     8048bcf !   mov     [ebp-10h], eax                                                                                       
>     8048bd2 !   mov     esi, esi                                                                                             
>     8048bd4 !                                                                                                                
>     ....... ! loc_8048bd4:                    ;xref j8048c73                                                                 
>     ....... !   sub     esp, 0ch                                                                                             
>     8048bd7 !   mov     ebx, [edi]                                                                                           
>     8048bd9 !   push    0                                                                                                    
>     8048bdb !   call    time                                                                                                 
>     8048be0 !   mov     edx, [ebx+8]                                                                                         
>     8048be3 !   add     edx, [ebx]                                                                                           
>     8048be5 !   add     esp, 10h                                                                                             
>     8048be8 !   cmp     eax, edx                                                                                             
>     8048bea !   jng     loc_8048c8c                                                                                          
>     8048bf0 !   sub     esp, 8                                                                                               
>     8048bf3 !   push    strz_Not_ready___8048fb4

Είπαμε πως ο edx περιέχει την ημερομηνία λήξης του demo. Αυτή προκύπτει από το άθροισμα των τιμών στις διευθύνσεις \[ebx+8\] και \[ebx\]. Προχωρώντας πιο πάνω
βλέπουμε πως ο ebx εξαρτάται από το edi (8048bd7 ! mov ebx, \[edi\]) το οποίο με τη σειρά του εξαρτάται από το ebp (8048bc9 ! mov edi, \[ebp+8\]). Μάλιστα το
ebp+8 είναι η πρώτη παράμετρος της συνάρτησης στην οποία είμαστε! Επομένως, κατά κάποιο τρόπο τα δεδομένα για τη λήξη έχουν περαστεί ως παράμετρος στη
συνάρτηση. Παρατηρήστε πως η παράμετρος γίνεται dereferenced 2 φορές και επομένως μπορούμε να υποθέσουμε πως είναι κάποιο είδος δείκτη σε δείκτη. Η συνάρτηση
στην οποία βρισκόμαστε καλείται από το σημείο 0x8048a7d (xref c8048a7d) οπότε καλό θα ήταν να ελέγξουμε τι συμβαίνει εκεί.

>     80489c8 !                                                                                                                
>     ....... ! offset_80489c8:                 ;xref o804892f                                                                 
>     ....... !   push    ebp                                                                                                  
>     80489c9 !   mov     ebp, esp                                                                                             
>     80489cb !   push    esi                                                                                                  
>     80489cc !   push    ebx                                                                                                  
>     80489cd !   sub     esp, 70h                                                                                             
>     80489d0 !   and     esp, 0fffffff0h                                                                                      
>     80489d3 !   push    eax                                                                                                  
>     80489d4 !   lea     ebx, [ebp-78h]                                                                                       
>     80489d7 !   push    ebx
>     80489d8 !   mov     eax, [ebp+0ch]                                                                                       
>     80489db !   push    dword ptr [eax]                                                                                      
>     80489dd !   push    3                                                                                                    
>     80489df !   call    __xstat                                                                                              
>     80489e4 !   mov     eax, [ebp-38h]                                                                                       
>     80489e7 !   mov     [ebp-18h], eax                                                                                       
>     80489ea !   mov     eax, [ebp-40h]                                                                                       
>     80489ed !   mov     [ebp-14h], eax                                                                                       
>     80489f0 !   lea     esi, [ebp-18h]                                                                                       
>     80489f3 !   mov     dword ptr [ebp-10h], 2a300h                                                                          
>     80489fa !   mov     edx, ?data_804a470                                                                                   
>     80489ff !   mov     eax, 1                                                                                               
>     8048a04 !   lock add        [edx], eax                                                                                   
>     8048a07 !   mov     dword ptr [ebp-74h], ?data_804a474                                                                   
>     8048a0e !   mov     dword ptr [ebp-6ch], 0                                                                               
>     8048a15 !   mov     dword ptr [ebp-68h], 0                                                                               
>     8048a1c !   mov     dword ptr [ebp-70h], data_804a0a8                                                                    
>     8048a23 !   mov     dword ptr [ebp-60h], 0                                                                               
>     8048a2a !   mov     dword ptr [ebp-5ch], 0                                                                               
>     8048a31 !   mov     dword ptr [ebp-64h], data_804a098                                                                    
>     8048a38 !   mov     dword ptr [ebp-54h], 0                                                                               
>     8048a3f !   mov     dword ptr [ebp-50h], 0                                                                               
>     8048a46 !   mov     dword ptr [ebp-58h], data_804a078                                                                    
>     8048a4d !   mov     dword ptr [ebp-48h], 0                                                                               
>     8048a54 !   mov     dword ptr [ebp-44h], 0                                                                               
>     8048a5b !   mov     dword ptr [ebp-4ch], data_804a088                                                                    
>     8048a62 !   mov     dword ptr [ebp-3ch], 0                                                                               
>     8048a69 !   mov     dword ptr [ebp-38h], 0                                                                               
>     8048a70 !   mov     dword ptr [ebp-40h], data_804a068                                                                    
>     8048a77 !   mov     [ebp-78h], esi                                                                                       
>     8048a7a !   mov     [esp], ebx        <---- Ο ebx είναι παράμετρος της συνάρτησης                                                                                    
>     8048a7d !   call    sub_8048bc0     <---- Η συνάρτηση στην οποία βρισκόμασταν                                                                                     
>     8048a82 !   mov     edx, [ebp-74h]

Πάνω από την call sub\_8048bc0 υπάρχει η εντολή *mov \[esp\],ebx*. Αυτή είναι ένας τρόπος να αντικαταστήσουμε την κορυφαία τιμή στο σωρό. Αντιστοιχεί με pop
\<κάπου\>, push ebx. Παρατηρήστε πιο πάνω πως η \_xstat δεν \"καθαρίζει\" το σωρό και επομένως, η τιμή που αντικαθίσταται είναι απλώς η πρώτη παράμετρος της
\_xstat, άχρηστη πια (για περισσότερες πληροφορίες περί σωρού βλ. προηγούμενο άρθρο \#1).

Και τώρα αρχίζει το μπλέξιμο\...\
Πιο πάνω:

>     80489d4 !   lea     ebx, [ebp-78h] (load effective address)

Ο ebx, δηλαδή, περιέχει τη διεύθυνση ebp-78 (είναι ένας δείκτης προς αυτή). Ας προσπαθήσουμε να βρούμε τι περιέχει αυτή η διεύθυνση. Ψάχνοντας για μια άλλη
αναφορά στην ebp-78 βρίσκουμε λίγο πριν την κλήση της συνάρτησης sub\_8048bc0:

>     8048a77 !   mov     [ebp-78h], esi

Ο καταχωρητής esi παίρνει τιμή πιο πάνω και περιέχει τη διεύθυνση της θέσης μνήμης ebp-18:

>     80489f0 !   lea     esi, [ebp-18h]                                                                                       

Σχηματικά:

![](/34/img/hands_on_stack.png)

Στη συνάρτηση sub\_8048bc0 θυμηθείτε πως η παράμετρος edi=\[ebp+8\] (που είναι το ebx της καλούσας συνάρτησης και του σχήματος) γινόταν dereferenced μια φορά
στο 8048bd7 ! mov ebx, \[edi\] οπότε και το ebx περιέχει τη διεύθυνση ebp\'-18 (με τον ebp\' να είναι ο frame pointer της προηγούμενης (καλούσας) συνάρτησης).
Μετά είχαμε τα \[ebx\] και \[ebx+8\] που αναφέρονται τελικά στο \[ebp\'-18\] και \[ebp\'-10\]. Επομένως, επιστρέφοντας τη συζήτηση στην καλούσα συνάρτηση
(ebp=ebp\'), τo άθροισμα \[ebp-18\]+\[ebp-10\] καθορίζει πότε θα λήξει το πρόγραμμα!

Στη διεύθυνση 0x80489f3 έχουμε mov dword ptr \[ebp-10h\], 2a300h δηλαδή το ένα από τα δύο μέρη του αθροίσματος έχει τη σταθερή τιμή 0x2a300=172800. Επειδή όλες
οι χρονικές συγκρίσεις γίνονται σε δευτερόλεπτα μπορούμε να υποθέσουμε πως και αυτή η τιμή είναι σε δευτερόλεπτα οπότε 172800sec=48h=2 μέρες! Το πρώτο κομμάτι
του αθροίσματος παίρνει τιμή μετά από μια κλήση στην stat. Μετά από λίγο ψάξιμο συμπεραίνουμε πως είναι η τιμή που έχει, είναι η χρονική στιγμή της τελευταίας
τροποποίησης του εκτελέσιμου αρχείου (βλέπε ασκήσεις\...).

Με λίγα λόγια λοιπόν, το πρόγραμμα διαβάζει την ώρα τελευταίας τροποποίησης του αρχείου, προσθέτει σε αυτή 2 μέρες και ελέγχει αν η τρέχουσα ώρα είναι
μεγαλύτερη από αυτό το όριο. Αν αναλογιστεί κάποιος την προστασία αυτή, συμπεραίνει πως είναι εντελώς άχρηστη :) Εκτός από το γεγονός ότι αν γυρίσουμε το ρολόι
πίσω το ληγμένο πρόγραμμα λειτουργεί ξανά, μπορούμε απλώς να κάνουμε *touch* το εκτελέσιμο ώστε να αλλάξουμε το last modification time και έτσι να επεκτείνουμε
το όριο για 2 μέρες ακόμα!

### [6.4 To patch]{#ss6.4}

Αν θέλουμε να πειράξουμε το πρόγραμμα για να λειτουργεί για πάντα (σχεδόν\...), μια επιλογή είναι να αντικαταστήσουμε την

        80489f3 !   mov     dword ptr [ebp-10h], 2a300h 
    με 
        80489f3 !   mov     dword ptr [ebp-10h], 7fffffffh (η μεγαλύτερη θετική τιμή)
    και την 
        80489e4 !   mov     eax, [ebp-38h] 
    με 
        80489e4 !   xor     eax, eax                                                                                       

Η δεύτερη αλλαγή γίνεται ώστε να μην έχουμε αρνητικό αποτέλεσμα κατά την πρόσθεση των \[ebp-10h\] και \[ebp-18h\]. Αυτό θα είχε ως συνέπεια ο έλεγχος να
αποτυγχάνει πάντα!

Αρκεί, λοιπόν, να βρούμε που στο αρχείο βρίσκεται η συγκεκριμένη εντολή. Θα μπορούσαμε να ψάξουμε το αρχείο για την ακολουθία από bytes που αποτελούν την εντολή
και μερικές άλλες γύρω της (βλέπε hands-on στο προηγούμενο τεύχος) αλλά αυτή τη φορά θα στηριχτούμε στον ELF Header. H έξοδος του objdump είναι:

>     bash$ objdump -x ./hands-on-unpacked
>
>     ./hands-on-unpacked:     file format elf32-i386
>     ./hands-on-unpacked
>     architecture: i386, flags 0x00000112:
>     EXEC_P, HAS_SYMS, D_PAGED
>     start address 0x08048918
>
>     Program Header:
>         PHDR off    0x00000034 vaddr 0x08048034 paddr 0x08048034 align 2**2
>              filesz 0x000000e0 memsz 0x000000e0 flags r-x
>       INTERP off    0x00000114 vaddr 0x08048114 paddr 0x08048114 align 2**0
>              filesz 0x00000013 memsz 0x00000013 flags r--
>         LOAD off    0x00000000 vaddr 0x08048000 paddr 0x08048000 align 2**12
>              filesz 0x00001050 memsz 0x00001050 flags r-x
>         LOAD off    0x00001050 vaddr 0x0804a050 paddr 0x0804a050 align 2**12
>              filesz 0x000002f4 memsz 0x00000430 flags rw-
>      DYNAMIC off    0x000011f8 vaddr 0x0804a1f8 paddr 0x0804a1f8 align 2**2
>              filesz 0x000000e0 memsz 0x000000e0 flags rw-
>         NOTE off    0x00000128 vaddr 0x08048128 paddr 0x08048128 align 2**2
>              filesz 0x00000020 memsz 0x00000020 flags r--
>     EH_FRAME off    0x00001014 vaddr 0x08049014 paddr 0x08049014 align 2**2
>              filesz 0x0000003c memsz 0x0000003c flags r--
>              ...

Η διεύθυνση 0x80489f3 βρίσκεται στο τρίτο segment διότι αυτό καταλαμβάνει τις διευθύνσεις 0x08048000-0x08049050 (*vaddr* μέχρι *vaddr+memsz-1*) στην οποία
ανήκει και η προηγούμενη.

>     LOAD off    0x00000000 vaddr 0x08048000 paddr 0x08048000 align 2**12
>              filesz 0x00001050 memsz 0x00001050 flags r-x

Το virtual offset της 0x80489f3 από την αρχή του segment είναι 0x80489f3-0x08048000=0x09f3. Στο αρχείο, τώρα, το segment αρχίζει από το 0 και επομένως η
διεύθυνση 0x80489f3 αντιστοιχεί στο byte offset 0 + 0x09f3=0x09f3. Απλά μαθηματικά :)

Η εντολή καταλαμβάνει 7 bytes (0x80489fa - 0x80489f3, όπου 0x8048bf0 η αρχή της επόμενης εντολής): 0xc7 0x45 0xf0 **0x00 0xa3 0x02 0x00**. Τα τονισμένα bytes
είναι η τιμή 0x0002a300 (σε little endian μορφή) τα οποία αρκεί να αντικαταστήσουμε με **0xff 0xff 0xff 0x7f**.

Ομοίως, βρίσκουμε ότι η διεύθυνση 0x80489e4 αντιστοιχεί στο byte offset 0x09e4. Η εντολή καταλαμβάνει 3 bytes: 8b 45 c8. Αντικαθιστούμε το πρώτο byte με 0x31,
το δεύτερο με 0xc0 (xor eax, eax) και τo τελευταίο με 0x90 (nop). Τώρα το εκτελέσιμο θα λειτουργεί χωρίς πρόβλημα για τα επόμενα 30 χρόνια περίπου :)

### [6.5 Ασκήσεις για το σπίτι :)]{#ss6.5}

1.  Πως φτάσαμε στο συμπέρασμα πως η εντολή *80489e7 ! mov \[ebp-18h\], eax* τοποθετεί στη διεύθυνση \[ebp-18h\] την ώρα τελευταίας τροποποίησης του
    εκτελέσιμου;
2.  Εκτός από τον χρονικό έλεγχο για την εκτύπωση του \"Ready\>\"/\"Not Ready\>\" γίνεται χρονικός έλεγχος και σε κάποιο άλλο σημείο. Που είναι αυτό και τι
    επιπτώσεις έχει στο πρόγραμμα;

Ο πηγαίος κώδικας του προγράμματος: [rce2-files/hands-on.cpp.gz](rce2-files/hands-on.cpp.gz). Το πρόγραμμα έχει γραφεί επίτηδες ώστε να χρησιμοποιεί στοιχεία
της C++ τα οποία στην προκειμένη περίπτωση δεν αποτελούν την καλύτερη, σχεδιαστικά, επιλογή. Για παράδειγμα, όλες οι μέθοδοι των κλάσεων έχουν δηλωθεί (έμμεσα)
να είναι inline και για αυτό δημιουργείται ένας μικρός χαμός στο εκτελέσιμο!


### [7. Πρόκληση]{#s7}

### [7.1 Προηγούμενη Πρόκληση (\#1) - Λύση και Hall Of Fame]{#ss7.1}

Σκοπός του προηγούμενου challenge ήταν να κάνετε authenticate. Αρχικά το πρόγραμμα διαβάζει 18 bytes από το αρχείο \"auth.key\". Αυτά αποτελούν το
authentication key.

Στην όλη διαδικασία του authentication εμπλέκονται επίσης το username, το όνομα του υπολογιστή και την έκδοση του πυρήνα. Το πρόγραμμα βρίσκει το username με
την κλήση getpwuid(getuid()). Αυτή επιστρέφει έναν δείκτη σε struct passwd, το πεδίο pw\_name της οποίας περιέχει το login name. Οι υπόλοιπες δύο πληροφορίες
βρίσκονται με την κλήση uname() που επιστρέφει πληροφορίες για το σύστημα σε μια δομή struct utsname.

Τα τρία στοιχεία συνδυάζονται για να παραχθεί ένα τελικό pass-string. Αυτό γίνεται στη συνάρτηση merge().

> ----------------------------------------------------------------------------------------------------------------------------------------------------------------
>
>     char *merge(char *u,char *n,char *v)
>     {
>         char u1[]="connor";
>         char n1[]="skynet";
>         char v1[]="tx2000";
>         int len=0;
>         char *r;
>         int i;
>
>         replace(u1,6,u);
>         Debug("New username: \'%s\'\n",u1);
>         replace(n1,6,n);
>         Debug("New nodename: \'%s\'\n",n1);
>         replace(v1,6,v);
>         Debug("New kver: \'%s\'\n",v1);
>
>         r=malloc(18+1);
>         if (r==NULL) {
>             fprintf(stderr,"Internal Error #923\n");
>             exit(1);
>         }
>
>         i=0;
>         while (i<6) {
>             r[i*3]=u1[i];
>             r[i*3+1]=n1[i];
>             r[i*3+2]=v1[i];
>             i++;
>         }
>         Debug("Final pass-phrase: \'%s\'\n",r);
>
>         return r;
>     }
>
> ----------------------------------------------------------------------------------------------------------------------------------------------------------------

Αρχικά τα strings u1, n1, v1 αντικαθίστανται με τους 6 πρώτους χαρακτήρες των username, nodename και kernel version αντίστοιχα. Αν κάποιο από τα προηγούμενα
έχει λιγότερους από 6 χαρακτήρες, αντικαθίστανται μόνο όσοι υπάρχουν. Όλα αυτά τα κάνει η replace().

Oι χαρακτήρες των strings γράφονται σε ένα καινούργιο string κατά *στήλες*. Δηλαδή, πρώτα γράφονται οι πρώτοι χαρακτήρες των u1, n1 και v1, μετά οι δεύτεροι
κτλ. Αυτό το αναδιοργανωμένο string αποτελεί το τελικό pass-string.

Τέλος, καλείται η do\_math() με παραμέτρους το authentication key και το pass-string, η οποία αποφασίζει αν είναι το κλειδί είναι εντάξει. Ο έλεγχος είναι ο
ακόλουθος. Αρχικά τα δύο strings χωρίζονται σε τρεις ομάδες των 6 bytes η κάθε μια. Κάθε ομάδα προστίθεται byte-wise με την αντίστοιχη ομάδα του άλλου string
και έτσι παράγονται τρεις αριθμοί x, y και r. Όταν γράφω byte-wise εννοώ ότι κατά την πρόσθεση των ομάδων αθροίζονται όλα τα bytes των αντίστοιχων ομάδων από τα
δύο strings ένα προς ένα (τα bytes θεωρούνται προσημασμένα):

>     1η Ομάδα            2η Ομάδα              3η Ομάδα
>     k0 k1 k2 k3 k4 k5  | k6 k7 k8 k9 k10 k11 | k12 k13 k14 k15 k16 k17
>     p0 p1 p2 p3 p4 p5  | p6 p7 p8 p9 p10 p11 | p12 p13 p14 p15 p16 p17
>
>       5                   11                    17
>     x=Σ(ki+pi)          y=Σ(ki+pi)            r=Σ(ki+pi)
>       i=0                 i=6                   i=12

Για να είναι επιτυχής ο έλεγχος θα πρέπει x\^2 + y\^2 = r\^2 με r!=0. Οι τριάδες (x,y,r) που ικανοποιούν την προηγούμενη σχέση ονομάζονται πυθαγόρειες τριάδες.
Η πιο απλή είναι η (3,4,5).

Εμείς γνωρίζουμε τα pi και ψάχνουμε τα ki ώστε να ισχύουν τα παραπάνω. Αν θέσουμε ki=-pi για όλα εκτός από ένα σε *κάθε ομάδα* πχ το πρώτο, τότε x=k0+p0,
y=k6+p6, r=k12+p12 =\> k0=x-p0 k6=y-p6, k12=r-p12. Επειδή τα (x,y,r) πρέπει να είναι πυθαγόρεια τριάδα επιλέγουμε x=3, y=4, r=5. Επομένως k0=3-p0, k6=4-p6,
k12=5-p12. Και αυτό ήταν!

Παρακάτω θα βρείτε άλλους δύο key generators που είναι πιο πολύπλοκοι αλλά και πιο δημιουργικοί από αυτόν που προτείνω.

#### Hall Of Fame

Συγχαρητήρια για τη λύση και τους key generators στους:

1.  **Γιώργος Πρέκας** [Challenge \#1 Keygen](rce2-files/prekas_giorgos-rce1sol.tgz)

    > \...Το πρόγραμμα keygen είναι ένας ολοκληρωμένος key generator. Παρέχει περισσότερες δυνατότητες από όσες περιμένει κανείς από ένα key generator\...

2.  **Αντώνης Σταμπούλης** [Challenge \#1 Keygen](rce2-files/stampoulis_antonis-rce1sol.tgz)

    > \... Δουλεύει σχετικά απλά, ψάχνοντας να βρει μια πυθαγόρεια τριάδα κοντά στην περιοχή που βρίσκονται τα a, b και c που δημιουργούνται όταν το input
    > string αποτελείται από χαρακτήρες κενού (ascii 32). Μετά προσθέτει τυχαίους αριθμούς στους χαρακτήρες του input string έτσι ώστε να βγαίνουν τελικά τα
    > επιθυμητά a, b και c\...

Ο δικός μου keygen και το source αρχείο του challenge \#1 : [Challenge \#1 source](rce2-files/alf-rce1sol.tgz)

### [7.2 Πρόκληση \#2]{#ss7.2}

Αγαπητοί αναγνώστες,\
πρόσφατα στο υπόγειο των καινούργιων κτιρίων του περιοδικού μας ανακαλύφθηκε ένα κρυφό δωμάτιο. Μέσα σε αυτό βρέθηκε μια tamperproof θήκη που από ότι φαίνεται
περιέχει ένα υπολογιστικό σύστημα. Το μόνο που φαίνεται από το σύστημα είναι μια μικρή οθόνη και μια υποδοχή για rom memory modules που περιέχουν τον προς
εκτέλεση κώδικα. Ένας από τους εργαζόμενους θυμάται πως η εταιρεία που υπήρχε εδώ παλιότερα είχε ασχοληθεί με την υλοποίηση ενός πρότυπου υπολογιστικού
συστήματος τεχνολογίας RISC αλλά το project εγκαταλείφθηκε λόγω έλλειψης χρημάτων.

Δυστυχώς οι προσπάθειες μας για επικοινωνία με άτομα που πιστεύουμε πως έχουν σχέση με το εν λόγω project δεν έχουν φέρει αποτέλεσμα. Ύστερα από διεξοδικότερη
έρευνα στο κρυφό δωμάτιο ήρθε στο φως μια δισκέτα που γράφει πάνω \"RISC-Emu v0.42rox\" και από ότι φαίνεται περιέχει και έναν emulator του επεξεργαστή.
Εικάζεται πως αυτός είχε χρησιμοποιηθεί για λόγους prototyping. Τα αρχεία που βρέθηκαν στη δισκέτα βρίσκονται στο αρχείο:
[rce2-files/challenge2.tar.gz](rce2-files/challenge2.tar.gz).

Η tamperproof θήκη γράφει με μεγάλα γράμματα \"Προσοχή! Η θήκη μπορεί να ανοίξει μόνο από το ίδιο το σύστημα. Οποιαδήποτε προσπάθεια για παραβίαση θα έχει ως
αποτέλεσμα την απελευθέρωση χημικών που θα καταστρέψουν το hardware\".

Η αποστολή σας, αν την αποδεχτείτε, είναι να βρείτε έναν τρόπο να ανοιχτεί η θήκη χωρίς να προκληθεί ζημιά στο hardware. Από όσα ξέρουμε ως τώρα αυτό θα πρέπει
να γίνεται με την εισαγωγή ενός σωστού memory module. Η ανταμοιβή θα είναι πλουσιοπάροχη και θα φθάνει το ύψος των 10000 δωρεάν συνδρομών στο περιοδικό μας.

Με εκτίμηση,

        Ο Πρόεδρος

