#define KI_USER_SHARED_DATA 0xffdf0000
#define SharedUserData ((KUSER_SHARED_DATA * const) KI_USER_SHARED_DATA)
KUSER_SHARED_DATA 结构区域在 User 和 Kernel 层地址分别为:
User 层地址为:0x7ffe0000
Kernnel 层地址为:0xffdf0000
kd> dt nt!KUSER_SHARED_DATA 0xffdf0000
+0x000 TickCountLowDeprecated : 0
+0x004 TickCountMultiplier : 0xa03afb7
+0x008 InterruptTime : _KSYSTEM_TIME
+0x014 SystemTime : _KSYSTEM_TIME
+0x020 TimeZoneBias : _KSYSTEM_TIME
+0x02c ImageNumberLow : 0x14c
+0x02e ImageNumberHigh : 0x14c
+0x030 NtSystemRoot : [260] 0x43
+0x238 MaxStackTraceDepth : 0
+0x23c CryptoExponent : 0
+0x240 TimeZoneId : 0
+0x244 LargePageMinimum : 0x400000
+0x248 Reserved2 : [7] 0
+0x264 NtProductType : 3 ( NtProductServer )
+0x268 ProductTypeIsValid : 0x1 ''
+0x26c NtMajorVersion : 5
+0x270 NtMinorVersion : 2
+0x274 ProcessorFeatures : [64] ""
+0x2b4 Reserved1 : 0x7ffeffff
+0x2b8 Reserved3 : 0x80000000
+0x2bc TimeSlip : 0
+0x2c0 AlternativeArchitecture : 0 ( StandardDesign )
+0x2c8 SystemExpirationDate : _LARGE_INTEGER 0x0
+0x2d0 SuiteMask : 0x112
+0x2d4 KdDebuggerEnabled : 0x3 ''
+0x2d5 NXSupportPolicy : 0x2 ''
+0x2d8 ActiveConsoleId : 0
+0x2dc DismountCount : 0
+0x2e0 ComPlusPackage : 0xffffffff
+0x2e4 LastSystemRITEventTickCount : 0x9dd368
+0x2e8 NumberOfPhysicalPages : 0xff7a
+0x2ec SafeBootMode : 0 ''
+0x2f0 TraceLogging : 0
+0x2f8 TestRetInstruction : 0xc3
+0x300 SystemCall : 0x7c95ed50 //KiFastCallEntry() stub 函数也就是//KiFastSystemCall()
+0x304 SystemCallReturn : 0x7c95ed54
+0x308 SystemCallPad : [3] 0
+0x320 TickCount : _KSYSTEM_TIME
+0x320 TickCountQuad : 0x38e31e
+0x330 Cookie : 0x38d2fc64
+0x334 Wow64SharedInformation : [16] 0
kd> u 0x7c95ed50
7c95ed50 8bd4 mov edx,esp
7c95ed52 0f34 sysenter
7c95ed54 c3 ret
7c95ed55 8da42400000000 lea esp,[esp]
7c95ed5c 8d642400 lea esp,[esp]
7c95ed60 8d542408 lea edx,[esp+8]
7c95ed64 cd2e int 2Eh
7c95ed66 c3 ret
kd> u 0x7c95ed54
7c95ed54 c3 ret
7c95ed55 8da42400000000 lea esp,[esp]
7c95ed5c 8d642400 lea esp,[esp]
7c95ed60 8d542408 lea edx,[esp+8]
7c95ed64 cd2e int 2Eh
7c95ed66 c3 ret
7c95ed67 55 push ebp
7c95ed68 8bec mov ebp,esp
kd> u 0x7c95ed50 //KiFastSystemCall()
7c95ed50 8bd4 mov edx,esp
7c95ed52 0f34 sysenter
7c95ed54 c3 ret
kd> u 0x7c95ed54
7c95ed54 c3 ret
ntdll!ZwWriteFile:
7c957b9d b81c010000 mov eax,11Ch ; 系统服务例程号
7c957ba2 ba0003fe7f mov edx,offset SharedUserData!SystemCallStub (7ffe0300)
; 取得 KiFastCallEntry() stub 函数
7c957ba7 ff12 call dword ptr [edx]
; 调用这个 stub 函数
7c957ba9 c22400 ret 24h
在 x86 体系的 sysenter/sysexit 指令快速切入机制里 IA32_SYSENTER_ESP 寄存器(MSR 地址为 175h)提供了 ESP 值。但是,在 windows 里并没有使用这个值,而是使用 KPCR 结构内 TSS 块里的 ESP 值。
//
// 得到当前 TSS 块,并读取 0 级的 esp 值
// 注意:这个 Esp0 指向一个 KTRAP_FRAME 结构的 V86Es 成员!
就是指到STACK原点
// Esp0 值减去 0x7c 就等于 KTRAP_FRAME 结构地址,trap 用于 context 信息
// esp 被赋予 KTRAP_FRAME 结构地址:esp = KtrapFrame,它以 push 的方式保存 context 信息 //
PKTSS Tss = GetCurrentTss();
PKTRAP_FRAME KtrapFrame = (PKTRAP_FRAME)(Tss->Esp0 - 0x7c);
在KiFastCallEntry() 在 KTRAP_FRAME 里保存下面的内容:
KtrapFrame->Eip = UserSharedData->SystemCallReturn; // 保存返回函数
总结:R3的函数调用通过USERSHAREDATA中的/KiFastSystemCall(),实际也就是
/KiFastCallEntry() 的一个代理函数stub,进入sysenter, 在系统INIT的时候其EIP被WRMSR为KiFastCallEntry函数,其ESP指到V86ES,这样将类似与INT2E,陆续将起SS,EIP CS FLAG压入,创建一个等同与INT2E,但未触发中断的快速调用。
当返回时,KiFastCallEntry将其返回的EIP设置成USERSHAREDATA中的KiFastSystemCallret,从而返回到用户R3