Zoom Icon

User:Fego/Alla scoperta del Boot

From UIC

Alla scoperta del Boot

Contents


Fego/Alla scoperta del Boot
Author: Fego
Email: federicogorla(at)hotmail(dot)com
Website: Fego @ UIC
Date: 31/08/1990 (dd/mm/yyyy)
Level: Some skills are required
Language: Italiano
Comments: Commenti, se volete



Introduzione

In questo breve tutorial daremo uno sguardo più o meno approfondito a quella che è una delle parti fondamentali del funzionamento della macchina: IL BOOT. Andremo ad analizzare cosa succede alla pressione del tasto di avvio del PC per poi addentrarci nei processi che consentono il caricamento del Sistema Operativo. Una premessa è doverosa: il tute è destinato a newbies e a coloro che sono a digiuno di informatica, di conseguenza cercherò di spiegare ogni cosa che potrebbe risultare oscura a costo di risultare pedante ;P

Allegato anche il codice di un semplicissimo(ma davvero tanto) MasterBootCode col quale andremo a caricare del codice(a 16bit) da un altro settore del disco(floppy in questo caso) per coronare la spiegazione dei concetti teorici.

Buon divertimento :)


Tools & Files

Requisiti minimi:
Masm
Lettore Floppy Disk o una macchina virtuale
Un HexEditor
Voglia di imparare
Cervello


URL o FTP del programma


Essay

Power Me Up, Scotty!

(La citazione a Star Trek era d'obbligo...)
Bene, dovendo scegliere dove iniziare, la mia mente schematica mi suggerisce di partire dal 'very beginning'; il pulsante rotondo che campeggia sul mio case :) Vi siete mai chiesti come fa il vostro caro PC ad accendersi e a caricare il vosto amato S.O.?
Ebbene appena premuto il pulsante di accensione la scheda madre invia un segnale all'alimentatore il quale provvede a fornire la potenza necessaria all'avvio del sistema. A questo punto se tutto si e' svolto come si deve, l'alimentatore ritorna un segnale atto ad indicare la corretta erogazione della potenza e da qui in poi il comando passa alla MotherBoard (MoBo da qui in avanti).
A questo punto inizia il cosidetto POST (Power On Self Test), un programma della MoBo atto ad inizializzare i componenti principali del sistema ed a verificare che non ci siano errori hardware. I compiti del POST sono ad esempio il check della memoria, fare "l'inventario" dell'hardware presente e di consegueza nel caso trovasse altri BIOS proprietari (come quelli di una scheda video), caricarli e cedergli il controllo.
Una cosa curiosa da notare sono i BEEP che le casse della MoBo emettono all'accensione. Quello e' infatti un primitivo esempio di segnalazione d'errore che genera la MoBo nel caso qualcosa sia andato storto. Quando il suono e' uno solo significa che tutto e' OK, nel caso di altre problematiche la vostra scheda madre vi avvertirà emettendo varie combinazioni di suoni, ciscuno corrispondente all'errore in questione.
Come avrete notato, fino ad ora la nostra possibilita' di intervento è piuttosto limitata; passeremo quindi subito alla fase successiva nella quale smanettando con un po' di Assembly riusciremo ad impadronirci della macchina (ed a far danni volendo... ;p).

Il BOOT vero e proprio

Molto bene dopo le fasi di inizializzazione e verifica hardware è arrivato il momento di caricare il Sistema Operativo vero e proprio.
Ma come fa la nostra macchina a sapere da dove iniziare il suo lavoro di caricamento del software considerando che non ha ancora nulla in memoria (RAM) ne tantomeno sa come caricarci qualcosa?
Ebbene, la maggior parte dei computer di oggi è basata sull' IMB PC dei lontanti anni '70 e da esso eredita le caratteristiche della struttura di Boot. La scelta di avere un processo di Boot identico per tutte le macchine non è ovviamente casuale ma, come avviene spesso in informatica, l'avere degli standard serve a rendere più facile il compito degli sviluppatori che altrimenti dovrebbero rilasciare una versione del S.O. per ogni macchina sul quale andrebbe installato.
Per capire bene il tutto qualche informazione in più è necessaria.
Sulla nostra scheda madre è presente una piccola memoria chiamata ROM. ROM è l'acronimo di Read Only Memory che infatti sta a testimoniare come questo tipo di memoria sia disegnata apposta per contenere informazioni di sola lettura; queste informazioni sotto forma di codice eseguibile rappresentato il BIOS.
BIOS è a sua volta l'acronimo di Basic Input Output System che è il programma responsabile dei processi di inizializzazione di cui abbiamo parlato prima, POST incluso.
Il BIOS viene caricato dall'hardware della macchina alla locazione di memoria FFF0h che se ci fate caso è a Fh (16 in decimale) byte dalla fine della memoria disponibile.
Per i meno esperti di voi è il caso secondo me di spiegare un poco alcuni concetti relativi alla memoria ed alla sua gestione da parte delle architetture Intel.

Brevi cenni sulla memoria negli x86

Siccome stiamo parlando di PC derivati dall' IBM PC, ci stiamo riferendo a macchine che usano l'architettura x86, architettura basata sui processori 8086 compatibili.
Tutti i processori di questo tipo (inclusi quelli della moderna IA32) si avviano in quella che viene chiamata Real Mode. La real mode è semplicemente una delle modalità operative grazie alle quali il la CPU è in grado di operare, ed essendo una delle più semplici è stata scelta come punto di partenza sempre per motivi di (retro)compatibilià.
In questa modalità per motivi strutturali, (generalmente) la memoria possibile indirizzabile è di 1MB questo perche' un processore che opera in Real Mode utilizza un adress bus di 20bit, consentendogli quindi di accedere a 220  locazioni di memoria differenti che corrispondono ad 1048576 Byte, 1024 KB od appunto 1MB.
Un'altra cosa da notare è come venga indirizzata questa memoria tramite i registri. Vengono utilizzati infatti due tipi di registri, quelli di segmento e quelli di offset che stanno a specificare rispettivamente il segmento di memoria e l'offset all'interno di esso della locazione alla quale si vuole accedere.
Nonostante siano entrambi registri a 16bit, la loro combinazione abbinata ad alcune computazioni matematiche è in grado di produrre un indirizzo fisico ad 20bit che verrà caricato sull'adress bus.
Il procedimento piuttosto semplice è tuttavia importante per quando andremo a buttar giù del codice; una sua padronanza è quindi necessaria.

Il processo è il seguente:
il contenuto del registro di segmento viene shiftato a sinistra di 4 bit, il che equivale a moltiplicare il contenuto per 10h:

6666h << 4 = 66660h

In seguito a cio' il contenuto del registro di offset (DI) gli viene sommato:

66660h + 1234h = 67894h (mi pare... ;)

producendo così un simpatico indirizzo a 20bit. Da notare anche come svariate (4096) coppie SEG:OFF originino lo stesso indirizzo...

Organizzazione della memoria in Real Mode

Per concludere la parte teorica sulla real mode mi pare il caso di fare un po' di chiarezza sulla situazione.
Avendo detto che in R-Mode la memoria accessibile è di 1MB, può essere utile e sopratutto interessante capire come essa viene suddivisa all'avvio del PC, questo per sapere dove possiamo e non metterci le nostre mani senza far danni.
Ok quindi all'avvio del pc la nostra memoria sarà utilizzata così:

x86 Memory Map


