【问题标题】:Why does PC halt when i try to hook INT 13h from my bootloader?为什么当我尝试从引导加载程序中挂接 INT 13h 时 PC 会停止?
【发布时间】:2018-02-09 11:21:44
【问题描述】:

当我将软件写入 MBR 时,我的计算机停止运行。我的软件用于挂钩 INT 13h,并在执行 INT 13h 时执行一些代码。我已经为 INT 13h 尝试了太多的 ISR,但没有成功。这是我的示例来源:

cli
cs
mov si,[4Ch]
cs
mov di,[4Eh]
cs
mov [180h],cx
cs
mov [182h],dx
mov si,0h
mov di,2000h
cs
mov [4Ch],si
cs
mov [4Eh],di
sti
mov si,2000h
mov di,0
mov ds,di
mov es,si
mov si,7C6DH
mov di,0
mov cx,codelastbyte-payload
cld     
repz
movsb

mov ax,201h
push cs
pop es
mov bx,7c00h
mov cx,7
mov dx,80h
int 60h
jmp 0:7C00h

payload:           ;NEW INT13H
sti
INT 60H
iret

codelastbyte:

怎么了?

【问题讨论】:

  • 我认为这段代码比你展示的还要多?您在这里发布的内容之前是否有代码? (没有引导签名 0xaa55 所以我认为这已经被削减了)。但至少mov [180h],cx 我相信应该是mov [180h],simov [182h],dx 应该是mov [182h],di。你有mov si,7C6DH。你能用mov si,payload吗?

标签: assembly x86 x86-16 bootloader fasm


【解决方案1】:

您没有提供任何上下文,而且您的代码似乎并不完整。这些行中似乎存在一个明显的错误:

mov si,[4Ch]
cs
mov di,[4Eh]
cs
mov [180h],cx
cs
mov [182h],dx

看来你的意思是最后 4 行是 SIDI

cs
mov [180h],si
cs
mov [182h],di

如果chain loading 您无法在代码已经执行的区域顶部加载新的引导加载程序。您可能会出现异常行为。您需要将引导加载程序复制到其他地方;继续在该新位置执行代码;然后将新的引导加载程序加载到物理地址 0x07C00 的内存中。

为了便于阅读,最好将段覆盖(本例中为CS)放在内存操作数内。这段代码:

cs
mov [180h],si

可以写成:

mov [cs:180h],si

在 FASM 中完成实现

下面的代码示例:

  • 设置堆栈指针,以便我们知道我们的磁盘读取不会破坏它
  • 保存由 BIOS 通过 DL 传入的引导驱动器号。如果没有必要,最好不要硬编码引导驱动器号。
  • 将引导加载程序代码和数据复制到 0x0060:0x0000,以便在将新引导扇区链接到 0x07c0:0x0000 时不会破坏它。内存位置 0x0060:0x0000 位于中断表、BIOS 数据区和保留内存的上方。
  • 使用 FAR JMP 继续执行 0x0060 段中的代码
  • 将新的 Int 13h 中断处理程序复制到 0x2000:0x0000
  • 安装新的 Int 13h 中断处理程序
  • 在物理地址 0x07c00 的原始磁盘之上读取引导磁盘的第 7 扇区
  • FAR JMP 到 0x0000:0x7c00 处新加载的引导加载程序
  • 将汇编文件填充到 1.44MiB 软盘大小

实现这一点的 FASM 代码:

RESIDENT_SEG equ 0x2000
BOOT_SEG     equ 0x07c0
BOOTCOPY_SEG equ 0x0060
STACK_OFFSET equ 0x7c00

INT13_OFFSET equ 0x13 * 4

org 0x0000
boot_start:
    ; Set up our own stack just below bootloader @ 0x0000:0x7c00
    xor ax, ax
    mov ss, ax
    mov sp, STACK_OFFSET

    ; Copy the bootloader code and data from 0x07C0:0x0000 to 0x0060:0x0000
    mov ax, BOOT_SEG
    mov ds, ax
    mov [boot_drive], dl
    mov ax, BOOTCOPY_SEG
    mov es, ax
    cld
    xor si, si
    mov di, si
    mov cx, SIZEOF_BOOT+SIZEOF_PAYLOAD
    rep movsb

    ; Transfer control to copy of bootloader relocated to segment 0x0060
    jmp BOOTCOPY_SEG:bootcopy_cont
