1. 背景
本文介绍了元神操作系统API的调用,并详细介绍了“调用元神系统API读取磁盘扇区”程序的编写以及测试结果。
2. 方法
(1)元神操作系统API的调用方法
元神操作系统0.4版beta4开始提供了对OS功能的调用,调用相关的定义如下:
OS_API equ 0x00030C16
API_PARAM equ 0x03000000
其中,OS_API定义的是API调用的入口,设置好要调用的API类型及其参数之后,直接call该入口即可实现系统API调用。而要调用的API类型及参数则由API_PARAM指定,其指定的格式如下:
PARAM_1: 要调用的API类型
PARAM_2:传给API的参数个数
PARAM_3:传给API的第一个参数
PARAM_4:传给API的第二个参数(如果有的话),依次类推
其中,每个PARAM都是4字节大小。例如,要读取优盘的第一个扇区,其API_PARAM设置如下:
PARAM_1 = API_READ_USB_SECTOR
PARAM_2 = 2
PARAM_3 = 0
PARAM_4 = 扇区数据存放地址
由此可知,要调用的API是“读取优盘扇区”,传递2个参数给该API,第一个参数为0(表示读取第一个扇区,即0号扇区),第二个参数是接收扇区数据的内存地址。
(2)编写程序读取优盘的0号扇区
本例使用汇编语言编写,代码如下所示:
use32
START:
pusha
call demo_read_usb
popa
iret
include 'api_def.inc'
cursor_x equ 0x02004B10
cursor_y equ 0x02004B12
OS_API equ 0x00030C16
API_PARAM equ 0x03000000
sector_buff: times 512 db 0
demo_read_usb:
pusha
mov edi, API_PARAM
mov dword [fs:edi], API_READ_USB_SECTOR
mov dword [fs:edi+4], 2 ;2 parameters
mov dword [fs:edi+8], 0 ;param_1: sector no.
xor eax, eax
mov ax, ds
shl eax, 4
add eax, sector_buff
mov dword [fs:edi+12], eax ;param_2: start address of buffer to store result
call pword [fs:OS_API]
mov eax, 512
movzx ebx, word [fs:cursor_y]
movzx ecx, word [fs:cursor_x]
mov esi, [fs:edi+12]
call print_bytes_hex
add word [fs:cursor_y], 20
popa
ret
;print hex bytes
;input:
; eax: byte count to print
; ebx: y coordinate to print (from 0)
; ecx: x coordinate to print (from 0)
; esi: buffer storing data to print
print_bytes_hex:
pusha
imul edi,ebx,80*2
add edi,ecx
add edi,ecx
mov ecx,eax
mov ah,0x0F ;should use edx in stack
.next_char:
mov bl,byte [fs:esi]
.hex_char:
mov al,bl
and al,0x0F
add al,0x30
cmp al,0x39
jbe .num_char
add al,'A'-0x30-10
.num_char:
mov [gs:edi+2],ax
shr ebx,4
mov al,bl
and al,0x0F
add al,0x30
cmp al,0x39
jbe .num_char2
add al,'A'-0x30-10
.num_char2:
mov [gs:edi],ax
mov al,' '
mov [gs:edi+4],ax
add edi,6
inc esi
loop .next_char
popa
ret
将以上代码保存为DEMO.ASM,编译生成DEMO.BIN,并将该可执行文件复制到装有元神操作系统的U盘中,之后用该U盘开机进入元神系统并输入命令“ZX DEMO.BIN”执行该程序如下:
这里以二进制显示的就是U盘0号扇区的数据,对应到示例程序,语句“call pword [fs:OS_API]”完成的就是系统API调用,该语句之前的部分是对调用参数的设置,之后的部分是对调用结果的输出显示。参数设置部分在本章开头部分已经进行介绍,需要补充的是数据存储地址,该地址需要是全局地址,而非本应用程序的地址,所以将其和数据段寄存器DS的值结合在一起,之后再传给参数。
至于最后的输出显示函数print_bytes_hex,其以十六进制字节序列的形式完成输出,每两个字节之间以空格分隔。要输出的字节数通过EAX寄存器传递,本例指明要输出512字节,因为一个扇区的大小为512字节。将显示结果向下滚动查看完整的扇区数据如下:
从该图能看出,读出的的确是0号扇区的数据,其最后两个字节“55 AA”是该扇区的结束标志。
另外,本例中涉及到的文件api_def.inc是用于定义元神操作系统API类型的,目前为止数据较少,如下所示:
API_READ_USB_SECTOR equ 0x00000003
API_READ_DISK_SECTOR equ 0x00000004
第一句表示读取优盘的扇区,第二句表示读取硬盘/磁盘的扇区。
(3)编写程序读取磁盘的0号扇区
本例展示读取硬盘/磁盘的第一个扇区的API调用,其大部分和上例相同,含有差异的主要部分如下所示:
use32
START:
pusha
call demo_read_disk
popa
iret
include 'api_def.inc'
cursor_x equ 0x02004B10
cursor_y equ 0x02004B12
OS_API equ 0x00030C16
API_PARAM equ 0x03000000
sector_buff: times 512 db 0
demo_read_disk:
pusha
mov edi, API_PARAM
mov dword [fs:edi], API_READ_DISK_SECTOR
mov dword [fs:edi+4], 2 ;2 parameters
mov dword [fs:edi+8], 0 ;param_1: sector no.
xor eax, eax
mov ax, ds
shl eax, 4
add eax, sector_buff
mov dword [fs:edi+12], eax ;param_2: start address of buffer to store result
call pword [fs:OS_API]
mov eax, 512
movzx ebx, word [fs:cursor_y]
movzx ecx, word [fs:cursor_x]
mov esi, [fs:edi+12]
call print_bytes_hex
add word [fs:cursor_y], 20
popa
ret
由于本例和上例都是读取磁盘扇区,区别仅在于一个读的是U盘、另一个读的是硬盘,所以仅改变API类型即可,本例将类型设置为API_READ_DISK_SECTOR。
如上例那般编译运行程序,结果如下图所示:
和上例一样,本例扇区数据的最后两个字节仍然是“55 AA”。两例都是读取磁盘的第一个扇区,但U盘是没有分区的,而硬盘是经过分区的,所以可以看到本例含有两个分区表项,具体内容可以查阅MBR、DBR、分区表等的详细文章阅览。
3. 总结
元神操作系统API的调用方式比较统一,调用接口设计为唯一的,将API及其参数都作为数据进行传递,改动起来比较灵活,而且不会因为过量的参数导致堆栈溢出。