[ Embedded in untfs.dll,
winsetup.dll and
various other
System files; see Introduction ]
Web Presentation and Text are Copyright©2012, 2015 by Daniel B. Sedory
NOT to be reproduced in any form without Permission of the Author !
This page examines the Windows 7 OS's Volume Boot Record (VBR); which is considered to be only the first sector of the system area at the beginning of a Win 7 OS volume (thus, its alternate name: Boot Sector). The BOOTMGR Loader code, immediately following the VBR Sector, spans across the boundaries of eight more sectors: Seven full 512-byte sectors, plus 40 bytes at the beginning of the eighth sector. This structure is similar to the layout of the Windows XP VBR and its NTLDR Loader code. [Note: If you compare the Windows 7 BOOTMGR Loader code to the Vista BOOTMGR Loader (both of which have the same total number of bytes), there are 19 bytes different in the executable code. But, after examining all the differences, we found they were only in the offsets of jump instructions, which had to be adjusted due to the fact the Windows 7 Boot Sector had added 12 new bytes to its code, forcing many of the jump instructions in the BOOTMGR Loader to also change. Therefore, the source code instructions for both the Windows Vista and Windows 7 BOOTMGR Loaders are still identical.] |
Just as we urged readers of our Win 7
MBR page to make a copy of their MBR sector, you may wish to create copies of your Win 7 VBR. Though more difficult to work with;
considering all the details stored in this sector, there may come a time when you need/want to edit or replace this and other system sectors manually. Some advice: Save all the data from the BIOS Parameter Block (BPB) area of the sector somewhere apart from your main hard disk or write it down on paper(!); it does no good to have data you might need to access your OS 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, or you can use a number of utility programs to save the binary data to a file on say a thumb drive, and later on restore the VBR and other sectors from the saved file(s). |
This page examines the Windows™ 7 OS Volume Boot Record code; the code which actually tests and begins to load a Windows™ 7 operating system from within the OS volume.
For our Windows 7 install, all the code bytes of Win7's Volume Boot Record
sector were also found 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 VBR sector, but locations for the Volume Serial Number and other vital data in the BPB area are all
zero-filled in these 'template' files; the correct data being entered when the file is copied to disk by the installation program or operating system. The
last two bytes will always be a 55h followed by an AAh:
(Note: For each of the files in this list, there are also copies of them
in various folders under the C:\Windows\winsxs\ folder.)
1. C:\Windows\System32\autochk.exe [Offset: 80530h];
immediately followed by all 3,624 bytes of the BOOTMGR Loader code (beginning at offset 80730h and continuing through 81557h) plus the next 4,056
bytes (all zeros) for a total of 8,192 bytes (16 sectors).
("Auto Check Utility"; File version: "6.1.7601.17514
(win7sp1_rtm.101119-1850)"; 777,728 bytes; Modification Date: "11/20/2010 5:24 AM").
2. C:\Windows\SysWOW64\autochk.exe [Offset: 66D58h];
immediately followed by all 3,624 bytes of the BOOTMGR Loader code (beginning at offset 66F58h and continuing through 67D7Fh); again followed by 4,056
zero bytes ending at offset 68D57h; 16 sectors total.
("Auto Check Utility"; File version: "6.1.7601.17514
(win7sp1_rtm.101119-1850)"; 668,160 bytes; Modification Date: "11/20/2010 4:16 AM").
3. C:\Windows\System32\autoconv.exe [Offset: 83F30h];
immediately followed by all 3,624 bytes of the BOOTMGR Loader code (beginning at offset 84130h and continuing through 84F57h); again followed by 4,056
zero bytes ending at offset 85F2Fh; 16 sectors total.
("Auto File System Conversion Utility"; File version:
"6.1.7601.17514 (win7sp1_rtm.101119-1850)"; 793,088 bytes; Modification Date: "11/20/2010 5:24 AM").
4. C:\Windows\SysWOW64\autoconv.exe [Offset: 69970h];
immediately followed by all 3,624 bytes of the BOOTMGR Loader code (beginning at offset 69B70h and continuing through 6A997h); again followed by 4,056
zero bytes ending at offset 6B96Fh; 16 sectors total.
("Auto File System Conversion Utility"; File version:
"6.1.7601.17514 (win7sp1_rtm.101119-1850)"; 679,424 bytes; Modification Date: "11/20/2010 4:16 AM").
5. C:\Windows\System32\autofmt.exe [Offset: 7CF30h];
immediately followed by all 3,624 bytes of the BOOTMGR Loader code (beginning at offset 7D130h and continuing through 7DF57h); again followed by 4,056
zero bytes ending at offset 7EF2Fh; 16 sectors total.
("Auto File System Format Utility"; File version:
"6.1.7601.17514 (win7sp1_rtm.101119-1850)"; 763,904 bytes; Modification Date: "11/20/2010 5:24 AM").
6. C:\Windows\SysWOW64\autofmt.exe [Offset: 64938h];
immediately followed by all 3,624 bytes of the BOOTMGR Loader code (beginning at offset 64B38h and continuing through 6595Fh); followed by the 4,056
zero bytes ending at offset 66937h; 16 sectors total.
("Auto File System Format Utility"; File version:
"6.1.7601.17514 (win7sp1_rtm.101119-1850)"; 658,944 bytes; Modification Date: "11/20/2010 4:16 AM").
7. C:\Windows\System32\RelPost.exe [Offset: 148E0h];
immediately followed by all 3,624 bytes of the BOOTMGR Loader code (beginning at offset 14AE0h and continuing through 15907h); followed by the 4,056
zero bytes ending at offset 168DFh; 16 sectors total.
("Windows Diagnosis and Recovery"; File version:
"6.1.7600.16385 (win7_rtm.090713-1255)"; 173,056 bytes; Modification Date: "07/13/2009 5:39 PM").
8. C:\Windows\System32\untfs.dll [Offset: 5E7A0h];
immediately followed by all 3,624 bytes of the BOOTMGR Loader code (beginning at offset 5E9A0h and continuing through 5F7C7h); followed by the 4,056
zero bytes ending at offset 6079Fh; 16 sectors total.
("NTFS Utility DLL"; File version:
"6.1.7601.17514 (win7sp1_rtm.101119-1850)"; 403,968 bytes; Modification Date: "11/20/2010 5:27 AM").
9. C:\Windows\SysWOW64\untfs.dll [Offset: 4FC00h];
immediately followed by all 3,624 bytes of the BOOTMGR Loader code (beginning at offset 4FE00h and continuing through 50C27h); followed by the 4,056
zero bytes ending at offset 51BFFh; 16 sectors total.
("NTFS Utility DLL"; File version:
"6.1.7601.17514 (win7sp1_rtm.101119-1850)"; 346,624 bytes; Modification Date: "11/20/2010 4:21 AM").
10. C:\Windows\System32\oobe\winsetup.dll [Offset: 1EC980h];
immediately followed by all 3,624 bytes of the BOOTMGR Loader code (beginning at offset 1ECB80h and continuing through 1ED9A7h); followed by the 4,056
zero bytes ending at offset 1EE97Fh; 16 sectors total.
("Windows System Setup"; File version:
"6.1.7601.17514 (win7sp1_rtm.101119-1850)"; 2,199,040 bytes; Modification Date: "11/20/2010 5:27 AM").
Note: The code for the whole Windows 7 Boot Record Area actually spans across 9 (512-byte) sectors: This includes the Boot Sector we're examining here, plus 40 bytes in the ninth one, for a total of 4,136 bytes [40 + (512 x 8)]. And, technically, because the Boot Record area is a full 16 contiguous sectors (Sectors 0 - 15 of the Volume), even the 4,056 zero-bytes of the remaining padded area are loaded into Memory by the VBR code; see the code lines below at 07C0:00BB and following.
Like all previous MS Boot Records, the first three bytes are often called the Jump Instruction. But only the first two bytes (EB 52 in this case) are actually used to form the actual JMP (Jump) code to the rest of the executable x86 (PC) Assembly code; the third byte (90h) is just a NOP ('No Op' or do nothing) instruction. The next 8 bytes are the "OEM ID" or System Name ("NTFS" and four blank spaces) for an NTFS volume; followed by the BPB (BIOS Parameter Block).
Just like the
All the elements of a Win7 VBR's _ BPB _ area are the same as those for earlier NTFS boot records (for details on the NTFS BPB, see our NTFS Boot Record page). Just like Vista, a new Microsoft retail DVD Windows 7 OS install will have 2,048 reserved sectors at the beginning of an MBR partitioned disk, so its 100 MiB "System Reserved" partition VBR will have "00 08 00 00" (0x800 = 2048) at offsets 1Ch through 1Fh in its BPB area. In the VBR below, copied from a Windows 7 OS's C: drive, we see the bytes "00 28 03 00" shown between the brackets at those offsets (which represent 206,848 sectors; 0x32800 = 206848). This is the total of the 2048 sector offset at the beginning of the disk plus the 100 MiB size (100 MiB = 104,857,600 bytes/512-byte sectors = 204800 sectors) of that first partition (2048 + 204800 = 206848 sectors).
The following is a disk editor view of how the bytes of this VBR are stored on a hard disk in the first sector of a Windows 7 OS install's C: drive volume:
Relative Sector 0 (within the Volume) NTFS BPB "OEM ID" | | 0 1 2 3 4 5 6 7 8 9 A B C| D E F | 0000: EB 52 90 4E 54 46 53 20 20 20 20 00 02 08 00 00 .R.NTFS ..... 0010: 00 00 00 00 00 F8 00 00 3F 00 FF 00[00 28 03 00] ........?....... 0020: 00 00 00 00 80 00 80 00 FF CF FC 02 00 00 00 00 ..........?..... 0030: 00 00 0C 00 00 00 00 00 02 00 00 00 00 00 00 00 ................ 0040: F6 00 00 00 01 00 00 00 6B E5 F9 78 1A FA 78 EA ........k..x..x. 0050: 00 00 00 00 FA 33 C0 8E D0 BC 00 7C FB 68 C0 07 .....3.....|.h.. 0060: 1F 1E 68 66 00 CB 88 16 0E 00 66 81 3E 03 00 4E ..hf......f.>..N 0070: 54 46 53 75 15 B4 41 BB AA 55 CD 13 72 0C 81 FB TFSu..A..U..r... 0080: 55 AA 75 06 F7 C1 01 00 75 03 E9 DD 00 1E 83 EC U.u.....u....... 0090: 18 68 1A 00 B4 48 8A 16 0E 00 8B F4 16 1F CD 13 .h...H.......... 00A0: 9F 83 C4 18 9E 58 1F 72 E1 3B 06 0B 00 75 DB A3 .....X.r.;...u.. 00B0: 0F 00 C1 2E 0F 00 04 1E 5A 33 DB B9 00 20 2B C8 ........Z3... +. 00C0: 66 FF 06 11 00 03 16 0F 00 8E C2 FF 06 16 00 E8 f............... 00D0: 4B 00 2B C8 77 EF B8 00 BB CD 1A 66 23 C0 75 2D K.+.w......f#.u- 00E0: 66 81 FB 54 43 50 41 75 24 81 F9 02 01 72 1E 16 f..TCPAu$....r.. 00F0: 68 07 BB 16 68 70 0E 16 68 09 00 66 53 66 53 66 h...hp..h..fSfSf 0100: 55 16 16 16 68 B8 01 66 61 0E 07 CD 1A 33 C0 BF U...h..fa....3.. 0110: 28 10 B9 D8 0F FC F3 AA E9 5F 01 90 90 66 60 1E (........_...f`. 0120: 06 66 A1 11 00 66 03 06 1C 00 1E 66 68 00 00 00 .f...f.....fh... 0130: 00 66 50 06 53 68 01 00 68 10 00 B4 42 8A 16 0E .fP.Sh..h...B... 0140: 00 16 1F 8B F4 CD 13 66 59 5B 5A 66 59 66 59 1F .......fY[ZfYfY. 0150: 0F 82 16 00 66 FF 06 11 00 03 16 0F 00 8E C2 FF ....f........... 0160: 0E 16 00 75 BC 07 1F 66 61 C3 A0 F8 01 E8 09 00 ...u...fa....... 0170: A0 FB 01 E8 03 00 F4 EB FD B4 01 8B F0 AC 3C 00 ..............<. 0180: 74 09 B4 0E BB 07 00 CD 10 EB F2 C3 0D 0A 41 20 t.............A 0190: 64 69 73 6B 20 72 65 61 64 20 65 72 72 6F 72 20 disk read error 01A0: 6F 63 63 75 72 72 65 64 00 0D 0A 42 4F 4F 54 4D occurred...BOOTM 01B0: 47 52 20 69 73 20 6D 69 73 73 69 6E 67 00 0D 0A GR is missing... 01C0: 42 4F 4F 54 4D 47 52 20 69 73 20 63 6F 6D 70 72 BOOTMGR is compr 01D0: 65 73 73 65 64 00 0D 0A 50 72 65 73 73 20 43 74 essed...Press Ct 01E0: 72 6C 2B 41 6C 74 2B 44 65 6C 20 74 6F 20 72 65 rl+Alt+Del to re 01F0: 73 74 61 72 74 0D 0A 00 8C A9 BE D6 00 00 55 AA start.........U. 0 1 2 3 4 5 6 7 8 9 A B C D E F |
The last 116 bytes of this Boot Record contain Error Messages, Message Offset bytes and the Word-sized signature ID (or Magic number) of AA55h. Remember that hex Words (numerical data requiring more than a single byte) for Intel x86 CPUs are always stored in memory with the Least-Significant byte first and the Most-Significant byte last to make CPU processing quicker.
Each Error Message begins with the Hex bytes 0Dh and 0Ah; a Carriage Return and Line Feed, and ends with a 00h byte which makes these what's commonly known in various programming languages as zero-terminated or 'sz' strings (a character string followed by a single zero byte). The error messages are exactly the same as those under Windows XP, except 'NTLDR' has been replaced by "BOOTMGR".
Note that the string of letters ("TCPA") at offsets E3h through E6h are not coincidental; they stand for "Trusted Computing Platform Alliance" and are actually part of the code which tests for the existence of a TPM chip. If the hardware supports TPM (Trusted Platform Module) version 1.2, then it can be used to provide extra functionality for Win 7's BitLocker™ Drive Encryption. Neither are the bytes at offsets 6Fh through 72h a coincidence. The characters ("NTFS") are used in the code to check for an "OEM ID" of that name, and display "A disk read error occurred" if that string is not found (at offset 0003).
The eight physical sectors directly following a Windows™ 7 NTFS Boot Sector, contain code which can interface with the older NTLDR file (in order to boot up Windows NT, 2000, XP, 2003 OS partitions) plus code to interact with the new BOOTMGR (boot manager) program introduced with the Vista OS. This code is still necessary when booting up a Windows OS (even though the bootmgr or NTLDR files may have been copied to the OS partition you start booting up from; as would be the case if, for example, you installed Windows™ 7 on a disk already containing a bootable Win 98 OS in the first partition followed by a Win 7 install partition). When the code in such an altered volume boot record is executed, it will look for, and require the existence of, the Windows XP or 7/8 OS partition's system code in order to boot-up the original Windows™ 98 OS (cf. FAT32 Boot Record under Windows NT OSs).
The four bytes at offsets 1F8h through 1FBh ("8C A9 BE D6") are used by the Microsoft Windows 7 VBR for a very specific purpose; for English versions of Windows 7, you'll always see these same Hex values ("8C A9 BE D6") in your VBR. They're used by the code to display Error Messages on your screen. But for those using Windows 7 in a different language, their VBRs may have different values in the second, third and fourth bytes depending upon how many characters are in each of the messages. In the disassembled code, we'll point out where these values show up. In any case, since the code portion above the messages will always be the same, the first offset (018Ch) will never change no matter what languages (or string lengths) are used.
Now that you know what the bytes at offsets 1F8h through 1FBh 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 18Ch and 1F7h) by counting the character lengths and using a disk editor to change the appropriate bytes in the VBR sector.
After the code in your disk drive's MBR sector transfers control to this Boot Sector,
it will test critical aspects of the Win 7 operating system, then load and run the BOOTMGR Loader (or "bootstrap") code which will eventually
run the actual "bootmgr" program that finally attempts to load an operating system!
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 Windows 7 MBR code. Until noted, the instructions below are referenced to a CS (Code Segment) of 0000. If you see an asterisk (*) next to an instruction, it means MS-DEBUG can not disassemble its code; you'd only see "DB nn" displayed.
7C00 EB52 JMP 7C54 ; Jump over BPB (BIOS Parameter ; Block) to code at 7C54. 7C02 90 NOP ; 7C03 thru 7C0A 'NTFS ' 8-byte System Name or OEM ID. (Some think ; this is part of the BPB; it's not!) ; 7C0B thru 7C53 BIOS Parameter Block (BPB) Compare with XP VBR here. ; 0 1 2 3 4 5 6 7 8 9 A B C D E F 7C03 4E 54 46 53 20 20 20 20 00 02 08 00 00 NTFS ..... 7C10 00 00 00 00 00 F8 00 00 3F 00 FF 00 00 28 03 00 ........?....... 7C20 00 00 00 00 80 00 80 00 FF CF FC 02 00 00 00 00 ..........?..... 7C30 00 00 0C 00 00 00 00 00 02 00 00 00 00 00 00 00 ................ 7C40 F6 00 00 00 01 00 00 00 6B E5 F9 78 1A FA 78 EA ........k..x..x. 7C50 00 00 00 00 .... 7C54 FA CLI ; Disable maskable Interrupts. 7C55 33C0 XOR AX,AX ; Zero out both the Accumulator 7C57 8ED0 MOV SS,AX ; and Stack Segment Registers. 7C59 BC007C MOV SP,7C00 ; Set Stack Pointer to 0000:7C00 7C5C FB STI ; Enable Interrupts again. ; NOTE: The code here simply changes the Segment reference for locations in ; memory. It switches the Segment from 0000 to 07C0 when RETF is executed ; at 0000:7C65. The next instruction, at 07C0:0066, is the same location ; as linear address 0x7C66 (or, 0000:7C66). 7C5D 68C007 * PUSH 07C0 ; New segment ref. to be used for 7C60 1F POP DS ; both Data (DS = Data Segment) 7C61 1E PUSH DS ; . . . 7C62 686600 * PUSH 0066 ; and Code segments . . . 7C65 CB RETF ; after this RETF instruction.
For those of you who have taken the time to set up BOCHS to step through this code, we want to
clear-up some confusion about how the Stack is displayed in its GUI Debugger: Even though BOCHS is debugging "CPU: Real Mode 16" code, its
display always shows the 32-bit registers, eax, ebx, etc., so we mentally eliminate the upper 16 bits of the display when in 16-bit mode (we drew black
lines through those bytes in Figure 2 below). But the most confusing thing may be how values on the Stack are displayed: Always as 32 bits
even when the Memory Location Addresses count up by only 16 bits! So, you must first mentally block out the four leading zero bytes (we've used black
lines again to do so in the figure below). After that, the key to interpreting values on this Stack is knowing that it is arranged in order to show 16-bit
WORD values, but due to a PC's little-endian architecture, where the least significant byte in a numerical WORD comes first, the Memory is not only
displayed as increasing from Top to Bottom, but also from RIGHT to LEFT. Therefore, the 16-bit WORD in Memory Locations 7bfe to 7bff (which is: 0x07C0) is
referenced only by its lower byte in Memory, 7BFE, which corresponds to the byte at the RIGHT side of the WORD:
Figure 2.
So, all Code (CS) and Data (DS) Segments in the instructions which follow are in reference to Segment 07C0. This means the memory location of the next instruction is, technically: 07C0:0066 (so only the "Offsets" are shown below). Note, however, in debuggers, such as BOCHS, which use Linear Memory addressing, these would be displayed as 0x7C66 and following.
0066 88160E00 MOV DS:[000E],DL ; DL = Drive # (often 80h); see MBR code @ 727. ; Used here at 0096, 013D and in Subrtn. @ 11D. ; Since DS was set to 07C0, contents of DL register are loaded into Linear Memory address: 0x7C0E 006A 66813E03004E544653 * CMP DWORD PTR [0003],5346544E ;/ Points to -> "NTFS" at 7C03. ;| Check if NTFS Boot Record, and 0073 7515 JNZ 008A ;\ if not, display Disk read error -> 016A. ; NOTE: A Windows 7 or 8 OS must be run on a computer with INT 13 Extensions! ; ========================================================================== 0075 B441 MOV AH,41 ;/ Function 41h (with BX=55AAh): 0077 BBAA55 MOV BX,55AA ;| Checks for INT 13 Extentions 007A CD13 INT 13 ;| 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 is 'odd' number), ;| extended disk access functions (AH=42h-44h,47h,48h) are supported. ;\ So, only if _no_ extended support is available, will it fail. 007C 720C JB 008A ; If CF flag not cleared, then ; declare 'Disk error' -> 016A. 007E 81FB55AA CMP BX,AA55 ; Was [BX] changed to AA55h ? 0082 7506 JNZ 008A ; If not, 'Disk error' -> 016A. 0084 F7C10100 TEST CX,0001 ; If bit 0 of CX isn't zero ... 0088 7503 JNZ 008D ; ... we Jump to 07C0:008D. 008A E9DD00 JMP 016A ; If zero, -> 'error routine'. 008D 1E PUSH DS ; Save DS on Stack 008E 83EC18 SUB SP,+18 ; Make room for Buffer on Stack 0091 681A00 * PUSH 001A ; Size of Buffer = 1Ah = 26 bytes 0094 B448 MOV AH,48 ; Function 48h of INT 13 : ; "GET DRIVE PARAMETERS" 0096 8A160E00 MOV DL,[000E] ; Put Drive Number (usually 80h) in DL. ; (Already set at 0066; usually 80h.) 009A 8BF4 MOV SI,SP ; Put SP into SI to set up Buffer on ; the Stack for Drive Parameters. 009C 16 PUSH SS ;/ These two lines change 009D 1F POP DS ;\ DS to zero before doing INT13. 009E CD13 INT 13 ; Get Drive Parameters. +------------------------------------------------------+ | Format of INT 13, Function 48h, DRIVE PARAMETERS: | | | | Offset Size Description | | ------ ----- ------------------------------------ | | 00h WORD (CALL) Size of Buffer (1Ah for v1.x) | | (RET) Size of Returned Data | | 02h WORD Information Flags, Bitfields: | | +==================================================+ | | | Bits Description | | | | ---- ------------------------------------------| | | | 0 DMA boundary errors handled transparently | | | | 1 C/H/S Information is valid. | | | | 2 Removable Drive. | | | | 3 Write with verify supported. | | | | 4 Drive has change-line support: | | | | (Required if Drive is Removable!) | | | | 5 Drive can be locked: | | | | (Required if Drive is Removable!) | | | | 6 CHS Information set to maximum supported | | | | values; _not_ current media. | | | | 15-7 Reserved (0). | | | | (Bits 4-6 are only valid if bit 2 is set.) | | | +==================================================+ | | 04h DWORD Number of physical Cylinders | | 08h DWORD Number of physical Heads on drive | | 0Ch DWORD Number of physical Sectors Per Track | | 10h QWORD Total Number of Sectors on drive | | 18h WORD Bytes per Sector (200h = 512) | +------------------------------------------------------+
Parameters for a small 365 MiB BOCHS drive we first used to study this code were found as
follows:
Figure 3.
Note: The drive parameters for a Windows 7 OS drive quite often have
255 Heads (the BIOS on some Laptop/Notebook PCs may be around 240 instead). So for 63 Sectors per Track at 512 Bytes per Sector, each full Cylinder
would equal 16,065 sectors. But in order to get Bochs to even begin to function with a flat image based upon such a drive, the drive parameters in its
configuration file can not exceed a value of 16 Heads.
Note: The Cylinder count stored in chips on the controller boards of disk
drives cannot exceed 16,383 (0x3FFF), so for any drive or image file larger than 16383 x 16 x 63 (or a Maximum CHS of: 16382,15,63) =
16,514,064 sectors (8,455,200,768 bytes; about 8.45 GB), only the data for Total Sectors would be valid. However, there are further limitations
by a PC's BIOS Interrupt 13h code (which reads/writes sectors from/to a drive among other things) and the maximum number of bits
availble for use by a Partition Table's CHS Starting and Ending entries on a Basic partitioned drive (see our notes
about a 'bug' in MS-DOS here and Partition Tables here), which reduces the limitation of CHS addressable drives to 1024 x 255 x 63 (for a Maximum CHS of: 1023,254,63) =
16,450,560 sectors (8,422,686,720 bytes; or about 8.42 GB).
Real Example: When debugging the MBR and VBR of a 36 GiB Win 7 image of exactly 75,497,472 sectors (38,654,705,664 bytes); obviously not
installed under Bochs, we simply approximated its pseudo-CHS values as: 74898,16,63 (Bochs actually didn't care if we used some other cylinder values
as long as there were 16 heads!) Running the code above (using any [x,16,63] CHS parameter values in Bochs; provided x was greater than 16838)
still resulted in the correct sector count in Memory locations 7BF4 to 7BFB for that drive: "00 00 80 04 00 00 00 00" (in little-endian) =
0x4800000 = 75497472 sectors.
But when running BOCHS on a different PC, we got: "e0 fe 7f 04 00 00 00 00" = 0x47FFEE0 = 75497184 sectors (under the same settings)!
00A0 9F LAHF ; Load Status flags into AH 00A1 83C418 ADD SP,+18 ; Change Stack Pointer to 7BFC 00A4 9E SAHF ; Save AH into flags register. 00A5 58 POP AX ; Usually 200h (512 bytes/sector). 00A6 1F POP DS ; DS goes back to 07C0. 00A7 72E1 JB 008A ; If below, 'Disk error' -> 016A 00A9 3B060B00 CMP AX,[000B] ; [0B - 0C] (Usually, 200h = 512 Bytes per Sector.) 00AD 75DB JNZ 008A ; If not zero, 'Disk error' -> 016A 00AF A30F00 MOV [000F],AX ; Copies Bytes per Sector into 7c10 to 7c0F. 00B2 C12E0F0004 * SHR WORD PTR [000F],04 ; For a 200h in 7c10 to 7c0F, shifts the ; binary '1' bit (or the '2' of 200h) in ; the MSB to the right by 4 places; thus SHR WORD,04 is the same as dividing it by 16: ; 10 0000 0000 (200h) -> 00 0010 0000 (20h) ; Or: 512/16 = 32 (20h), and the contents of 7C0F becomes 32 (20h). ; The reason for doing the math above is because for each loop of the code executed below ; (starting at 00C5), each sector will be copied by adding the Sector Size divided by 16 ; to the initial Segment value of 07C0; this way, only the Segment part of the "Transfer ; Buffer"'s Segment:Offset needs to be changed. 00B7 1E PUSH DS ; Save current DS on Stack. 00B8 5A POP DX ; Change DX to 7c0. 00B9 33DB XOR BX,BX ; zero-out BX register.
The Win 7 MBR already loaded the first sector (Boot Sector) of our Win 7 VBR into Memory at 7C00 through 7DFF (which is being executed here). The next 3 instructions set up the code which follows to copy the remaining 15 sectors (if 512 bytes/sector is in use) of the Volume Boot Record Area into Memory locations 7E00 through 9BFF (normally only about half those sectors contain executable code; the remaining bytes being zero-padded):
00BB B90020 MOV CX,2000 ; 2000h = 8192 = 16 512-byte sectors, ; or only 2 4096-byte sectors. 00BE 2BC8 SUB CX,AX ; If AX=200; CX - AX -> CX, so ; the 2000 in CX becomes: 1E00. 00C0 66FF061100 * INC DWORD PTR [0011] ; Sets [7C11] = 1 (it was 0). ; Used in setting the offset ; from an initial sector location (at line 121) in the Extended Disk Read ; Subroutine (7C0:011D) below, where it is increased by 1 (at line 154) ; for each loop, until no more sectors are left to read. Total number of ; sectors to read having been set at lines 00BB and 00BE above.
The following code from 00C5 through 00D5 (and the Subroutine it CALLs at 011D through 0169) is used to load the BOOTMGR Loader code and zero-byte padding into Memory (see notes at 00D4):
00C5 03160F00 ADD DX,[000F] ; Add [7C1F] to DX for each pass, so ; 1st pass (of 15): 20h + 7c0 = 7e0. 00C9 8EC2 MOV ES,DX ; 1st pass: ES = 7E0, 2nd pass: 800, ; 3rd: 820; 4th: 840, 5th: 860, 6th: 880, 7th: 8A0, 8th: 8C0, 9th: 8E0, ; 10th: 900, 11th: 920, 12th: 940, 13th: 960, 14th: 980 and 15th: 9A0. 00CB FF061600 INC WORD PTR [0016] ; [7C16] changes from 0 -> 1. ; This is a flag which is set(1) ; to control how the Extended Disk Read Subroutine will be used (see lines ; at 15F and 163 in Subroutine at 011D). 00CF E84B00 CALL 011D 00D2 2BC8 SUB CX,AX ; 1st pass: 1e00 (in CX) - 200h = 1C00. ; 2nd pass: 1c00 (in CX) - 200h = 1A00, ; 3rd: 1800, 4th: 1600, 5th: 1400, 6th: 1200, 7th: 1000, 8th: 0E00, ; 9th: 0C00, 10th: A00, 11th: 800, 12th: 600, 13th: 400, 14th: 200. On ; the 15th pass: CX becomes zero, so the next instruction stops looping. ===================================================================== 00D4 77EF JA 00C5 ; This loops until all 15 sectors of (or: JNBE) ; the BOOTMGR Loader Area are copied ; from the drive to Memory locations 7E00h ; through 9BFFh; the code ends at 8C27h, ; but it's followed by 4,056 zero bytes. ; ================================================================= ; This code (from 00D6 through 010B) is related to discovering if ; TPM version 1.2 interface support is operational on the system. ; ; 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). 00D6 B800BB MOV AX,BB00 ; With AH = BBh and AL = 00h 00D9 CD1A INT 1A ; Int 1A -> TCG_StatusCheck 00DB 6623C0 * AND EAX,EAX ;/ If EAX does not equal zero, 00DE 752D JNZ 010D ;\ then no BIOS support for TCG. 00E0 6681FB54435041 * 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.) 00E7 7524 JNZ 010D ; If not, exit TCG code. 00E9 81F90201 CMP CX,0102 ; Version 1.2 or higher ? 00ED 721E JB 010D ; 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). 00EF 16 PUSH SS 00F0 6807BB * PUSH BB07 00F3 16 PUSH SS 00F4 68700E * PUSH 0E70 00F7 16 PUSH SS 00F8 680900 * PUSH 0009 00FB 6653 * PUSH EBX 00FD 6653 * PUSH EBX 00FF 6655 * PUSH EBP 0101 16 PUSH SS 0102 16 PUSH SS 0103 16 PUSH SS 0104 68B801 PUSH 01B8 0107 6661 POPAD 0109 0E PUSH CS 010A 07 POP ES 010B CD1A INT 1A (BIOS Clock) ; On return, "(EAX) = Return Code as defined in Section 12.3" and
; "(EDX) = Event number of the event that was logged". ; ================================================================
Note: The following 11 bytes of code (from offsets 10D through 117) are new to the Windows 7 VBR (they are not found in Vista's VBR). This code uses the REPeat and STOSB (STOre String Byte) instructions to overwrite a block of Memory with the byte value found in AL (which is zero); effectively zero-filling all the Linear Memory locations from AA28 (09A0:1028) through B9FF (09A0:1FFF): A span of 4,056 bytes (B9FFh - AA28h + 1 = FD8h; which is 4056 in decimal).
010D 33C0 XOR AX,AX ; Zero out the Accumulator,
; which sets AL = 0.
; Extra Segment (ES) was already set to 09A0 by adding 20h to DX
; (which begins as 7C0) 15 times in a row: (0Fh x 20h = 1E0h) + 7C0h = 9A0h.
010F BF2810 MOV DI,1028 ; 1028h = 4,136
0112 B9D80F MOV CX,0FD8 ; to zero-fill with 4,056 bytes
0115 FC CLD
0116 F3AA REP STOSB ; REP STOSB BYTE PTR ES:[DI], AL
; The starting location of ES:DI (09A0:1028) is equivalent to a Linear (or Absolute)
; Memory Location of:
; (Segment value * 16h) + Offset value = 9A00 + 1028h = AA28
; The VBR code has already loaded Linear Memory locations 7E00 through 8C27 with the
; BOOTMGR Loader Code (3,624 bytes) plus another 4,056 zero bytes; which brings the
; last Memory location of these 16 sectors to: 8C27 + FD8 = 9BFF hex.
; By using a Bochs command (set al = 0x22) just before executing the STOSB instruction, we were able
; to fill all 4,056 byte locations with 22h instead of zero; making it very easy to locate this area
; in Memory and observe what happened when we continued to execute the BOOTMGR's Bootstrap Loader
; code in the Boot Record Area's second and following sectors. See Figures 4 and 5 below.
; The BOOTMGR Loader (or "Bootstrap") code copies file system data from the partition on the
; drive that it has boot-up from (usually the System Reserved partition) into Memory locations
; A000 and following, searching for the location of the bootmgr file. More info about this
; may be found on our BOOTMGR Loader Code page.
; Speculating: AA28 - 9BFF - 1 = E28 (3,624 decimal). Why does the code need to zero-out
; the same number of zero bytes (4,056) found at the end of the Boot Loader Area, which
; are also exactly the same number of bytes away from the end of the 16 sectors we already
; loaded as there are of the number of bytes of code they contain (3,624)?
; (Curiously, 1028 hex = 4,136, the exact number of bytes in the Win 7 VBR + BOOTMGR Loader Code!)
This is the normal "Exit point" for the VBR code, where execution jumps to Linear Memory location 7E7A (or 07C0:027A):
0118 E95F01 JMP 027A ; Entry point into BOOTMGR Loader ; (or "bootstrap") Code in Boot ; Record Area's second sector. 011B 90 NOP 011C 90 NOP ; The following code uses INT 13, Function 42h ("Extended Disk Read") to read ; 1 sector at a time of the remaining 15 sectors of the Boot Record Area into ; Memory; starting at location 7E00. It does this by pushing what's called ; the "Disk Address Packet" (DAP) onto the Stack in reverse order of how the ; Interrupt will read the data, so the 00h (Reserved) and 10h (Packet Size) ; bytes are the last to be pushed onto the Stack (see instruction 0138 below): ; ; Offset Size Description of DISK ADDRESS PACKET's (DAP'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 at a time here). ; 04h DWORD Points to -> Transfer Buffer (0000 07E0 for this code), so: ; 07E0:0000 = Memory Location 7E00 (1st pass; ; Transfer Buffer is changed for each of 15 passes). ; 08h QWORD Starting Absolute Sector (on Disk Drive or media) obtained ; from verified Location of Volume Boot Sector after being ; loaded into Memory by MBR code. ; ; 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. ; (Then size of packet would be 24 bytes.) ; ========================================================================= ; SUBROUTINE - INT 13 Function 42h Extended DISK READ ; ========================================================================= 011D 6660 * PUSHAD ; "Push All Double" - all 32-bit ; GP Regs pushed onto Stack! 011F 1E PUSH DS ; Currently DS = 07c0. 0120 06 PUSH ES ; 1st pass: ES = 07e0. 0121 66A11100 MOV EAX,[0011] ; 1st pass: EAX = 1; 2nd = 2, etc. 0125 6603061C00 ADD EAX,[001C] ; [7C1C] + [7C11]; which for first ; pass is often: 800h + 1 = 801h (2049), the first sector after Boot Sector ; of System Reserved partition. 2nd pass, read from: 802h (Sector 2050), etc. 012A 1E PUSH DS ; Save DS, since DS -> 0 at 0142. 012B 666800000000 * PUSH 00000000 ;\ 0131 6650 * PUSH EAX ;/ Location of Sector to Read from. 0133 06 PUSH ES ;\ Segment part of Transfer Buffer 0134 53 PUSH BX ;/ Offset part of Transfer Buffer 0135 680100 * PUSH 0001 ; Copy only 1 sector. 0138 681000 * PUSH 0010 ; Reserved and Packet Size bytes. 013B B442 MOV AH,42 ; Function 42h (INT13) 013D 8A160E00 MOV DL,[000E] ; Drive # (usually 80h) -> DL ; (This was set at 0066 above.) 0141 16 PUSH SS ; (which is zero)... 0142 1F POP DS ; ...changing DS to zero. 0143 8BF4 MOV SI,SP ; DS:SI must point to -> "Disk ; Address Packet" on Stack. ; ( DS:SI -> 0000:7BC8 ) 0145 CD13 INT 13 ; Read Sector from media. Upon entry into the INT 13 Interrupt with AX=4201, we have: DL = drive number = 80h DS:SI -> Disk Address Packet = 0000:7BC8 (Top of Stack; onto which we stored all required data as follows!) Format of DAP: ----------------------------- Offst Size Description ----------------------------------------------------------- 00 BYTE Size of packet (in this case: 10h or 16 bytes) [7BC8] 01 BYTE Reserved (00) [7BC9] 02 WORD Number of Blocks to Transfer (always 1 here; [7BCA - 7BCB] "01 00" -> 0001 ) 04 DWORD -> Transfer Buffer = (00 00 E0 07) = 07E0:0000 [7BCC - 7BCF] ( First Pass) 08 QWORD Starting Absolute Sector Number = 801h = 2049 [7BD0 - 7BD7] (Example Pass ) (for non-LBA devices, compute as follows: ( ( (Cylinder x Number of Heads) + Selected Head) ) x Sectors Per Track) + Selected Sector - 1), or for here: ( ( (0 x 16) + 1) x 63) + 1 - 1 = 63 ========================================================== Return: CF clear if successful and AH = 00h ========================================================== CF set on error; AH = error code and DAP's block count field set to number of blocks (sectors) successfully transferred. ---------------------------------------------------------- 0147 6659 * POP ECX 0149 5B POP BX 014A 5A POP DX 014B 6659 * POP ECX 014D 6659 * POP ECX 014F 1F POP DS 0150 0F821600 * JB 016A 0154 66FF061100 * INC DWORD PTR [0011] ; 1st pass: [7C11] -> 2. ; On 15th pass [7C11] = 10h (16). 0159 03160F00 ADD DX,[000F] ; 1st pass: 7e0 + 20h = 800h. ; 2nd pass: 800 + 20h = 820h, ; etc. And on last (15th) pass, DX = 9A0 + 20h = 9C0. 015D 8EC2 MOV ES,DX ; Just as we commented on the ; lines at 00C5 and 00C9 above, here too ES = DX, and ; on the last pass (15th), it becomes: 9C0. 015F FF0E1600 DEC WORD PTR [0016] ; [7C16] goes back -> 0 (flag is cleared). 0163 75BC JNZ 0121 ; If flag is not set, go back and ; read another sector. Win 7 Boot Sector ; 0165 07 POP ES 0166 1F POP DS 0167 6661 * POPAD ; "Pop All Double" - all 32-bit ; GP Regs reset from Stack! 0169 C3 RET ; Return to 00D2. ; Note: When the last character of any Error Message has been displayed on ; the screen, the HLT instruction at offset 0176 should prevent any further ; code execution. But if it doesn't, the JMP instruction at 0177 loops back ; to the HLT instruction; effectively locking the computer into an endless ; loop (whether HLT stops execution or not)! You must reboot the machine. 016A A0F801 MOV AL,[01F8] ; [1F8] = 8C + 100 -> 18C h 016D E80900 CALL 0179 ; Displays: "A disk read error occurred" 0170 A0FB01 MOV AL,[01FB] ; [1FB] = D6 + 100 -> 1D6 h 0173 E80300 CALL 0179 ; Displays: "Press Ctrl+Alt+Del to restart" 0176 F4 HLT ; HLT: Not found in Vista VBR code! 0177 EBFD JMP 0176 ; If HLT fails, jumps back to try again! ; INT 10, Function 0Eh (Teletype Output) is used to display each ; character of the error messages. 0179 B401 MOV AH,01 ; Adds 100h to offsets from above. 017B 8BF0 MOV SI,AX ; Offset of message -> Source Index Reg. 017D AC LODSB ; Load one character into AL from [SI]. 017E 3C00 CMP AL,00 ;/ Have we reached end of message 0180 7409 JZ 018B ;\ marker?(00) If so, then RETurn. 0182 B40E MOV AH,0E ;/ Otherwise use Teletype Output to ... 0184 BB0700 MOV BX,0007 ;| (Display page 0, normal white ;| on black characters.) 0187 CD10 INT 10 ;| ... display one character at a time, 0189 EBF2 JMP 017D ;\ and go back for another character... 018B C3 RET
Location of Error
Messages and
Message Offsets in Memory
0 1 2 3 4 5 6 7 8 9 A B C D E F 018C 0D 0A 41 20 ..A 0190 64 69 73 6B 20 72 65 61 64 20 65 72 72 6F 72 20 disk read error 01A0 6F 63 63 75 72 72 65 64 00 0D 0A 42 4F 4F 54 4D occurred...BOOTM 01B0 47 52 20 69 73 20 6D 69 73 73 69 6E 67 00 0D 0A GR is missing... 01C0 42 4F 4F 54 4D 47 52 20 69 73 20 63 6F 6D 70 72 BOOTMGR is compr 01D0 65 73 73 65 64 00 0D 0A 50 72 65 73 73 20 43 74 essed...Press Ct 01E0 72 6C 2B 41 6C 74 2B 44 65 6C 20 74 6F 20 72 65 rl+Alt+Del to re 01F0 73 74 61 72 74 0D 0A 00 8C A9 BE D6 00 00 55 AA start.........U. 0 1 2 3 4 5 6 7 8 9 A B C D E F
First Published: March 30, 2012. (30.03.2012).
Updated: March 28, 2012 (28.03.12), April 15, 2012 (15.04.2012); April 19, 2012 (19.04.2012); May 29, 2015 (29.05.2015); 14 JUN 2015 (14.06.2015);
12 JUL 2015 (12.07.2015); 28 JUL 2015 (28.07.2015); 19 AUG 2015 (19.08.2015); 19 MAY 2021 (19.05.2021).
Last Update: 21 September 2015. (21.09.2015). (And we're not finished yet!)
You can write to us 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