紧接上文, sysenter 指令最终导致进入内核模块的 KiFastSystemCall
在分析这个函数之前需要补充一些知识
1.) FS寄存器的值存的是什么?在R3 FS寄存器的值是0x3B, 在R0 FS寄存器的值是0x30
这里我们对 0x30 选择子进行拆分如下:
kd> dg 30
P Si Gr Pr Lo
Sel Base Limit Type l ze an es ng Flags
---- -------- -------- ---------- - -- -- -- -- --------
0030 ffdff000 00001fff Data RW Ac 0 Bg Pg P Nl 00000c93 得到的是 Base: ffdff000, 那么这个数据段指向的是什么呢?我们用 WinDbg 的 !pcr 指令查看:
kd> !pcr
KPCR for Processor 0 at ffdff000:
Major 1 Minor 1
NtTib.ExceptionList: 8054a4b0
NtTib.StackBase: 8054acf0
NtTib.StackLimit: 80547f00
NtTib.SubSystemTib: 00000000
NtTib.Version: 00000000
NtTib.UserPointer: 00000000
NtTib.SelfTib: 00000000
SelfPcr: ffdff000
Prcb: ffdff120
Irql: 00000000
IRR: 00000000
IDR: ffffffff
InterruptMode: 00000000
IDT: 8003f400
GDT: 8003f000
TSS: 80042000
CurrentThread: 80553740
NextThread: 00000000
IdleThread: 80553740
DpcQueue: 0x80553da0 0x80500df0 [Normal] nt!KiTimerExpiration 通过上面我们可以知道,其是一个 KPCR 结构体, 继续用 WinDbg 查看, 如下, 由此我们可以知道 FS 指向的是一个名为 KPCR 的结构体(注意在 R3 指向的 TEB结构体)
kd> dt _KPCR ffdff000
nt!_KPCR
+0x000 NtTib : _NT_TIB
+0x01c SelfPcr : 0xffdff000 _KPCR
+0x020 Prcb : 0xffdff120 _KPRCB
+0x024 Irql : 0 ''
+0x028 IRR : 0
+0x02c IrrActive : 0
+0x030 IDR : 0xffffffff
+0x034 KdVersionBlock : 0x80546ab8 Void // 指向 _DBGKD_GET_VERSION64 结构体
+0x038 IDT : 0x8003f400 _KIDTENTRY
+0x03c GDT : 0x8003f000 _KGDTENTRY
+0x040 TSS : 0x80042000 _KTSS
+0x044 MajorVersion : 1
+0x046 MinorVersion : 1
+0x048 SetMember : 1
+0x04c StallScaleFactor : 0x8a0
+0x050 DebugActive : 0 ''
+0x051 Number : 0 ''
+0x052 Spare0 : 0 ''
+0x053 SecondLevelCacheAssociativity : 0 ''
+0x054 VdmAlert : 0
+0x058 KernelReserved : [14] 0
+0x090 SecondLevelCacheSize : 0
+0x094 HalReserved : [16] 0
+0x0d4 InterruptMode : 0
+0x0d8 Spare1 : 0 ''
+0x0dc KernelReserved2 : [17] 0
+0x120 PrcbData : _KPRCB 2). 陷阱帧(_KTRAP_FRAME),用于保存 R3 的寄存器参数结构体,如下:
kd> dt _KTRAP_FRAME 0x8054acf0
nt!_KTRAP_FRAME
+0x000 DbgEbp : 0x27f
+0x004 DbgEip : 0
+0x008 DbgArgMark : 0
+0x00c DbgArgPointer : 0
+0x010 TempSegCs : 0
+0x014 TempEsp : 0
+0x018 Dr0 : 0x1f80
+0x01c Dr1 : 0
+0x020 Dr2 : 0
+0x024 Dr3 : 0
+0x028 Dr6 : 0
+0x02c Dr7 : 0
+0x030 SegGs : 0
+0x034 SegEs : 0
+0x038 SegDs : 0
+0x03c Edx : 0
+0x040 Ecx : 0
+0x044 Eax : 0
+0x048 PreviousPreviousMode : 0
+0x04c ExceptionList : (null)
+0x050 SegFs : 0
+0x054 Edi : 0
+0x058 Esi : 0
+0x05c Ebx : 0
+0x060 Ebp : 0
+0x064 ErrCode : 0
+0x068 Eip : 0
+0x06c SegCs : 0
+0x070 EFlags : 0
+0x074 HardwareEsp : 0
+0x078 HardwareSegSs : 0 ; TSS 中的 ESP0 默认指向的是这个位置
+0x07c V86Es : 0
+0x080 V86Ds : 0
+0x084 V86Fs : 0
+0x088 V86Gs : 0 3). 系统服务表和SSDT、SSDTShadow
系统服务表 (System service table),结构如下, 是用来记录指定模块对外导出的函数相关信息, 包括(Ntoskrl.exe、Win32k.Sys)
struct System_service_table
{
PVOID ServiceTableAddr; // 函数地址表的地址 (4字节成员)
ULONG Count; // 当前系统服务表被调用的次数
ULONG ServiceLimit; // 系统服务表中函数的个数
PVOID ArgMentTable; // 系统参数表地址 (1字节成员)
} SSDT表(非UI线程所使用的表)
在 WinXp 上是导出的全局变量 KeServiceDescriptorTable(记录了SSDT表的起始地址), 在此表中只包含了记录 Ntoskrl.exe 内核模块导出的函数相关信息的系统服务表,如下:
kd> dd KeServiceDescriptorTable
80553fa0 80502b8c 00000000 0000011c 80503000 ; 此为 Ntoskrl.exe 的系统服务表, 该模块记录了一般处理系统功能性的函数
80553fb0 00000000 00000000 00000000 00000000
80553fc0 00000000 00000000 00000000 00000000
80553fd0 00000000 00000000 00000000 00000000 SSDTShadow表(UI线程所使用的表)
在 WinXp 上是导出的全局变量 KeServiceDescriptorTableShadow 记录了SSDTShadow表的起始地址), 在此表中包含了 Ntoskrl.exe、Win32k.Sys导出的函数相关信息的系统服务表,如下:
kd> dd KeServiceDescriptorTableShadow
80553f60 80502b8c 00000000 0000011c 80503000 ; 此为 Ntoskrl.exe 的系统服务表, 该模块记录了一般处理系统功能性的函数
80553f70 bf999b80 00000000 0000029b bf99a890 ; 此为 Win32k.Sys 的系统服务表(又称影子表), 该模块记录了关于系统UI界面的函数
80553f80 00000000 00000000 00000000 00000000
80553f90 00000000 00000000 00000000 00000000 根据线程的不一样, 使用的表也是不一样的, 线程中的 KPCR.PrcbData.CurrentThread.ServiceTable 所指向的地址也不一样, (0x80553fa0 或 0x80553f60)
4). 现在我们开始分析 KiFastSystemCall 函数, 以下是我个人分析(如有错误请指教)
请查看附件
5). 最后要注意的是 int 0x2E 进入内核,更快速调用还是有不一样, INT 0x2E操作大体如下
阿里云助力开发者!2核2G 3M带宽不限流量!6.18限时价,开
发者可享99元/年,续费同价!
最后于 2020-6-3 21:34
被灵幻空间编辑
,原因: 排版问题
上传的附件: