Прерывание BIOS заменено на дальний вызов НЕ работает - PullRequest
0 голосов
/ 20 декабря 2018

Важное примечание: код в этом вопросе может сделать носители не загружаемыми !!

Поэтому я пытался, чтобы мой стек никогда не переполнялся, но здесь у меня вопрос.

Я пытался выполнить дальний вызов адреса таблицы векторов прерываний для INT 0x13 (в моем случае 0000f000 при 0x4C) после того, как я установил флаги из загрузчика.Int 0x13 (который записывает на диск 200h, начиная с адреса 0x0) не работал.Это не имеет смысла, так как вики говорят, что прерывания взаимозаменяемы в реальном режиме с дальними вызовами, которым предшествует нажатие флага: 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 того же диска, который загружает этот загрузчикfrom:

[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 голосов
/ 22 декабря 2018

Ваш FAR CALL для 0xF000: 0x0000 не работает, потому что это не адрес Int 0x13 в вашей таблице прерываний.Хотя 0xF000 выглядит как разумный сегмент в области BIOS, вероятность того, что вектор Int 0x13 начинается со смещения 0x0000, не очень высока.

Я потратил немало времени на этот вопрос, но некоторая настойчивость окупилась.Я нашел конкретный BIOS Intel, который демонстрирует такого рода странное поведение.Если физический адрес для записи начинается с 0x00000, запись возвращает успех, но данные неверны.В моей системе, кажется, записывается часть памяти BIOS, а не IVT.Подобные ошибки в BIOS встречаются, но некоторые случаи их обнаружения трудно найти, если вы не намеренно отлаживаете BIOS.Вероятно, это осталось незамеченным, потому что запись памяти с 0x0000: 0x0000 с Int 0x13 - это не то, что вы видите каждый день.Информация о моем BIOS:

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

Кроме того, вы можете использовать другой механизм, отличный от записи на диск.Вы можете получить записи IVT, отображая их на экране, выводя их на последовательный порт и т. Д. Вы можете написать код для прямого доступа к контроллеру жесткого диска вместо использования Int 0x13, чтобы сделать это за вас.

Я не пытался обновить BIOS, хотя История изменений BIOS ничего не говорит об этой ошибке / функции.


Чтобы найти обходные пути, я дажеЯ старался отключить линию A20 , чтобы я мог попробовать другой сегмент: адреса смещения, которые сопоставляются с тем же физическим адресом 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
0 голосов
/ 21 декабря 2018

Было обнаружено следующее необычное поведение 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, среди прочего.Вы можете даже найти значимые смещения / сегменты, которые читаются как «F0FA» как фонетическая транскрипция Vova, который является именем Владимира Путина.

Удобное напоминание о том, как читать адреса IVT: скажем, вы получаете 0x12345678 в качестве записи IVT для прерывания.Ваш сегмент и смещение будут 0x7856: 0x3412.

И использование адреса, полученного с помощью этого метода для удаленного вызова после pushf, покажет ожидаемое поведение и вызовет код прерывания.Я только что проверил, и это работает.

...