Acquiring and Unassembling MBR and Boot codes


Abstract

Information on how the MBR and boot sectors were produced as ASCII/hex text files and on the disassembly of the program codes for presentation in the following files.

Table of Contents


Introduction

There are many ways of extracting and unassembling the MBR or boot sectors. In producing the listings, both the ASCII hex and the unassembled program code, two methods were employed. For the Windows 95a files, Norton DiskEdit was used to produce the binary files (for DEBUG unassemble) and ASCII text of the MBR and boot sectors while DEBUG was used to unassemble the program code. However the Windows 95b files were on a different computer on which Norton DiskEdit was not installed and an older version on diskette could not be run under Windows 95b. The solution was to use the DEBUG program already on the computer to produce the binary files. However DEBUG has not been upgraded to recognize the newer (beyond 8088/86) opcodes. This was overcome by transferring the binary files from DEBUG to another computer which had Microsoft Macro Assembler (MASM) 5.1 installed and CodeView was used to unassemble the program code. Another problem was that the MBR code had two breaks resulting in 3 code segments that had to be unassembled separately. See MASM section.

Norton DiskEdit

The MBR and OS Boot sectors can be looked at and saved as binary files, which contain a copy of these sectors, or as ASCII/hex files, which contain the hex codes and ASCII equivalents, by using the Norton Utilities. In the present case, The Norton Utilities, Version 8.0, Disk Editor (DiskEdit.exe) was used for this purpose. Unfortunately the Norton Utilities, Version 8.0 doesn't have a program for disassembling program code. The DOS program DEBUG and Microsoft's MASM are examples of programs that can be used to unassemble program code and will be discussed later.

Getting the MBR Using DiskEdit

The MBR record in hex and ASCII as presented in the above documents as well as a copy of the MBR in binary that was used to create the unassembled listing were obtained using The Norton Utilities, Version 8.0, Disk Editor (DiskEdit.exe).

In DiskEdit, select Object, then Physical Sector... and set Cylinder = 0, Side = 0, Sector = 1 and Number of Sectors = 1.

The MBR should now be loaded and can be viewed as Partition Table or as Hex.

To obtain a copy of the MBR as a binary file (duplicate copy of MBR):

To obtain a copy of the MBR as an ASCII file:

Getting the Boot Sector Using DiskEdit

Same steps as the section on the MBR Getting the MBR Using DiskEdit except that the proper Cylinder, Side and Sector numbers for the boot sectors need to be used. The first boot sector is usually at Cylinder = 0, Side = 1, and Sector = 1. After selecting the proper physical sector and setting Number of Sectors = 1, the boot sector should now be loaded and can be viewed as Boot Record or as Hex. In this case the output files will be called BOOT_BIN.TXT and BOOT_ASC.TXT.

Go back to the Table of Contents.

DEBUG

Most PCs with a Microsoft OS have the DOS program DEBUG.EXE (DEBUG.COM in older versions, and can be found in C:\DOS or C:\WINDOWS\COMMAND or possibly in one of the CAB files on CD). DEBUG is a powerful but unfriendly program that can load, display and alter any file (or even physical disk sector). It can also be used to assemble and unassemble code, that is translate assembly language instructions into machine language and machine language into assembly language instructions, as well as trace through the code and enable the user to display results. It can even be used to send or receive data from a port (the keyboard, display, printer, etc. are ports as well as the CMOS). DEBUG commands used below are summarized in the section DEBUG Command Summary below.

Getting the MBR Using DEBUG

From a DOS command line, either from DOS or an MS-DOS Prompt in Windows, navigate to the desired directory where you want the file to be written. This is only to make it easy to type in the filename without having to type in the entire path name. Then start DEBUG by typing DEBUG on the command line. Alternatively one could start Debug by giving the filename on the command line (i.e. DEBUG D:\MBR.BIN) and then skipping the name command (-N MBR.BIN) in the script file. The script below will write the output file to D:\MBR.BIN which has a .BIN extension to note that it is a binary file but do not use a .COM or other executable extension since we do not want to accidentally execute the file. It should be obvious from the script that by changing the Cylinder, Head and sector numbers that any physical sector on a hard drive could be accessed (within the limits imposed by use of the standard Int 13 functions) or the script could be altered to use Int 13 extensions to access sectors on larger drives. Both the MBR and OS boot sectors can be obtained together if the number of sectors in the script is high enough, greater than around 69, as shown below.

