Contenu | Rechercher | Menus
Cette page est en cours de rédaction.
Apportez votre aide…

.


Que trouve-t-on comme programme dans le mbr

Si vous êtes arrivés sur cette page par erreur, faites demi tour sans tarder car ici se trouve l'antre de la bête :-( - et il ne faut pas connaitre la peur car vous allez découvrir les entrailles de votre machine. 8-o
Le mbr est le premier secteur du disque chargé en mémoire lors du démarrage d'un ordinateur. Il a pour fonction principale de rechercher une partition où se trouve un système d'exploitation à lancer.
Avant tout il faudra vérifier que la table des partitions est conforme - à défaut un message d'erreur sera affiché.

Pré-requis

  • Connaitre la numération hexadécimale.
  • Connaitre le langage assembleur
  • Avoir installé un assembleur/désassembleur comme le paquet nasm

Que se passe-t-il au démarrage d'un PC ?

Lors de la mise sous tension, différentes routines se mettent en place ; la première consiste à attendre que la tension de l'alimentation soit stabilisée puis des tests processeur, carte mère, barrettes de mémoire sont effectués. Ceci correspond à la séquence POST.
Vient ensuite la recherche de périphériques de démarrage selon l'ordre de boot.
Le bios charge alors le premier secteur du disque (512 octets) en mémoire vive à l'adresse 0000:7C00
Ce type d'adressage correspond au mode réel de fonctionnement d'un PC, c'est un fonctionnement en mode 16 bits.
Une fois le chargement terminé et sans erreur, l'exécution se poursuit à l'adresse 0000:7C00, et donc suit les instructions qui figurent dans le premier secteur du mbr

Comment accéder à ces informations

Nous avons vu comment afficher le contenu du mbr ; ici il faudra effectuer deux opérations :

