Windows 2K通过2Eh中断来实现系统调用的,但是在XP后使用SysEnter来实现系统调用了,同时2Eh中断还是保存着的。不管是2EH中断还是SYSENTER,Windows对所有的系统调用都会生成下面的KTRAP_FRAME堆栈框架。
KTRAP_FRAME框架结构图
用户态下使用2EH中断时,CPU会自动产生0x78和0x74 以保存用户态下的堆栈和指针;若直接是从系统层调用2EH,则CPU是不会自动保存堆栈的,所以需要程序自己保存。
SYSTENTER只能是从RING3(用户态)到RING0(系统态)。和2EH中断不同,CPU执行SYSENTER是不会自动在堆栈中保存数据的。所以为了2EH时堆栈情况一致,需要处理程序模拟保存一些数据。
2EH和SYSENTER的堆栈一致后,下面真正的系统调用时一样的,最后返回时根据调用的不同返回情况也不同。
==========================================================================================
SYSENTER系统服务调用过程
以NtReadFile调用为例。
一.NtDll.Dll中,NtReadFile过程如下:
ntdll!NtReadFile:
7c92d9b0 b8b7000000 mov eax,0B7h
7c92d9b5 ba0003fe7f mov edx,offset SharedUserData!SystemCallStub (7ffe0300)
7c92d9ba ff12 call dword ptr [edx]
7c92d9bc c22400 ret 24h
二.0x7ffe0300地址存放0x7c92e4f0,反汇编它:
ntdll!KiFastSystemCall:
7c92e4f0 8bd4 mov edx,esp
7c92e4f2 0f34 sysenter
因为SYSENTER执行时,CPU并不会向CALL一样保存返回地址和状态信息,所以需要这样一个“桩”(STUB)段,通过它来保存返回信息。同样的,下面的(五)就是利用这里保存的返回信息返回值NtReadFile中。
这里的KiFastSystemCall和(五)中的SystemCallReturn 都是保存在 _KUSER_SHARED_DATA结构中。用户态下的0X7FFE0000和系统态下的0XFFDF0000同时指向它。结构如下:
nt!_KUSER_SHARED_DATA
+0x000 TickCountLow : Uint4B
+0x004 TickCountMultiplier : Uint4B
+0x008 InterruptTime : _KSYSTEM_TIME
+0x014 SystemTime : _KSYSTEM_TIME
+0x020 TimeZoneBias : _KSYSTEM_TIME
+0x02c ImageNumberLow : Uint2B
+0x02e ImageNumberHigh : Uint2B
+0x030 NtSystemRoot : [260] Uint2B
+0x238 MaxStackTraceDepth : Uint4B
+0x23c CryptoExponent : Uint4B
+0x240 TimeZoneId : Uint4B
+0x244 Reserved2 : [8] Uint4B
+0x264 NtProductType : _NT_PRODUCT_TYPE
+0x268 ProductTypeIsValid : UChar
+0x26c NtMajorVersion : Uint4B
+0x270 NtMinorVersion : Uint4B
+0x274 ProcessorFeatures : [64] UChar
+0x2b4 Reserved1 : Uint4B
+0x2b8 Reserved3 : Uint4B
+0x2bc TimeSlip : Uint4B
+0x2c0 AlternativeArchitecture : _ALTERNATIVE_ARCHITECTURE_TYPE
+0x2c8 SystemExpirationDate : _LARGE_INTEGER
+0x2d0 SuiteMask : Uint4B
+0x2d4 KdDebuggerEnabled : UChar
+0x2d5 NXSupportPolicy : UChar
+0x2d8 ActiveConsoleId : Uint4B
+0x2dc DismountCount : Uint4B
+0x2e0 ComPlusPackage : Uint4B
+0x2e4 LastSystemRITEventTickCount : Uint4B
+0x2e8 NumberOfPhysicalPages : Uint4B
+0x2ec SafeBootMode : UChar
+0x2f0 TraceLogging : Uint4B
+0x2f8 TestRetInstruction : Uint8B
+0x300 SystemCall : Uint4B
+0x304 SystemCallReturn : Uint4B
+0x308 SystemCallPad : [3] Uint8B
+0x320 TickCount : _KSYSTEM_TIME
+0x320 TickCountQuad : Uint8B
+0x330 Cookie : Uint4B
三.显示MSR,因为SYSENTER和SYSEXIT需要它。
lkd> rdmsr 174
msr[174] = 00000000`00000008 ;RING0下CS
lkd> rdmsr 175
msr[175] = 00000000`f78bb000 ;进入RING0后的ESP
lkd> rdmsr 176
msr[176] = 00000000`804de89f ;进入RING0后的EIP
XP GDT如下,SYSENTER和SYSEXIT用到这些:
0008 00000000 ffffffff Code RE Ac 0 Bg Pg P Nl 00000c9b ;RING0下CS
0010 00000000 ffffffff Data RW Ac 0 Bg Pg P Nl 00000c93 ;RING0下SS
0018 00000000 ffffffff Code RE Ac 3 Bg Pg P Nl 00000cfb ;RING3下CS
0020 00000000 ffffffff Data RW Ac 3 Bg Pg P Nl 00000cf3 ;RING3下SS
四.进入RING0
反汇编0x804de89f,nt!KiFastCallEntry.
这个过程分成3部分:
1).每次调用都会创建一个_KTRAP_FRAME框架,第一部分就是创建这个框架
nt!_KTRAP_FRAME
+0x000 DbgEbp : Uint4B
+0x004 DbgEip : Uint4B
+0x008 DbgArgMark : Uint4B
+0x00c DbgArgPointer : Uint4B
+0x010 TempSegCs : Uint4B
+0x014 TempEsp : Uint4B
+0x018 Dr0 : Uint4B
+0x01c Dr1 : Uint4B
+0x020 Dr2 : Uint4B
+0x024 Dr3 : Uint4B
+0x028 Dr6 : Uint4B
+0x02c Dr7 : Uint4B
+0x030 SegGs : Uint4B
+0x034 SegEs : Uint4B
+0x038 SegDs : Uint4B
+0x03c Edx : Uint4B
+0x040 Ecx : Uint4B
+0x044 Eax : Uint4B
+0x048 PreviousPreviousMode : Uint4B
+0x04c ExceptionList : Ptr32 _EXCEPTION_REGISTRATION_RECORD
+0x050 SegFs : Uint4B
+0x054 Edi : Uint4B
+0x058 Esi : Uint4B
+0x05c Ebx : Uint4B
+0x060 Ebp : Uint4B
+0x064 ErrCode : Uint4B
+0x068 Eip : Uint4B
+0x06c SegCs : Uint4B
+0x070 EFlags : Uint4B
+0x074 HardwareEsp : Uint4B
+0x078 HardwareSegSs : Uint4B
+0x07c V86Es : Uint4B
+0x080 V86Ds : Uint4B
+0x084 V86Fs : Uint4B
+0x088 V86Gs : Uint4B
2).直接调用内核中的服务过程
3).从第一部分中创建的框架_KTRAP_FRAME中,返回至RING3状态
第一部分创建框架
nt!KiFastCallEntry:
804de89f b923000000 mov ecx,23h
804de8a4 6a30 push 30h
804de8a6 0fa1 pop fs ;RING0下 FS=0x30
804de8a8 8ed9 mov ds,cx ;RING3下 0x20 数据段
804de8aa 8ec1 mov es,cx ;RING3下 0x20 数据段
804de8ac 648b0d40000000 mov ecx,dword ptr fs:[40h] ;TSS
804de8b3 8b6104 mov esp,dword ptr [ecx+4]
804de8b6 6a23 push 23h
804de8b8 52 push edx
804de8b9 9c pushfd
804de8ba 6a02 push 2
804de8bc 83c208 add edx,8
804de8bf 9d popfd ;EFLAGS = 2
804de8c0 804c240102 or byte ptr [esp+1],2 ;EFLAGS设置。
804de8c5 6a1b push 1Bh
804de8c7 ff350403dfff push dword ptr ds:[0FFDF0304h]
804de8cd 6a00 push 0
804de8cf 55 push ebp
804de8d0 53 push ebx
804de8d1 56 push esi
804de8d2 57 push edi
804de8d3 648b1d1c000000 mov ebx,dword ptr fs:[1Ch]
804de8da 6a3b push 3Bh
804de8dc 8bb324010000 mov esi,dword ptr [ebx+124h]
804de8e2 ff33 push dword ptr [ebx]
804de8e4 c703ffffffff mov dword ptr [ebx],0FFFFFFFFh
804de8ea 8b6e18 mov ebp,dword ptr [esi+18h]
804de8ed 6a01 push 1
804de8ef 83ec48 sub esp,48h
804de8f2 81ed9c020000 sub ebp,29Ch
804de8f8 c6864001000001 mov byte ptr [esi+140h],1
804de8ff 3bec cmp ebp,esp
804de901 0f8565ffffff jne nt!KiFastCallEntry2+0x25 (804de86c)
804de907 83652c00 and dword ptr [ebp+2Ch],0
804de90b f6462cff test byte ptr [esi+2Ch],0FFh
804de90f 89ae34010000 mov dword ptr [esi+134h],ebp
804de915 0f8535feffff jne nt!Dr_FastCallDrSave (804de750)
804de91b 8b5d60 mov ebx,dword ptr [ebp+60h]
804de91e 8b7d68 mov edi,dword ptr [ebp+68h]
804de921 89550c mov dword ptr [ebp+0Ch],edx
804de924 c74508000ddbba mov dword ptr [ebp+8],0BADB0D00h
804de92b 895d00 mov dword ptr [ebp],ebx
804de92e 897d04 mov dword ptr [ebp+4],edi
804de931 fb sti
第一部分执行完后,_KTRAP_FRAME如下图。
第二部分真正的系统调用,此时EAX=系统调用号;EDX=调用参数;ESI=当前线程ETHREAD.
804de932 8bf8 mov edi,eax
804de934 c1ef08 shr edi,8
804de937 83e730 and edi,30h
804de93a 8bcf mov ecx,edi
804de93c 03bee0000000 add edi,dword ptr [esi+0E0h]
804de942 8bd8 mov ebx,eax
804de944 25ff0f0000 and eax,0FFFh
804de949 3b4708 cmp eax,dword ptr [edi+8]
804de94c 0f8330fdffff jae nt!KiBBTUnexpectedRange (804de682)
804de952 83f910 cmp ecx,10h
804de955 751b jne nt!KiFastCallEntry+0xcf (804de972)
804de957 648b0d18000000 mov ecx,dword ptr fs:[18h]
804de95e 33db xor ebx,ebx
804de960 0b99700f0000 or ebx,dword ptr [ecx+0F70h]
804de966 740a je nt!KiFastCallEntry+0xcf (804de972)
804de968 52 push edx
804de969 50 push eax
804de96a ff1568355680 call dword ptr [nt!KeGdiFlushUserBatch (80563568)]
804de970 58 pop eax
804de971 5a pop edx
804de972 64ff0538060000 inc dword ptr fs:[638h] <--KPRCB.KeSystemCalls增加一个计数
804de979 8bf2 mov esi,edx
804de97b 8b5f0c mov ebx,dword ptr [edi+0Ch]
804de97e 33c9 xor ecx,ecx
804de980 8a0c18 mov cl,byte ptr [eax+ebx]
804de983 8b3f mov edi,dword ptr [edi]
804de985 8b1c87 mov ebx,dword ptr [edi+eax*4]
804de988 2be1 sub esp,ecx
804de98a c1e902 shr ecx,2
804de98d 8bfc mov edi,esp
804de98f 3b35d48e5680 cmp esi,dword ptr [nt!MmUserProbeAddress (80568ed4)]
804de995 0f83a8010000 jae nt!KiSystemCallExit2+0x9f (804deb43)
804de99b f3a5 rep movs dword ptr es:[edi],dword ptr [esi]
804de99d ffd3 call ebx
804de99f 8be5 mov esp,ebp
804de9a1 648b0d24010000 mov ecx,dword ptr fs:[124h]
804de9a8 8b553c mov edx,dword ptr [ebp+3Ch]
804de9ab 899134010000 mov dword ptr [ecx+134h],edx
第三部分返回至RING3
nt!KiServiceExit:
804de9b1 fa cli
<DISPATCH_USER_APC宏>
804de9b2 f7457000000200 test dword ptr [ebp+70h],20000h
804de9b9 7506 jne nt!KiServiceExit+0x10 (804de9c1)
804de9bb f6456c01 test byte ptr [ebp+6Ch],1
804de9bf 7456 je nt!KiServiceExit+0x66 (804dea17)
804de9c1 648b1d24010000 mov ebx,dword ptr fs:[124h]
804de9c8 c6432e00 mov byte ptr [ebx+2Eh],0
804de9cc 807b4a00 cmp byte ptr [ebx+4Ah],0
804de9d0 7445 je nt!KiServiceExit+0x66 (804dea17)
804de9d2 8bdd mov ebx,ebp
804de9d4 894344 mov dword ptr [ebx+44h],eax
804de9d7 c743503b000000 mov dword ptr [ebx+50h],3Bh
804de9de c7433823000000 mov dword ptr [ebx+38h],23h
804de9e5 c7433423000000 mov dword ptr [ebx+34h],23h
804de9ec c7433000000000 mov dword ptr [ebx+30h],0
804de9f3 b901000000 mov ecx,1
804de9f8 ff152c904d80 call dword ptr [nt!_imp_KfRaiseIrql (804d902c)]
804de9fe 50 push eax
804de9ff fb sti
804dea00 53 push ebx
804dea01 6a00 push 0
804dea03 6a01 push 1
804dea05 e8f7f3ffff call nt!KiDeliverApc (804dde01)
804dea0a 59 pop ecx
804dea0b ff1530904d80 call dword ptr [nt!_imp_KfLowerIrql (804d9030)]
804dea11 8b4344 mov eax,dword ptr [ebx+44h]
804dea14 fa cli
804dea15 ebaa jmp nt!KiServiceExit+0x10 (804de9c1)
804dea17 8b54244c mov edx,dword ptr [esp+4Ch]
804dea1b 648b1d50000000 mov ebx,dword ptr fs:[50h]
804dea22 64891500000000 mov dword ptr fs:[0],edx
804dea29 8b4c2448 mov ecx,dword ptr [esp+48h]
804dea2d 648b3524010000 mov esi,dword ptr fs:[124h]
804dea34 888e40010000 mov byte ptr [esi+140h],cl
804dea3a f7c3ff000000 test ebx,0FFh
804dea40 7579 jne nt!KiSystemCallExit2+0x17 (804deabb)
804dea42 f744247000000200 test dword ptr [esp+70h],20000h
804dea4a 0f8506090000 jne nt!KiExceptionExit+0x12c (804df356)
804dea50 66f744246cf8ff test word ptr [esp+6Ch],0FFF8h
804dea57 0f84b4000000 je nt!KiSystemCallExit2+0x6d (804deb11)
804dea5d 66837c246c1b cmp word ptr [esp+6Ch],1Bh
804dea63 660fba64246c00 bt word ptr [esp+6Ch],0
804dea6a f5 cmc
804dea6b 0f878e000000 ja nt!KiSystemCallExit2+0x5b (804deaff)
804dea71 66837d6c08 cmp word ptr [ebp+6Ch],8
804dea76 7405 je nt!KiServiceExit+0xcc (804dea7d)
804dea78 8d6550 lea esp,[ebp+50h]
804dea7b 0fa1 pop fs
804dea7d 8d6554 lea esp,[ebp+54h]
804dea80 5f pop edi
804dea81 5e pop esi
804dea82 5b pop ebx
804dea83 5d pop ebp
804dea84 66817c24088000 cmp word ptr [esp+8],80h
804dea8b 0f87e1080000 ja nt!KiExceptionExit+0x148 (804df372)
804dea91 83c404 add esp,4
804dea94 f744240401000000 test dword ptr [esp+4],1
nt!KiSystemCallExitBranch:
804dea9c 7506 jne nt!KiSystemCallExit2 (804deaa4)
804dea9e 5a pop edx
804dea9f 59 pop ecx
804deaa0 9d popfd
804deaa1 ffe2 jmp edx
nt!KiSystemCallExit:
804deaa3 cf iretd
nt!KiSystemCallExit2:
804deaa4 f644240901 test byte ptr [esp+9],1
804deaa9 75f8 jne nt!KiSystemCallExit (804deaa3)
804deaab 5a pop edx
804deaac 83c404 add esp,4
804deaaf 80642401fd and byte ptr [esp+1],0FDh
804deab4 9d popfd
804deab5 59 pop ecx
804deab6 fb sti
804deab7 0f35 sysexit
五.返回RING3
0FFDF0304H和7FDF0304H中执行相同的物理地址,其值为:7c92e4f4h,反汇编这个地址:
7c92e4f4 c3 ret
返回至NtReadFile中。至此,整个调用过程结束。