Hard drive won't boot?

Lost partitions?

Let us help!

MBR & Boot Sector Repair

Home Contact Features FAQ Manual ScreenShots Support Users

 

NTFS Boot Sector

 

The NTFS partition boot sector is part of the NTFS metadata file $Boot, which includes the boot sector as its initial 512 bytes, followed by several sectors containing code which is called by the boot sector's IPL (initial program loader).

The NTFS boot sector is very similar in structure to FAT partition boot sectors. It begins with a jump to the entry point of the boot loader code, followed by a data record, called the BIOS Paramter Block, which describes the geometry of the partition, followed by the IPL or initial program loader, a small program that locates, loads to memory, and then executes the partition's startup code.

 

HEX/ASCII dump of NTFS Boot Sector

 

Table - The BIOS Parameter Block

Byte Offset Field Length Sample Value Field Name
0x0B Word 0x0002 (512) Bytes per Sector
0x0D Byte 0x08 Sectors per Cluster
0x0E Word 0x000 Reserved Sectors
0x10 3 Bytes 0x000000 reserved
0x13 Word 0x0000 not used
0x15 Byte 0xF8 Media Descriptor
0x16 Word 0x0000 reserved
0x18 Word 0x3F00 (63) Sectors per Track
0x1A Word 0xFF00 (255) Number of Heads
0x1C DWord 0x3F000000 (63) Hidden Sectors
0x20 DWord 0x00000000 not used
0x24 DWord 0x00800080 not used
0x28 QWord 0x00000000009C25FD Total Sectors
0x30 QWord 0x0000000000000004 $MFT Start Cluster
0x38 QWord 0x000000000009C25F $MFTmirr Start Cluster
0x40 DWord 0x000000F6 Clusters per FRS
0x44 DWord 0x00000001 Cluster per Index
0x48 QWord 0xD83AEE5E98D83B12 Volume Serial Number
0x50 DWord 0x00000000 CRC
Note: The values Clusters per FRS (File Record Segment) and Clusters per Index will be negative in the case where the sectors per cluster is greater than size of the FRS or Index record. In the case described here the value in the Clusters per FRS field is F6h or -10. The actual size of the record is then calculated as 2 ^ (-1 * -10) or 1024 bytes.

The IPL begins by determining whether or not the active partition begins outside the 8GB boundry. If it does, the IPL must use the BIOS LBA extensions to read from the disk. It uses CHS addressing otherwise (only the first 8GB of a hard disk can be addressed via CHS).

Having the addressing mode, the IPL then reads the initial 16 sectors of $Boot, which includes a copy of the boot sector itself plus the extended part of the IPL, to memory at 0D00h:0000h, then continues execution at 0D00h:026Ah.

The code in the extended part of the IPL has the job of locating and starting NTLDR. This requires reading the Master File Table to locate the root index (ie, root directory), finding the NTLDR entry in the root index, reading NTLDR's file record segment from the Master File Table, then loading NTLDR to memory and jumping into it.

Problems Involving the Boot Sector

The most common boot sector-related problem is an overwritten boot sector. NTFS partitions on Windows 2000 & XP systems have a backup boot sector stored in last sector of the partition, and the backup can be used to replace a damaged primary boot sector. For example, here is the procedure used to replace a damaged boot sector with BootMaster. Also, the Windows Recovery Console command FIXBOOT will replace the $Boot metadata file, inlcuding the boot sector.

In rather rare cases both the boot sector and its backup are corrupted. Sometimes this situation is complicated by the presence of a FAT12 boot sector in the place of the NTFS boot sector. The presence of the FAT12 boot sector is a "feature" of FIXBOOT. It writes the FAT12 boot sector into place, apparently, when the partition is damaged in a way that prevents it from reliably writing an NTFS boot sector. At any rate, the boot sector must be rebuilt from scratch, regardless of whether or not the FAT12 boot sector is present.

Our method for doing this is to install a boot sector template, then obtain and fill in the values which are given in red in the BIOS Parameter Block table above. The needed values are obtained from the BootMaster Diagnostics report and from a supplemental report created by the utility FINDMFT.EXE which we provide free for customers in those cases where it is needed.

Note that rebuilding the boot sector in this way is not neccessarily sufficient to recover a partition that is internally damaged, but it is worth doing as a preparation for recovering files from the damaged partition.

