.
{{tag> tutoriel mbr BROUILLON}}
----
====== 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 :-( - où il ne faut pas connaître 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 =====
* Disposer des [[:sudo|droits d'administration]]
* Connaitre la numération hexadécimale.
* Connaitre le langage assembleur
* Avoir installé un assembleur/désassembleur comme le paquet [[apt>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
\\
Lors d'un démarrage en mode UEFI avec un disque GPT, le mbr (protector) ne semble quasiment pas utilisé et seul l'emplacement de l'en-tête GPT est nécessaire (unique entrée de la table des partitions du mbr protector)
===== 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 disponibles à ce stade du démarrage du PC) et je me suis servi de la liste des [[http://www.ctyme.com/intr/int.htm|interruptions]]
établies par Ralph Brown.
\\
\\
Voilà donc à quoi ressemble la chose.
\\
; Programme 16 bits chargé en 0000:7C00
00000000 EB63 jmp short 0x65
00000002 90 nop
00000003 D0
00000004 resb 1 ; mode : 0x00 pour le mode CHS, 0x01 pour le mode LBA
; Buffer pour chargement en mode CHS
00000005 resd 1 ; nombre de secteurs
00000009 resd 1 ; nombre de têtes
0000000D resd 1 ; nombre de cylindres
; Buffer pour chargement en mode LBA
00000005 resw 1 ; 0x0010 - taille paquet
00000007 resw 1 ; 0x0001 - nb blocs à transférer
00000009 resw 1 ; 0x0000
0000000B resw 1 ; 0x7000 - buffer en 0x70000000
0000000D resd 1 ; 0x00000001 - emplacement LBA du bloc à charger
00000011 resd 1 ; 0x00000000 - démarrer au bloc 0x0000000000000001
0000005A 0080 dw 0x8000 ; Emplacement de l'offset où le contenu du tampon sera copié
0000005C 01000000 dd 0x00000001 ; Adresse LBA (valeur basse) où se trouve le secteur suivant de chargement (core.img)
00000060 00000000 dd 0x00000000 ; Valeur haute du qword de l'adresse LBA
00000064 FF db 0xff ; 0xff pour le chargement de core.img sur le disque de boot, si 0x80 premier disque dur, si 0x81 deuxième...
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 - si core.img est sur un autre disque
00000087 52 push dx
00000088 BB1704 mov bx,0x417 ; adresse clavier
0000008B 802703 and byte [bx],0x3 ; teste si une touche shift est activée
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 pour les paramètres de chargement
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
000000AF 83E101 and cx,byte +0x1
000000B2 7432 jz 0xe6 ; fonctions 42h-44h, 47h et 48h non supportées
; traitement extension lba_mode
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 (1=lba_mode)
000000BD 894402 mov [si+0x2],ax ; met 0x0001 en 7c07
000000C0 C7041000 mov word [si],0x10 ; met 0x0010 en 7c05
000000C4 668B1E5C7C mov ebx,[0x7c5c] ; récupère l'emplacement (partie basse du qword) de core.img
000000C9 66895C08 mov [si+0x8],ebx ; sauvegarde cet emplacement pour le charger
000000CD 668B1E607C mov ebx,[0x7c60] ; récupère la partie haute du qword de core.img
000000D2 66895C0C mov [si+0xc],ebx ; sauvegarde
000000D6 C744060070 mov word [si+0x6],0x7000 ; adresse de segment du tampon
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 chs_mode
000000E6 B408 mov ah,0x8
000000E8 CD13 int 0x13 ; récupère les paramètres du disque (numéro maxi tête, numéro maxi secteur, numéro maxi cylindre)
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
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 ; erreur de géométrie
; Convertit adresse linéaire en tête, secteur et cylindre
00000125 66A15C7C mov eax,[0x7c5c] ; charge l'adresse LBA de l'emplacement de core.img (valeur basse qword)
00000129 6631D2 xor edx,edx ; met à zéro
0000012C 66F734 div dword [si] ; divise l'adresse LBA par le nombre de secteurs par piste
0000012F 88D1 mov cl,dl ; reste de la division = numéro secteur (commencement à 0)
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] ; compare au nombre de cylindres du disque
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
; Copie des données chargées (partie commune mode CHS ou LBA)
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:si 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) - début de core.img
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
; Chaînes 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
\\
L'emplacement de la LBA où se trouve core.img est indiquée en 5c (8 octets).
\\
Ici nous avons la LBA qui vaut 1, soit le secteur qui suit le mbr. Dans le cas d'un partitionnement GPT cet emplacement est occupé par l'en-tête GPT et n'est plus disponible pour core.img. Il faudra donc mettre l'adresse LBA de la partition bios_boot pour le boot en mode bios sur un disque GPT
\\
Le programme chargé en mémoire à l'adresse 0000:7c00 commence par l'instruction jmp short 0x65 qui saute directement à l'adresse 065
\\
\\
Différentes parties sont visibles :
\\
\\
de 065 à 095 - Routine vérifie que le boot s'effectue à partir du disque dur
\\
de 096 à 0b3 - Définit l'emplacement des paramètres de chargement du prochain secteur et le mode CHS ou LBA selon les capacités du bios
\\
de 0b4 à 0e5 - Charge le premier secteur de core.img en mode LBA (interruption bios int13/ah=42h)
\\
de 0e6 à 0f8 - Récupère les paramètres du disque et gère les erreurs
\\
de 0f9 à 124 - Sauvegarde ces paramètres dans la zone des paramètres de chargement
\\
de 125 à 15b - Convertit l'adresse LBA de core.img dans le mode CHS et charge ce secteur dans le tampon (interruption bios int13/ah=02h)
\\
de 15c à 172 - Recopie le secteur chargé à son nouvel emplacement et saute à cet emplacement (première partie de core.img, soit diskboot.img)
\\
de 173 à 187 - Affichage des messages d'erreur
\\
de 1ab à 1b0 - Affichage de caractères
\\
de 1b2 à 1b7 - Affichage des chaînes des messages d'erreurs
\\
===== Voir aussi =====
\\
* **(fr)** [[https://fr.wikipedia.org/wiki/Master_boot_record]]
* **(fr)**[[https://fr.wikipedia.org/wiki/Partition_de_disque_dur]]
* [[https://forum.ubuntu-fr.org/viewtopic.php?id=390336]] sur le forum ubuntu-fr
* **(fr)**[[https://fr.wikipedia.org/wiki/Logical_block_addressing]]
----
//Contributeurs principaux : [[:utilisateurs:Nasman]].//