- effectuer une copie de la partie exécutable du mbr (les 440 premiers octets) sous la forme d'un fichier
- utiliser un désassembleur pour afficher les instructions sous une forme lisibles par un humain (c'est tout relatif - à moins que je ne sois pas humain) au lieu de valeurs hexadécimales (opcodes)

Pour la première opération, on rentrera dans un terminal

sudo dd if=/dev/sda of=~/mbr_exec.bs bs=1 count=440


La deuxième opération transforme le fichier d'instruction hexadécimales en adresses, opcodes, instructions

ndisasm -b16 ~/mbr_exec.bs > ~/mbr_exec.asm


ndisasm est le désassembleur du paquet nasm, -b16 indique que le code doit être considéré comme de l'assembleur 16 bits. Le résultat est écrit dans le fichier ~/mbr_exec.asm
Le résultat brut pose problème car des chaines de texte ont été considérées comme des instructions et sont donc mal interprétées. Il faut alors procéder par tâtonnement pour les repérer (par exemple avec un éditeur hexa) et les exclure du traitement de désassemblage.
Une autre difficulté est que certaines adresses peuvent contenir, soit du code à un moment donné, soit des données (zone tampon) lorsque le code n'est plus utilisé.

Exemple de zone exécutable d'un mbr

L'exemple qui suit concerne un mbr obtenu lors de l'installation de Lucid. Lucid a été installé en mettant grub-pc dans le mbr.
J'ai effectué une analyse (partielle) du fonctionnement des différents morceaux mais des parties restent encore nébuleuses.
Le programme utilise des fonctions du bios (seules fonctions disponible à ce stade du démarrage du PC) et je me suis servi de la liste des interruptions établies par Ralph Brown.

Voilà donc à quoi ressemble la chose.

; Programme chargé en 0000:7C00
00000000  EB63              jmp short 0x65
00000002  90                nop
00000003  D0

; Buffer pour disque dur
00000004		resb 1	; 0x00
00000005		resd 1	; nombre de secteurs
00000009		resd 1	; nombre de têtes
0000000D		resd 1	; nombre de cylindres

; Buffer pour extension
(00000004		resb 1	; 0x01)
(00000005  		resw 1	; 0x0010 - taille paquet)
(00000007		resw 1	; 0x0001 - nb block à transférer)
(00000009		resw 1	; 0x0000)
(0000000B		resw 1	; 0x7000 - buffer en 0x70000000)
(0000000D		resd 1	; 0x00000001)
(00000011		resd 1	; 0x00000000 - démarrer au bloc 0x0000000000000001)

00000004  BC007C	    mov sp,0x7c00
00000007  8EC0              mov es,ax
00000009  8ED8              mov ds,ax
0000000B  BE007C            mov si,0x7c00
0000000E  BF0006            mov di,0x600
00000011  B90002            mov cx,0x200
00000014  FC                cld
00000015  F3A4              rep movsb		; copie le secteur de 7C00-7DFF en 600-7FF
00000017  50                push ax
00000018  681C06            push word 0x61c
0000001B  CB                retf		; saute en 61c (contenu ci dessous)

0000001C  FB                sti
0000001D  B90400            mov cx,0x4
00000020  BDBE07            mov bp,0x7be	; pointe sur le début de la table des partitions

00000023  807E0000          cmp byte [bp+0x0],0x0
00000027  7C0B              jl 0x34		; teste si marqueur "boot"
00000029  0F851001          jnz word 0x13d	; ni boot ni zéro
0000002D  83C510            add bp,byte +0x10	; pointe sur partition suivante
00000030  E2F1              loop 0x23		; 4 boucles pour 4 partitions
00000032  CD18              int 0x18		; appelé si pas de partition de boot
00000034  885600            mov [bp+0x0],dl
00000037  55                push bp		; sauvegarde adresse (partition de boot)
00000038  C6461105          mov byte [bp+0x11],0x5
0000003C  C6461000          mov byte [bp+0x10],0x0
00000040  B441              mov ah,0x41
00000042  BBAA55            mov bx,0x55aa
00000045  CD13              int 0x13		; installation check
00000047  5D                pop bp
00000048  720F              jc 0x59		; extension non supportée
0000004A  81FB55AA          cmp bx,0xaa55	; 
0000004E  7509              jnz 0x59		; extension non installée
00000050  F7C10100          test cx,0x1
00000054  7403              jz 0x59		; fonctions 42h-44h, 47h et 48h non supportées
00000056  FE4610            inc byte [bp+0x10]
00000059  66
0000005A  0080
0000005C  01000000          dd 0x00000001	; numéro secteur 
00000060  00000000          dd 0x00000000	;
00000064  FF                db 0xff

00000065  FA                cli
00000066  90                nop
00000067  90                nop
00000068  F6C280            test dl,0x80	; teste le bit 7 de dl (si activé=disque dur)
0000006B  7502              jnz 0x6f		; si disque dur
0000006D  B280              mov dl,0x80		; marque le périphérique comme disque dur
0000006F  EA747C0000        jmp word 0x0:0x7c74	; saute à la ligne suivante (car mbr chargé en 0000:7c00)
00000074  31C0              xor ax,ax
00000076  8ED8              mov ds,ax
00000078  8ED0              mov ss,ax
0000007A  BC0020            mov sp,0x2000	; la pile pointe sur 0000:2000
0000007D  FB                sti
0000007E  A0647C            mov al,[0x7c64]	; examine le contenu de l'adresse 7C64 (ici 0xff)
00000081  3CFF              cmp al,0xff
00000083  7402              jz 0x87
00000085  88C2              mov dl,al		; si non égal à 0xff, sauvegardé dans dl
00000087  52                push dx
00000088  BB1704            mov bx,0x417
0000008B  802703            and byte [bx],0x3
0000008E  7406              jz 0x96
00000090  BE887D            mov si,0x7d88	; pointe sur la chaine "GRUB"
00000093  E81C01            call word 0x1b2

00000096  BE057C            mov si,0x7c05	; définit une zone tampon
00000099  F6C280            test dl,0x80	; teste si disque dur
0000009C  7448              jz 0xe6		; pas disque dur
0000009E  B441              mov ah,0x41
000000A0  BBAA55            mov bx,0x55aa
000000A3  CD13              int 0x13		; installation check
000000A5  5A                pop dx
000000A6  52                push dx
000000A7  723D              jc 0xe6		; extensions non supportées
000000A9  81FB55AA          cmp bx,0xaa55
000000AD  7537              jnz 0xe6		; extension non installée

; traitement extension
000000AF  83E101            and cx,byte +0x1
000000B2  7432              jz 0xe6		; fonctions 42h-44h, 47h et 48h non supportées
000000B4  31C0              xor ax,ax		
000000B6  894404            mov [si+0x4],ax	; met zéro en 7c09 et 7c0a
000000B9  40                inc ax
000000BA  8844FF            mov [si-0x1],al	; met 1 en 7c04
000000BD  894402            mov [si+0x2],ax	; met 0001 en 7c07
000000C0  C7041000          mov word [si],0x10	; met 0x0010 en 7c05
000000C4  668B1E5C7C        mov ebx,[0x7c5c]
000000C9  66895C08          mov [si+0x8],ebx
000000CD  668B1E607C        mov ebx,[0x7c60]
000000D2  66895C0C          mov [si+0xc],ebx
000000D6  C744060070        mov word [si+0x6],0x7000
000000DB  B442              mov ah,0x42
000000DD  CD13              int 0x13		; fonction extended read
000000DF  7205              jc 0xe6		; si erreur
000000E1  BB0070            mov bx,0x7000
000000E4  EB76              jmp short 0x15c

; traitement sans extension
000000E6  B408              mov ah,0x8
000000E8  CD13              int 0x13		; récupère les paramètres du disque
000000EA  730D              jnc 0xf9		; si pas d'erreur
000000EC  F6C280            test dl,0x80
000000EF  0F84D000          jz word 0x1c3
000000F3  BE937D            mov si,0x7d93	; pointe sur la chaine "Hard Disk" 
000000F6  E98200            jmp word 0x17b

; Disque dur OK
000000F9  660FB6C6          movzx eax,dh	; numéro maxi de têtes
000000FD  8864FF            mov [si-0x1],ah	; met zéro en 7c04
00000100  40                inc ax		; nombre de têtes
00000101  66894404          mov [si+0x4],eax	; sauvegardé en 7c09
00000105  0FB6D1            movzx dx,cl		; 2bits pour cylindre+nombre max de secteurs
00000108  C1E202            shl dx,0x2		; décale de 2 bits vers la gauche
0000010B  88E8              mov al,ch		; 8 bits de poids faible n° maxi cylindre
0000010D  88F4              mov ah,dh		; 2 bits de poids fort cylindre
0000010F  40                inc ax		; nb de cylindres
00000110  894408            mov [si+0x8],ax	; sauvegardé en 7c0d
00000113  0FB6C2            movzx ax,dl		; copie le numéro maxi de secteurs (x4)
00000116  C0E802            shr al,0x2		; numéro maxi de secteurs=nb secteurs
00000119  668904            mov [si],eax	; sauvegardé
0000011C  66A1607C          mov eax,[0x7c60]
00000120  6609C0            or eax,eax		; teste si zéro
00000123  754E              jnz 0x173

; Convertit adresse linéaire en tête, secteur et cylindre
00000125  66A15C7C          mov eax,[0x7c5c]
00000129  6631D2            xor edx,edx		; met à zéro
0000012C  66F734            div dword [si]	; division numéro secteur/nb secteurs par piste
0000012F  88D1              mov cl,dl		; reste de la division=numéro secteur
00000131  31D2              xor dx,dx
00000133  66F77404          div dword [si+0x4]	; divise par le nombre de têtes - donne un nb de cylindres 
00000137  3B4408            cmp ax,[si+0x8]
0000013A  7D37              jnl 0x173		; supérieur au nombre de cylindres du disque - erreur
0000013C  FEC1              inc cl		; rajoute 1 car les n°secteurs commencent à 1
0000013E  88C5              mov ch,al		; 8 bits de poids faible n°cylindre
00000140  30C0              xor al,al
00000142  C1E802            shr ax,0x2		; décale de 2 bits à droite (les bits 6 et 7 pour poids fort cylindre)
00000145  08C1              or cl,al		; modifie les bits 7 et 6 de cl en conséquence (poids fort cylindre)
00000147  88D0              mov al,dl		; numéro de tête = reste division
00000149  5A                pop dx
0000014A  88C6              mov dh,al		; numéro de tête
0000014C  BB0070            mov bx,0x7000
0000014F  8EC3              mov es,bx
00000151  31DB              xor bx,bx		; tampon en 7000:0000
00000153  B80102            mov ax,0x201	; fonction ah=02h = lecture secteur, al=01 = 1 secteur
00000156  CD13              int 0x13		; lit un secteur
00000158  721E              jc 0x178		; erreur de lecture
0000015A  8CC3              mov bx,es

0000015C  60                pushaw
0000015D  1E                push ds
0000015E  B90001            mov cx,0x100
00000161  8EDB              mov ds,bx		; charge le segment du buffer
00000163  31F6              xor si,si		; ds:di pointe sur 7000:0000
00000165  BF0080            mov di,0x8000
00000168  8EC6              mov es,si		; es:di pointe sur 0000:8000
0000016A  FC                cld
0000016B  F3A5              rep movsw		; copie le contenu du buffer de 7000:0000-7000:01FF en 0000:8000-0000:81FF
0000016D  1F                pop ds
0000016E  61                popaw
0000016F  FF265A7C          jmp word near [0x7c5a]; saute en 0000:8000 (car 7c5a contient 8000)


00000173  BE8E7D            mov si,0x7d8e	; pointe sur la chaine "Geom"
00000176  EB03              jmp short 0x17b
00000178  BE9D7D            mov si,0x7d9d	; pointe sur la chaine "Read"
0000017B  E83400            call word 0x1b2
0000017E  BEA27D            mov si,0x7da2	; pointe sur la chaine "Error"
00000181  E82E00            call word 0x1b2
00000184  CD18              int 0x18
00000186  EBFE              jmp short 0x186	; boucle sans fin

; Chaines messages d'erreur
00000188                db "GRUB ",0
0000018E  		db "Geom",0
00000193  		db "Hard Disk",0
0000019D  		db "Read",0
000001A2		db " Error",13,10,0

; Affiche caractère
000001AB  BB0100            mov bx,0x1
000001AE  B40E              mov ah,0xe
000001B0  CD10              int 0x10		; affiche un caractère

; Affiche une chaine
000001B2  AC                lodsb
000001B3  3C00              cmp al,0x0
000001B5  75F4              jnz 0x1ab		; teste la fin de la chaine
000001B7  C3                ret


La partie qui commence à l'adresse hexa 65 est commune avec le fichier boot.img qui se trouve dans /boot/grub/
Le programme chargé en mémoire à l'adresse 0000:7c00 commence par l'instruction jmp short 0x65 qui saute directement dans la partie commune à boot.img

Différentes parties sont visibles de 004 à 01b - Routine qui recopie à une autre adresse le contenu du mbr - peut être en prévision du chargement d'un autre secteur.
de 01c à 037 - Détermine la partition de boot
de 038 à 059 - Détermine si le bios reconnait le système d'adressage LBA
de 125 à 14a - Calcule les valeurs HSC à partir de la LBA
de 14c à 158 - Charge un secteur
de 173 à 186 - Gestion des erreurs
de 1ab à 1b0 - Affichage de caractères
de 1b2 à 1b7 - Affichage des chaines des messages d'erreurs

Voir aussi



Le contenu de ce wiki est sous licence : CC BY-SA v3.0