如何实现用于视频输出的基础x86中断管理器?相关技术疑问
我原本打算逆向分析加载到内存中的BIOS模块,不过先在此咨询问题。我写了一个极简bootloader(可在屏幕输出'e'):
mov ah, 0x0e mov al, 'e' int 0x10 jmp $ times 510-($-$$) db 0 dw 0xaa55
用nasm编译后,在VirtualBox中创建虚拟软盘的命令:
head -c 1474560 /dev/zero > bootloader.vfd dd status=noxfer conv=notrunc if=test.bin of=bootloader.vfd
生成的镜像可正常运行,现在我想尝试向输出设备渲染图形,遇到几个瓶颈问题,以下是对应的解决方法:
问题解答
1. 如何覆盖BIOS已设置的IVT?
实模式下IVT(中断向量表)位于内存0x00000到0x003FF区域,每个中断向量占4字节(低2字节是偏移地址,高2字节是段地址)。覆盖步骤:
- 执行
cli指令关闭中断,避免修改过程中触发中断引发异常 - 计算目标中断的向量地址:
中断号 * 4,比如替换int 0x10的话,地址就是0x10 * 4 = 0x40 - 将自定义中断处理程序的偏移地址写入该地址的低2字节,段地址写入高2字节
- 执行
sti指令重新开启中断
注意:替换前建议保存原向量内容,后续可能需要恢复;自定义处理程序必须遵循x86中断调用约定,最后用iret指令返回。
2. 如何通过编程方式选择可用的显示设备?
实模式下可借助BIOS中断int 0x10完成显示设备的检测与模式设置:
- 调用
int 0x10且ah=0x0F,可获取当前显示模式:返回后al存储模式号,ah存储列数,bh存储当前页号 - 调用
int 0x10且ah=0x00,al传入目标模式号即可设置显示模式(比如0x13是320x200 256色图形模式,0x03是80x25文本模式) - 检测可用设备时,可枚举标准显示模式,调用
int 0x10 ah=0x00尝试设置,成功则说明该模式对应的设备可用;也可调用int 0x11获取设备列表,其中位4-5表示显示适配器类型(00=CGA/EGA/VGA,01=MDA,10=CGA,11=EGA)
3. 如何确定哪些内存区域可用于存放代码/堆?
最可靠的方式是通过BIOS中断int 0x15的ah=0xE820功能获取内存映射(支持扩展内存):
- 初始化寄存器:
eax=0xE820,ebx=0,ecx=24,edx=0x534D4150(SMAP签名),es:di指向一个24字节的缓冲区 - 调用
int 0x15,成功后缓冲区会填充内存区域的基地址、长度、类型(1=可用,2=保留等) - 循环调用直到
ebx=0,收集所有标记为“可用”的内存区域
另外,实模式下前640KB(0x00000到0x9FFFF)是常规内存,其中0x00000-0x003FF是IVT,0x00400-0x004FF是BIOS数据区(BDOS),剩余大部分区域可用;注意bootloader加载在0x7C00,需避开该区域及周边空间。
实现用于视频输出的基础x86中断管理器
以替换int 0x10(BIOS视频中断)为例,实现步骤如下:
- 保存原中断向量:读取IVT中
int 0x10对应的4字节地址,存储到内存安全区域,方便后续调用原BIOS功能或恢复 - 编写自定义中断处理程序:
- 开头用
pusha和pushf保存所有寄存器状态(避免破坏调用方环境) - 根据
ah的值判断要处理的功能:比如ah=0x0E是电传输出,可自行实现文本输出逻辑;对于不需要自定义处理的功能,直接跳转到原BIOS中断处理程序执行 - 处理完成后用
popf和popa恢复寄存器,最后执行iret返回
- 开头用
- 更新IVT向量:按照前面覆盖IVT的方法,将自定义处理程序的段地址和偏移地址写入
int 0x10对应的IVT位置 - 功能测试:调用
int 0x10的相关功能,验证自定义处理程序是否正常工作
内容的提问来源于stack exchange,提问作者Gabriel Reyes
相关产品推荐
相关产品推荐

