You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

拦截INT 15H/4FH实现Ctrl+Alt+S/H热键控制的问题咨询

INT 15H/4FH键盘钩子问题排查与修正

问题背景

需求是按下Ctrl+Alt+S时将boolDisplay变量设为1,按下Ctrl+Alt+H时设为0,通过拦截INT 15H的4FH服务实现键盘钩子,但按热键后无反应,同时有两个疑问:

  1. 拦截INT15H后是否需等待其再次触发才会生效?
  2. 如何正确拦截4FH服务?

用户提供的代码如下:

; Input Handling

 ; get-vector safe keep orignal int 15
mov ax, es:[15 * 4] 
mov word ptr oldInt15, ax 
mov ax, es:[15 * 4 + 2]
mov word ptr oldInt15[2], ax
  
; Decide wether to call keyboard hook  
cmp ah, 4Fh
je _KeyboardHook

_KeyboardHook:
     
in al, 60h
cmp al, 16h
je _set
cmp al, 0bh
je _clear

_set:
mov ax, 40h
mov es, ax
mov ax, es:[0017]
and ax, 00110000B
jz _dontSet
mov boolDisplay, 01h
_dontSet:
jmp _Further

_clear:
mov ax, 40h
mov es, ax
mov ax, es:[0017]
and ax, 00110000B
jz _dontClear
mov boolDisplay, 00h
_dontClear:
jmp _Further 

代码核心问题分析

  1. 中断向量保存逻辑错误
    直接读取es:[15*4]获取INT15向量是错误的——ES寄存器未被设置为中断向量表所在的0段,因此读取的是错误内存地址的值,保存的旧中断向量无效。正确做法是使用INT 35H获取中断向量:

    mov ah, 35h
    mov al, 15h
    int 21h         ; ES:BX = 原INT15中断向量
    mov word ptr oldInt15, bx
    mov word ptr oldInt15+2, es
    
  2. 钩子未注册到中断向量表
    代码仅保存了原向量,但未将自己的处理程序设置为INT15的新中断向量,导致钩子从未被触发。需要用INT 25H注册:

    mov ah, 25h
    mov al, 15h
    mov dx, offset MyInt15Handler
    mov ds, cs      ; 若处理程序在代码段,需将DS指向CS
    int 21h
    
  3. 热键状态检测完全错误
    代码中用and ax, 00110000B检测40:17H键盘状态字节,实际这个掩码对应的是Scroll Lock和Num Lock状态,而非Ctrl和Alt。正确的Ctrl+Alt检测掩码应为00001100B(对应Bit2=Ctrl、Bit3=Alt):

    and ax, 00001100B
    cmp ax, 00001100B  ; 确保Ctrl和Alt同时按下
    jne _dontSet
    
  4. INT15H处理逻辑缺失

    • 当AH≠4FH时,代码未调用原INT15H处理程序,会导致系统功能异常;
    • 进入_KeyboardHook后,未调用原INT15H的4FH服务,也没有执行IRET返回中断,会导致系统崩溃;
    • 直接读取60H端口获取扫描码时机错误——INT15H/4FH被调用时,INT09H已经处理过按键,60H端口的内容可能不是当前按键的扫描码,应通过INT15H的参数获取(调用AH=4FH时,AL通常携带扫描码相关信息)。

疑问解答

  1. 拦截INT15H后是否需等待再次触发才生效?
    是的。中断处理程序只有在对应的中断被触发时才会执行。但前提是你已经正确将自己的处理程序注册到中断向量表中,否则永远不会被调用。

  2. 如何正确拦截4FH服务?
    正确流程如下:

    • 用INT 35H获取原INT15H的中断向量并保存;
    • 用INT 25H将自定义处理程序设置为INT15H的新向量;
    • 在自定义处理程序中:
      1. 先检查AH是否为4FH,若是则执行热键检测逻辑;
      2. 无论是否是4FH服务,都要调用原INT15H处理程序(保证系统原有功能正常);
      3. 最后用IRET指令返回中断。

修正后的代码示例

; 定义全局变量
oldInt15      dd 0       ; 保存原INT15中断向量
boolDisplay   db 0       ; 目标标志变量

; 安装钩子
InstallHook:
    ; 获取原INT15向量
    mov ah, 35h
    mov al, 15h
    int 21h
    mov word ptr oldInt15, bx
    mov word ptr oldInt15+2, es

    ; 设置新INT15向量为自定义处理程序
    mov ah, 25h
    mov al, 15h
    mov dx, offset MyInt15Handler
    push cs
    pop ds
    int 21h
    ret

; 自定义INT15处理程序
MyInt15Handler:
    pushf
    cmp ah, 4Fh
    jne CallOldInt15  ; 非4FH服务,直接调用原中断

    ; 处理4FH服务:检测热键
    push ax bx es
    mov ax, 40h
    mov es, ax
    mov ax, es:[17h]  ; 读取键盘状态字节
    and ax, 00001100B ; 检测Ctrl+Alt是否同时按下
    cmp ax, 00001100B
    jne SkipHotkeyCheck

    ; 获取扫描码(INT15H/4FH调用时AL通常为扫描码)
    cmp al, 16h       ; S键的通码
    je SetFlag1
    cmp al, 0bh       ; H键的通码
    je SetFlag0

SkipHotkeyCheck:
    pop es bx ax

CallOldInt15:
    ; 调用原INT15处理程序
    jmp dword ptr [cs:oldInt15]

SetFlag1:
    mov byte ptr [cs:boolDisplay], 1
    jmp SkipHotkeyCheck

SetFlag0:
    mov byte ptr [cs:boolDisplay], 0
    jmp SkipHotkeyCheck

内容的提问来源于stack exchange,提问作者MUHAMMAD AWAIS

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 06:27:07