Windows内核情景分析-系统调用4

接上,快速系统调用sysenter的调用过程

通过硬件支持,增加了指令sysenter和sysexist,且增加了三个MSR寄存器,用于支撑该指令,旨在实现轻便高效的系统调用。

这样只要预先设置好三个寄存器中的内容,CPU在执行sysenter指令时候就可以进入系统空间且从指定地址开始执行,同时使用系统空间堆栈。 但此时,CPU不像在执行int 0x2e自陷时那样,自动把用户空间的堆栈指针保存在系统空间堆栈上,也不将返回地址压入堆栈,所以需要相应程序来完成这些操作;此时不需要从中断向量表来获取函数地址。

系统初始化过程对三个MSR寄存器的初始化

 

 KGDT_R0_CODE 为 0x8,当作为段选择子解释时候为:GDT,ring0,索引为1的段(见段选择子格式解析)。那么对于的堆栈段SS内容为:0x8 + 8(这个是十进制) = 0x10 ,当作为断选择自解释为:GDT,ring0,索引2的段。SYSENTER_EIP_MSR设置为函数KiFastCallEntry的地址,该函数为快速系统调用的总入口。

快速系统调用返回

返回地址是固定的,就是KiFastSystemCallRet()函数地址,由ntdll.dll导出,在系统初始化时获取且写入数据结构SharedUserData中。

此时CS为24(十进制),对应的 段选择子解释时候为:GDT,ring0,索引为3的段。

SS为32(十进制),对应段选择子解释时候为:GDT,ring0,索引为4的段 

所以,使得ECX持有用户空间的堆栈指针,且报SharedUserData->SystemCallReturn置于EDX,在执行sysexist(他会按照上图规则执行),就可以返回了。

KiFastCallEntry

此时CS和SS已经分别设置成系统空间代码段和堆栈段的选择项,而堆栈指针则指向一个临时的、过渡的堆栈,这些由指令sysenter完成的。SharedCode和int 0x2e形式的是相同的。

通过上图代码可以看到,这里通过获取当前线程的TSS内容,设置了ESP的内容。 剩下的内容包含了构建与int 自陷指令相同的仿真框架,最后返回时,按照sysexit指令的要求设置相关寄存器内容,最终返回调用。这里更为细节的内容需要慢慢去看书了。

从内核发起的系统调用

 windows运行从内核进行系统调用,但是一般不能直接使用NtReadFile()一类函数,一方面,内核并未导出这些函数,另一方面,这些系统调用的代码中很多是精心构造的,需要处理堆栈框架,所以有了ZwReadFile()一类函数,这些函数开头分别单独处理堆栈框架,然后进行系统调用。

至此系统调用就这么多了,这里如果大家熟悉了一下这些过程,那么对于windows的系统提供的win32API接口就不会感觉陌生了。

猜你喜欢

转载自blog.csdn.net/shabihundan/article/details/81586476