In the following script, the xxxx:xxxx values (from the DEBUG program) are segment:offset values in memory where the code will be written and should be ignored. After the command -G=100, DEBUG will display all the registers and flags. Following both the RBX and RCX commands, DEBUG will display the current values of the BX and CX registers and then the : prompt. After the -W 200 command, "Writing nnn bytes" is displayed and then the - prompt, where nnn is the number of bytes (in hex) as stored in the BX and CX registers. At this point all is done except to quit DEBUG with the Q command. The letters h and d after numbers denote that the numbers are in hexadecimal or decimal notation respectively. All numbers in DEBUG are hexadecimal numbers. A semicolon (;) in DEBUG indicates that the following text is a comment but be careful as this may not work in all cases. For more information on the values in the AX, BX, CX and DX registers see Int 13/AH=02h from Ralf Brown's Interrupt List.

The following line in the DEBUG script can be expanded as follows:
xxxx:xxxx MOV AX,201    ;Set AH=02 (function Read Sectors)
                        ;Set AL=01 (number of sectors to Read is 1)
and could be altered to:
xxxx:xxxx MOV AX,23F    ;Read 63 sectors, 3Fh=63d (for the entire first track)
xxxx:xxxx MOV AX,264    ;Read 100 sectors, 64h=100d
xxxx:xxxx MOV AX,27E    ;Read 126 sectors, 7Eh=126d (for the entire first two tracks)
(also see corresponding CX values in script below)

DEBUG script to load MBR sector(s) (Physical sectors).

D:\>DEBUG               (Start DEBUG program)
-A 100                  ;Assemble the following at offset 100
xxxx:xxxx MOV AX,201    ;Read 1 sector
xxxx:xxxx MOV BX,200    ;  into memory at offset 200h
xxxx:xxxx MOV CX,1      ;  from Cylinder 0, Sector 1
xxxx:xxxx MOV DX,80     ;  Head 0, on Drive # 80h (81h for 2nd drive, 82h for 3rd, etc.)
xxxx:xxxx INT 13        ;Interrupt for Disk/Diskette functions
xxxx:xxxx INT 3         ;Breakpoint instruction
                        ;Press ENTER an extra time here to return to dash prompt
-G=100                  ;Start program execution at memory offset 100h
-D 200                  ;This will display first 128 bytes of MBR - Optional
-RBX                    ;Length of file - High 2 bytes in BX register
:                       ;  Type in 0 at : prompt
-RCX                    ;Length of file - Low 2 bytes in CX register
:                       ;  Type in 200 at : prompt (200h = 512d bytes = 1 sector) or
                        ;  (7E00 for 63 sectors, C800 for 100 sectors, FC00 for 126 sectors)
-N MBR.BIN              ;Enter a name for the file
                        ;   (or MBR_nnnS.BIN where nnn is the number of sectors)
-W 200                  ;Write BX:CX bytes to filename starting at memory offset 200h
-Q                      ;Quit Debug, return to DOS command prompt

Getting the OS boot sector Using DEBUG

The following DEBUG script loads one sector, beginning at relative sector 0 (this is the volume boot sector, i.e. first OS sector on C:, D:, E:, etc. that contains the bootable code if present), from drive 2 (in DEBUG, 0 is A, 1 is B, 2 is C, etc.), into memory beginning at offset 100 in the current segment, gives a filename to hold the boot sector, sets file size and writes the boot sector as a binary file. DEBUG can then be used to produce an ASCII listing or to Unassemble the boot code as shown in subsequent DEBUG scripts. Physical sectors on the hard drive such as the MBR and extended partition sectors cannot be accessed by the following script as these are not volume records.

This will also not work for Windows XP. Instead use the above DEBUG script with 100 or 126 sectors which will acquire both the MBR and OS boot sectors together. For Windows XP, use a boot floppy disk with an older version of Windows or DOS, and the corresponding copy of DEBUG, as Windows XP will not let DEBUG access the disk. If you make an MS-DOS startup diskette in Windows XP, the DOS version on the diskette will be Windows ME (type ver on the command line) which is incompatible with the version of DEBUG in Windows XP. Also see the next section for another method of aqcuiring the OS sectors.

The first line in the DEBUG script can be expanded as follows:
-L 100 2 0 1            ;Load into memory offset 100, from drive 2, 
                         beginning at relative sector 0, 1 sector
For the entire first track (63 sectors) the first line would be:
-L 100 2 0 3F           ;Load into memory offset 100, from drive 2, 
                         beginning at relative sector 0, 63 sectors
and the length of file would be 63 * 512 bytes = 32256 bytes (7E00)
-RCX                    ;Length of file - Low 2 bytes in CX register
:                       ;  Type in 7E00 at : prompt (7E00h = 32256d bytes)

DEBUG script to load volume boot sector(s).

D:\>DEBUG               (Start DEBUG program)
-L 100 2 0 1            ;Load volume boot sector
-RBX                    ;Length of file - High 2 bytes in BX register
:                       ;  Type in 0 at : prompt
-RCX                    ;Length of file - Low 2 bytes in CX register
:                       ;  Type in 200 at : prompt (200h = 512d bytes)
-N D:\BOOT_BIN.TXT      ;Enter a name for the file
-W                      ;Write memory to filename starting at default offset 100
-Q                      ;Quit Debug, return to DOS command prompt

