BIOS中断已替换为无法正常通话

时间:2018-12-20 14:11:29

标签: assembly x86 interrupt bootloader bios

重要说明:此问题中的代码会使媒体无法启动!

所以我试图让我的堆栈永不溢出,但是我这里有一个问题。

我尝试从引导加载程序中推送标志后,对INT 0x13的中断向量表地址进行远距离调用(在我的情况下为0x4C时为0000f000)。 Int 0x13(从0x0地址开始写入磁盘200h)无效。这是没有道理的,因为Wiki表示中断在实模式下可以与远方调用在标志推送https://en.wikipedia.org/wiki/INT_(x86_instruction)之前互换。因此,这一点至关重要。以防万一,我尝试使用地址的4个变体(每个字节中的F0)进行调用,但无济于事。

[bits 16]
[org 0x7c00]
xor ax, ax
cli
mov es, ax
mov al, 0x01
mov bx, 0x7c00
mov cx, 0x0004
mov dl, 0x80
xor dh, dh
mov ah, 0x03
pushf
call 0xf000:0x0000
;int 0x13
times 510 - ($ - $$) db 0
dw 0xaa55

我用它来将IVT写入装载器从中启动的同一驱动器的扇区4:

[bits 16]
[org 0x7c00]
xor ax, ax
cli
mov es, ax
mov al, 0x01
mov bx, 0x0
mov cx, 0x0004
mov dl, 0x80
xor dh, dh
mov ah, 0x03
int 0x13
times 510 - ($ - $$) db 0
dw 0xaa55

对于讲俄语的人,我用俄语重复了这个问题:БИОС прерывание INT, подмененное на CALL, не срабатывает

如开头所述,请使用不带操作系统的媒体,因为此代码将覆盖引导加载程序及其后的扇区-这将使媒体无法引导。它还将擦除其上任何分区的分区信息。使用空的或未使用的介质。

2 个答案:

答案 0 :(得分:4)

您的FAR CALL到0xF000:0x0000无效,因为它不是中断表中Int 0x13的地址。尽管0xF000在BIOS区域中看起来像是一个合理的段,但Int 0x13的矢量从偏移量0x0000开始的机会并不高。

我在这个问题上花了很多时间,但是坚持不懈才有回报。我发现一个特定的Intel BIOS表现出这种奇怪的行为。如果要写入的物理地址从0x00000开始,则写入返回成功,但数据不正确。在我的系统上,它似乎是在写入部分BIOS内存,而不是IVT。确实会发生这种性质的BIOS错误,但是除非您有意调试BIOS,否则很难找到找到它们的附带条件。可能没有引起注意,因为您每天都不会看到用Int 0x13从0x0000:0x0000写入内存。我的BIOS信息:

BIOS Manufacturer: Intel
Version: CR94510J.86a.0045.2007.0418.1532
Date:April 18th, 2007

或者,除了写入磁盘外,您可以使用其他机制。您可以通过将IVT条目显示在屏幕上,在串行端口上输出等方式来获得IVT条目。您可以直接向access the hard disk controller写代码,而无需使用Int 0x13来为您完成。

我没有尝试更新BIOS,尽管BIOS revision history对此错误/功能没有任何说明。


要找到解决方法,我甚至竭尽全力关闭A20 line,以便尝试其他segment:偏移地址,它们映射到相同的物理地址0x00000。 0xFF00:0x1000 = 0x10000、0xFFFF:0x0010 = 0x10000和0x0000:0x0000 = 0x00000。当A20关闭时,物理地址0x10000等于0x00000。如果我从IVT中的第二个条目0x0000:0x0004开始读取,绝对没有问题。

闻起来很像臭虫。除了将IVT表复制到内存中的另一个位置(我在引导加载程序之后立即复制它)然后将其写入磁盘,我找不到任何解决方法。我采用了您的原始代码并对其进行了增强:

  • 将1024字节的IVT复制到0x0000:0x7e00。
  • 保留通过STI启用的中断(尽管您可能仍然可以使用CLI)。
  • 使用BIOS在寄存器 DL 中传递的引导驱动器号。这使我们可以写入(或读取)引导到的磁盘,而不必对值进行硬编码。
  • 在出现错误消息失败之前,请重试磁盘操作3次。
  • 当磁盘操作成功时通知用户。
  • 在继续引导周期之前提示用户敲击任何键。
  • 自从我使用USB和硬盘驱动器仿真以来,我不得不添加一个带有可引导项的分区表。该分区是自参考分区,使整个磁盘看起来像一个以MBR作为第一个扇区的分区。如果您是从真正的硬盘驱动器启动的,则可以将其删除,但是保持它不会受到伤害。
  • 评论了代码

boot.asm

DISK_RETRIES EQU 3              ; Retry disk operation 3 times on error

bits 16
org 0x7c00