Cosa notiamo dalla tabella? (presa da OSDev...) Le zone di memoria sicuramente utilizzabili per caricare nostro codice sono sostanzialmente 3 e sulla tabella sono indicate come Conventional Memory. Notiamo inoltre come a 7c00h venga caricato il MBR del disco da cui abbiamo bootato (concetto di MBR che approfondiremo tra poco), e che come si diceva all'inizio le routine della ROM, incluso il BIOS vengono mappate agli indirizzi piu' altri disponibili.
Dicevamo prima come il BIOS venisse caricato all'indirizzo ffff0h che pero' dista dalla fine della cosiddetta Low Memory solo 16 bytes. E' quindi possibile che tutto il codice del BIOS sia in quei 16 bytes?
La risposta e' ovviamente no infatti per motivi di compatibilita' si e' scelto di mappare a ffff0h solo un JUMP che punta al vero codice del BIOS, tutto questo perche' qualora la dimensione del codice stesso dovesse aumentare non sarebbe necessario cambiare tutti gli indirizzi ma solamente quello a cui punta quel JUMP.
Vorrei far notare inoltre ai piu' inesperti come tutti gli indirizzi espressi in esadecimale sia indirizzi FISICI, il che significa che ogni indirizzo rappresenta in realta' un OFFSET dall'inizio della memoria fisica che, come gia' detto, in RealMode e' di 1MB.
Parlando quindi di indirizzo 07C00h ci stiamo in realta' riferendo al 07C00h byte nell'array della memoria RAM.
Detto questo continuiamo col BOOT...

Booting da Disco

