系统调用-KiSystemService
2020年3月16日
17:07
找到KiSystemService
通过分析3环的调用过程可以知道, 系统调用会使用int 2e进入0环. 2e就是中断向量. 对应了IDT中索引为2e的中断描述符.
通过WinDbg在IDT中找到索引为2e的中断描述符, 并分析描述符的字段.
可以看到这个中断描述符的目标代码段(CS段)是0008, 这是一个0环的代码段.
中断处理函数地址是 0x8053E481, 这个地址对应的就是 KiSystemService
|
|
保存现场
如果发生了特权等级提升. CPU会依次把3环的SS/ESP/EFLAGS/CS/EIP压入0环的堆栈.这意味着, 当CPU执行到KiSystemService的时候, 堆栈中已经压入了这5个3环的寄存器.
进入到KiSystemService首先看到的是6个push. 这是在保存现场.
其实Windows用了结构体KTRAP_FRAME来保存现场. Windows设定TSS.Esp0指向的是 KTRAP_FRAME+7C.
+78对应的是字段HardwareSegSs. +74则是HardwareEsp,+70:Eflags, +6C:SegCs, +68:Eip.
切换FS
Windows设计FS.Base指向的是KPCR结构, 所以0环处理函数.会切换FS.
Windows对每个处理器都使用一个KPCR结构保存辅助信息.如果你只有一个处理器, 这个KPCR结构有一个固定的地址:0xFFDFF000.
可以看到KiSystemService中切换了FS为0x30.这个0x30对应的是GDT中Index为6的段描述符, 这个段描述符的Base刚好就是0xFFDFF0000.
设置异常链表
KiSystemService会把原本保存在KPCR中的ExceptionList保存在KTRAP_FRAME.Exception中.
并把KPCR的ExceptionList置为-1, 表明当前异常链表为空.
设置先前模式
KiSystemService把当前线程的PreviousMode(先前模式)备份到KTRAP.PreviousMode中.并计算PreviousMode后存到当前线程结构ETHREAD.PreviousMode中.
Windows只使用了3环/0环, CS的CPL只有两种情况:3或者0, 3 and 1 = 1;0 and 1 = 0;
所以PreviousMode 为1时表示先前模式是用户模式, 为0时表示先前模式是内核模式.
保存调试相关
在KiSystemService中保存了一些DbgXxx字段.同时还会判断线程的DebugActive, 如果bit0~7有一位不是0, 就会去保存调试相关的寄存器.
跳转到SharedCode
可以看到在KiSystemService中并没有开始调用系统函数. 而是在最后跳入到另一份代码中.
在跳转前使用指令sti打开了中断, 这是因为在执行int 2e后CPU会把中断位关闭.
Created with Microsoft OneNote 2016.