Jump to content

- - - - -

Beware: Some BIOSes can modify bytes in your boot code!

  • Please log in to reply
No replies to this topic

#1 steve6375


    Platinum Member

  • Developer
  • 7566 posts
  • Location:UK
  • Interests:computers, programming (masm,vb6,C,vbs), photography,TV,films
    United Kingdom

Posted 2 weeks ago

I recently came across a user who had written their own 512-byte 'Hello World'  boot code in assembler and wrote it using dd to the first sector of a USB drive.

The code he used was similar to here:



They then tested it on various PCs and also QEMU.

Whilst QEMU and some PCs worked fine and printed 'Hello World', two particular DELL PCs only printed 'Hell'.


It turned out that the reason was that the two Dell PCs were booting the USB drive as a floppy disk instead of a hard disk - but the user's code did not depend on what drive it booted from. It simply printed a message so it should not have mattered whether it booted from a floppy or a hard disk!


It turns out that some BIOSes have a 'feature' in that if they boot from a floppy disk MBR, they assume that the boot sector contains a BPB  (BIOS Parameter Block) and after reading the sector data into memory at 7C00h, they then go and 'update' some bytes in the code before jumping to the start (7C0:0).


See here for more info.


The code to test this behaviour was:

; Simple bootloader that dumps the bytes in the BIOS Parameter
; Block BPB. First 3 bytes should be EB 3C 90. The rest should be 0xAA
; unless you have a BIOS that wrote drive geometry information
; into what it thinks is a BPB.
; Macro to print a character out with char in BX
%macro print_char 1
    mov al, %1
    call bios_print_char
org 0x7c00
bits 16
    jmp main
    TIMES 3-($-$$) DB 0x90   ; Support 2 or 3 byte encoded JMPs before BPB.
    ; Fake BPB filed with 0xAA
    TIMES 59 DB 0xAA
    xor ax, ax
    mov ds, ax
    mov ss, ax              ; Set stack just below bootloader at 0x0000:0x7c00
    mov sp, boot
    cld                     ; Forward direction for string instructions
    mov si, sp              ; Print bytes from start of bootloader
    mov cx, main-boot       ; Number of bytes in BPB
    mov dx, 8               ; Initialize column counter to 8
                            ;     So first iteration prints address
    cmp dx, 8               ; Every 8 hex value print CRLF/address/Colon/Space
    jne .procbyte
    print_char 0x0d         ; Print CRLF
    print_char 0x0a
    mov ax, si              ; Print current address
    call print_word_hex
    print_char ':'          ; Print ': '
    print_char ' '
    xor dx, dx              ; Reset column counter to 0
    lodsb                   ; Get byte to print in AL
    call print_byte_hex     ; Print the byte (in BL) in HEX
    print_char ' '
    inc dx                  ; Increment the column count
    dec cx                  ; Decrement number of  bytes to process
    jnz .tblloop
    cli                     ; Halt processor indefinitely
    jmp .end
; Print the character passed in AL
    push bx
    xor bx, bx              ; Attribute=0/Current Video Page=0
    mov ah, 0x0e
    int 0x10                ; Display character
    pop bx
; Print the 16-bit value in AX as HEX
    xchg al, ah             ; Print the high byte first
    call print_byte_hex
    xchg al, ah             ; Print the low byte second
    call print_byte_hex
; Print lower 8 bits of AL as HEX
    push bx
    push cx
    push ax
    lea bx, [.table]        ; Get translation table address
    ; Translate each nibble to its ASCII equivalent
    mov ah, al              ; Make copy of byte to print
    and al, 0x0f            ;     Isolate lower nibble in AL
    mov cl, 4
    shr ah, cl              ; Isolate the upper nibble in AH
    xlat                    ; Translate lower nibble to ASCII
    xchg ah, al
    xlat                    ; Translate upper nibble to ASCII
    xor bx, bx              ; Attribute=0/Current Video Page=0
    mov ch, ah              ; Make copy of lower nibble
    mov ah, 0x0e
    int 0x10                ; Print the high nibble
    mov al, ch
    int 0x10                ; Print the low nibble
    pop ax
    pop cx
    pop bx
.table: db "0123456789ABCDEF", 0
; boot signature
TIMES 510-($-$$) db 0
dw 0xAA55

and the bin file was made using NASM

nasm -f bin floppyboottest.asm -o floppyboottest.bin

and the sector was written to a USB drive LBA0 (could use RMPrepUSB - File>Drive or dd, etc.)


The expected output should be all AAs (after the first 3 bytes), but the user found that his Dell PCs gave the attached screen.

You can see that some bytes (Reserved sectors and disk number - 1c-1f and 24h) have been modified by the BIOS before the code was executed.


So it seems that an MBR needs to have 59 bytes of padded space to allow for bad BIOSes which assume that all USB floppy MBR's are actually on DOS 3 or higher formatted floppy drives!

Attached Thumbnails

  • badflopboot.jpg

Attached Files

#2 Wonko the Sane

Wonko the Sane

    The Finder

  • Advanced user
  • 16065 posts
  • Location:The Outside of the Asylum (gate is closed)

Posted 2 weeks ago

A good case for using the makebootfat MBR/PBR (deriving from syslinux, but with a "hole" for bootsector data).


But I don't see the need for the 59 bytes padding, one could only workaround/bypass those five (4+1) bytes, or - easier - the 9 bytes from 1c to 24h.




#3 Mikorist


    ▂ ▃ █ ▅ ▆

  • Advanced user
  • 771 posts
    United Nations

Posted A week ago

I am much more concerned about the BIOS Intel Me engine.
I had several inexplicable hacks on turned off machines of my users ....It doesn't matter what operating system it was. (Linux - Windows or macOS) So I investigated.
Every modern processor made by Intel contains a backdoor known as the Intel Management Engine (IME). 
This is an isolated and protected coprocessor that is embedded in all Intel chipsets that are newer than the first quarter of 2008. 
This includes all desktops, servers, ultrabooks, tablets, and laptops with the Intel Core vPro processor family. It includes the Intel Core i3, i5, i7, and Intel Xeon processor E3-1200 product family.
The Intel Management Engine  can:
Access all areas of your computer's memory, without the CPU’s knowledge.
Access every peripheral attached to your computer.
Set up a TCP/IP server on your network interface that can send and receive traffic, regardless of whether the OS is running a firewall or not.
Run remotely even when your computer is turned off.
Enable a remote user to power on, power off, view information about, and otherwise manage your PC.
ME firmware versions 4.0 and later (Intel 4 Series and later chipsets) include a DRM application called "Protected Audio Video Path" (PAVP). This allows a remote user to access everything that is shown on your screen.
Here's a demo of how to hack a turned of computer via IME



python me_cleaner.py -S -O modified_image.bin original_dump.bin

On some machines, this is impossible to do without programming the BIOS chip. So I used CH341A USB Programmer .

1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users