Siamo arrivati quindi a dover analizzare come il Sistema Operativo vero e proprio viene caricato in memoria per l'esecuzione.
Fino a questo punto siamo arrivati ad avere una macchina in funzione, che ha gia' eseguito tutti i vari test diagnostici (tra i quali anche la ricerca dei dischi) e che e' pronta per caricare il nostro OS.
Ma dove lo andra' a cercare?
Come vedete la macchina non puo' improvvisare ed e' per questo che sono state impiegate delle regole standard (sugli IBM PC) per la ricerca dei dischi da cui BOOTARE.
Non potendoselo inventare il nostro PC seguira' l'ordine da noi presumibilmente imposto della sequenza di BOOT. Da BIOS e' infatti possibile modificare l'ordine secondo le quali il BIOS stesso andra' ad effettuare uno SCAN sui nostri dischi, siano essi floppy, CD-ROM o HardDisk.
Una scelta molto comune e' quella di dare priorita' al Floppy Disk (per chi c'e' l'ha...) seguito dal lettore ottico ed infine dall'hard drive.
In questo caso il BIOS andra' alla ricerca (nel suddetto ordine) di quello che viene chiamato Master Boot Record, situato nel Cilindro 0, Testina 0, Settore 1 di ciascun disco.
Nel caso non lo trovasse un messaggio di errore verra' mostrato, ma noi analizzeremo il caso in cui sul disco sia presente un MBR valido (o settore di avvio).
Per capire dov'e' localizzato (non che c'e' ne interessi molto dal punto di vista fisico) il MBR e' necessario capire come e' strutturato un disco.

Struttura fisica di un disco

Un'immagine vale piu' di mille parole.


alt CHS



Lo so la qualita' non e' il massimo ma l'immagine mi pareva esplicativa piu' di altre.
Qualita' dell'immagine a parte, cosi' e' come si presenta internamente un disco (per chi di voi non ha mai avuto la libidine di smontarne uno e di giocare coi magneti al Neodimio...). Una serie di dischi (PLATTERS) sovrapposti sono leggibili da entrame le facciate (HEADS) indicata con 0 la prima e 1 quella dell'altro lato.
Queste HEADS vengono divise in settori circolari da questi cerchi concentrici che rappresentano le tracce (TRACKS) che a loro volta vengono divise in settori (SECTORS) ciascuno dei quali reca la minima porzione di informazione possbile (multipli di 512 bytes comunque) e che sono rappresentati dai "segmenti" staccati sui settori circolari.
Avendo detto che il MBR si trova in posizione CHS(0,0,1) stiamo dando una precisa informazione alla testina di lettura del disco che sapra' quindi dove andare a cercare le informazioni che servono al BIOS a lanciare il S.O.
Giusto per passate un po' dalla teoria alla pratica, supponiamo di avere un disco con:
2 Piatti(PLATTERS) e di conseguenza 4 Testine (HEADS)
500 TRACKS per ogni testina
32 Settori per TRACKS
Assumento inoltre che ogni settore sia di 512 bytes, il computo della dimensione totale del disco risulta essere:
500 * 4 * 32 * 512 = 32768000 bytes che sono esattamente 31,25 MB, piuttosto piccino eh?

Il MBR

Detto questo passiamo alla parte piu' software e che come tale ci interessa di piu'.
Il Master Boot Record non e' altro che il settore alla posizione CHS(0,0,1) di un disco. Essendo 1 settore, la sua dimensione non potra' essere MAI maggiore di 512 bytes, qualora lo fosse il BIOS si "rifiuterebbe" di Bootare mostrandoci l'apposito messaggio a video.
Il MBR contiene del codice cosiccome dei dati ed e' proprio questo il codice al quale, una volta caricato per convenzione all'indirizzo 07c00h, viene dato il controllo, lasciando cosi' il proseguo del processo di boot nelle nostre mani.
Infatti nulla vieta ad un programmatore di scriversi il proprio MBC (master boot code) che se propriamente posizionato all'interno di un disco verra' caricato dal BIOS.
Di MBR si parla diffusamente senza quasi mai sapere che in realta' si possono intendere due cose differenti.
Il MBR puo' essere come gia' detto il primo settore di un disco, ma puo' anche stare ad indicare il primo settore all'interno di una partizione. Questa differenza in realta' non e' cosi' abissale in quanto il compito del MBR e' comunque quello di caricare il resto del S.O., presumiblilmente un BOOT LOADER, il quale andra' a caricare il Kernel.
Detto questo urge fare un poco di chiarezza lessicale:

BOOT LOADER: il boot loader e' un programma che generalmente viene caricato in memoria dal codice sito nel MBR. Esso non soffre dunque della limitazione dei 512 byte in quanto non e' il BIOS, ma il programmatore stesso che tramite il suo MBC decide di caricare il BOOT LOADER.
In questo caso si parla di vari STAGE del boot loader; il primo e' generalmente considerato il MBR che a sua volta carica un loader che a sua volta carica il kernel.
Il processo qui descritto puo' non essere tuttavia cosi' semplice dal momento che alcuni BOOT LOADER (tipo Grub) utilizza anche degli STAGE intermedi prima di arrivare a caricare il kernel vero e proprio.

KERNEL: il Kernel e' invece il nucleo vero e proprio del sistema operativo che agisce a basso livello interfacciandosi con l'harware al fine di fornire un'implementazione piu' astratta delle funzioni harware. Su un kernel viene quasi sempre "installata" una GUI che e' responsabile di un ulteriore livello di astrazione per rendere semplice all'utente finale il controllo della macchina stessa.

Sempre per esemplificare, nei sistemi Windows basati sulla tecnologia NT, il processo di boot puo' essere schematizzato come segue:
Come gia' detto il BIOS cerca sui dischi presenti un MBR valido (cosa si intende per valido verra' chiarito successivamente).
Una volta trovato lo carica all'indirizzo fisico 7C00h e cede il controllo al codice appena caricato.
A questo punto il codice in memoria tentera' di localizzare una partizione attiva cercando nella sua Partition Table.
Trovata tale partizione ne carichera' il relativo MBR (ed ecco la seconda accezzione del MBR) sempre all'indirizzo 7C00h e ne effettuera' un JUMP di nuovo a quell'indirizzo.
A questo punto il controllo passa completamente dal BIOS al Sistema Operativo dal momento che il codice che viene eseguito da 7C00h è quello responsabile di caricare il loader vero e proprio che su Win 2k/XP e' il modulo NTLDR.
Il compito di NTLDR è appunto quello di caricare il Kernel e tutto cio' che e' Sistema Opeativo dipendente.
I concetti di Partition Table, loader e tutto cio' che e' solo stato accennato verra' debitamente spiegato nei prossimi paragrafi.

Detto questo andiamo ad analizzare le caratteristiche fondamentali del MBR affinche' ne sia agevole per noi la scrittura.

Struttura del MBR

