Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentesRévision précédente
la_partie_executable_du_mbr [Le 05/12/2018, 11:04] Nasmanla_partie_executable_du_mbr [Le 23/04/2020, 12:49] (Version actuelle) – [Exemple de zone exécutable d'un mbr] 82.254.192.58
Ligne 1: Ligne 1:
 +.
 +{{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
 +\\
 +<note tip>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)</note>
 +===== 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
 +<code>sudo dd if=/dev/sda of=~/mbr_exec.bs bs=1 count=440</code>
 +\\
 +La deuxième opération transforme le fichier d'instruction hexadécimales en adresses, opcodes, instructions
 +\\
 +<code>ndisasm -b16 ~/mbr_exec.bs > ~/mbr_exec.asm</code>
 +\\
 +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.
 +\\
 +<code>; 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</code>
 +\\
 +<note tip>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</note>
 +\\
 +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)** [[http://fr.wikipedia.org/wiki/Master_boot_record]]
 +  * **(fr)**[[http://fr.wikipedia.org/wiki/Partition_de_disque_dur]]
 +  * [[http://forum.ubuntu-fr.org/viewtopic.php?id=390336]] sur le forum ubuntu-fr
 +  * **(fr)**[[http://fr.wikipedia.org/wiki/Logical_block_addressing]]
 +
 +
 +----
 +//Contributeurs principaux : [[:utilisateurs:Nasman]].//