Apportez votre aide…
Ceci est une ancienne révision du document !
.
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.
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 droits d'administration
- 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 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 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 ; Adresse LBA où se trouve le secteur suivant de chargement (core.img) 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] ; charge l'adresse LBA de l'emplacement de core.img 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 05c à 05f - Adresse LBA de core.img
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
- http://forum.ubuntu-fr.org/viewtopic.php?id=390336 sur le forum ubuntu-fr
Contributeurs principaux : Nasman.