Arrivati a questo punto andiamo ad analizzare quel piccolissimo (512bytes) pezzo di codice che pero' riveste una cruciale importanza.
La prima limitazione è come dicevamo la lunghezza: esattamente 512 bytes, non c'e' possibilita' di sgarrare!
Per fare questo ci avverremo di una simpatica direttiva del MASM che consente di specificare l'offset di un'istruzione all'interno del nostro codice.
Seconda cosa, piuttosto curiosa, e' la necessita' di terminare il nostro MBR con la signature AA55H. Questi due bytes che devono essere posizionati all'offset 1FFh, cioe' al 510 byte, servono a far capire al BIOS che quello che sta esaminando e' un MBR valido.
Nonostante la loro inutilita', e' sempre consigliato inserire questa firma anche se ho constatato come su certe macchine (virtuali e non) la loro assenza e' del tutto irrilevante...
Come dicevamo, lo standard piu' affermato al momento in fatto di MBR e' quello degli IBM PC.
Esso prevede una precisa divisione dei bytes all'interno del MBR per standardizzare il piu' possibile i processi di boot su macchine diverse.


alt Tabella MBR


Come si evince dalla tabella, la sezione completamente dedicata al nostro codice e' di appena 440 bytes.
Subito dopo di essa compare una parte molto spesso opzionale: al 440 bytes una signature del disco di 4 bytes utilizzata da Win e subito dopo 2 bytes vuoti per staccare da quella che e' la partition table del disco.
Una struttura di 64 bytes divisi in 4 membri da 16bytes identifica le partizioni presenti sul disco che, come appare chiaro, non possono essere piu' di 4.
Ogni membro della struttura definisce infatti le informazioni necessarie al BIOS per capire quale partizione bootare e tutto cio' che gli serve per localizzare il primo byte di tale partizione.

Timeout







Note Finali

Note finali e saluti....


Disclaimer

I documenti qui pubblicati sono da considerarsi pubblici e liberamente distribuibili, a patto che se ne citi la fonte di provenienza. Tutti i documenti presenti su queste pagine sono stati scritti esclusivamente a scopo di ricerca, nessuna di queste analisi è stata fatta per fini commerciali, o dietro alcun tipo di compenso. I documenti pubblicati presentano delle analisi puramente teoriche della struttura di un programma, in nessun caso il software è stato realmente disassemblato o modificato; ogni corrispondenza presente tra i documenti pubblicati e le istruzioni del software oggetto dell'analisi, è da ritenersi puramente casuale. Tutti i documenti vengono inviati in forma anonima ed automaticamente pubblicati, i diritti di tali opere appartengono esclusivamente al firmatario del documento (se presente), in nessun caso il gestore di questo sito, o del server su cui risiede, può essere ritenuto responsabile dei contenuti qui presenti, oltretutto il gestore del sito non è in grado di risalire all'identità del mittente dei documenti. Tutti i documenti ed i file di questo sito non presentano alcun tipo di garanzia, pertanto ne è sconsigliata a tutti la lettura o l'esecuzione, lo staff non si assume alcuna responsabilità per quanto riguarda l'uso improprio di tali documenti e/o file, è doveroso aggiungere che ogni riferimento a fatti cose o persone è da considerarsi PURAMENTE casuale. Tutti coloro che potrebbero ritenersi moralmente offesi dai contenuti di queste pagine, sono tenuti ad uscire immediatamente da questo sito.

Vogliamo inoltre ricordare che il Reverse Engineering è uno strumento tecnologico di grande potenza ed importanza, senza di esso non sarebbe possibile creare antivirus, scoprire funzioni malevole e non dichiarate all'interno di un programma di pubblico utilizzo. Non sarebbe possibile scoprire, in assenza di un sistema sicuro per il controllo dell'integrità, se il "tal" programma è realmente quello che l'utente ha scelto di installare ed eseguire, né sarebbe possibile continuare lo sviluppo di quei programmi (o l'utilizzo di quelle periferiche) ritenuti obsoleti e non più supportati dalle fonti ufficiali.