VBR, WIN95, en, FAT16, junk =========================== NOTE: partition table says, that the volume starts at sector 63. So what we see @0001e00 (which looks like a VBR) is kind of junk. However, we wanna see, what it has to tell: It mentions a WINBOOT.SYS so it is probably a WIN95|98|ME bootloader. what sectors sum absolute address [hex] hidden 15 15 15 0000 reserved 1 1 16 1E00 fat 2*248 496 512 2000 / dirs 512*32/512 32 544 40000 1st cluster 1 1 545 44000 7C00: eb 3e jmp 0x7C40 # jump to 7C40h 7C02: 90 nop 7C03: 2a 5e 77 59 26 49 48 43 # OEM ID: *^wY&IHC ==START BPB== 7C0B: 00 02 # bytes/sector: 512 (0x0200) 7C0D: 20 # sectors/cluster: 32 7C0E: 01 00 # reserved sectors: 1 (0x0001) 7C10: 02 # FAT count: 2 7C11: 00 02 # max. / dir entries_16: 512 (0x0200) 7C13: 20 f9 # volume size_16: 63776 (0xf920) 7C15: f8 # media type: 0xf8 (fixed disk) 7C16: f8 00 # FAT size_16: 248 sectors (0x00f8) 7C18: 3f 00 # sector/track: 63 7C1A: ff 00 # heads: 255 7C1C: 0f 00 00 00 # hidden sectors: 15 7C20: 00 00 00 00 # volume size_32: 0 7C24: 80 # drive number (0x80 = HDD0) 7C25: 00 # reserved (used by NT) 7C26: 29 # extended boot signature 7C27: 38 12 d4 12 # Volume ID: 12D4-1238 7C2B: 4e 4f 20 4e 41 4d 45 20 20 20 20 # Volume label: 'NO NAME ' 7C36: 46 41 54 31 36 20 20 20 # filesystemID: 'FAT16 ' ==END BPB== 7C3E: f1 7d # Pointer to 'WINBOOT SYS' (7DF1h) # Gets changed by search_* ==BOOTLOADER START== 7C40: fa cli # Disable interrupts 7C41: 33 c9 xor CX,CX # Zero out CX, 7C43: 8e d1 mov SS,CX # and SS 7C45: bc fc 7b mov sp,0x7bfc # Set StackPointer to 0000:7BFC 7C48: 16 push SS # Zero out ... 7C49: 07 pop ES # ES 7C4A: bd 78 00 mov BP,0x78 # Set BP to point to 0000:0078, # which holds the vector for INT 1E. # Vectors are 4B in IP:CS format. 7C4D: c5 76 00 lds SI,[BP] # Load the content from 0000:0078 into 7C50: 1e push DS # DS:SI (upper 16b into DS, lower 16b 7C51: 56 push SI # into SI) => points now to the ROM DPT 7C52: 16 push SS # Save SS and 7C53: 55 push BP # BP 7C54: bf 22 05 mov DI,0x522 # Set DI to 0522h (DOS DPT) 7C57: 89 7e 00 mov [BP],DI # Re-route: i.e. let 0000:0078 point to 7C5A: 89 4e 02 mov [BP+2],CX # 0000:0522h (CX:DI) 7C5D: b1 0b mov CL,0xb # Set number of bytes to move (CX=11) 7C5F: fc cld # Clear direction flag => increment SI # as well as DI after each movs 7C60: f3 a4 rep movs ES:[DI],DS:[SI] # execute movsb CX times: i.e. # copy 11 bytes from DS:SI (*DPT) to # ES:DI (0000:0522). Finally DI is 52Dh # and CX == 0. 7C62: 06 push ES # Set DataSegment back 7C63: 1f pop DS # to 0000 and 7C64: bd 00 7c mov BP,0x7c00 # BP to 7C00h (this VBR[0] copy) 7C67: c6 45 fe 0f mov [DI-2],0xf # Set head settle time in the DOS DTP # to 15ms (0x52D-2 = 0x52B) 7C6B: 8b 46 18 mov AX,[BP+0x18] # Copy sectors/track from BPB (0x7C18h) 7C6E: 88 45 f9 mov [DI-7],AL # to the DOS DTP (0x52D-7 = 0x526) 7C71: fb sti # Enable interrupts 7C72: 38 66 24 cmp [BP+0x24],AH # Check, whether the drive number in the 7C75: 7c 04 jl 0x7C7B # BPB (7C24h) denotes a valid device, # i.e. >= 0. Since this is usually the # case, jump to prepare_read dead_code_fillbytes: 7C77: cd 13 int 0x13 7C79: 72 3c jb 0x7CB7 ; end of dead_code_fillbytes prepare_read: 7C7B: 8a 46 10 mov AL,[BP+0x10] # Set AX=number of FATs (7C10h) 7C7E: 98 cbw # by converting byte to word 7C7F: f7 66 16 mul [BP+0x16] # Set DX:AX to the size of all FATs in # blocks (7C16h == size of one FAT) 7C82: 03 46 1c add AX,[BP+0x1c] # Add number of "hidden blocks" (7C1Ch) 7C85: 13 56 1e adc DX,[BP+0x1e] # and take possible overflow (if CF==1) # into account 7C88: 03 46 0e add AX,[BP+0xe] # Add number of reserved sectors (incl. 7C8B: 13 d1 adc DX,CX # boot sector 7C0Eh) - usually 1 7C8D: 50 push AX # Save AX and 7C8E: 52 push DX # DX to the stack 7C8F: 89 46 fc mov [BP-4],AX # Put the absolute block number of the 7C92: 89 56 fe mov [BP-2],DX # first root dir sector on the stack # (DX:AX) 7C95: b8 20 00 mov AX,0x20 # AX=32 (bytes per entry) 7C98: 8b 76 11 mov SI,[BP+0x11] # SI=Max. entries in root dir (7C11h) 7C9B: f7 e6 mul SI # Calculate the size of the root dir # region: DX:AX=SI*AX 7C9D: 8b 5e 0b mov BX,[BP+0xb] # BX=bytes/sector (7C0Bh) 7CA0: 03 c3 add AX,BX # Root dir size in sectors gets calced, 7CA2: 48 dec AX # so round up that all entries will fit 7CA3: f7 f3 div BX # and finally set AX to the root dir sz # in blocks (AX=AX/BX) 7CA5: 01 46 fc add [BP-4],AX # Add root dir size to the absolute num 7CA8: 11 4e fe adc [BP-2],CX # of the first root dir block stored on # the stack at 7BFCh and clear flags 7CAB: 5a pop DX # Restore DX:AX the absolute block 7CAC: 58 pop AX # number of the first root dir sector read_next_clusterblock: 7CAD: bb 00 07 mov BX,0x700 # Set read buffer address to 0000:0700 7CB0: 8b fb mov DI,BX # as well as current "cursor" to 0700h 7CB2: b1 01 mov CL,1 # Set number of blocks to read 7CB4: e8 94 00 call 0x7D4B # Jump to prep_normal_read_params # and read 7CB7: 72 47 jc 0x7D00 # On error jump to io_error search_winboot_sys: 7CB9: 38 2d cmp [DI],CH # If the byte at DI == 0 (unused) 7CBB: 74 19 jz 0x7CD6 # jump to search_io_sys 7CBD: b1 0b mov CL,0xb # Set number of chars to compare (11) 7CBF: 56 push SI # Save SI 7CC0: 8b 76 3e mov SI,[BP+0x3e] # Set the index to the address stored # stored at 7C3Eh (in first pass this # is 7DF1 aka 'WINBOOT SYS', on 2nd pass # it is 7DD8 aka 'IO SYS') 7CC3: f3 a6 repz cmps DS:[SI],ES:[DI] # compare 0000:7DD8 with 0000:7DF1 7CC5: 5e pop SI # Restore SI 7CC6: 74 4a jz 0x7D12 # jump to read_io_sys 7CC8: 4e dec SI # Decrement remaining dir entries 7CC9: 74 0b jz 0x7CD6 # If none left jump to search_io_sys 7CCB: 03 f9 add DI,CX # Clear flags 7CCD: 83 c7 15 add DI,0x15 # Advance to the next entry (one entry # has 32 bytes) 7CD0: 3b fb cmp DI,BX # While DI-0700h < bytes read 7CD2: 72 e5 jb 0x7CB9 # jump to search_winboot_sys (7CB9) 7CD4: eb d7 jmp 0x7CAD # Jump to read_next_clusterblock search_io_sys: 7CD6: 2b c9 sub CX,CX # Zero out CX 7CD8: b8 d8 7d mov AX,0x7dd8 # Set AX to the address of the string # 0x7DD8 ('IO SYS') 7CDB: 87 46 3e xchg [BP+0x3e],AX # Save address at 7CE3h (Pointer to # 'WINBOOT SYS') into AX and put the # content of AX into 7CE3h (Pointer to # 'IO SYS') 7CDE: 3c d8 cmp AL,0xd8 # If AX does not contain the pointer to 7CE0: 75 99 jne 0x7C7B # IO.SYS, jump to prepare_read invalid_sys_disk: 7CE2: be 80 7d mov SI,0x7d80 # SI=message offset in 0x7D80 (0x3) # => 7D84h '\r\nInvalid system disk' print_msg: 7CE5: ac lods AL,DS:[SI] # Load the msg offset into DS:AL 7CE6: 98 cbw # Convert AL to AX keeping the sign bit 7CE7: 03 f0 add SI,AX # Add the message offset to SI print_next_line: 7CE9: ac lods AL,DS:[SI] # Load string byte at DS:SI into AL 7CEA: 84 c0 test AL,AL # If AL == 00 (end of messages) 7CEC: 74 17 je 0x7D05 # jump to wait_for_keystroke 7CEE: 3c ff cmp AL,0xff # If AL == 0xff (EndOfLine marker) 7CF0: 74 09 je 0x7CFB # jump to replace_disk 7CF2: b4 0e mov AH,0xe # Set function teletype output 7CF4: bb 0700 mov BX,7 # Set color to white (0x7) 7CF7: cd 10 int 0x10 # Call INT10 to print out the char # in AL, advance the cursor and scroll # screen if necessary 7CF9: eb ee jmp 0x7CE9 # jump to print_next_line replace_disk: 7CFB: be 83 7d mov SI,0x7d83 # SI=load msg offset in 0x7D83 (0x27) # => 7DABh '\r\nReplace the disk, and \ # then press any key\r\n' 7CFE: eb e5 jmp 0x7CE5 # jump to print_msg io_error: 7D00: be 81 7d mov SI,0x7d81 # Set msg offset to 7D81h (0x18) # => 7D9Ah '\r\nDisk I/O error' 7D03: eb e0 jmp 0x7CE5 # jump to print_msg wait_for_keystroke: 7D05: 33 c0 xor AX,AX # Zero out AX 7D07: cd 16 int 0x16 # Get keystroke from keyboard 7D09: 5e pop SI # Restore the vector address 7D0A: 1f pop DS # of the ROM-DPT 7D0B: 8f 04 pop [SI] # to 0000:0078 (and clean up the stack) 7D0D: 8f 44 02 pop [SI+2] # and 7D10: cd 19 int 0x19 # Call BIOS "bootstrapper" (reboot) # without clearing memory and restoring # interrupt vectors read_io_sys: 7D12: be 82 7d mov SI,0x7d82 # SI=0x7d82 (inital error msg offset) 7D15: 8b 7d 0f mov DI,[DI+0xf] # Set DI to to the address of the first # cluster number of the entry (entry # byte is 26-27, DI points after the # filename, i.e. DI-11=start of the # entry) 7D18: 83 ff 02 cmp DI,2 # If cluster num < 2 7D1B: 72 c8 jb 0x7CE5 # jump to print_msg (error) 7D1D: 8b c7 mov AX,DI # Copy 1st cluster num to AX 7D1F: 48 dec AX # 1st cluster in data area has num=2 7D20: 48 dec AX # so decrement by 2 7D21: 8a 4e 0d mov CL,[BP+0xd] # CL=sectors/cluster (7C0Dh) 7D24: f7 e1 mul CX # DX:AX==block number of the 1st file # block relative to the data area start 7D26: 03 46 fc add AX,[BP-4] # Add number of blocks preceding data 7D29: 13 56 fe adc DX,[BP-2] # area => DX:AX == absolute number of # the 1st file block 7D2C: bb 00 07 mov BX,0x700 # Set read buffer address 7D2F: 53 push BX # Save the current offset 7D30: b1 04 mov CL,4 # Set num of blocks to read (4) 7D32: e8 16 00 call 0x7D4B # Jump to prep_normal_read_params 7D35: 5b pop BX # Restore BX 7D36: 72 c8 jc 0x7D00 # On error jump to io_error 7D38: 81 3f 4d 5a cmp [BX],0x5a4d # If first word of IO.SYS != 5a 4d 7D3C: 75 a7 jne 0x7CE5 # jump to print_msg (error) 7D3E: 81 bf 00 02 42 4a cmp [BX+0x200],0x4a42 # If first word of the second # 512B block != 4a 42 7D44: 75 9f jne 0x7CE5 # jump to print_msg (error) 7D46: ea 00 02 70 00 jmp 0x70:0x200 # Jump to 0070:0200 which is the same as # 0000:0900, i.e. start DOS ; prepare parameters for int13 (disk read) ; AH: read sector function (02h) ; AL: number of sectors to read ; CH: number of cylinder (lower 8 bits), where to start reading ; CL: starting sector number (7:6 upper 2b of cylinder, 5:0 sector) ; DH: head number ; DL: drive number ; ES:BX: where to store bytes read (already set) prep_normal_read_params: 7D4B: 50 push AX # Save AX, 7D4C: 52 push DX # and DX 7D4D: 51 push CX # and CX to the stack 7D4E: 91 xchg CX,AX # this..7D6A: calculate CHS values 7D4F: 92 xchg DX,AX # 7D50: 33 d2 xor DX,DX # zero out DX 7D52: f7 76 18 div [BP+0x18] # devide by sectors/track (7C18h) 7D55: 91 xchg CX,AX # 7D56: f7 76 18 div [BP+0x18] # devide by sectors/track (7C18h) 7D59: 42 inc DX # 7D5A: 87 ca xchg DX,CX # 7D5C: f7 76 1a div [BP+0x1a] # divide by num of heads (7C1Ah) 7D5F: 8a f2 mov DH,DL # Set head number (DL gets later # overwritten with drive number) 7D61: 8a 56 24 mov DL,[BP+0x24] # Set drive number to read (7C40h) 7D64: 8a e8 mov CH,AL # Set starting cylinder (lower 8b) and 7D66: d0 cc ror AH,1 # set the upper 2b to bits 7:6 in the 7D68: d0 cc ror AH,1 # starting sector field 7D6A: 0a cc or CL,AH # 7D6C: b8 01 02 mov AX,0x201 # Set function to "Read sectors into # memory" (AH=2) and number of sectors # to read 1 (AL=1) do_read: 7D6F: cd 13 int 0x13 # Read the sector into mem at ES:BX 7D71: 59 pop CX # Restore CX 7D72: 5a pop DX # and DX 7D73: 58 pop AX # and AX 7D74: 72 09 jc 0x7D7F # On error jump to return 7D76: 40 inc AX # Increment the absolute number of block # to read next 7D77: 75 01 jnz 0x7D7A # If increment did not cause an overflow # skip next instruction 7D79: 42 inc DX # Take AX overflow into account 7D7A: 03 5e 0b add BX,[BP+0xb] # Increment position, where to store # next bytes to read by bytes/sector 7D7D: e2 cc loop 0x7D4B # Jump to prep_normal_read_params # until CX==0 (all blocks read) return: 7D7F: c3 ret # message strings and filenames (string table) 7D80: 03 # Msg offset table 7D81: 18 # wrt. to the address 7D82: 01 # where they are 7D83: 27 # defined 7D84: 0d 0a 49 6e 76 61 6c 69 64 20 73 79 73 74 65 6d # '\r\nInvalid system\ 20 64 69 73 6b ff # disk' 7D9A: 0d 0a 44 69 73 6b 20 49 2f 4f 20 65 72 72 6f 72 # '\r\nDisk I/O error' ff # 7DAB: 0d 0a 52 65 70 6c 61 63 65 20 74 68 65 20 64 69 # '\r\nReplace the di\ 73 6b 2c 20 61 6e 64 20 74 68 65 6e 20 70 72 65 # sk, and then pre\ 73 73 20 61 6e 79 20 6b 65 79 0d 0a # ss any key\r\n' 7DD7: 00 # End of msg marker 7DD8: 49 4f 20 20 20 20 20 20 53 59 53 # 'IO SYS' 7DE3: 4d 53 44 4f 53 20 20 20 53 59 53 # 'MSDOS SYS' 7DEE: 80 01 00 # unused 7DF1: 57 49 4e 42 4f 4f 54 20 53 59 53 # 'WINBOOT SYS' # string table end 7DFC: 00 00 # unused 7DFE: 55 aa # 2 byte boot signature