bootcopy_cont:

    ; Set DS = ES= 0x0060
    push es
    pop  ds

    ; ES = 0 to access IVT that begins at 0x0000:0x0000
    xor  ax, ax
    mov  es, ax

    ; Place the original FAR PTR of Int 13 into BX:AX
    cli
    mov ax, [es:INT13_OFFSET]
    mov bx, [es:INT13_OFFSET+2]

    ; Install our new int 0x13 handler
    mov si, int13
    mov di, RESIDENT_SEG
    mov [es:INT13_OFFSET], si
    mov [es:INT13_OFFSET+2], di

    ; Copy the interrupt handler to 0x2000:0x0000
    mov es, di
    mov si, payload_boot_offset
    xor di, di
    mov cx, SIZEOF_PAYLOAD
    rep movsb

    ; Now that interrupt and interrupt data (payload) is copied to 0x2000 segment
    ; save the orig_int13 to the interrupt data area. AX and BX were set earlier
    mov [es:orig_int13], ax
    mov [es:orig_int13+2], bx

    sti

    ; Read sector 7(CHS=0,0,7) to 0x07c0:0x0000 (phys address 0x07c00)
    mov ax, 201h
    mov bp, BOOT_SEG
    mov es, bp
    xor bx, bx
    mov cx, 7
    xor dx, dx
    mov dl, [boot_drive]
    call do_orig_int13

    ; Jump to newly loaded bootloader
    jmp 0:0x7C00

    ; Function : do_orig_int13
    ; Return   : none
    ; Clobbers : Same as int 0x13
    ;
    ; Description:
    ; Manually call the original Int 0x13 handler. Int instruction pushes
    ; the flags and then calls through the interrupt vector table. We
    ; Do that same process. This avoids having to use Int 0x60. The
    ; Old interrupt vector was saved to RESIDENT_SEG(0x2000):orig_int13
    ; earlier.
do_orig_int13:
    push ds
    push bp
    mov bp, RESIDENT_SEG
    mov ds, bp
    pop bp
    pushf
    call far [ds:orig_int13]
    pop ds
    ret

; Boot data
boot_drive: db 0x00

SIZEOF_BOOT = $-$$

payload_boot_offset:
org 0x0000
int13:           ;NEW INT 0x13

    ; Print MDP to upper left corner of screen in magenta on white
    push ax
    push es
    mov ax, 0xb800
    mov es, ax
    mov word [es:0x0000], (0x75 shl 8) or 'M'
    mov word [es:0x0002], (0x75 shl 8) or 'D'
    mov word [es:0x0004], (0x75 shl 8) or 'P'
    pop es
    pop ax

    ; Do original disk interrupt routine. We jump to it
    ; instead of using the INT instruction because
    ; The Int 0x13 original routine sets the flags and we
    ; want them to be returned to whoever called us.
    jmp far [cs:orig_int13]

    ; The original interrupt handler will do the IRET for us
    ; Will never return to this point

; Insert data used by the interrupt handler here
orig_int13: dd 0x0000          ; Copy of the original Int 13h handler

SIZEOF_PAYLOAD = $-$$

;Pad first sector with 0, add boot signature to last 2 bytes
times 510-(SIZEOF_BOOT+SIZEOF_PAYLOAD) db 0
dw 0xaa55

; Pad out 5 more sectors with 0
times 512 * 5 db 0x00

; Sector 7 test code
org 0x7c00
sector7:
    ; Set DS = 0x0000
    xor ax, ax
    mov ds, ax

    ; Call Int 0x13 to reset disk. Our interrupt handler should also display MDP
    ; in upper left corner of the screen. AX set to zero above. Int 0x13/AH=0 is reset.
    ; DL set by the code that loaded this bootloader just like the BIOS would have done.
    int 0x13

    cli

; Infinite loop to end the code
.endloop:
    hlt
    jmp .endloop

; Pad out remainder of sector 7
times 512-($-$$) db 0x00

; Pad out remaining bytes to create a 1.44MiB floppy image
times (2880-7)*512 db 0x00

您可以使用以下方法将其组装成软盘映像:

fasm bootload.asm disk.img

运行它:

qemu-system-i386 -fda disk.img

输出类似于:


注意事项:

  • FASM 和 NASM 的 ORG 指令的工作方式不同。
  • 代码不再将原始 Int 0x13 中断向量保存到 Int 0x60。我们通过存储到内存中的地址执行 PUSHFFAR CALL 手动调用旧中断。
  • 代码修改 Int 0x13,使其在屏幕左上角以白色洋红色显示 MDP,然后将控制权传递给原始处理程序。
  • 扇区 7 (CHS=0,0,7) 中的代码使用 Int 0x13/AH=2 来重置引导驱动器。此代码用于测试目的,但将是您希望链式加载的实际引导加载程序。
  • 此代码假定我们正在从启动的同一个磁盘链式加载不同的启动扇区 (@ CHS=0,0,7)。

【讨论】:

    猜你喜欢
    • 2012-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-29
    • 2015-07-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多