[ Embedded in bootsect.exe,
winsetup.dll and
various other
System files ]
Web Presentation and Text are Copyright©2018 by Daniel B. Sedory
NOT to be reproduced in any form without Permission of the Author !
This page examines the Windows 8 / 8.1 / 10 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 8 / 10 OS volume (thus, its alternate name: Boot Sector). The BOOTMGR
Loader code, immediately following the VBR Sector, spans across the boundaries of nine more sectors: Eight full 512-byte sectors, plus 266 bytes at
the beginning of the ninth sector. The structure is similar to that of the Windows 7 Boot Record area, but the Windows 8/10 BOOTMGR Loader contains more data
(mostly error messages and two new filenames: BOOTTGT and BOOTNXT) and of course more code in its additional 738 bytes. |
Just as we urged readers of our Win 7/8
MBR page to make a copy of their MBR sector, you may wish to create copies of your Win 8/10 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™ 8 / 8.1 / 10 OS Volume Boot Record code; the code which actually tests and begins to load a Windows™ 8/10 operating systems from within the OS volume.
For our Windows 8 install, all the code bytes of Win8'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: 791B8h];
immediately followed by all 4,362 bytes of the BOOTMGR Loader code (beginning at offset 793B8h and continuing through 7A4C0h) plus the next 3,318
bytes (all zeros) for a total of 8,192 bytes (16 sectors).
("Auto Check Utility"; File version:
"6.2.9200.16384 (win8_rtm.120725-1247)"; 792,064 bytes; Modification Date: "7/25/2012 7:20 PM").
2. C:\Windows\System32\autoconv.exe [Offset: h];
immediately followed by all 4,362 bytes of the BOOTMGR Loader code (beginning at offset h and continuing through h) plus the next 3,318
zero bytes ending at offset h; 16 sectors total.
("Auto Check Utility"; File version:
"6.2.9200.16384 (win8_rtm.120725-1247)"; bytes; Modification Date: "7/25/2012 7:20 PM").
3. C:\Windows\System32\autofmt.exe [Offset: h];
immediately followed by all 4,362 bytes of the BOOTMGR Loader code (beginning at offset h and continuing through h) plus the next 3,318
zero bytes ending at offset h; 16 sectors total.
("Auto Check Utility"; File version:
"6.2.9200.16384 (win8_rtm.120725-1247)"; bytes; Modification Date: "7/25/2012 7:20 PM").
4. C:\Windows\System32\bootsect.exe [Offset: F958h];
immediately followed by all 4,362 bytes of the BOOTMGR Loader code (beginning at offset FB58h and continuing through 10C61h) plus the next 3,318
zero bytes ending at offset h; 16 sectors total.
("Boot Sector Manipulation Tool"; File version:
"6.2.9200.16384 (win8_rtm.120725-1247)"; 110,832 bytes; Modification Date: "7/25/2012 7:38 PM").
6. C:\Windows\System32\RelPost.exe [Offset: 148E0h];
immediately followed by all 4,362 bytes of the BOOTMGR Loader code (beginning at offset 14AE0h and continuing through 15907h); followed by the 3,318
zero bytes ending at offset h; 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").
7. C:\Windows\System32\untfs.dll [Offset: 5E7A0h];
immediately followed by all 4,362 bytes of the BOOTMGR Loader code (beginning at offset 5E9A0h and continuing through 5F7C7h); followed by the 3,318
zero bytes ending at offset h; 16 sectors total.
("NTFS Utility DLL"; File version:
""; bytes; Modification Date: "11/20/2010 5:27 AM").
8. C:\Windows\System32\oobe\winsetup.dll [Offset: 1EC980h];
immediately followed by all 4,362 bytes of the BOOTMGR Loader code (beginning at offset 1ECB80h and continuing through 1ED9A7h); followed by the 3,318
zero bytes ending at offset h; 16 sectors total.
("Windows System Setup"; File version:
""; bytes; Modification Date: "11/20/2010 5:27 AM").
Note: The code for the whole Win 8/10 Boot Record area actually spans across 10 sectors: This includes the Boot Sector we're examining here, plus 266 bytes in the tenth one, for a total of 4,874 bytes [266 + (512 x 9)]. And, technically, because the Boot Record area is a full 16 contiguous sectors (Sectors 0 - 15 of the Volume), even the 3,318 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 Win 8/10 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 / Win 7, a new Microsoft retail DVD Windows 8 OS install will have 2,048 reserved sectors at the beginning of an MBR partitioned disk, so its 350 MiB "System Reserved" partition VBR will have "00 08 00 00" (0x800 = 2048) at offsets 1Ch through 1Fh in its BPB area; as we've shown below. However, if you examine the VBR of a Windows 8/10 OS's C: drive, you would normally see the bytes "00 F8 0A 00" at those byte offsets (which would represent 718,848 sectors; 0xAF800 = 718848). That would be a total of the 2048 sector offset at the beginning of the disk plus the 350 MiB size (367,001,600 bytes/512-byte sectors = 716800 sectors) of that first partition (2048 + 716800 = 718848).
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 8 / 10 OS install's System Reserved partition:
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 08 00 00] ........?....... 0020: 00 00 00 00 80 00 80 00 FF EF 0A 00 00 00 00 00 ................ 0030: AA 74 00 00 00 00 00 00 02 00 00 00 00 00 00 00 .t.............. 0040: F6 00 00 00 01 00 00 00 1F AA F8 12 C3 F8 12 D6 ö............... 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 52 11 16 68 09 00 66 53 66 53 66 h...hR..h..fSfSf 0100: 55 16 16 16 68 B8 01 66 61 0E 07 CD 1A 33 C0 BF U...h..fa....3.. 0110: 0A 13 B9 F6 0C FC F3 AA E9 FE 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 A1 F6 01 E8 09 00 ...u...fa....... 0170: A1 FA 01 E8 03 00 F4 EB FD*8B F0 AC 3C 00 74 09 ............<.t. 0180: B4 0E BB 07 00 CD 10 EB F2 C3 0D 0A 41 20 64 69 ............A di 0190: 73 6B 20 72 65 61 64 20 65 72 72 6F 72 20 6F 63 sk read error oc 01A0: 63 75 72 72 65 64 00 0D 0A 42 4F 4F 54 4D 47 52 curred...BOOTMGR 01B0: 20 69 73 20 63 6F 6D 70 72 65 73 73 65 64 00 0D is compressed.. 01C0: 0A 50 72 65 73 73 20 43 74 72 6C 2B 41 6C 74 2B .Press Ctrl+Alt+ 01D0: 44 65 6C 20 74 6F 20 72 65 73 74 61 72 74 0D 0A Del to restart.. 01E0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 01F0: 00 00 00 00 00 00 8A 01 A7 01 BF 01 00 00 55 AA ..............U. 0 1 2 3 4 5 6 7 8 9 A B C D E F |
The last 118 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 we see here are exactly the same as they were under Windows XP, Vista and 7 (except for the 'NTLDR' of Windows XP being replaced by "BOOTMGR"). However, one was removed: "BOOTMGR is missing" Instead, a much longer error message was added to the bootmgr Loader: "An operating system wasn't found. Try disconnecting any drives that don't contain an operating system."
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 8/10'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 nine physical sectors directly following a Windows™ 8 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™ 8 on a disk already containing a bootable Win 98 OS in the first partition followed by a Win 8/10 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 six bytes at offsets 1F6h through 1FBh ("8A 01 A7 01 BF 01") are used by the Microsoft Windows 8 VBR for a very specific purpose; for English versions of Windows 8 or 10, you'll always see these same Hex values ("8A 01 A7 01 BF 01") in your VBR. They're used by the code to display Error Messages on your screen. But for those using Windows 8 or 10 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 (018Ah) will never change no matter what languages (or string lengths) are used.
Now that you know what the bytes at offsets 1F6h 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 18Ah and 1F5h) 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 8/10 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/8 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 0x7C54. 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 08 00 00 ........?....... 7C20 00 00 00 00 80 00 80 00 FF EF 0A 00 00 00 00 00 ................ 7C30 AA 74 00 00 00 00 00 00 02 00 00 00 00 00 00 00 .t.............. 7C40 F6 00 00 00 01 00 00 00 1F AA F8 12 C3 F8 12 D6 ................ 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 0x7bfe to 0x7bff (which is: 0x07C0)
is referenced only by its lower byte in Memory, 0x7BFE, 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 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 [000E],DL ; DL = Drive # (often 80h). ; (See Win7/8 MBR code here.) 006A 66813E0300+ * CMP DWORD PTR [0003],5346544E ;/ -> "NTFS" 4E544653 ;| Check to see if this is an NTFS Boot Record, and if not display... 0073 7515 JNZ 008A ;\ ... Disk read error -> 016A. ; NOTE: A Windows 7, 8 or 10 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. ; (In most cases, DL is already 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) | +------------------------------------------------------+ 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 2 into high bits of ; 7c0F; a SHR WORD,04 is the same as dividing it by 16. So 512/16 = 32 (20h). ; The binary '1' bit shifts 4 places to the right: ; 10 0000 0000 (200h) -> 00 0010 0000 (20h) 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. 00BB B90020 MOV CX,2000 ; 2000h = 8192 = 16 sectors. 00BE 2BC8 SUB CX,AX ; AX=200; CX - (1 sector) = CX. ; (Sets CX from 2000 -> 1E00.) 00C0 66FF061100 * INC DWORD PTR [0011] ; Sets [0x11] = 1 (it was 0). ; The following code from 00C5 through 00D4 and the Subroutine it CALLs ; at 011D through 0169 is used to load the BOOTMGR Loader code and ; zero-bytes padded sectors into Memory (see notes below at location D4): 00C5 03160F00 ADD DX,[000F] ; For 1st pass (of 15): 7c0 (in DX) adds ; 20h (in 7C0:000F) and becomes: 7e0. 00C9 8EC2 MOV ES,DX ; 1st pass: So, 7e0 (in DX) -> ES. ; 2nd pass: 800 goes into -> ES. ; 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] ; [0x16] from 0 -> 1. 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 8F09h, ; but it's followed by 3,318 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 685211 * PUSH 1152 ; Changed from Win 7; why? 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) have the same function as they did under the Windows 7 VBR, but because Windows 8 has more code in its BOOTMGR ("bootstrap") Loader, where and how many bytes are written has changed. As before, 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 AD0A (09A0:130A) through B9FF (09A0:1FFF): A span of 3,318 bytes (B9FFh - AD0Ah + 1 = CF6h; which is 3318 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 BF0A13 MOV DI,130A ; 130Ah = 4,874
0112 B9F60C MOV CX,0CF6 ; to zero-fill with 3,318 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 + 130A = AD0A
; The VBR code has already loaded Linear Memory locations 7E00 through 8F09 with the
; BOOTMGR Loader Code (4,362 bytes) plus another 3,318 zero bytes; which brings the
; last Memory location of these 16 sectors to: 8F09 + CF6 = 9BFF hex.
; By using a Bochs command (set al = 0x22) just before executing the STOSB instruction, we were able
; to fill all 3,318 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.
; 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. We will provide more info
; about this at a later time.
; Speculating: AD0A - 9BFF - 1 = 110A (4,362 decimal). Why does the code need to zero-out
; the same number of zero bytes (3,318) 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 (4,362)?
; (Curiously, 130A hex = 4,874, the exact number of bytes in the Win 8 VBR + BOOTMGR Loader Code!)
This is the normal "Exit point" for the VBR code, where execution jumps to Linear Memory location 7F19 (or 07C0:0319):
0118 E9FE01 JMP 0319 ; 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 8/10 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 A1F601 MOV AX,[01F6] ; Word in [1F6-1F7] = 018A h 016D E80900 CALL 0179 ; Displays: "A disk read error occurred" 0170 A1FA01 MOV AX,[01FA] ; Word in [1FA-1FB] = 01BF 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 8BF0 MOV SI,AX ; Offset to message -> Source Index Reg. 017B AC LODSB ; Load one character into AL from [SI]. 017C 3C00 CMP AL,00 ;/ Have we reached end of message 017E 7409 JZ 0189 ;\ marker?(00) If so, then RETurn. 0180 B40E MOV AH,0E ;/ Otherwise use Teletype Output to ... 0182 BB0700 MOV BX,0007 ;| (Display page 0, normal white ;| on black characters.) 0185 CD10 INT 10 ;| ... display one character at a time, 0187 EBF2 JMP 017B ;\ and go back for another character... 0189 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 018A 0D 0A 41 20 64 69 ..A di 0190 73 6B 20 72 65 61 64 20 65 72 72 6F 72 20 6F 63 sk read error oc 01A0 63 75 72 72 65 64 00 0D 0A 42 4F 4F 54 4D 47 52 curred...BOOTMGR 01B0 20 69 73 20 63 6F 6D 70 72 65 73 73 65 64 00 0D is compressed.. 01C0 0A 50 72 65 73 73 20 43 74 72 6C 2B 41 6C 74 2B .Press Ctrl+Alt+ 01D0 44 65 6C 20 74 6F 20 72 65 73 74 61 72 74 0D 0A Del to restart.. 01E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 01F0 00 00 00 00 00 00 8A 01 A7 01 BF 01 00 00 55 AA ..............U. 0 1 2 3 4 5 6 7 8 9 A B C D E F
First Published: 14 June 2015. (14.06.2015).
Updated: 14 JUN 2015 (14.06.2015); 7 NOV 2015 (07.11.2015).
Last Update: 3 May 2018. (03.05.2018). (And we're certainly 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