Getting the MBR and OS Boot Sectors Using GetSect

Feedback For The Starman's Realm mentions a GetSect program which is easier and faster than DEBUG for acquiring MBR and OS boot sectors. See that page for further info.

Go back to the Table of Contents.

Producing an ASCII/hex file using DEBUG

There is no command in DEBUG to produce an ASCII/hex listing to a file. However since the following commands display one sector in hex and ASCII, we can easily use redirection to obtain a file that contains this information. The filename BIN_FILE.TXT will be used to indicate either MBR_BIN.TXT or BOOT_BIN.TXT, which will be assumed to have already been created by any of the preceding methods.

D:\DEBUG BIN_FILE.TXT
-D 100 L 200            ;Display 200h (512d) bytes starting at memory offset 100h
-Q

If we put the following 2 lines in a file, making sure to include the Q and pressing the Enter key after the Q (or DEBUG will hang), and naming the file LIST_IN.TXT,

D 100 L 200
Q

we can use the following command:

DEBUG BIN_FILE.TXT < LIST_IN.TXT > LIST_OUT.TXT

to produce a listing of the sector in hex and ASCII, assuming that the command is given in the same directory as BIN_FILE.TXT is located.

Unassembling Program Code Using DEBUG

There is no command in DEBUG to send an unassembled listing to a file. However since the following commands display an unassembled listing for one sector on the screen, we can easily use redirection to obtain a file that contains this information. The filename BIN_FILE.TXT will be used to indicate either MBR_BIN.TXT or BOOT_BIN.TXT, which will be assumed to have already been created by any of the preceding methods.

D:\DEBUG BIN_FILE.TXT
-U 100 2FF              ;Unassemble BIN_FILE.TXT from memory offset 100 to offset 2FF
-Q

However the above commands will try to unassemble the code irrespective of whether the code contains instructions, messages or unused bytes. DEBUG assumes every byte consists of instructions. Thus using DEBUG to unassemble code is an iterative process and may have to be run several times with different memory locations to get a complete unassembled listing.

For the MBR, assuming no unused bytes within the portion containing valid code, the above commands would work fine and one would just ignore the output produced from the last 66 bytes, which consist of the partition table and the two signature bytes (55AA), and any immediately preceding 00's. Or one could use the DEBUG display (D) command to determine where the code ends by looking at the entire sector and noting where the code ends (all 00's) preceding the last 66 bytes and use that information in the Unassemble command.

For the OS boot sector, the first 3 bytes consist of a JMP instruction and a NOP instruction. The location of the remainder of the boot code is given by the JMP instruction (the BPB follows these first 3 bytes), so we can determine where to start the unassembly by using the Unassemble instruction on the first 3 bytes as follows.

D:\DEBUG BOOT_BIN.TXT
-U 100 102              ;Unassemble first 3 bytes of OS boot code

which produces:

xxxx:0100 EB3E        JMP    0140
xxxx:0102 90          NOP

where the xxxx indicates the memory segment where BOOT_BIN.TXT has been loaded. So now we can use

-U 140 2FD              ;Unassemble OS boot code from offset 140h to end of sector

to unassemble the main portion of the OS boot code, omitting the last two signature bytes (55AA). This will include the message area, which will produce meaningless instructions, but these can be ignored. Or one can use the display (D) command to determine the start of the message area and stop the unassembly at that point. Once we have determined the desired start and end points of the code, we can use that information and redirection to produce a listing of the unassembled code. See the MASM section as to why this procedure may have to be iterative.

If we put the following 2 lines in a file, making sure to include the Q and pressing the Enter key after the Q (or DEBUG will hang), and naming the file UASM_IN.TXT,

U 140 2FD
Q

we can use the following command:

DEBUG BOOT_BIN.TXT < UASM_IN.TXT > UASM_OUT.TXT

to produce a listing of the unassembled code (OS boot code for this example), assuming that the command is given in the same directory as BOOT_BIN.TXT is located.

Go back to the Table of Contents.

DEBUG Command Summary

This will just be a brief overview of DEBUG. Only those commands used in this document will be discussed. For other commands and additional information, see the references at the bottom of the page.