Disassembly of NTFS Partition Boot Sector

For readers with an interest in technical details, here is a disassembly of the NTFS Boot Sector. I have disassembled the actual boot sector (the initial 512 bytes of $Boot), but not the extended IPL code which reads from the Master File Table in order to locate NTLDR in the partition's root directory.

The boot sector begins with a jump over the BPB area to the IPL's entry point.

07C0:0000      jmp 052h            ; jump to IPL entry point
07C0:0002      90h                 ; nop
                       BIOS PARAMETER BLOCK
07C0:0003     db "NTFS    "        ; OEM
07C0:000B     dw 0200h (512)       ; Bytes per sector
07C0:000D     db 08h               ; Sectors per cluster
07C0:000E     dw 0h                ; Reserved Sectors
07C0:0010     db 0h DUP(3)         ; undefined - always 0
07C0:0013     dw 0h                ; not used
07C0:0015     db 0F8h              ; Media Type
07C0:0016     dw 0h                ; undefined - always 0
07C0:0018     dw 03Fh (63)         ; Sectors per track
07C0:001A     dw 0FFh (255)        ; Heads 
07C0:001C     dd 03fh (63)         ; Hidden Sectors
07C0:0020     dd 0h                ; not used
07C0:0024     dd 80008000h         ; not used
07C0:0028     qw 9C25FDh (10233341); Total Sectors
07C0:0030     qw 04h               ; MFT start cluster
07C0:0038     qw 9C25Fh (639583)   ; MFT mirror start cluster
07C0:0040     dd 0F6h              ; Clusters per FRS
07C0:0044     dd 01h               ; Clusters per index
07C0:0048     qw D83AEE5E98D83B12h ; Volume serial number
07C0:0050     dd 0h                ; CRC
                          IPL ENTRY POINT
07C0:0054      cli                     ; disable interrupts
07C0:0055      xor     ax, ax          ; ax = 0
07C0:0057      mov     ss, ax          ; stack segment = 0
07C0:0059      mov     sp, 7C00h       ; stack @ 0:7C00
07C0:005C      sti                     ; enable interrupts
07C0:005D      mov     ax, 7C0h        ;
07C0:0060      mov     ds, ax          ; data segment = 07C0
07C0:0062      call    007B            ; calculate drive's total sectors
07C0:0065      mov     ax, 0D00h       ;
07C0:0068      mov     es, ax          ; es = 0D00h
07C0:006A      xor     bx, bx          ; zero bx
07C0:006C      mov     b(ds:0Eh), 10h ; store read count index
07C0:0071      call    00C7            ; go read the disk
JUMP INTO IPL EXTENSION
07C0:0074      push    0D00h           ; segment for retf
07C0:0077      push    26Ah            ; offset for retf
07C0:007A      retf                    ; jump into extended IPL
   CALCULATE TOTAL SECTORS ON DRIVE
