从 DOS 启动 MBR

发布于 2024-08-29 01:52:06 字数 2216 浏览 6 评论 0原文

对于一个项目,我想直接从 DOS 调用第一个硬盘上的 MBR。我编写了一个小型汇编程序,该程序将 MBR 加载到内存中的 0:7c00h 处,并进行远跳转。我已将实用程序放在 (DOS) 可启动软盘上。我尝试启动的磁盘(HD0,0x80)上有一个 TrueCrypt 启动加载程序。当我在此设置中运行该工具时,它会显示 TrueCrypt 屏幕,但输入密码后会导致系统崩溃。当我在普通的 WinXP 机器上运行我的小实用程序 (w00t.com) 时,它似乎立即崩溃。

显然我忘记了 BIOS 通常所做的一些重要的事情,我猜这是一些微不足道的事情。有更好的裸机 DOS 和 BIOS 经验的人可以帮助我吗?

这是我的代码:

.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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

九公里浅绿 2024-09-05 01:52:06

已编辑 - 新答案:

好的,看来我首先误解了你的问题。我可以给出的唯一进一步建议是:

  • 检查您是否没有加载 HIMEM.SYS 和/或 EMM386.EXE(也没有加载任何其他内存管理器) )。执行引导加载程序时,CPU必须处于实模式。

  • 看看 Ralf Brown 的中断列表。如果我没记错的话,其中有一些有关启动过程的技术信息。它可能会给您一个提示。

  • 查看其他加载器实用程序的源代码,例如loadlin。 (它所做的事情与您的实用程序并不完全相同,但可能会给您一些见解。)


之前的答案:

Is ORG 100h 在引导加载程序中确实是正确的做法吗?

我认为这仅与 DOS .com 可执行文件相关,因为 DOS 将使用以下命令初始化前 256 个字节:程序段前缀 (PSP)。如果你编写一个引导加载程序,就没有 DOS,也没有 PSP 之类的东西。我想这必须是ORG 0

Edited -- new answer:

OK, seems like I first misunderstood your question. The only further advice I can give is this:

  • Check that you don't load either HIMEM.SYS and/or EMM386.EXE (nor any other memory manager). The CPU must be in Real Mode when the bootloader executes.

  • Have a look at Ralf Brown's interrupt list. If I remember correctly, there's some technical info somewhere in there about the boot process. It might give you a hint.

  • Look at the source code of other loader utilities, e.g. loadlin. (It doesn't do exactly the same thing as your utility, but might give you some insight, nevertheless.)


Previous answer:

Is ORG 100h really the correct thing to do in a boot loader?

I thought this was just relevant for DOS .com executables, because DOS will initialize the first 256 bytes with the Program Segment Prefix (PSP). If you write a boot loader, there is no DOS, and no such thing as a PSP. I'd suppose this has to be ORG 0.

薄荷梦 2024-09-05 01:52:06

好吧,我的 DOS 知识很生疏,我没有时间测试/验证我的答案,但我猜你的问题如下:

当启动 DOS 或任何其他操作系统时,它们会更改中断表。 DOS 将更改中断表,因此 - 例如 - 中断 20 可用于向 DOS“内核”发送命令。他们通过保存原始中断处理程序,用自己的处理程序替换它,然后作为默认后备,如果他们不知道如何处理中断,则链接到原始中断处理程序来做到这一点。这样他们就为已经存在的BIOS功能“添加”了新的功能,并且每个在DOS下运行的程序都可以通过设置一些寄存器然后调用中断来使用系统调用。

但是,当您启动新操作系统时,该新操作系统将假定 a) 所有中断均由 BIOS 处理,b) 所有内存都是空闲/未使用的,除非该 BIOS 报告正在使用。

因此,新操作系统将覆盖旧操作系统当前使用的内存,然后它会在某个时刻调用其中一个中断,并在无效内存中执行某些操作,然后您的计算机将崩溃。

所以,将你的中断表重置为原始的BIOS版本,你应该没问题......

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...

汐鸠 2024-09-05 01:52:06

我不认为这是一个引导加载程序,它是加载引导扇区并尝试执行它的 .com 文件。所以它在DOS初始化之后运行。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文