1. 背景
本文介绍了“调用元神操作系统API向硬盘扇区写数据”的程序实现及测试结果。
2. 方法
(1)调用元神操作系统API读硬盘扇区
本部分内容已在前面的文章中进行介绍,详细内容请参考“编写程序调用元神操作系统的API”。
(2)调用元神操作系统API写硬盘扇区
本例通过调用系统API来向硬盘扇区写数据,代码如下所示:
sector_buff: times 512 db 1
demo_write_disk:
pusha
mov edi, API_PARAM
mov dword [fs:edi], API_WRITE_DISK_SECTOR
mov dword [fs:edi+4], 2 ;2 parameters
mov dword [fs:edi+8], 0 ;parameter_1: sector no.
xor eax, eax
mov ax, ds
add eax, SEG_BASE
mov bh,byte [fs:eax+7]
mov bl,byte [fs:eax+4]
shl ebx,16
mov bx,word [fs:eax+2]
add ebx, sector_buff
mov dword [fs:edi+12], ebx ;parameter_2: start address of buffer
call pword [fs:OS_API]
popa
ret
代码中先定义了变量sector_buff,用于存储要写入硬盘扇区的数据,本例为512个1。然后在代码中如前述文章所描述的那般进行参数设置,将API类型设置为API_WRITE_DISK_SECTOR,该API需要2个参数,第一个参数是要写数据的扇区的LBA号(本例要写0号扇区),第二个参数为保存要写入数据的缓冲区起始地址(本例为sector_buff)。设置好参数后通过“call pword [fs:OS_API]”进行API调用、完成写扇区操作。
本例和前述系统API调用的主要差别在于新的API类型和缓冲区地址转换,新增的定义如下:
SEG_BASE equ 0x00040000
API_WRITE_DISK_SECTOR equ 0x00000008
其中,SEG_BASE表示的是保护模式下GDT的起始地址,通过它和DS中的段选择子定位到本demo程序加载到内存的位置,并提取出其起始地址,再加上sector_buff的偏移,得到该变量的真实地址,最后才将该地址赋给调用参数。
(3)附属程序
本例先读取0号扇区的内容并打印到屏幕上,然后将新的数据写入0号扇区,最后再重新读取0号扇区并打印到屏幕上,代码如下所示:
use32
START:
pusha
call demo_read_disk
call demo_write_disk
call demo_read_disk
popa
iret
include 'api_def.inc'
OS_API equ 0x00030C16
API_PARAM equ 0x03000000
SEG_BASE equ 0x00040000
cursor_x equ 0x02004B10
cursor_y equ 0x02004B12
代码中的demo_read_disk函数直接采用前述文章中的实现代码即可,具体可参考前述文章。
(4)运行程序
将以上的代码保存为DEMO.ASM,编译生成DEMO.BIN,并将该可执行文件复制到装有元神操作系统的U盘中,之后用该U盘开机进入元神系统并输入命令“ZX DEMO.BIN”执行程序如下:
可以看到,硬盘0号扇区的内容已经成功修改,改成了全1的512个字节数据。由于硬盘的0号扇区是MBR扇区,包含着启动操作系统的关键代码,所以修改后无法再从硬盘启动操作系统。拔掉装有元神操作系统的U盘,然后开机如下图所示:
可以看到,的确无法再从硬盘启动操作系统。使用上述代码将备份的MBR扇区内容重新写回0号扇区,然后拔掉装有元神操作系统的U盘并重新开机,发现可以从硬盘启动系统了,如下图所示:
3. 总结
本文介绍的方法成功地向硬盘的目标扇区写入了数据。但是,写扇区须谨慎,以免错写某些文件已经占用的扇区从而导致文件出错。