views:

302

answers:

3

For a project I would like to invoke the MBR on the first harddisk directly from DOS. I've written a small assembler program that loads the MBR in memory at 0:7c00h an does a far jump to it. I've put my util on a (DOS) bootable floppy. The disk (HD0, 0x80) i'm trying to boot has a TrueCrypt boot loader on it. When I run the tool in this setup, it shows up the TrueCrypt screen, but after entering the password it crashes the system. When I run my little utlility (w00t.com) on a normal WinXP machine it seems to crash immediately.

Apparently I'm forgetting some crucial stuff the BIOS normally does, my guess is it's something trivial. Can someone with better bare-metal DOS and BIOS experience help me out?

Heres my code:

.MODEL tiny
.386
_TEXT SEGMENT USE16

INCLUDE BootDefs.i

ORG 100h

start:
    ; http://vxheavens.com/lib/vbw05.html
    ; Before DOS has booted the BIOS stores the amount of usable lower memory 
    ; in a word located at 0:413h in memory. We going to erase this value because
    ; we have booted dos before loading the bootsector, and dos is fat (and ugly).

    ; fake free memory  
    ;push ds
    ;push   0
    ;pop        ds
    ;mov        ax, TC_BOOT_LOADER_SEGMENT / 1024 * 16 + TC_BOOT_MEMORY_REQUIRED
    ;mov    word ptr ds:[413h], ax  ;ax = memory in K
    ;pop ds
    ;lea si, memory_patched_msg
    ;call print

    ;mov ax, cs
    mov ax, 0
    mov es, ax

    ; read first sector to es:7c00h (== cs:7c00)
    mov  dl, 80h
    mov  cl, 1
    mov  al, 1
    mov  bx, 7c00h ;load sector to es:bx
    call read_sectors

    lea si, mbr_loaded_msg
    call print

    lea si, jmp_to_mbr_msg
    call print

    ;Set BIOS default values in environment
    cli
    mov dl, 80h ;(drive C)
    xor ax, ax
    mov ds, ax
    mov es, ax
    mov ss, ax
    mov sp, 0ffffh
    sti

    push es
    push 7c00h
    retf            ;Jump to MBR code at 0:7c00h


    ; Print string
print:
    xor bx, bx
    mov ah, 0eh
    cld

@@: lodsb
    test al, al
    jz print_end

    int 10h
    jmp @B

print_end:
    ret

    ; Read sectors of the first cylinder
read_sectors:
    mov ch, 0           ; Cylinder
    mov dh, 0           ; Head
                        ; DL = drive number passed from BIOS
    mov ah, 2
    int 13h
    jnc read_ok

    lea si, disk_error_msg
    call print
read_ok:
    ret

memory_patched_msg      db 'Memory patched', 13, 10, 7, 0
mbr_loaded_msg          db 'MBR loaded', 13, 10, 7, 0
jmp_to_mbr_msg          db 'Jumping to MBR code', 13, 10, 7, 0
disk_error_msg          db 'Disk error', 13, 10, 7, 0

_TEXT ENDS
END start
+1  A: 
stakx
It is a COM file indeed, so that's whys it's ORGed at 100h. Just like any other .com file. It loads the MBR to mem and jumps to is. As you can read in my initial question it actually does the job: the TrueCrypt bootloader gets started and shows the right screen. So loading and jumping works. Only after that, the computer freezes. Something must be wrong, perhaps the environment is not set correctly?
If that TrueCrypt boot loader on your disk actually _expects_ a regular `.com` file, then the `ORG 100h` should not be a problem. Otherwise, I think it's an error. -- Second, it's no surprise that your program crashes when executed under Windows XP. When the computer first boots, the CPU is in Real Mode (8086 emulation), and boot loaders expect that. Once Windows XP has started, the CPU will never get back into Real Mode. DOS programs might be executed in what's called Virtual 8086 mode (if I remember the name correctly), and bootloaders won't work in that CPU mode.
stakx
No, even loading a bootloader to address 0:7c00 is not possible in Windows(XP) with this utils. You cannot acces the disk directly from windows and you cannot just go pokin' around in the mem.But please read in my question that i'm running the tool from floppy (image), i.e. it's running in DOS, 16bit real mode. Furthermore is actually does the job partly already; the TC Bootloader GETS started and show the "Welcome to TC, please enter passsword" screen. Only after that it craches. Ergo, there must be something wrong in the environmnt the BIOS normally sets up.
For your informatin, interes, or good nights sleep: When you run such executable under WinXP nothin really happens, Windows complaints a bit about you hacking around on the drive directly and stops the application.
Changed my answer. It seems like I mis-read or mis-understood the OP's question at first; sorry for that.
stakx
Ok.. thanks for the new answer! Anyway, the memory managers might be the cause of all the trouble as I'm running himem.sys from the boot floppy. I'll give it a try without.As a side note: To me, memory management in DOS is kind of black magic to me; I don't know enough about it (because it's " redundant legacy" knowledge) and not much is to be found about it on the net either... (for the same reason).
Tried without himem.sys still same issue.The funny thing is, it DOES load the MBR. In this case it's the TrueCrypt MBR. This TrueCrypt bootloader actually works, it's able to load its second stage. You can enter a password (it's an ecrypted system volume) but it hangs just before it give over control to the OS laoder (winxp in this case).Any ideas? Maybe some grub devver around? :)
A: 

I don't think this is a boot loader, it's .com file that loads the boot sector and tries to execute it. So it runs after DOS has been initialized.

enix
A: 

Ok my DOS knowledge is very rusty and I haven't had the time to test/validate my answer, but I guess your problem is as follows:

When booting DOS or any other OS, they will change the interrupt table. DOS will change the interrupt table so - for example - interrupt 20 can be used to send commands to the DOS "kernel". They do this by saving the original interrupt handler, replacing it by their own handler and afterwards, as a default fallback, chaining to the original interrupt handler if they do not know how to handle the interrupt. This way they "add" new functionality to the already existing bios funcitionality, and every program running under DOS can use the system call by just setting some registers and then calling the interrupt.

However, when you boot a new operating system, this new operating system will assume that a) all interrupts are handled by the bios and b) all memory is free/unused unless reported in use by that bios.

So the new os will overwrite the memory currently in use by your old OS and then it will at some point call one of the interrupts, and will execute something in invalid memory, and your computer will crash.

So, reset your interrupt table to the original bios version and you should be fine...

Peter