start:
    xor ax, ax
    mov es, ax                  ; Set ES=0
    mov ds, ax                  ; Set DS=0
    mov ss, ax
    mov sp, 0x7c00              ; Place our stack below the bootloader @ 0x0000:0x7c00
    sti                         ; Enable external interrupts

    ; Appears to be a bug with Int 0x13 on some BIOSes where an attempt
    ; to write to disk from the physical address 0x00000 fails. Copy the
    ; 1024 byte IVT from 0x0000:0x0000 to 0x0000:0x7e00 just after bootloader

    mov di, 0x7e00              ; Destination ES:DI = 0x0000:0x7e00
    mov si, 0x0000              ; Source      DS;SI = 0x0000:0x0000
    mov cx, 1024/ 2             ; IVT is 512 16-bit words
    rep movsw                   ; Copy all 512 words (1024 bytes)

write_sector:
    mov bp, DISK_RETRIES        ; Set disk retry count

    ; Write CHS=(0,0,4)
    mov es, ax
    mov bx, 0x7e00              ; ES:BX=0x0000:0x7e00 where copy of the IVT resides
    mov cx, 0x0004              ; ch=cylinder=0, cl=sector=4
    xor dh, dh                  ; dh=heads=0
                                ; Use DL passed by the BIOS
.retry:
    mov ax, 0x0302              ; Call function 0x03 of int 13h (write sectors)
                                ;     AL = 2 = Sectors to write
    int 0x13                    ; Write 512 bytes from memory @ 0x0000:0x7e00
                                ;     to CHS=(0,0,4) LBA=3 on the boot drive
    jc .disk_error              ; If CF set then disk error

.success:
    mov si, successMsg          ; Display messageabout success
    call print_string
    mov si, anyKeyMsg           ; Press any key
    call print_string

    xor ax,ax                   ; Wait for keystroke
    int 0x16
    xor ax,ax                   ; Tell BIOS to continue and disk non-bootable
    int 0x18                    ; Our bootloader has exited back to BIOS at this point

.disk_error:
    xor ah, ah                  ; Int13h/AH=0 is drive reset
    int 0x13
    dec bp                      ; Decrease retry count
    jge .retry                  ; If retry count not exceeded then try again

error_end:
    ; Unrecoverable error; print drive error; enter infinite loop
    mov si, diskErrorMsg        ; Display disk error message
    call print_string

end_loop:
    hlt
    jmp end_loop                ; Infinite loop to prevent processor from
                                ;    getting past this point.

; Function: print_string
;           Display a string to the console on display page 0
;
; Inputs:   SI = Offset of address to print
; Clobbers: AX, BX, SI

print_string:
    mov ah, 0x0e                ; BIOS tty Print
    xor bx, bx                  ; Set display page to 0 (BL)
    jmp .getch
.repeat:
    int 0x10                    ; print character
.getch:
    lodsb                       ; Get character from string
    test al,al                  ; Have we reached end of string?
    jnz .repeat                 ;     if not process next character
.end:
    ret

diskErrorMsg: db "Unrecoverable disk error!", 0x0d, 0x0a, 0
successMsg:   db "Successfully written data to disk!", 0x0d, 0x0a, 0
anyKeyMsg:   db "Press any key to continue...", 0x0d, 0x0a, 0

times 446-($-$$) db 0   ; Pad remainder of boot sector up to first partition entry
part1_entry:
db 0x80                 ; Bootable partiion
db 0x00, 0x01, 0x00     ; CHS of first absolute sector (MBR) of hard drive
                        ;     Head=0, Sector=1, Cylinder=0
db 0x0c                 ; Partition type (has to be non-zero)
                        ;     0x0c = Win 95 FAT32 (LBA)
db 0x00, 0x01, 0x00     ; CHS of last absolute sector (MBR) of hard drive
                        ;     Head=0, Sector=1, Cylinder=0
                        ;     We are effectively saying Size of partition is 1 sector
dd 0x0                  ; LBA of first absolute sector (0=MBR)
dd 0x1                  ; Number of sectors in partition. We set it to 1 but if you
                        ;     wish you could set it to the number of sectors on the disk

times 510-($-$$) db 0   ; Pad remainder of boot sector up to boot signature. This zeroes
                        ;     partition entries 2,3,4 effectively making them inactive

dw 0xaa55

可以使用以下命令将其内置到引导加载程序/ MBR中:

nasm -f bin boot.asm -o boot.bin 

在具有此引导加载程序的实际系统上,我没有请求该代码,而是获得了正确的实模式IVT转储,而不是获取内存。十六进制转储似乎是合理的,因为大多数条目的段均为0xF000且偏移量非零:

