1、_KiSystemService()
_KiSystemService()是所有的系统调用入口函数。对应于中断向量0x2e。所以,当中间函数执行int 0x2e时,CPU就进入系统空间中的这个函数。
进入系统空间时,CPU自动将下列信息压入系统空间堆栈:
①用户空间的堆栈位置,包括SS和ESP的内容
②EFLAGS的内容
③用户空间指令位置,包括CS和EIP的内容
这些信息是将来返回用户空间所必须的。
2、快速系统调用
x86系列从P2开始增设了两条指令和三个寄存器用来用来实现快速系统调用。分别是:
sysenter和sysexit(对应于自陷方式中的int/call和iret/ret)
sysenter_cs_msr
sysenter_ip_msr
sysenter_esp_msr
快速系统调用实现更为高效。
采用快速系统调用的总入口时_KiFastCallEntry(对应于_KiSystemService)。
快速系统调用代码摘要:
__decksoec(naked) __stdcall NtReadFile(int dummy, int dummy1, int dummy2) { __asm{ mov eax,152 mov ecx, KUSER_SHARED_SYSCALL CALL [ecx] ret 9 } }
其中,KUSER_SHARED_SYSCALL指向用户空间的一个地址(0x7ffe0300),这个位置存储了一个函数指针,指向KiIntSystemCall()或KiFastSystemCall()两个函数其中之一。
_KiIntSystemCall@0: lea edx, [esp+8] int 0x2e ret _KiFastSystemCall@0: mov edx,csp sysenter _KiFastSystemCallRet@0: ret
不难看出KiIntSystemCall()就是原先采用中断方式进入内核。
而KiFastSystemCall()则是采用快速系统调用进入内核。
快速系统调用流程图:
3、从内核中发起系统调用
在内核中不能直接调用NtReadFile之类的实现函数。一般也是通过中介函数进行调用。
以NtReadFile为例,其在内核中的中介函数由工具生成,其名称为ZwReadFile。
代码:
__declspec(naked) _stdcall ZwReadFile(int dummy0, int dummy1, int dummy2) { asm{ mov eax 152 lea edx,[esp+4] push KGDT_R0_CODE call _KiSystemservice ret 36 } }
流程图: