系统调用1和系统调用2说了这么多,还未进入int 0x2e所对应的系统服务函数KiSystemService(),这里来看下这个函数内部的处理;通过0x2e和IDTR从IDT中 查询获取对应的方法KiSystemService()。
- 所以这里 int 0x2e 对应 KiSystemService 入口
- sysenter 对应的是 KiFastCallEntry 入口,这里不要被这些函数给搞乱了。
系统空间堆栈
每个线程有自己的系统空间堆栈,其系统空间的SS和ESP保存在TSS数据结构里面。TR寄存器存放当前线程的TSS地址,当从用户空间进入系统空间,CPU根据TR寄存器从TSS获取系统空间的SS和ESP。
KiSystemService()
从SharedCode开始的代码是共同的,前奏SYSCALL_PORLOG部分则是专门针对自陷指令系统调用的。
KPCR 处理器控制区(Processor Control Region)
Windows内核特殊的基本要求,当CPU在内核运行,那么FS指向KPCR的数据结构,且每个CPU(核心?)都有自己的KPCR结构,其次,要使ESI 指向当前线程KTHREAD结构,这两个过程将在SYSCALL_PORLOG宏中实现,再次,KPCR结构存放在固定的虚拟地址,这就可以通过构造特殊的段选择子使得其指向该地址;在保护模式中段寄存器存放的是段选择子,共16bit,特殊的结构使其最终指向GDT或者LDT,如下图:
这里就是特殊构造的段选择子(FS),使其指向KPCR结构
KPCR结构大小0x120 Byte:
其中子结构PRCB 结构(部分,见下图):注意在+0x004处指向了当前运行的线程KTHREAD结构体,所以通过KPRC能够获取线程的很多信息(在线程切换后会去更新PRCB结构开始的相关数据?)
先前模式
指在进入KiSystemService这个函数的前夕,CPU处于何种状态(系统态或者用户态);由于windows运行在内核中发起系统调用,所以如果从内核中发起的调用,那么这里先前模式就是系统态,从用户系统调用进入的则为用户态。这里通过将先前模式保存当当前线程KTHREAD结构中对应的先前模式字段中,为了可以方便,高效访问先前模式;先前模式的作用就是用来区分是从内核还是用户空间进入的,所以在系统调用返回的时候要做不同的处理。其次,系统调用是可以嵌套的了,这里会在赋值先前模式字段时,先将原有的内容入栈。KTHREAD 中字段TrapFrame也要更新指向当前的调用堆栈框架。
其次,内核版函数Zwxxxxxx(),通常就是模拟自陷指令的效果,把一些寄存器的内容压入系统空间堆栈,然后调用进行系统调用,先前模式就是系统态。
这里接着看SharedCode
Windows NT 基本系统调用多个,如果调用号大于0x1000,则判断为扩展系统调用号(windows将视窗部分移入内核造成)。对应的线程控制块KTHREAD结构中指针ServiceTable,指向本线程的系统调用函数表,不是指向KeServiceDescriptorTable[]就是指向KeServiceDescriptorTableShadow[],前者基本系统调用,后者则额外包含了扩展系统调用。
SSDT与SSPT
typedef struct _KSYSTEM_SERVICE_TABLE{
PULONG ServiceTableBase; //SSDT的基地址指针
PULONG ServiceCounterTableBase; //SSDT中每个服务被调用次数表的基地址指针
ULONG NumberOfService; //服务函数个数,*4就是整个地址表的大小
ULONG ParamTableBase; //SSPT的基地址
}KSYSTEM_SERVICE_TABLE,*PKSYSTEM_SERVICE_TABLE;
typedef struct _KSERVICE_TABLE_DESCRIPTOR{
KSYSTEM_SERVICE_TABLE ntoskrnl; //ntoskrnl.exe的服务函数
KSYSTEM_SERVICE_TABLE win32k; //win32k.sys的服务函数(GDI32/User32)
KSYSTEM_SERVICE_TABLE notUsed1;
KSYSTEM_SERVICE_TABLE notUsed2;
}KSERVICE_TABLE_DESCRIPTOR,*PKSERVICE_TABLE_DESCRIPTOR;
结构如上图,对应的SSPT表则记录索引对应函数的参数数量。
在SharedCode中通过一系列判断与运算,最终决定使用的SSDT,然后根据系统调用号计算出本次调用的函数地址以及函数的参数,将用户空间堆栈的参数复制到系统空间堆栈,最后调用该函数。
注:这里所涉及细节需要结合书籍内容理解,上面所说的并不完整,只是挑出容易让人混的内容,需要细细推敲。