0000000 ff53 f000 ff53 f000 e2c3 f000 27b8 f000
0000010 ff53 f000 ff54 f000 27b8 f000 27b9 f000
0000020 fea5 f000 e987 f000 27b9 f000 27b9 f000
0000030 27b9 f000 27ac f000 ef57 f000 27b9 f000
0000040 0014 c000 f84d f000 f841 f000 4902 f000 <--- offset 0x4c is Int 0x13 0xf000:0x4902
0000050 e739 f000 ec6a f000 e82e f000 efd2 f000
0000060 53b5 f000 e6f2 f000 fe6e f000 ff53 f000
0000070 ff53 f000 f0a4 f000 efc7 f000 7011 c000
0000080 27b9 f000 27b9 f000 27b9 f000 27b9 f000
0000090 27b9 f000 27b9 f000 27b9 f000 27b9 f000
00000a0 27b9 f000 27b9 f000 27b9 f000 27b9 f000
00000b0 27b9 f000 27b9 f000 27b9 f000 27b9 f000
00000c0 27b9 f000 27b9 f000 27b9 f000 27b9 f000
00000d0 27b9 f000 27b9 f000 27b9 f000 27b9 f000
00000e0 27b9 f000 27b9 f000 27b9 f000 27b9 f000
00000f0 27b9 f000 27b9 f000 27b9 f000 27b9 f000
0000100 ec59 f000 00b0 0040 f065 f000 6c11 c000
0000110 27b9 f000 27b9 f000 00c0 0040 27b9 f000
0000120 27b9 f000 27b9 f000 27b9 f000 27b9 f000
0000130 27b9 f000 27b9 f000 27b9 f000 27b9 f000
0000140 27b9 f000 27b9 f000 27b9 f000 27b9 f000
0000150 27b9 f000 27b9 f000 27b9 f000 27b9 f000
0000160 27b9 f000 27b9 f000 27b9 f000 27b9 f000
0000170 27b9 f000 27b9 f000 27b9 f000 27b9 f000
0000180 0000 0000 0000 0000 0000 0000 0000 0000
0000190 0000 0000 0000 0000 0000 0000 27b9 f000
00001a0 27b9 f000 27b9 f000 27b9 f000 27b9 f000
00001b0 27b9 f000 0014 c000 27b9 f000 27b9 f000
00001c0 660b f000 27a3 f000 27b9 f000 c394 f000
00001d0 2c77 f000 2794 f000 3229 f000 3229 f000
00001e0 0000 0000 0000 0000 0000 0000 0000 0000
... The remainder up to 0x400 was all zero

答案 1 :(得分:-1)

已发现BIOS的以下异常行为,这解释了远端调用为何不起作用的原因。

仅使用INT 0x13执行有问题的代码时,打算将中断向量表从es:bx的0x0:0x0(将mov bx,0x7c00替换为mov bx,0x0)写入驱动器上的扇区,您可能无法获得确切的RAM内存标记。就我而言,我得到的是零,我得到的是ASCII,而不是合法的地址。即使当我尝试远距离调用我在某个时候看到的看似正确的地址时,它也没有执行中断代码,这说明我收到了伪造的IVT。

不使用中断而将原始位读取并显示到屏幕缓冲区,似乎确实显示了真正的IVT,当然,数据与中断13h的输出完全不符。我相信这种消极后果是显而易见的。

今晚我迅速记下了awesombler代码,以在不使用任何中断的情况下将中断向量表的前20个条目打印到屏幕上:

[bits 16]
[org 0x7C00]

xor ax, ax
cli
mov ax, 0xb800
mov es, ax
mov di, 0
mov ax, 0
mov ds, ax
mov si, 0x0     ;starting RAM address, 0 for IVT
mov cx, 0
mov dl, 20      ;how many interrupt vectors to print (<25 for vga)
moreints:
mov bh, 4       ;counter for bytes of each interrupt vector entry to print
morebytes:      
mov ah, [ds:si]
mov bl, 8       ;counter for bits of each byte to print
morebits:
shl ah, 1
mov al, 48
jnc zero
mov al, 49
zero:
mov [es:di], al
inc di
inc di
dec bl
jnz morebits
mov al, 32
mov [es:di], al
inc di
inc di
inc si
dec bh
jnz morebytes
add cx, 80*2
mov di, cx
dec dl
jnz moreints
times 510 - ($ - $$) db 0
dw 0xaa55

现在,您可以找到您确切的中断例程的地址,并出于教育目的将其废止。如果您得到怪异的读数,则可能表明存在BIOS rootkit。您甚至可能会找到有意义的偏移量/段,这些段/段读作“ Vova”的语音记录的“ F0FA”,这是弗拉基米尔·普京的名字。

有关如何读取ivt地址的便捷提示:例如,您将0x12345678作为中断的IVT条目。您的细分和偏移量将为0x7856:0x3412。

并且在pushf之后使用通过此方法获取的地址进行far调用将表现出预期的行为并调用中断代码。我刚刚对其进行了测试,并且可以正常工作。