C 实模式下的中断处理程序链接
我试图钩住biosint13h,将我的自定义功能添加到其中,并劫持一些现有功能。 旧Int 13h向量存储在全局变量中。 当调用中断处理程序时,DS被设置为与调用者的原始数据段不匹配的值。因此,访问调用者的全局变量变成了一件令人头痛的事情 链接中断处理程序的最佳实践是什么 吊钩的安装方式如下:C 实模式下的中断处理程序链接,c,assembly,interrupt-handling,tasm,real-mode,C,Assembly,Interrupt Handling,Tasm,Real Mode,我试图钩住biosint13h,将我的自定义功能添加到其中,并劫持一些现有功能。 旧Int 13h向量存储在全局变量中。 当调用中断处理程序时,DS被设置为与调用者的原始数据段不匹配的值。因此,访问调用者的全局变量变成了一件令人头痛的事情 链接中断处理程序的最佳实践是什么 吊钩的安装方式如下: #ifdef __cplusplus # define INTARGS ... #else # define INTARGS unsigned bp, unsigned di, unsigned si
#ifdef __cplusplus
# define INTARGS ...
#else
# define INTARGS unsigned bp, unsigned di, unsigned si,\
unsigned ds, unsigned es, unsigned dx,\
unsigned cx, unsigned bx, unsigned ax
#endif
void interrupt (far *hackInt13h)(INTARGS) = NULL;
void interrupt (far *biosInt13h)(INTARGS) = (void interrupt (far *)(INTARGS))0xDEADBEEF;
void main(void)
{
struct REGPACK reg;
biosInt13h = getvect(0x13);
hackInt13h = int13h;
setvect(0x13, hackInt13h);
// Calling CAFE
reg.r_ax = 0xCAFE;
intr(0x13, ®);
printf("Cafe returned: 0x%04x\n", reg.r_ax);
// Resetting FDD just to check interrupt handler chaining
reg.r_ax = 0;
reg.r_dx = 0;
intr(0x13, ®);
printf("CF=%i\n", reg.r_flags & 0x01);
setvect(0x13, biosInt13h);
}
Int 13h钩代码:
P286
.MODEL TINY
_Data SEGMENT PUBLIC 'DATA'
EXTRN _biosInt13h:FAR
_Data ENDS
_Text SEGMENT PUBLIC 'CODE'
PUBLIC _int13h
_int13h PROC FAR
pusha
cmp AX,0CAFEh
jnz chain
popa
mov AX, 0BEEFh
iret
chain:
popa
call far ptr [_biosInt13h] ; <-- at this moment DS points to outer space
; and _biosInt13h is not valid
_int13h ENDP
_Text ENDS
END
P286
.微型模型
_数据段公共“数据”
EXTRN_biosInt13h:远
_数据端
_文本段公共“代码”
公共_int13h
_int13h PROC FAR
普沙
cmp AX,0CAFEh
jnz链
波帕
mov AX,0BEEFh
艾雷特
链:
波帕
呼叫远ptr[_biosInt13h] 谢谢你们,我找到了解决办法
我错过的第一件事是将变量移动到代码段并显式指定它
第二种方法是使用hacked(栈上推送)返回地址和retf
,而不是call
,后者在栈上添加真实的返回地址
无需显式地pushf
,因为标记已在int
之后的堆栈上。无论是在我的处理程序中还是在链接的处理程序中,标记都将在iret上弹出
P286
.MODEL TINY
_Text SEGMENT PUBLIC 'CODE'
EXTRN _biosInt13h:FAR ; This should be in CODE 'cause CS is only segreg reliable
PUBLIC _int13h
_int13h PROC FAR
pusha
cmp AX, 0CAFEh
jnz chain
popa
mov AX, 0BEEFh
iret
chain:
popa
push word ptr cs:[_biosInt13h + 2] ; Pushing chained handler SEG on stack
push word ptr cs:[_biosInt13h] ; Pushing chained handler OFFSET on stack
retf ; ...actually this is JMP FAR to address on stack
_int13h ENDP
_Text ENDS
END
谢谢你们,我找到了解决办法
我错过的第一件事是将变量移动到代码段并显式指定它
第二种方法是使用hacked(栈上推送)返回地址和retf
,而不是call
,后者在栈上添加真实的返回地址
无需显式地pushf
,因为标记已在int
之后的堆栈上。无论是在我的处理程序中还是在链接的处理程序中,标记都将在iret上弹出
P286
.MODEL TINY
_Text SEGMENT PUBLIC 'CODE'
EXTRN _biosInt13h:FAR ; This should be in CODE 'cause CS is only segreg reliable
PUBLIC _int13h
_int13h PROC FAR
pusha
cmp AX, 0CAFEh
jnz chain
popa
mov AX, 0BEEFh
iret
chain:
popa
push word ptr cs:[_biosInt13h + 2] ; Pushing chained handler SEG on stack
push word ptr cs:[_biosInt13h] ; Pushing chained handler OFFSET on stack
retf ; ...actually this is JMP FAR to address on stack
_int13h ENDP
_Text ENDS
END
通常的解决方案是将变量移动到代码段中,这样您就可以使用call far ptr[cs:_biosInt13h]
或根据需要设置段,检索指针,将其放在堆栈上,恢复段,然后执行retf
跳转到BIOS中断处理程序。请注意,由于中断处理程序除了返回地址外还会弹出标志,因此代码将按原样崩溃。如果您使用的是tiny model,则可以对far调用使用cs
段覆盖。但是,您需要将其更改为远跳转,或者在远调用之前添加pushf
。如果您没有返回到处理程序并且正在尾调用旧的处理程序,那么您可以使用jmp远ptr[cs:_biosInt13h]
。然后,iret
将由旧的中断处理程序直接执行。只有在微型模型中执行此操作并最终构建COM程序时,CS段重写才会起作用,否则您必须显式加载DS寄存器,其中包含特定于所用模型的段。@MichaelPetch您只需将变量与访问它的中断函数位于同一段中。通常的解决方案是将变量移动到代码段中,以便使用调用far ptr[cs:_biosInt13h]
或根据需要设置段,检索指针,将其放在堆栈上,还原段,然后执行retf
跳转到BIOS中断处理程序。请注意,由于中断处理程序除了返回地址外还会弹出标志,因此代码将按原样崩溃。如果您使用的是tiny model,则可以对far调用使用cs
段覆盖。但是,您需要将其更改为远跳转,或者在远调用之前添加pushf
。如果您没有返回到处理程序并且正在尾调用旧的处理程序,那么您可以使用jmp远ptr[cs:_biosInt13h]
。然后,iret
将由旧的中断处理程序直接执行。只有在微型模型中执行此操作并最终构建COM程序时,CS段重写才会起作用,否则您必须显式加载DS寄存器,其中包含特定于所用模型的段。@MichaelPetch您只需将变量与访问它的中断函数位于同一段中。为什么使用push
push
retf
。你就不能做一个间接跳远吗。试着记住TASM的语法。也许jmp-dword-ptr-cs:[\u-biosInt13h]
?您只需编写jmp[\u-biosInt13h]
,而不必编写RETF内容,但是您需要将\u biosInt13h
正确地声明为EXTERN\u biosInt13h:DWORD
,并且您需要告诉汇编程序它不能假设DS和ES指向与\u TEXT
相同的段,而假设DS:NOTHING,ES:NOTHING
@MichaelPetch也可以工作push
push
retf
的灵感来源于MS-DOS 5.0启动记录的反汇编。@RossRidge远指针的大小与DWORD相同,但似乎最好使用适当的类型,而不是相同长度的类型。因此我更喜欢jmp-far-ptr
而不是jmp-dword-ptr
No,远指针的合适类型是dword。。FAR是您直接跳转到的FAR标签的适当类型。DWORD是您间接跳转到的远指针的合适类型。为了明确起见,我要说的是,您不应该使用jmp-far-ptr
,因为这将是一个直接跳转,如果您正确声明\u biosInt13h
,则不需要使用jmp-dword-ptr
。DWORD和FAR的大小相同,但与跳转和调用指令一起使用时不能互换。DWORD是获得间接跳转所需的类型。为什么使用push
push
retf
。你就不能做一个间接跳远吗。试着记住TASM的语法。也许jmp-dword ptr-cs:[\u-biosInt13h]
?您可以只编写jmp[\u-biosInt13h]
而不是RETF内容,但是您需要将\u-biosInt13h
正确地声明为EXTERN\u-biosInt13h:dword
,并且您需要告诉汇编程序它不能假设DS和ES指向同一个点