|
|
第16章习题
1.修改代码清单16-1和15-3,使用户程序能够正常返回到内核,并在显示消息后停机。
答案:将jmp far [fs:TerminateProgram]改为call far [fs:TerminateProgram]。
2.修改代码清单16-1和15-3,使得通过调用门请求读取硬盘扇区的服务时,通过栈传递参数。而且,传递的参数分别是逻辑扇区号、数据段选择子和段内偏移。要求使用arpl指令。
参考答案:
内核程序较为复杂,尽量不改变原有的设计和元素,仅添加新的功能较好。为此,我们需要在内核公用例程段内新增加一个例程read_hard_disk_with_gate并用它创建一个新的调用门。以下是这个新例程的代码。
- ;此例程用于说明如何通过请求特权级RPL解决因请求者身份与CPL不同而带来的安全问题
- read_hard_disk_with_gate: ;从硬盘读取一个逻辑扇区
- ;输入:PUSH 逻辑扇区号
- ; PUSH 目标缓冲区在段内的偏移量
- ; PUSH 目标缓冲区所在段的选择子
- ;返回:无
- push ebp
- mov ebp,esp
- push eax
- push ebx
- push ds
- mov ax,[ebp+0x08] ;获取调用者的CS
- arpl [ebp+0x0c],ax ;将数据段选择子调整到真实的请求特权级别
- mov ds,[ebp+0x0c] ;用真实的段选择子加载段寄存器DS
- mov eax,[ebp+0x14] ;从栈中取得逻辑扇区号
- mov ebx,[ebp+0x10] ;从栈中取得缓冲区在段内的偏移量
- ;此部分的功能是读硬盘,并传送到缓冲区。调用现成的例程。
- call sys_routine_seg_sel:read_hard_disk_0
- pop ds
- pop ebx
- pop eax
- pop ebp
- retf 12 ;必须是参数的总字节数
复制代码
接下来,转到内核数据段,在原来的符号地址检索表末尾添加一个新的条目:
- salt_5 db '@ReadDiskDataWithGate'
- times 256-($-salt_5) db 0
- dd read_hard_disk_with_gate
- dw sys_routine_seg_sel
复制代码
注意修改salt_item_len,将其改为
- salt_item_len equ $-salt_5
复制代码
再转到内核的入口点,找到安装调用门的循环代码。这段代码不能处理调用门中的参数数量部分,所以要将其删除,手动逐个安装调用门。实施:删除原来的循环,插入以下代码:
- ;以下开始安装为整个系统服务的调用门。特权级之间的控制转移必须使用门
- ;安装'PrintString'
- mov eax,[salt_1+256] ;该条目入口点的32位偏移地址
- mov bx,[salt_1+260] ;该条目入口点的段选择子
- mov cx,1_11_0_1100_000_00000B ;特权级3的调用门(3以上的特权级才
- ;允许访问),0个参数(因为用寄存器
- ;传递参数,而没有用栈)
- call sys_routine_seg_sel:make_gate_descriptor
- call sys_routine_seg_sel:set_up_gdt_descriptor
- mov [salt_1+260],cx ;将返回的门描述符选择子回填
- ;安装'ReadDiskData'
- mov eax,[salt_2+256] ;该条目入口点的32位偏移地址
- mov bx,[salt_2+260] ;该条目入口点的段选择子
- mov cx,1_11_0_1100_000_00000B ;特权级3的调用门(3以上的特权级才
- ;允许访问),0个参数)
- call sys_routine_seg_sel:make_gate_descriptor
- call sys_routine_seg_sel:set_up_gdt_descriptor
- mov [salt_2+260],cx ;将返回的门描述符选择子回填
- ;安装'PrintDwordAsHexString'
- mov eax,[salt_3+256] ;该条目入口点的32位偏移地址
- mov bx,[salt_3+260] ;该条目入口点的段选择子
- mov cx,1_11_0_1100_000_00000B ;特权级3的调用门(3以上的特权级才
- ;允许访问),0个参数(因为用寄存器
- ;传递参数,而没有用栈)
- call sys_routine_seg_sel:make_gate_descriptor
- call sys_routine_seg_sel:set_up_gdt_descriptor
- mov [salt_3+260],cx ;将返回的门描述符选择子回填
- ;安装'TerminateProgram'
- mov eax,[salt_4+256] ;该条目入口点的32位偏移地址
- mov bx,[salt_4+260] ;该条目入口点的段选择子
- mov cx,1_11_0_1100_000_00000B ;特权级3的调用门(3以上的特权级才
- ;允许访问),0个参数(因为用寄存器
- ;传递参数,而没有用栈)
- call sys_routine_seg_sel:make_gate_descriptor
- call sys_routine_seg_sel:set_up_gdt_descriptor
- mov [salt_4+260],cx ;将返回的门描述符选择子回填
- ;安装'ReadDiskDataWithGate'
- mov eax,[salt_5+256] ;该条目入口点的32位偏移地址
- mov bx,[salt_5+260] ;该条目入口点的段选择子
- mov cx,1_11_0_1100_000_00011B ;特权级3的调用门(3以上的特权级才
- ;允许访问),3个参数。
- call sys_routine_seg_sel:make_gate_descriptor
- call sys_routine_seg_sel:set_up_gdt_descriptor
- mov [salt_5+260],cx ;将返回的门描述符选择子回填
复制代码
接下来修改用户程序c15_app.asm。
由于是使用内核中新添加的调用门,所以要在头部段中,将
- ReadDiskData db '@ReadDiskData'
- times 256-($-ReadDiskData) db 0
复制代码
修改为
- ReadDiskData db '@ReadDiskDataWithGate'
- times 256-($-ReadDiskData) db 0
复制代码
既然是通过栈传递参数,那就删除第74~77行,插入以下指令:
- push dword 100 ;压入起始逻辑扇区号
- push dword buffer ;压入段内偏移量
- push ds ;压入数据段选择子
- call far [fs:ReadDiskData] ;段间调用
复制代码
为保证程序正常工作,将代码段最后的
- jmp far [fs:TerminateProgram]
复制代码 改成
- call far [fs:TerminateProgram]
复制代码
由于文件较大,这里将它作为附件发布。
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
×
|