The DEBUG prompt is simply the hyphen (-) and a single letter command is expected. This command can be in either upper case or lower case or a mixture of both and can be followed by one or more parameters. There does not have to be a space following the single letter command so the command R CX can be written as RCX and the command D 100 can also be written as D100, d100 or d 100. After some commands, such as RCX, DEBUG will display the current value of the CX register and then the colon (:) prompt which allows the user to enter a new value, or by just pressing the Enter key to keep the current value. Except for .EXE files, DEBUG loads files so that they start at memory offset 100 (memory segment is not fixed). All numbers in DEBUG are in hex, so unless otherwise stated, this will be assumed. DEBUG can be started with or without a filename parameter (file to load or create). If DEBUG is started without a filename, then a filename will have to be given with the N command before the memory contents are written (writing to physical sectors is not discussed). The BX register should be set to 0 before writing (W) unless the file is huge (> 64K) as a large value of BX could produce a multi GB file when writing (been there, done that). The BX register holds the high 2 bytes of the file size or length (in bytes), while the CX register holds the low 2 bytes.

Assume that the following command has been given on a DOS command line, where BIN_FILE.TXT is the file we wish to use in DEBUG.

DEBUG BIN_FILE.TXT

Then the following commands are issued with the comments after the ; indicating the results of the command.

-D                 ;Displays first 128d bytes of BIN_FILE.TXT
-D                 ;Displays next 128d bytes of BIN_FILE.TXT
-D 100 L 200       ;Displays 200h (512d) bytes starting at memory offset 100h
-RCX               ;Displays value of CX register and allows value to be changed
-N XXXX.XXX        ;Name of file (XXXX.XXX) to read or write (similar to Save As)
-W                 ;Writes memory to file (BX:CX bytes starting at offset 100h)
-L 100 2 0 1       ;Loads into memory offset 100h from Drive 2 (C:) and Sector 0, 1 sector
-U 140 2FD         ;Unassembles code from memory offset 140h to offset 2FDh

-A 100             ;Assembles the following commands at offset 100h (extra Enter to stop)
xxxx:xxxx          ;   Assembly language commands entered after Segment:Offset prompt,
xxxx:xxxx          ;      one per line.

-G=100             ;Go - starts program execution at memory offset 100h
-Q                 ;Quits DEBUG

Microsoft MASM

The Windows 95b MBR and OS boot sector program codes were unassembled using Microsoft Macro Assembler (MASM) 5.1 CodeView in sequential mode. This is an old DOS version of MASM that was handy, but it worked. Many other Assemblers could also be used, especially versions that can at least handle 80386 opcodes. DEBUG, through DOS 7, will only unassemble 8088/86 instructions. However the boot programs include a few instructions, but not many, that are newer. These are PUSHA, POPA, variations of PUSH and ROR, and the operand-size override prefix (66h). This causes a mess when using DEBUG to unassemble the code (lots of DB instructions).

Unassembling Program Code Using MASM

MASM 5.1 CodeView had to be started in sequential mode in order to unassemble the entire program and send the unassembled listing to a file. The file BOOT_BIN.TXT had to be renamed to BOOT_BIN.COM as files loaded into CodeView must have a .COM or .EXE extension. MBR_BIN.TXT also was temporarily renamed to MBR_BIN.COM for the same reason. The following example shows the commands to unassemble the Windows 95b OS boot program. The CodeView prompt is the right arrow (>) shown on the extreme left. All hex numbers in the examples below are entered in the form 0x100 which is the same as 100h.

CV /T BOOT_BIN.COM    (Start CodeView in sequential mode and load OS boot code)

>U                    ;* Unassemble first 8 instructions, note beginning offset (:0100)
>T>BOOT_USM.TXT       ;* echo all output to file BOOT_USM.TXT as well as the screen
>u 0x15A 0x27D        ;* Unassemble all code from 0x15A to 0x27D
>q                    ;* Quit CodeView

The following example shows the commands to unassemble the Windows 95b MBR boot program. Note that the program code is divided up into 3 separate segments. This was determined by trial and error. The first break was due to a few unused bytes and the third code section was after the message area. See the unassembled code in Windows 95b MBR.

CV /T MBR_BIN.COM     (Start CodeView in sequential mode and load MBR boot code)

>U                    ;* Unassemble first 8 instructions, note beginning offset (:0100)
>T>MBR_USM.TXT        ;* echo all output to file MBR_USM.TXT as well as the screen
>u 0x100 0x1D9        ;* Unassemble all code from 0x100 to 0x1D9
>u 0x1E0 0x20E        ;* Unassemble all code from 0x1E0 to 0x20E
>u 0x283 0x289        ;* Unassemble all code from 0x283 to 0x289
>q                    ;* Quit CodeView

Go back to the Table of Contents.

References

On Line References

Debuggers

What doesn't seem to be addressed in any of the below references are the differences in DEBUG versions and which processor commands are supported. As far as I can tell, up through DOS 7, DEBUG only supports 8088/86 instructions.

Other References


MBR/Boot Index

Home Page

This page was created on 28 December 2000, last updated on 19 March 2010.