当我检查了内存为0x10
还有就是你的问题的内容。由于每个向量是4个字节,所以中断0x10
的入口位于地址0x40
。
(gdb) x/a 0x40
0x40: 0xc0004d65
(gdb) p/x $cs
$4 = 0xc000
(gdb) p/x $eip
$5 = 0x4d66
我的qemu + gdb组合似乎跳过中断后的一个字节,这可能是一个错误。
但我们相信这跳过一个字节是一个bug
是。让我们来测试:
xor ax, ax
mov ds, ax
mov ax, [0x40]
mov dx, [0x42]
mov [old], ax
mov [old+2], dx
mov word [0x40], handler
mov [0x42], cs
mov ah, 0x0e
mov al, 'H'
int 0x10
jmp $
handler:
inc ax
jmp far [old]
old: dd 0
此挂钩int 0x10
我们handler
,使用单字节指令(操作码0x40
),这增加ax
然后去到原来的处理程序。如果你运行这个,你会看到它打印I
而不是H
,所以inc ax
正确执行。此外,还可以将断点的处理程序,并把它停在那里,然后再继续原来的处理程序:
Breakpoint 2, 0x00007c24 in ??()
(gdb) x/a 0x7c29
0x7c29: 0xc0004d65
(gdb) si
0x00007c25 in ??()
(gdb)
0x00004d65 in ??()
注意,如果你单步,广发行将再次跳过第一个指令:
0x00007c20 in ??()
(gdb) x/4i $eip
=> 0x7c20: int $0x10
0x7c22: jmp 0x7c22
0x7c24: inc %ax
0x7c25: ljmp *0x7c29
(gdb) p/x $ax
$4 = 0xe48
(gdb) si
0x00007c25 in ??()
(gdb) p/x $ax
$5 = 0xe49
你可以看到它去了0x7c25
而不是0x7c24
,但ax
已经增加了,所以执行了inc ax
。
替换inc ax
与add ax, 1
(这是一个3字节)指令的工作原理是一样的,所以gdb
实际上是跳过第一条指令而不是一个字节。
谢谢....但是我们确定跳过一个字节是一个错误 – sarthak 2015-02-07 14:24:37
在执行int指令之前还有一件事,esp指向0x6f2c,它在执行后变为0x6f26。为什么ESP改变了? – sarthak 2015-02-08 07:27:50
因为'int'将返回地址和标志放在堆栈上。这是16位实模式下的6个字节。 – Jester 2015-02-08 13:34:01