Windows 系统调用
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 的堆栈一致后,下面真正的系统调用时一样的,最后返回时根据调用的不同返回情况也不同。
附:反汇编的代码,根据 WRK 注释。
nt!KiSystemService:
808696a1 6a00 push 0
808696a3 55 push ebp
808696a4 53 push ebx
808696a5 56 push esi
808696a6 57 push edi
808696a7 0fa0 push fs
808696a9 bb30000000 mov ebx,30h
808696ae 668ee3 mov fs,bx ;FS=0X30
808696b1 64ff3500000000 push dword ptr fs:[0]
808696b8 64c70500000000ffffffff mov dword ptr fs:[0],0FFFFFFFFh
808696c3 648b3524010000 mov esi,dword ptr fs:[124h] ;ESI=_ETHEAD
808696ca ffb640010000 push dword ptr [esi+140h] ;PreviousMode
808696d0 83ec48 sub esp,48h ;
808696d3 8b5c246c mov ebx,dword ptr [esp+6Ch] ;
808696d7 83e301 and ebx,1
808696da 889e40010000 mov byte ptr [esi+140h],bl ;新的PreviousMode
808696e0 8bec mov ebp,esp
808696e2 8b9e34010000 mov ebx,dword ptr [esi+134h] ;
808696e8 895d3c mov dword ptr [ebp+3Ch],ebx ;旧的TrapFrame保存至新TrapFrame的EDX中。以实现TrapFrame嵌套。
808696eb 89ae34010000 mov dword ptr [esi+134h],ebp ;新的TrapFrame保存至EThread中TrapFrame.
808696f1 fc cld
<SET_DEBUG_DATA>
808696f2 8b5d60 mov ebx,dword ptr [ebp+60h]
808696f5 8b7d68 mov edi,dword ptr [ebp+68h]
808696f8 89550c mov dword ptr [ebp+0Ch],edx
808696fb c74508000ddbba mov dword ptr [ebp+8],0BADB0D00h
80869702 895d00 mov dword ptr [ebp],ebx
80869705 897d04 mov dword ptr [ebp+4],edi
80869708 f6462cff test byte ptr [esi+2Ch],0FFh
8086970c 0f858afeffff jne nt!Dr_kss_a (8086959c) ;if nz, debugging is active on thread.
80869712 fb sti
80869713 e9e7000000 jmp nt!KiFastCallEntry+0x8f (808697ff)
nt!KiFastCallEntry2:
80869718 b930000000 mov ecx,30h
8086971d 8ee1 mov fs,cx
8086971f b923000000 mov ecx,23h
80869724 8ed9 mov ds,cx
80869726 8ec1 mov es,cx
80869728 648b0d40000000 mov ecx,dword ptr fs:[40h]
8086972f 8b6104 mov esp,dword ptr [ecx+4]
80869732 6a23 push 23h
80869734 52 push edx
80869735 9c pushfd
80869736 804c240101 or byte ptr [esp+1],1
8086973b eb4e jmp nt!KiFastCallEntry+0x1b (8086978b)
8086973d 648b0d40000000 mov ecx,dword ptr fs:[40h]
80869744 8b6104 mov esp,dword ptr [ecx+4]
80869747 6a00 push 0
80869749 6a00 push 0
8086974b 6a00 push 0
8086974d 6a00 push 0
8086974f 6a23 push 23h
80869751 6a00 push 0
80869753 6802020200 push 20202h
80869758 6a1b push 1Bh
8086975a 6a00 push 0
8086975c e973160000 jmp nt!KiTrap06 (8086add4)
80869761 ebda jmp nt!KiFastCallEntry2+0x25 (8086973d)
80869763 8da42400000000 lea esp,[esp]
8086976a 8d9b00000000 lea ebx,[ebx]
nt!KiFastCallEntry:
80869770 b923000000 mov ecx,23h
80869775 6a30 push 30h
80869777 0fa1 pop fs ;RING0下 FS=0x30
80869779 8ed9 mov ds,cx ;RING3下 0x20 数据段
8086977b 8ec1 mov es,cx ;RING3下 0x20 数据段
8086977d 648b0d40000000 mov ecx,dword ptr fs:[40h]
80869784 8b6104 mov esp,dword ptr [ecx+4]
80869787 6a23 push 23h
80869789 52 push edx
8086978a 9c pushfd
8086978b 6a02 push 2
8086978d 83c208 add edx,8
80869790 9d popfd
80869791 804c240102 or byte ptr [esp+1],2 ;EFLAGS设置。
80869796 6a1b push 1Bh
80869798 ff350403dfff push dword ptr ds:[0FFDF0304h]
8086979e 6a00 push 0
808697a0 55 push ebp
808697a1 53 push ebx
808697a2 56 push esi
808697a3 57 push edi
808697a4 648b1d1c000000 mov ebx,dword ptr fs:[1Ch]
808697ab 6a3b push 3Bh
808697ad 8bb324010000 mov esi,dword ptr [ebx+124h]
808697b3 ff33 push dword ptr [ebx]
808697b5 c703ffffffff mov dword ptr [ebx],0FFFFFFFFh
808697bb 8b6e18 mov ebp,dword ptr [esi+18h]
808697be 6a01 push 1
808697c0 83ec48 sub esp,48h
808697c3 81ed9c020000 sub ebp,29Ch
808697c9 c6864001000001 mov byte ptr [esi+140h],1
808697d0 3bec cmp ebp,esp
808697d2 758d jne nt!KiFastCallEntry2+0x49 (80869761)
808697d4 83652c00 and dword ptr [ebp+2Ch],0
808697d8 f6462cff test byte ptr [esi+2Ch],0FFh
808697dc 89ae34010000 mov dword ptr [esi+134h],ebp
808697e2 0f8538feffff jne nt!Dr_FastCallDrSave (80869620)
808697e8 8b5d60 mov ebx,dword ptr [ebp+60h]
808697eb 8b7d68 mov edi,dword ptr [ebp+68h]
808697ee 89550c mov dword ptr [ebp+0Ch],edx
808697f1 c74508000ddbba mov dword ptr [ebp+8],0BADB0D00h
808697f8 895d00 mov dword ptr [ebp],ebx
808697fb 897d04 mov dword ptr [ebp+4],edi
808697fe fb sti
KiSystemServiceRepeat:
808697ff 8bf8 mov edi,eax
80869801 c1ef08 shr edi,8
80869804 83e730 and edi,30h
80869807 8bcf mov ecx,edi
80869809 03bee0000000 add edi,dword ptr [esi+0E0h]
8086980f 8bd8 mov ebx,eax
80869811 25ff0f0000 and eax,0FFFh
80869816 3b4708 cmp eax,dword ptr [edi+8]
80869819 0f8333fdffff jae nt!KiBBTUnexpectedRange (80869552)
8086981f 83f910 cmp ecx,10h
80869822 751b jne nt!KiFastCallEntry+0xcf (8086983f)
80869824 648b0d18000000 mov ecx,dword ptr fs:[18h]
8086982b 33db xor ebx,ebx
8086982d 0b99700f0000 or ebx,dword ptr [ecx+0F70h]
80869833 740a je nt!KiFastCallEntry+0xcf (8086983f)
80869835 52 push edx
80869836 50 push eax
80869837 ff1528478880 call dword ptr [nt!KeGdiFlushUserBatch (80884728)]
8086983d 58 pop eax
8086983e 5a pop edx
8086983f 64ff0538060000 inc dword ptr fs:[638h]
80869846 8bf2 mov esi,edx
80869848 8b5f0c mov ebx,dword ptr [edi+0Ch]
8086984b 33c9 xor ecx,ecx
8086984d 8a0c18 mov cl,byte ptr [eax+ebx]
80869850 8b3f mov edi,dword ptr [edi]
80869852 8b1c87 mov ebx,dword ptr [edi+eax*4]
80869855 2be1 sub esp,ecx
80869857 c1e902 shr ecx,2
8086985a 8bfc mov edi,esp
8086985c 3b3514a18880 cmp esi,dword ptr [nt!MmUserProbeAddress (8088a114)]
80869862 0f83a8010000 jae nt!KiSystemCallExit2+0x9f (80869a10)
80869868 f3a5 rep movs dword ptr es:[edi],dword ptr [esi]
8086986a ffd3 call ebx
8086986c 8be5 mov esp,ebp ;恢复旧的TrapFrame
8086986e 648b0d24010000 mov ecx,dword ptr fs:[124h]
80869875 8b553c mov edx,dword ptr [ebp+3Ch]
80869878 899134010000 mov dword ptr [ecx+134h],edx
nt!KiServiceExit:
8086987e fa cli
8086987f f7457000000200 test dword ptr [ebp+70h],20000h
80869886 7506 jne nt!KiServiceExit+0x10 (8086988e)
80869888 f6456c01 test byte ptr [ebp+6Ch],1
8086988c 7456 je nt!KiServiceExit+0x66 (808698e4)
8086988e 648b1d24010000 mov ebx,dword ptr fs:[124h]
80869895 c6432e00 mov byte ptr [ebx+2Eh],0
80869899 807b4a00 cmp byte ptr [ebx+4Ah],0
8086989d 7445 je nt!KiServiceExit+0x66 (808698e4)
8086989f 8bdd mov ebx,ebp
808698a1 894344 mov dword ptr [ebx+44h],eax
808698a4 c743503b000000 mov dword ptr [ebx+50h],3Bh
808698ab c7433823000000 mov dword ptr [ebx+38h],23h
808698b2 c7433423000000 mov dword ptr [ebx+34h],23h
808698b9 c7433000000000 mov dword ptr [ebx+30h],0
808698c0 b901000000 mov ecx,1
808698c5 ff152c108080 call dword ptr [nt!_imp_KfRaiseIrql (8080102c)]
808698cb 50 push eax
808698cc fb sti
808698cd 53 push ebx
808698ce 6a00 push 0
808698d0 6a01 push 1
808698d2 e8dfe3fbff call nt!KiDeliverApc (80827cb6)
808698d7 59 pop ecx
808698d8 ff1530108080 call dword ptr [nt!_imp_KfLowerIrql (80801030)]
808698de 8b4344 mov eax,dword ptr [ebx+44h]
808698e1 fa cli
808698e2 ebaa jmp nt!KiServiceExit+0x10 (8086988e)
808698e4 8b54244c mov edx,dword ptr [esp+4Ch]
808698e8 648b1d50000000 mov ebx,dword ptr fs:[50h]
808698ef 64891500000000 mov dword ptr fs:[0],edx
808698f6 8b4c2448 mov ecx,dword ptr [esp+48h]
808698fa 648b3524010000 mov esi,dword ptr fs:[124h]
80869901 888e40010000 mov byte ptr [esi+140h],cl
80869907 f7c3ff000000 test ebx,0FFh
8086990d 7579 jne nt!KiSystemCallExit2+0x17 (80869988)
8086990f f744247000000200 test dword ptr [esp+70h],20000h
80869917 0f850b090000 jne nt!Kei386EoiHelper+0x12c (8086a228)
8086991d 66f744246cf8ff test word ptr [esp+6Ch],0FFF8h
80869924 0f84b4000000 je nt!KiSystemCallExit2+0x6d (808699de)
8086992a 66837c246c1b cmp word ptr [esp+6Ch],1Bh
80869930 660fba64246c00 bt word ptr [esp+6Ch],0
80869937 f5 cmc
80869938 0f878e000000 ja nt!KiSystemCallExit2+0x5b (808699cc)
8086993e 66837d6c08 cmp word ptr [ebp+6Ch],8
80869943 7405 je nt!KiServiceExit+0xcc (8086994a)
80869945 8d6550 lea esp,[ebp+50h]
80869948 0fa1 pop fs
8086994a 8d6554 lea esp,[ebp+54h]
8086994d 5f pop edi
8086994e 5e pop esi
8086994f 5b pop ebx
80869950 5d pop ebp
80869951 66817c24088000 cmp word ptr [esp+8],80h
80869958 0f87e6080000 ja nt!Kei386EoiHelper+0x148 (8086a244)
8086995e 83c404 add esp,4
80869961 f744240401000000 test dword ptr [esp+4],1 ;判断 CS最后一位是否为1,即是否从RING3调用来的。
nt!KiSystemCallExitBranch:
80869969 7506 jne nt!KiSystemCallExit2 (80869971) ;若不是,即从RING3调用的。
8086996b 5a pop edx ;EIP ;下面是从RING0调用的。直接返回。没有堆栈切换。
8086996c 59 pop ecx ;CS
8086996d 9d popfd ;EFLAGS
8086996e ffe2 jmp edx ;返回.下面的语句是不执行的。
nt!KiSystemCallExit:
80869970 cf iretd ;INT调用返回。下面的语句不执行。
nt!KiSystemCallExit2: ;若是从RING3调用的。
80869971 f644240901 test byte ptr [esp+9],1 ;判断EFLAGS的TF =1?
80869976 75f8 jne nt!KiSystemCallExit (80869970) ;=1,则表示是通过INT调用的。
80869978 5a pop edx ;返回的EIP(RING3) ;=0,则表示是通过SYSENTER调用的。
80869979 83c404 add esp,4
8086997c 80642401fd and byte ptr [esp+1],0FDh
80869981 9d popfd
80869982 59 pop ecx ;返回的堆栈指针(RING3)
80869983 fb sti
80869984 0f35 sysexit ;返回。下面的语句不执行。