[Also embedded in vdsutil.dll,
winsetup.dll and various other
System files; see Introduction ]
Web Presentation and Text are Copyright©2009 by Daniel B. Sedory
NOT to be reproduced in any form without Permission of the Author !
This page examines the Windows Vista MBR code. Whenever you install Windows Vista to a hard disk, even one with an existing MBR, its first sector may be overwritten with the Vista MBR code. (Note: If necessary, it will also change the Volume Boot Record of an existing Active Windows boot OS; usually found in the first partition of a PC's first hard disk.) This code is also installed on blank hard drives when using Windows Vista's Disk Management utility.
NOTE: On our Vista Install DVD (which included all the original editions: Starter, Home Basic, Home Premium, Business, Enterprise and Ultimate), all 512 bytes of this MBR (including the zero-bytes in the partition table) were found once in UPGDRIVER.DLL and twice in WINSETUP.DLL; see below for more files containing this code.
Like all other MBRs presented in this series, this MBR code could still be used to boot any OS on an x86 PC if it meets the conditions listed here*.
|IMPORTANT: One of the
first things that any PC user should do after setting up a new hard disk
(or creating a new partition with a utility such as Partition
Magic) is to make a copy of its MBR; especially if you
have more than one partition on the disk! Why? If you accidentally
overwrite this sector, or are infected by a Boot sector virus,
you may never be able to access some or even all of your disk again!
Even the most expensive HD utility might not correctly restore
the Partition Table of a multi-partitioned hard disk!|
Some advice: Save the Partition Table data on floppy disks or write it down on paper(!); it does no good to have the data you need to access your HD on the un-accessible HD itself! There are many ways you can do this... See our MBR Tools Page. Any good Disk Editor will allow you to manually enter data you've written down under an easy to use Partition Table View, or you can use a utility program, such as "MbrFix" (for Win NT/2K, XP, 2003, PE, Vista & 7; even 64-bit versions!) to save the binary data to a file on say a thumb drive, and later on restore the MBR from that saved file.
NOTE: Even though we're examining code created by a Microsoft Operating System, this MBR can also be used to start the boot process for any operating system's Boot Record on an x86-CPU based (PC) computer as long as that OS is: 1) on the Primary Master hard drive, 2) set to be the only Active partition and 3) it has a boot loader in the first sector of that partition. Most Linux OS distributions can install LILO or GRUB as a Boot Record rather than in the MBR and following sectors, so even the oldest MBR by Microsoft could still be used to boot Linux; as long as its boot code was at or under the 1024 cylinder limit that is.
Furthermore, the processor must be an 80386 or later in order to use the Win7 MBR code, since it includes the "Operand-Size Prefix" (66h which can only be executed by an 80386 or later CPU. See Code, location 0659). When certain 16-bit assembly instructions, such as PUSHA (PUSH All registers onto the Stack), are prefixed by the byte 0x66, it forces that instruction to act as if it were running in 32-bit mode. So PUSHA effectively becomes a PUSHAD instruction, pushing all the 32-bit registers onto the Stack.
Windows Vista can also boot multiple
OSs using its new console (Command Prompt) program BCDEDIT
(Boot Configuration Data Editor; "Sets properties in boot database to control boot loading") and BOOTMGR files, so for systems with multiple OSs, this would be a far more practical approach than changing the Active partition in the
MBR each time you want to boot up a different OS. If you intend to install a Linux OS, it would probably be best to do so after installing Vista, then use
the GRUB boot manager as the first boot code to load the others from. By the way, BCDEDIT, as with all programs under
Vista that can change its system files, cannot be used unless you first open the Command Prompt window in Administrator mode (you must right-click on the
icon or program name and choose to open it as Administrator). Running BCDEDIT without any switches will display a few facts about BOOTMGR and another new
program called the Windows Boot Loader (\Windows\system32\winload.exe); which is the Vista OS
Unlike all previous Windows versions, if you install Windows Vista on a hard disk with no existing partitions, the first partition will start at Absolute Sector 2048 (counting from zero; Sector 0 is where the MBR is located). This is an offset of exactly 1 Binary Megabyte (2048 * 512 = 1,048,576 bytes) into the disk. In hexadecimal, this is an offset of 100,000 hex (100000h = 1 MiB). The main reason Microsoft gave for doing this is found in their article, KB-923332; in which the number of sectors is given only in hexadecimal: 0x800 = 2048 and 0x3F = 63.
Basically, since the starting offset for many disks, including the majority of Windows XP installs, was 63 (an odd number, they chose a starting offset that should give an even number of sectors for any large-sector drive manufacturers produce. They believe it could cause performance issues on large-sector drives if there were a "misalignment" between the size of a physical sector and the partition(s). Western Digital has already begun production of such hard disks; they call them Advanced Format drives, with physical sectors 8 times the size of a 512-byte sector (8 * 512 = 4096 bytes). But even with disks using 4 KiB-sized sectors, the Windows Vista offset of 1 MiB still gives us an equivalent offset of 256 sectors (1048576/4096 or 2048/8). If Microsoft had picked an offset of any even number of sectors divisible by the size of a new large-sector, wouldn't that solve any "misalignment" issue? So why not simply pick an offset of 32, 64 or even 128 KiB? Did Microsoft really want to be sure you could continue to use your Vista OS on drives with even much larger sector sizes? Whatever their thoughts on the issue might have been, technicians working with Vista OS hard disks (on either current or future models) now have a much larger sized reserved space (1,048,576 bytes vs. 32,256 bytes) they must deal with.
So be aware of this when examining the MBR of a Vista OS disk. The typical Vista partition table (one with only a single Vista partition) will appear like this on current drive models:
=========================================================================== | B | FS TYPE | START | END | | | | F | (hex) | C H S | C H S | RELATIVE | TOTAL | =========================================================================== | * | 07 | 0 32 33 | 1023 254 63 | 2048 | 25331712 | | | 00 | 0 0 0 | 0 0 0 | 0 | 0 | | | 00 | 0 0 0 | 0 0 0 | 0 | 0 | | | 00 | 0 0 0 | 0 0 0 | 0 | 0 | =========================================================================== Figure 1.
The "RELATIVE" offset of the first partition is 2048 sectors; instead of the usual 63. For technicians, it may take some time getting used to seeing a Starting CHS triple of 0,32,33 instead 0,1,1. These values will also appear strange in a disk editor (as show below) where the hex equivalents of the Head and Sector values are 20h and 21h; the whole entry appearing as: "80 20 21 00 07 FE FF FF 00 08 00 00 00 88 82 01". This offset of 2048 sectors was chosen to ensure no matter how large sector sizes would become, the OS would still be aligned evenly with a disk's sectors. For example, Western Digital's "Advanced Format" disks have a sector size of 4096 bytes (8 times larger than current 512 bytes/sector disks). On a '4 KiB' Advanced Format disk, Vista's sector offset will be 256 sectors. Thus, Vista and Windows 7 would still be aligned correctly if they were installed on disks having sector sizes of 8,192-bytes (a 128-sector offset) or even 16,384-bytes (a 64-sector offset).
We did, however, find a very useful new feature in Windows Vista related to boot records and booting: Its Disk Management utility now has the ability to both shrink and expand partitions; just like Partition Magic can do for previous Windows versions. We'll be presenting a detailed page about this in the future.
This page examines the MBR code most likely to be found in a Microsoft® Windows Vista OS installation. Vista's various editions, such as Home Premium or Ultimate, all contain the same exact MBR code. When partitioning a disk without an MBR sector, this code will be written to Cylinder 0, Head 0, Sector 1 of the Hard Drive by various OS routines, such as Vista's Disk Management utility. But even in the case of a drive that already has a functioning Windows MBR, the Vista install DVD will overwrite the existing MBR code of the boot disk as part of the process. [As with XP, Vista itself will write data to an existing MBR sector (e.g., of a slave drive connected to the system), when necessary (compare Disk Signature comments for the Windows XP MBR).]
For our Windows Vista install, all the bytes of the Vista MBR's code were also contained inside the following files (listed by location, alphabetically; with offset to first byte of the code). In each case, there will be a full 512 bytes that comprise the MBR code (the location for the NT Disk Signature and the 64-byte Partition Table are all zero-filled, the last two bytes being 55h followed by AAh):
1. C:\Windows\System32\vdsutil.dll [Offset: 1A0C8h]
("Virtual Disk Service Utility Library"; File version: "6.0.6000.16386 (vista_rtm.061101-2205)"; 114,688 bytes; Modification Date: "11/02/2006 2:46 AM"). There's also a second copy here: C:\Windows\winsxs\x86_microsoft-windows-virtualdiskservice_31bf3856ad364e35_6.0.6000.16386_none_68b410a3fdc38b65\vdsutil.dll.
2. C:\Windows\System32\vssapi.dll [Offset: E6350h]
("Volume Shadow Copy Requestor/Writer Services API DLL"; File version: "6.0.6000.16386 (vista_rtm.061101-2205)"; 994,816 bytes; Modification Date: "11/02/2006 2:46 AM").
There's also a second copy here: C:\Windows\winsxs\x86_microsoft-windows-vssapi_31bf3856ad364e35_6.0.6000.16386_none_d2b01c5484d69a7a\vssapi.dll
3. C:\Windows\System32\VSSVC.exe [Offset: CD0A0h]
("Volume Shadow Copy Service"; File version: "6.0.6000.16386 (vista_rtm.061101-2205)"; 924,160 bytes; Modification Date: "11/02/2006 2:45 AM").
There's also a second copy here: C:\Windows\winsxs\x86_microsoft-windows-vssservice_31bf3856ad364e35_6.0.6000.16386_none_58960c7b1aec62f3\VSSVC.exe
4. C:\Windows\System32\wbengine.exe [Offset: 7FA00h]
("Block Level Backup Engine Service EXE"; File version: "6.0.6000.16386 (vista_rtm.061101-2205)"; 562,176 bytes; Modification Date: "11/02/2006 5:34 AM").
There's also a second copy here: C:\Windows\winsxs\x86_microsoft-windows-blb-engine-main_31bf3856ad364e35_6.0.6000.16386_none_e1ab33fc02d4d805\wbengine.exe.
5. C:\Windows\System32\oobe\winsetup.dll [Twice. Offsets: 12D0B8h and 1302E0h]
("Windows System Setup"; File version: "6.0.6000.16386 (vista_rtm.061101-2205)"; 1,374,208 bytes; Modification Date: "11/02/2006 2:46 AM").
There's also a second copy here: C:\Windows\winsxs\x86_microsoft-windows-setup-component_31bf3856ad364e35_6.0.6000.16386_none_2ff5bc52b05737c3\winsetup.dll.
Using the file "C:\Windows\System32\oobe\winsetup.dll" of "1,374,208 bytes" with a Modification Date of "Thursday, November 02, 2006, 2:46:13 AM" as an example, the second of the two Vista MBRs in this file was found at offsets 1302E0h through 1304D5Fh (of which only the last 96 bytes are shown here):
Figure 2. Showing the bytes "62 7A 99"which are part of the Vista MBR's code.
The following is a disk editor view of how the bytes of this MBR are stored on a hard disk's first sector; that's Absolute (or Physical) Sector 0, or CHS 0,0,1. (See Examination of the Code below to find out where this data ends up in Memory when it's executed.)
Absolute Sector 0 (Cylinder 0, Head 0, Sector 1) 0 1 2 3 4 5 6 7 8 9 A B C D E F 0000 33 C0 8E D0 BC 00 7C 8E C0 8E D8 BE 00 7C BF 00 3.....|......|.. 0010 06 B9 00 02 FC F3 A4 50 68 1C 06 CB FB B9 04 00 .......Ph....... 0020 BD BE 07 80 7E 00 00 7C 0B 0F 85 10 01 83 C5 10 ....~..|........ 0030 E2 F1 CD 18 88 56 00 55 C6 46 11 05 C6 46 10 00 .....V.U.F...F.. 0040 B4 41 BB AA 55 CD 13 5D 72 0F 81 FB 55 AA 75 09 .A..U..]r...U.u. 0050 F7 C1 01 00 74 03 FE 46 10 66 60 80 7E 10 00 74 ....t..F.f`.~..t 0060 26 66 68 00 00 00 00 66 FF 76 08 68 00 00 68 00 &fh....f.v.h..h. 0070 7C 68 01 00 68 10 00 B4 42 8A 56 00 8B F4 CD 13 |h..h...B.V..... 0080 9F 83 C4 10 9E EB 14 B8 01 02 BB 00 7C 8A 56 00 ............|.V. 0090 8A 76 01 8A 4E 02 8A 6E 03 CD 13 66 61 73 1E FE .v..N..n...fas.. 00A0 4E 11 0F 85 0C 00 80 7E 00 80 0F 84 8A 00 B2 80 N......~........ 00B0 EB 82 55 32 E4 8A 56 00 CD 13 5D EB 9C 81 3E FE ..U2..V...]...>. 00C0 7D 55 AA 75 6E FF 76 00[E8 8A 00 0F 85 15 00 B0 }U.un.v......... 00D0 D1 E6 64 E8 7F 00 B0 DF E6 60 E8 78 00 B0 FF E6 ..d......`.x.... 00E0 64 E8 71 00 B8 00 BB CD 1A 66 23 C0 75 3B 66 81 d.q......f#.u;f. 00F0 FB 54 43 50 41 75 32 81 F9 02 01 72 2C 66 68 07 .TCPAu2....r,fh. 0100 BB 00 00 66 68 00 02 00 00 66 68 08 00 00 00 66 ...fh....fh....f 0110 53 66 53 66 55 66 68 00 00 00 00 66 68 00 7C 00 SfSfUfh....fh.|. 0120 00 66 61 68 00 00 07 CD 1A]5A 32 F6 EA 00 7C 00 .fah.....Z2...|. 0130 00 CD 18 A0 B7 07 EB 08 A0 B6 07 EB 03 A0 B5 07 ................ 0140 32 E4 05 00 07 8B F0 AC 3C 00 74 FC BB 07 00 B4 2.......<.t..... 0150 0E CD 10 EB F2[2B C9 E4 64 EB 00 24 02 E0 F8 24 .....+..d..$...$ 0160 02 C3]49 6E 76 61 6C 69 64 20 70 61 72 74 69 74 ..Invalid partit 0170 69 6F 6E 20 74 61 62 6C 65 00 45 72 72 6F 72 20 ion table.Error 0180 6C 6F 61 64 69 6E 67 20 6F 70 65 72 61 74 69 6E loading operatin 0190 67 20 73 79 73 74 65 6D 00 4D 69 73 73 69 6E 67 g system.Missing 01A0 20 6F 70 65 72 61 74 69 6E 67 20 73 79 73 74 65 operating syste 01B0 6D 00 00 00 00 62 7A 99 D4 34 A0 2E 00 00 80 20 m....bz..4..... 01C0 21 00 07 FE FF FF 00 08 00 00 00 88 82 01 00 00 !............... 01D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 01E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 01F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 AA ..............U. 0 1 2 3 4 5 6 7 8 9 A B C D E F
The first 354 bytes (000h through 161h) of this 512-byte sector are executable code and the next 80 bytes (162h through 1B1h) contain error messages. The last 66 bytes of the sector contain the 64-byte Partition Table (1BEh through 1FDh); data in the Table area will depend upon the size, structure and file systems on each hard disk. [See our pages on Partition Tables, for notes on how to interpret the data in your own partition tables.] The sector ends with the Word-sized signature ID of AA55h (sometimes called the MBR's Magic number). Note: On PCs using an Intel (or x86 compatible) CPU, hex Words are stored with the Low-byte first and the High-byte last.
The programmers of this MBR had to use almost every bit of space available, because all 110 bytes of the code shown between brackets in Figure 3 (offsets C8h through 128h and offsets 155h through 161h) are either related to, or directly involved in, determining if the hardware supports TPM (Trusted Platform Module) version 1.2; which can then be used to provide extra functionality for Vista's BitLocker™ Drive Encryption. The letters "TCPA"at offsets F1h through F4h are not coincidental; they stand for "Trusted Computing Platform Alliance" and are part of the code which tests for the existence of a TPM chip (see comments below).
The remaining 12 bytes (between the Error Messages and the Partition Table; 1B2h through 1BDh) begin with only three zero-bytes as padding; followed by the three bytes (62 7A 99) at 1B5h through 1B7h for a Vista install with English messages (see below for all the details about this). If you stop the installation before any NT-type Operating Systems starts to boot-up, the next four bytes may remain as they were; usually zero-bytes. But once Windows has begun running, it will write a Disk Signature in the MBR. These four bytes from offsets 1B8h through 1BBh are called the Windows Disk Signature or NT Drive Serial Number. See here for details on Disk Signature use in the Windows XP Registry!
The three bytes at offsets 1B5h through 1B7h ("62 7A 99") are used by Microsoft Windows for a very specific purpose; for English versions of Windows Vista, you'll always see these same Hex values ("62 7A 99") in the MBR. They're used by the MBR code to display Error Messages on your screen. But for those using Windows Vista in a different language, their MBRs may have different values in the second and third bytes depending upon how many characters are in each of the three messages. If you look in the code section below, starting at offset 0733h (instruction: "MOV AL,[07B7]"), you'll see these three bytes are used to reference the offset in Memory of the first byte of each Error Message that can be displayed on screen at boot up: 0762h, 077Ah and 0799h. Since the code portion above the messages will always be the same, the first offset (0762h) will never change no matter what languages (and string lengths) are used.
Now that you know what the bytes at offsets 1B5h through 1B7h are used for, you could change these error messages to display whatever you wish (as long as they all fit into the space between offsets 162h and 1B4h) by counting their character lengths and using a disk editor on the MBR sector to make the appropriate changes.
After executing the POST (Power-On Self Test), the BIOS loads this sector into memory at 0000:7C00 (as it does any MBR) then transfers control to this code.
But this code must first copy itself into another area
of Memory. This is necessary because the code must also load the Boot Sector
of the Active Partition into the same area of Memory that it occupies
just after being loaded! Unlike the Windows 2000/XP MBR, this code copies all 512
of its bytes to the new location, starting at: 0000:0600. Only the first three
instructions are the same as the Windows 2000/XP MBR, so keep your eyes sharp if you're
comparing the two.
You can learn a great deal about the instructions used here by obtaining the x86 Opcode Windows Help file and Ralf Brown's Interrupt List from our Intro to Assembly page.
Here's a Listing of the disassembled code (; with comments) after first being loaded into Memory at 0000:7C00 by the BIOS (all Memory locations listed below are in Segment 0000:). If you see an asterisk (*) next to an instruction, it means that MS-DEBUG can not disassemble that code.
7C00 33C0 XOR AX,AX ; Zero out the Accumulator and 7C02 8ED0 MOV SS,AX ; Stack Segment register. 7C04 BC007C MOV SP,7C00 ; Set Stack Pointer to 0000:7C00 7C07 8EC0 MOV ES,AX ; Since AX=0, zero-out Extra Segment, 7C09 8ED8 MOV DS,AX ; and zero-out Data Segment. 7C0B BE007C MOV SI,7C00 ; Source Index: Copy from here... 7C0E BF0006 MOV DI,0600 ; Destination Index: Copy to here: ; Code will begin at: 0000:0600 7C11 B90002 MOV CX,0200 ; Set up Counter (CX) to copy all ; (200h) 512 bytes of the code. 7C14 FC CLD ; Clear Direction Flag 7C15 F3 REP ;/ REPeat the following MOVSB ;| instruction for 'CX' times; 7C16 A4 MOVSB ;\ copying one byte at a time. ; Note: Some debuggers disassemble the last two instructions above as: ; REP MOVSB BYTE PTR ES:[DI], BYTE PTR DS:[SI] ; making clear the source [SI] and destination [DI] of the bytes being copied. ; CX will count down from 200h to zero while DI increases in step up to 800h. 7C17 50 PUSH AX ; Set up Segment(AX) and Offset(DI) 7C18 681C06 * PUSH 061C ; for jump to 0000:061C. 7C1B CB RETF ; Use RETF to do Jump into where we ; copied all the code: 0000:061C. ; Since the preceding routine not only copies the MBR code to a new location, but ; also jumps there to continue its execution, the following addresses have been ; changed to reflect the code's actual location in memory at the time of execution. ; This next section of code tries to find an ACTIVE (i.e., bootable) entry in the ; Partition Table. The first byte of an entry indicates if it's bootable (an 80h) ; or not(a 00h); any other values in these locations means the Table is invalid! ; If none of the four entries in the Table is active, the 'Invalid' error message ; is displayed. [Microsoft MBR code prior to 2000/XP used the SI register here ; rather than BP; which can be seen at offsets 0620, 0623 and 062D below.] 061C FB STI ; Enable Interrupts 061D B90400 MOV CX,0004 ; Maximum of four entries. 0620 BDBE07 MOV BP,07BE ; Location of first entry ; in the partition table ; (see Sample Table here). 0623 807E0000 CMP BYTE PTR [BP+00],00 ; CoMPare first byte of entry at ; SS:[BP+00] to Zero. Anything from ; 80h to FFh will be less than, which means: 0627 7C0B JL 0634 ; We found a possible boot entry, so we ; check on it in more detail at 0634h 0629 0F851001 * JNZ 073D ; But if it's not zero (and greater than), ; then we have an Error! (Because we must ; have found a 01h through 79h byte.) So: ; -> "Invalid partition table" ; Otherwise, we found a zero; so we keep on 062D 83C510 ADD BP,+10 ; searching: Check the next entry ... ; (there are 10h = 16 bytes per entry) 0630 E2F1 LOOP 0623 ; Go back & check next Entry ... ; unless CL = 0 (we tried all four). 0632 CD18 INT 18 ; Checked all 4; NONE of them were bootable, ; so start ROM-BASIC (only available on some ; IBM machines!) Many BIOS simply display: ; "PRESS A KEY TO REBOOT" ; when an Interrupt 18h is executed.
Just like most of the MBR code we've studied here, if you were to load a copy of the Vista MBR with an empty partition table (or one that has no Active Boot Flag for any of its entries) as a *.bin file into MS-DEBUG (e.g., debug mbr.bin), move all the code to offset 0x0600 (-m 100 2ff 600), set the IP to 0x061C (-rip then 61c) and run it (-g; Note: Although MS-DEBUG cannot step through the code at 0x0629 since it doesn't understand instructions beyond the 8086 through 8088 processors, when you enter 'g' it will simply pass all the code it encounters to Win XP/Vista/Win7's NTVDM program; under which you are actually running DEBUG, without trying to disassemble it), you would then see the following error message on your screen:
Because NTVDM was never programmed to handle an 18h Interrupt any further than displaying this message. If you Ignore it, the NTVDM program itself might freeze; and you'd have to use Task Manager to end the DOS Prompt window.
0634 885600 MOV [BP+00],DL ; DL is already set to 80h. ; (Presumably by PC's BIOS.) 0637 55 PUSH BP ; Save Base Pointer on Stack. 0638 C6461105 MOV BYTE PTR [BP+11],05 ; Data storage for possible use ; by instructon at 069F. 063C C6461000 MOV BYTE PTR [BP+10],00 ; Used as a flag and/or counter ; for the INT13 Extensions being ; installed (see 0656 and 065B below). 0640 B441 MOV AH,41 ;/ 0642 BBAA55 MOV BX,55AA ;| 0645 CD13 INT 13 ;| INT13, Function 41h (with BX=55AAh): ;| Check for Int 13 Extensions in BIOS. ;| If CF flag cleared and [BX] changes to AA55h, they are installed; Major ;\ version is in AH: 01h=1.x; 20h=2.0/EDD-1.0; 21h=2.1/EDD-1.1; 30h=EDD-3.0. ;| CX = API subset support bitmap. If bit 0 is set (CX = 1, 3, 5, etc.; 'odd'), ;| then extended disk access functions (AH=42h-44h,47h,48h) are supported. ;\ Only if no extended support is available, will it fail TEST at 0650. 0647 5D POP BP ; Get back original Base Pointer. 0648 720F JB 0659 ; Below? If so, CF=1 (not cleared) ; so no INT 13 Ext. & do jump! 064A 81FB55AA CMP BX,AA55 ; Did contents of BX change? If 064E 7509 JNZ 0659 ; not, jump to offset 0659. 0650 F7C10100 TEST CX,0001 ; Final test for INT 13 Extensions! ; If bit 0 not set, this will fail, 0654 7403 JZ 0659 ; then we jump over next line... 0656 FE4610 INC BYTE PTR [BP+10] ; or increase [BP+10h] by one. 0659 6660 * PUSHAD ; Save all 32-bit Registers on the ; Stack in this order: eax, ecx, ; edx, ebx, esp, ebp, esi, edi. 065B 807E1000 CMP BYTE PTR [BP+10],00 ;/ CoMPare [BP+10h] to zero; 065F 7426 JZ 0687 ;\ if 0, can't use Extensions. ; The following code uses INT 13, Function 42h ("Extended Read") to read the ; first sector (VBR) of the bootable partition into Memory at location 0x7c00. ; It does this by first pushing what's called the "Disk Address Packet" onto ; the Stack in reverse order of how it will read the data, so 00h (Reserved) ; and 10h bytes are the last to be pushed onto the Stack at location 0674: ; ; Offset Size Description of DISK ADDRESS PACKET's Contents ; ------ ----- ------------------------------------------------------------ ; 00h BYTE Size of packet (10h or 18h; 16 or 24 bytes). ; 01h BYTE Reserved (00). ; 02h WORD Number of blocks to transfer (Only 1 sector for this code). ; 04h DWORD Points to -> Transfer Buffer (0000 7C00 for this code). ; 08h QWORD Starting Absolute Sector (get from Partition Table entry: ; (00000000 + DWORD PTR [BP+08]). Remember, the Partition ; Table Preceding Sectors entry can only be a max. of 32 bits! ; 10h QWORD NOT USED HERE. (EDD-3.0; optional) 64-bit flat address ; of transfer buffer; only used if DWORD at 04h is FFFF:FFFF. 0661 666800000000 * PUSH 00000000 ; Push 4 zero-bytes (32-bits) onto ; Stack to pad VBR's Starting Sector. 0667 66FF7608 * PUSH DWORD PTR [BP+08] ; Locaton of VBR Sector. 066B 680000 * PUSH 0000 ; \ 066E 68007C * PUSH 7C00 ; / Copy Sector to 0x7c00 in Memory. 0671 680100 * PUSH 0001 ; Copy only 1 sector. 0674 681000 * PUSH 0010 ; Reserved and Packet Size (16 bytes). 0677 B442 MOV AH,42 ; Function 42h. 0679 8A5600 MOV DL,[BP+00] ; Drive Number. 067C 8BF4 MOV SI,SP ; DS:SI must point to -> "Disk ; Address Packet" on Stack. 067E CD13 INT 13 ; Try to get VBR Sector from disk. ; If successful, CF (Carry Flag) is cleared (0) and AH set to 00h. ; If any errors, CF is set to 1 and AH = error code. In either ; case, DAP's block count field is set to number of blocks actually transferred. 0680 9F LAHF ; Load Status flags into AH. 0681 83C410 ADD SP,+10 ; Effectively removes all the DAP bytes ; from Stack by changing Stack Pointer. 0684 9E SAHF ; Save AH into flags register, so we do ; not change Status flags by doing so! 0685 EB14 JMP 069B ; The MBR uses the standard INT 13 "Read Sectors" function here, because ; no INT 13 Extended functions were found in the BIOS code above (065F): 0687 B80102 MOV AX,0201 ; Function 02h, read only 1 sector. 068A BB007C MOV BX,7C00 ; Buffer for read starts at 7C00. 068D 8A5600 MOV DL,[BP+00] ; DL = Disk Drive 0690 8A7601 MOV DH,[BP+01] ; DH = Head number (never use FFh). 0693 8A4E02 MOV CL,[BP+02] ; Bits 0-5 of CL (max. value 3Fh) ; make up the Sector number. 0696 8A6E03 MOV CH,[BP+03] ; Bits 6-7 of CL become highest two ; bits (8-9) with bits 0-7 of CH to ; make Cylinder number (max. 3FFh). 0699 CD13 INT 13 ; INT13, Function 02h: READ SECTORS ; into Memory at ES:BX (0000:7C00). ; Whether Extensions are installed or not, both routines end up here:
The following code is missing some comments, but all the instructions are here for you to study.
069B 6661 * POPAD ; Restore all 32-bit Registers from ; the Stack, which we saved at 0659. 069D 731C JNB 06BB 069F FE4E11 DEC BYTE PTR [BP+11] ; Begins with 05h from 0638. 06A2 0F850C00 * JNZ 06B2 ; If 0, tried 4 times! 06A6 807E0080 CMP BYTE PTR [BP+00],80 06AA 0F848A00 * JZ 0738 ; -> "Error loading ; operating system" 06AE B280 MOV DL,80 06B0 EB82 JMP 0634 06B2 55 PUSH BP 06B3 32E4 XOR AH,AH 06B5 8A5600 MOV DL,[BP+00] 06B8 CD13 INT 13 06BA 5D POP BP 06BB EB9C JMP 0659 06BD 813EFE7D55AA CMP WORD PTR [7DFE],AA55 06C3 756E JNZ 0733 ; If we don't see it, Error! ; -> "Missing operating system" 06C5 FF7600 PUSH WORD PTR [BP+00] ; Popped into DL again at 0729 ; (contains 80h if 1st drive).
(NOTE: The Windows 7 MBR made changes in its TPM code section!)
; ===================================================================== ; All of the code from 06C8 through 0728 is related to discovering if ; TPM version 1.2 interface support is operational on the system, since ; it could be used by BitLocker for validating the integrity of a PC's ; early startup components before allowing the OS to boot. The spec for ; the TPM code below states "There MUST be no requirement placed on the ; A20 state on entry to these INT 1Ah functions." (p.83) We assume here ; Microsoft understood this to mean access to memory over 1 MiB must be ; made available before entering any of the TPM's INT 1Ah functions. ; The following code is actually a method for gaining access to Memory ; locations above 1 MiB (also known as enabling the A20 address line). ; ; Each address line allows the CPU to access ( 2 ^ n ) bytes of memory: ; A0 through A15 can give access to 2^16 = 64 KiB. The A20 line allows ; a jump from 2^20 (1 MiB) to 2^21 = 2 MiB in accessible memory. But ; our computers are constructed such that simply enabling the A20 line ; also allows access to any available memory over 1 MiB if both the CPU ; and code can handle it (once outside of "Real Mode"). Note: With only ; a few minor differences, this code at 06C8-06E3 and the Subroutine at ; 0755 ff. are the same as rather old sources we found on the Net. 06C8 E88A00 CALL 0755 06CB 0F851500 * JNZ 06E4 06CF B0D1 MOV AL,D1 06D1 E664 OUT 64,AL 06D3 E87F00 CALL 0755 06D6 B0DF MOV AL,DF 06D8 E660 OUT 60,AL 06DA E87800 CALL 0755 06DD B0FF MOV AL,FF 06DF E664 OUT 64,AL 06E1 E87100 CALL 0755 ; Comments below checked with the document, "TCG PC Client Specific ; Implementation Specification For Conventional BIOS" (Version 1.20 ; FINAL/Revision 1.00/July 13, 2005/For TPM Family 1.2; Level 2), § ; 12.5, pages 85 ff. TCG and "TCG BIOS DOS Test Tool" (MSDN). 06E4 B800BB MOV AX,BB00 ; With AH = BBh and AL = 00h 06E7 CD1A INT 1A ; Int 1A -> TCG_StatusCheck 06E9 6623C0 * AND EAX,EAX ;/ If EAX does not equal zero, 06EC 753B JNZ 0729 ;\ then no BIOS support for TCG. 06EE 6681FB544350+ * CMP EBX,41504354 ; EBX must also return .. ; the numerical equivalent ; of the ASCII character string "TCPA" ("54 43 50 41") as a further ; check. (Note: Since hex numbers are stored in reverse order on PC ; media or in Memory, a TPM BIOS would put 41504354h in EBX.) 06F5 7532 JNZ 0729 ; If not, exit TCG code. 06F7 81F90201 CMP CX,0102 ; Version 1.2 or higher ? 06FB 722C JB 0729 ; If not, exit TCG code. ; If TPM 1.2 found, perform a: "TCG_CompactHashLogExtendEvent". 06FD 666807BB0000 * PUSH 0000BB07 ; Setup for INT 1Ah AH = BB, ; AL = 07h command (p.94 f). 0703 666800020000 * PUSH 00000200 ; 0709 666808000000 * PUSH 00000008 ; 070F 6653 * PUSH EBX ; 0711 6653 * PUSH EBX ; 0713 6655 * PUSH EBP ; 0715 666800000000 * PUSH 00000000 ; 071B 6668007C0000 * PUSH 00007C00 ; 0721 6661 * POPAD ; 0723 680000 * PUSH 0000 ; 0726 07 POP ES ; 0727 CD1A INT 1A ; On return, "(EAX) = Return Code as defined in Section 12.3" and
; "(EDX) = Event number of the event that was logged". ; ===================================================================== 0729 5A POP DX ; From [BP+00] at 06C5; often 80h. 072A 32F6 XOR DH,DH ; (Only DL matters) 072C EA007C0000 JMP 0000:7C00 ; Jump to Volume Boot Record code ; loaded into Memory by this MBR. 0731 CD18 INT 18 ; This instruction is prob. here to ; meet a specification of TPM v 1.2 ? ; Note: When the last character of any Error Message has been displayed on the ; screen, the instructions at offsets 0748 and 074A lock computer's execution ; into an infinite loop! You must reboot the machine. INT 10, Function 0Eh ; (Teletype Output) is used to display each character of these error messages. 0733 A0B707 MOV AL,[07B7] ; [7B7] = 99 + 700 -> 799 h 0736 EB08 JMP 0740 ; Displays: "Missing operating system" 0738 A0B607 MOV AL,[07B6] ; [7B6] = 7A + 700 -> 77A h 073B EB03 JMP 0740 ; Displays: "Error loading operating ; system" 073D A0B507 MOV AL,[07B5] ; [7B5] = 62 + 700 -> 762 h ; which will display: "Invalid ; partition table" 0740 32E4 XOR AH,AH ; Zero-out AH. 0742 050007 ADD AX,0700 ; Add 700h to offsets from above. 0745 8BF0 MOV SI,AX ; Offset of message -> Source Index Reg. 0747 AC LODSB ; Load character into AL from [SI]. 0748 3C00 CMP AL,00 ;/ Have we reached end of message ;| marker?(00) If so, then lock 074A 74FC JZ 0748 ;\ execution into infinite loop! 074C BB0700 MOV BX,0007 ; Display page 0, normal white on black ; characters. 074F B40E MOV AH,0E ;/ Teletype Output.. displays only 0751 CD10 INT 10 ;\ one character at a time. 0753 EBF2 JMP 0747 ; Go back for another character... ; ----------------------------------------------------------------------- ; SUBROUTINE - Part of A20 Line Enablement code (see 06C8 ff. above); ; This routine checks/waits for access to KB controller. ; ----------------------------------------------------------------------- 0755 2BC9 SUB CX,CX ; Sets CX = 0. 0757 E464 IN AL,64 ; Check port 64h. 0759 EB00 JMP 075B ; Seems odd, but this is how it's done. 075B 2402 AND AL,02 ; Test for only 'Bit 1' *not* set. 075D E0F8 LOOPNE 0757 ; Continue to check (loop) until ; CX = 0 (and ZF=1); it's ready. 075F 2402 AND AL,02 0761 C3 RET
Location of Error Messages and
Message Offsets in Memory
2 3 4 5 6 7 8 9 A B C D E F 0762 49 6E 76 61 6C 69 64 20 70 61 72 74 69 74 Invalid partit 0770 69 6F 6E 20 74 61 62 6C 65 00 45 72 72 6F 72 20 ion Table.Error 0780 6C 6F 61 64 69 6E 67 20 6F 70 65 72 61 74 69 6E loading operatin 0790 67 20 73 79 73 74 65 6D 00 4D 69 73 73 69 6E 67 g system.Missing 07A0 20 6F 70 65 72 61 74 69 6E 67 20 73 79 73 74 65 operating syste 07B0 6D 00 00 00 00 62 7A 99 m....bz. 0 1 2 3 4 5 6 7 8 9 A B C D E F
Location of Sample Disk Signature
and Partition Table in Memory
8 9 A B C D E F 07B8 D4 34 A0 2E 00 00 80 20 .4.."". 07C0 21 00 07 FE FF FF 00 08 00 00 00 88 82 01 00 00 !............... 07D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 07E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 07F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 AA ..............U. 0 1 2 3 4 5 6 7 8 9 A B C D E F
This is how it would be seen in a disk editor that can interpret Partition Table data:
Partition Active Starting Loc Ending Loc Relative Number of Type Boot Cyl Head Sec Cyl Head Sec sectors sectors ------------- ------ ------------ ------------- -------- --------- NTFS Yes 0 32 33 1023 254 63 2048 25331712 [Note: Cylinders and heads start counting at ZERO; sectors at 1. So, a CHS of 0,32,33 gives us 32 'full' heads of 32 x 63 = 2016 sectors; the 33rd head being only 33 sectors, for a total of: 2016 + 33 = 2049, or Absolute Sector 2048, as the sector where Vista partitions begin on a disk; 2048 sectors preceding.]
The sector must have a 'signature' of 0xAA55. It's located at the very end of the partition table (remember that low-bytes appear first and high-bytes last). The BIOS checks for the signature and if it's not there, you'll see an error message such as "Operating System not found." (The message being dependent upon the BIOS code; most PhoenixBIOS, including those modified for VMWare, display this one. But under BOCHS, you would see: "Boot failed: not a bootable disk" and on a PC using Award BIOS 6.00PG, it actually displays: DISK BOOT FAILURE, INSERT SYSTEM DISK AND PRESS ENTER.)
August 3, 2009. (03.08.09)
Updated: August 5, 2009. (05.08.09)
Updated: August 11, 2009. (11.08.09)
Updated: August 16, 2009. (16.08.09)
Updated: October 3, 2010. (03.10.10)
Updated: March 11, 2011. (11.03.11)
Last Update: May 12, 2013. (12.05.13)
You can write to me using this:
online reply form.
(It opens in a new window.)
The Starman's FREE TOOLS Page
MBR and Boot Records Index
The Starman's Realm Index Page