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如下图。
| +0×000 DbgEbp : Uint4B | Ring 3 下的 EBP |
| +0×004 DbgEip : Uint4B | 0x0FFDF0304, USER_SHARED_DATA + UsSystemCallReturn |
| +0×008 DbgArgMark : Uint4B | 0xBADE0D00 |
| +0x00c DbgArgPointer : Uint4B | Ring3 下的 EDX, Ring 3 下的 ESP |
| +0×010 TempSegCs : Uint4B | |
| +0×014 TempEsp : Uint4B | |
| +0×018 Dr0 : Uint4B | |
| +0x01c Dr1 : Uint4B | |
| +0×020 Dr2 : Uint4B | |
| +0×024 Dr3 : Uint4B | |
| +0×028 Dr6 : Uint4B | |
| +0x02c Dr7 : Uint4B | 0 |
| +0×030 SegGs : Uint4B | |
| +0×034 SegEs : Uint4B | |
| +0×038 SegDs : Uint4B | |
| +0x03c Edx : Uint4B | |
| +0×040 Ecx : Uint4B | |
| +0×044 Eax : Uint4B | |
| +0×048 PreviousPreviousMode : Uint4B | 1, UserMode |
| +0x04c ExceptionList : Ptr32 _EXCEPTION_REGISTRATION_RECORD | FS:[0] |
| +0×050 SegFs : Uint4B | FS(0x3B) |
| +0×054 Edi : Uint4B | Ring3 下的 EDI |
| +0×058 Esi : Uint4B | Ring3 下的 ESI |
| +0x05c Ebx : Uint4B | Ring3 下的 EBX |
| +0×060 Ebp : Uint4B | Ring3 下的 EBP |
| +0×064 ErrCode : Uint4B | 0 |
| +0×068 Eip : Uint4B | 返回到 Ring3 下的地址. 0x0FFDF0304, USER_SHARED_DATA + UsSystemCallReturn |
| +0x06c SegCs : Uint4B | 0x1B, Ring3 下的 CS |
| +0×070 EFlags : Uint4B | EFlags |
| +0×074 HardwareEsp : Uint4B | Ring3 下的 EDX (ring 3 下的 ESP) |
| +0×078 HardwareSegSs : Uint4B | 0×23, Ring3 下的 SS |
| +0x07c V86Es : Uint4B | |
| +0×080 V86Ds : Uint4B | |
| +0×084 V86Fs : Uint4B | |
| +0×088 V86Gs : Uint4B |
第二部分真正的系统调用,此时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 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中。至此,整个调用过程结束。

sysenter进入内核态后,为何ds,es还是用户态的ds,es?
这样数据段寄存器没有修正,可以直接访问吗?
(我知道内核是页级保护)