; Note that this routine uses the old interrupt 13, function 8 ("Get Drive
; Parameters"), which is limitied to a maximum cylinder count of 1023, so
; the total sector count will be 16450560 (8 GB) for drives larger than 8GB.
; The IPL uses this count to determine if the active partition begins
; beyond the 8GB point, in which case it will use it will use the interrupt
; 13 LBA extensions to read the drive. Otherwise, CHS addressing is used.
07C0:007B      mov     dl, ds:24h      ; load BIOS drive number (80h) to dl
07C0:007F      mov     ah, 8           ; Function "Get Hard Drive Parameters"
07C0:0081      int     13h             ; call BIOS disk service
;This call returns the hard disk's CHS parameters in registers cx and
;dh as follows:
;               ch = low eight bits of maximum cylinder number
;               cl = maximum sector number (bits 5-0)
;                    high two bits of maximum cylinder number (bits 7-6)
;               dh = maximum head number
;
;Note that the maximum cylinders this call can return is 1023.
07C0:0083      jnb     07C0:008A       ; jump if no error
07C0:0085      mov     cx, 0FFFFh      ; use dummy values for the calculation
07C0:0088      mov     dh, cl          ; below if an error occurs
07C0:008A      movzx   eax, dh         ; max head number to eax...
07C0:008E      inc     ax              ; and increment
07C0:008F      movzx   edx, cl         ; max sector number and high 2 bits
                                       ; of max cylinder number
07C0:0093      and     dl, 3Fh         ; mask off high 2 - dx now has
                                       ; max sector number
07C0:0096      mul     dx              ; multiply (max sectors) * (max heads)
07C0:0098      xchg    cl, ch          ; get maximum...
07C0:009A      shr     ch, 6           ; cylinder number...
07C0:009D      inc     cx              ; in...
07C0:009E      movzx   ecx, cx         ; ecx
07C0:00A2      mul     ecx             ; result will be drive's total sectors
07C0:00A5      mov     ds:20h, eax     ; store the value in the BPB area
07C0:00A9      retn                    ; return
           TEST FOR INTERRUPT 13 LBA EXTENSIONS SUPPORT IN BIOS
07C0:00AA      mov     ah, 41h         ; int13 Extensions Installation check   
07C0:00AC      mov     bx, 55AAh       ; test pattern in
07C0:00AF      mov     dl, ds:24h      ; BIOS number of hard drive
07C0:00B3      int     13h             ; do interrupt
07C0:00B5      jb      07C0:00C6       ; jump if error
07C0:00B7      cmp     bx, 0AA55h      ; test pattern out
07C0:00BB      jnz     07C0:00C6       ; jump if pattern miscompare
07C0:00BD      test    cl, 1           ; are extended read/write supported?
07C0:00C0      jz      07C0:00C6       ; jump if not
07C0:00C2      inc     bp(ds:14h)      ; set marker
07C0:00C6      retn                    ; return
                    READ $BOOT (16 SECTORS) TO MEMORY
                         
07C0:00C7      pushad                  ; save 
07C0:00C9      push    ds              ; registers on
07C0:00CA      push    es              ; stack
07C0:00CB      mov     eax, ds:10h     ; sector counter - starts at zero
07C0:00CF      add     eax, ds:1Ch     ; hidden sectors
07C0:00D4      cmp     eax, ds:20h     ; ds:20 has drive's total sectors
07C0:00D9      jb      0117            ; jump if active partition start
                                       ; is not beyond 8GB point
                            READ IN LBA MODE
;Now read first 16 sectors of the NTFS partition (these sectors comprise
;the metadata file $Boot) using either LBA or CHS reads as determined
;above
07C0:00DD      push    ds              ; save ds on stack
;Here, the IPL builds a disk address packet on the stack (the packet is
;defined for LBA reads/writes via int 13 functions 42h and 43h). The
;format of the packet is...
;
;
;    Offset  Size    Description
;    ------  ----    -----------
;     00h    BYTE    10h (size of packet)
;     01h    BYTE    reserved (0)
;     02h    WORD    number of blocks to transfer 
;     04h    DWORD   pointer to transfer buffer
;     08h    QWORD   starting logical block address
;                                                                                                ;

07C0:00DE      push    large 0         ; address of 
07C0:00E1      push    eax             ;  sectors to read
07C0:00E3      push    es              ; read buffer is at
07C0:00E4      push    bx              ;  0D00:0000
07C0:00E5      push    large 10010h    ; read 1 sector, etc
07C0:00EB      cmp     bp(ds:14h), 0   ; byte is set if BIOS is LBA capable
07C0:00F0      jnz     0100            ; jump if LBA capable,
07C0:00F4      call    00AA            ; else do install check for LBA extns
07C0:00F7      cmp     bp(ds:14h), 0   ; recheck - LBA capable?
07C0:00FC      jz      0161            ; go print error msg if not
07C0:0100      mov     ah, 42h         ; set up for int 13 LBA read 
07C0:0102      mov     dl, bp[ds:24h]  ; BIOS drive number into dl
07C0:0106      push    ss              ; ss on stack (ss = 0h)
07C0:0107      pop     ds              ; ds:si = address of packet
07C0:0108      mov     si, sp          ;  buffer (0:7C00)
07C0:010A      int     13h             ; perform read
07C0:010C      pop     eax             ; clean up
07C0:010E      pop     bx              ;    .
07C0:010F      pop     es              ;    .
07C0:0110      pop     eax             ;    .
07C0:0112      pop     eax             ;    .
07C0:0114      pop     ds              ; the stack   
07C0:0115      jmp     0144h           ; set up to read next sector
                               READ IN CHS MODE  
;on entry eax = number of hidden sectors.
07C0:0117      xor     edx, edx        ; zero edx
07C0:011A      movzx   ecx, wp(ds:18h) ; ecx = sectors per track
07C0:0120      div     ecx             ; (hidden sectors) / (sectors per track)
07C0:0123      inc     dl              ; increment remainder in dl
07C0:0125      mov     cl, dl          ; move to cl
                                       ; this is sector number for read
07C0:0127      mov     edx, eax        ; hidden sectors now in edx
07C0:012A      shr     edx, 10h        ;
07C0:012E      div     wp(ds:1Ah)      ; (hidden sectors) / (number of heads)
07C0:0132      xchg    dl, dh          ; remainder to dh
                                       ; this is head number for ead
07C0:0134      mov     dl, ds:24h      ; BIOS drive number (80h) in dl
07C0:0138      mov     ch, al          ; high 8 bits of cylinder number
07C0:013A      shl     ah, 6           ; shift hi 2 bits of cyl number
07C0:013D      or      cl, ah          ; or them to cl - now ready to read
07C0:013F      mov     ax, 201h        ; read 1 sector
07C0:0142      int     13h             ; do it

07C0:0144      jb      0161            ; jump if error
07C0:0148      mov     ax, es          ; move read buffer up
07C0:014A      add     ax, 20h         ;  by 512 bytes
07C0:014D      mov     es, ax          ;  to receive next sector
07C0:014F      inc     dp(ds:10h)      ; increment sector counter
07C0:0154      dec     wp(ds:0Eh)      ; decrement loop counter
07C0:0158      jnz     00CB            ; go read next sector
07C0:015C      pop     es              ; 16 sectors have been read...
07C0:015D      pop     ds              ; clean up
07C0:015E      popad                   ; and 
07C0:0160      retn                    ; return
                     ERROR MESSAGES PRINT ROUTINE
07C0:0161      mov     al, ds:1F8h     ; value is 83h
07C0:0164      call    0170h           ; print err msg
07C0:0167      mov     al, ds:1FBh     ; value is C9h
07C0:016A      call    sub_0_170       ; print err msg
07C0:016D      sti                     ; enable interrupts
07C0:016E      jmp     016Eh           ; hang (wait for CTL+ALT+DEL)
                                       ;
                                       ;
07C0:0170      mov     ah, 1           ;
07C0:0172      mov     si, ax          ; offset to start of msg
07C0:0174      lodsb                   ; get next char to print
07C0:0175      cmp     al, 0           ; test for end of msg
07C0:0177      jz      0182h           ; jump if done
07C0:0179      mov     ah, 0Eh         ; BIOS TTY output function
07C0:017B      mov     bx, 7           ; color wht on blk
07C0:017E      int     10h             ; print the character
07C0:0180      jmp     0174h           ; get next character
07C0:0182      retn                    ; return when done
                             ERROR MESSAGES
07C0:0183      db  "A disk read error occurred"
07C0:019F      db    0                 ;  
07C0:01A0      db  0Dh                 ; CR 
07C0:01A1      db  0Ah                 ; LF 
07C0:01A2      db  "NTLDR is missing"
07C0:01B2      db    0
07C0:01B3      db  0Dh                 ; CR
07C0:01B4      db  0Ah                 ; LF
07C0:01B5      db  "NTLDR is compressed"
07C0:01C8      db    0                 ;  
07C0:01C9      db  0Dh                 ; CR
07C0:01CA      db  0Ah                 ; LF
07C0:01CB      db  "Press Ctrl+Alt+Del to restart"
07C0:01E7      db    0
07C0:01E8      db  0Dh                 ; CR 
07C0:01E9      db  0Ah                 ; LF 
07C0:01EA      db    0 DUP (0Eh)       ;
07C0:01F8      db  83h                 ; these values are
07C0:01F9      db  A0h                 ; offsets to the 4
07C0:01FA      db  B3h                 ; text message strings
07C0:01FB      db  C9h                 ; which the IPL can print
07C0:01FC      db    0                 ;  
07C0:01FD      db    0                 ;  
                              SYSTEM SECTOR SIGNATURE
07C0:01FE      db  55h                 ; U
07C0:01FF      db  AAh                 ; ª