Windows XP/2003 系統調用(一)

    今天在這裏主要想了解一下Windows如何從ring3下的Win32 API轉到ring0下的Kernel Routine。

以NtReadFile爲例:

kd> u ntdll!NtReadFile (Win 2003 SP1)
ntdll!ZwReadFile:
7c821b78 b8bf000000      mov     eax,0BFh;(系統調用號)
7c821b7d ba0003fe7f      mov     edx,offset SharedUserData!SystemCallStub (7ffe0300)
7c821b82 ff12            call    dword ptr [edx]

 

可以看到NtReadFile被WinDBG自動轉成了ZwReadFile,其實這兩個函數都在ntdll中導出,實際指向的是同一個地址(7c821b78)。在kernel模式下對應的Routine也叫NtReadFile

kd> u nt!NtReadFile
nt!NtReadFile [e:/windowsresearchkernel-wrk/wrk-v1.2/base/ntos/io/iomgr/read.c @ 90]:
808e8552 6a58            push    58h
808e8554 68b8318080      push    offset nt!GUID_DOCK_INTERFACE+0x34c (808031b8)
808e8559 e852c9f8ff      call    nt!__SEH_prolog (80874eb0)
808e855e 33f6            xor     esi,esi
808e8560 8975e0          mov     dword ptr [ebp-20h],esi
808e8563 8975d0          mov     dword ptr [ebp-30h],esi
…………

 

但是kernel中也有一個叫ZwReadFile的函數
kd> u nt!ZwReadFile
nt!ZwReadFile [E:/WindowsResearchKernel-WRK/WRK-v1.2/base/ntos/ke/i386/sysstubs.asm @ 1644]:
8082cbd4 b8bf000000      mov     eax,0BFh;(系統調用號)
8082cbd9 8d542404        lea     edx,[esp+4]
8082cbdd 9c              pushfd
8082cbde 6a08            push    8
8082cbe0 e8a55b0500      call    nt!_KiSystemService (8088278a)
8082cbe5 c22400          ret     24h

這個函數其實是個stub,不做真正的事情,最終仍然要調用NtReadFile,所以內核中的NtReadFile纔是真正幹活的有用的函數!!

回到ntdll下的NtReadFile(ZwReadFile),0BFh是win 2003下的系統調用號(系統調用號其實就是一個索引,後面會講到)。SharedUserData 是操作系統爲每個進程提供的個共享數據結構,裏面存放有很多重要的系統信息,如TickCount、系統時間、SystemRoot等……
其在DDK定義爲:
#define KI_USER_SHARED_DATA     0xffdf0000
#define SharedUserData ((KUSER_SHARED_DATA * const) KI_USER_SHARED_DATA)
他在內核中的地址是0xffdf0000,操作系統通過共享映射把這個結構以只讀方式映射到每個進程的0x7ffe0000(2G邊界以下128K)的地方。

每個進程用戶空間的0x7ffe0000都以只讀方式映射到相同的物理頁面上,而這個物理頁面上就是KUSER_SHARED_DATA結構
的數據,因此操作系統上的每個進程都有一個這個結構,而操作系統只需要維護這一個結構就行了。
kd> dt KUSER_SHARED_DATA
nt!KUSER_SHARED_DATA
   +0x000 TickCountLowDeprecated : 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 LargePageMinimum : Uint4B
   +0x248 Reserved2        : [7] 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
   +0x334 Wow64SharedInformation : [16] Uint4B

所以ntdll!NtReadFile中的7ffe0300,就是上面紅色部分,這個值是系統啓動時設置的,它就是函數KiFastSystemCall

kd> u KiFastSystemCall
ntdll!KiFastSystemCall:
7c82ed50 8bd4            mov     edx,esp;edx->進入內核前ring3棧
7c82ed52 0f34            sysenter;進入內核
ntdll!KiFastSystemCallRet:
7c82ed54 c3              ret

 

ret(KiFastSystemCall)  <--edx,esp

ret(NtReadFile)

.                                      (參數)

.

.

.

.
進入內核前ring3棧

 

sysenter後就進入內核了,那麼到達內核的哪裏呢?查看Intel文檔

sysenter

 

也可以用winDBG查看:

kd> rdmsr 174
msr[174] = 00000000`00000008 (IA32_SYSENTER_CS)
kd> rdmsr 175
msr[175] = 00000000`fa027000 (IA32_SYSENTER_ESP)
kd> rdmsr 176
msr[176] = 00000000`80882850 (IA32_SYSENTER_EIP) ;KiFastCallEntry

所以進入內核後的函數是KiFastCallEntry,CS代碼段選擇子爲08h,ESP指向的內核棧叫DPC棧,這些值是全局不變的!

 

先回顧以下保護模式下的知識:

Segment Selector

Index (Bits 3 through 15) — Selects one of 8192 descriptors in the GDT or LDT. The processor multiplies the index value by 8 (the number of bytes in a segment descriptor) and adds the result to the base address of the GDT or LDT (from the GDTR or LDTR register, respectively).

在windows ring3下:

cs=0000001b (00011011) ;GDT,18

ds=00000023 (00100011) ;GDT,20

ss=00000023 (00100011) ;GDT,20

fs=0000003b (00111011)   ;GDT,38

在windows ring0下:
cs=00000008 (00001000)   ;GDT,08

ds=00000023 (00100011)   ;GDT,20

ss=00000010 (00010000)   ;GDT,10

fs=00000030 (00110000)    ;GDT,30

可見用的都是GDT,事實上windows幾乎不用LDT。

 

-------------------------------------------------------------------------------
Sel.  Base      Limit     DPL  P   G    Description
-------------------------------------------------------------------------------
0008  00000000  FFFFFFFF   0   P   4Kb  Execute/Read                  ;CS r0
0010  00000000  FFFFFFFF   0   P   4Kb  Read/Write                      ;SS r0
0018  00000000  FFFFFFFF   3   P   4Kb  Execute/Read                  ;CS r3
0020  00000000  FFFFFFFF   3   P   4Kb  Read/Write                      ;DS r3,r0 ; SS r3
0028  80042000  000020AB   0   P   1b   32-Bit TSS (Busy)           

0030  FFDFF000  00001FFF   0   P   4Kb  Read/Write                      ;FS r0

0038  7FFDE000  00000FFF   3   P   1b   Read/Write, accessed      ;FS r3
0040  00000400  0000FFFF   3   P   1b   Read/Write
0048  00000000  00000000   0   NP  1b   Reserved
0050  808945B0  00000068   0   P   1b   32-Bit TSS (Available)
0058  80894618  00000068   0   P   1b   32-Bit TSS (Available)
0060  000230C0  0000FFFF   0   P   1b   Read/Write
0068  000B8000  00003FFF   0   P   1b   Read/Write
0070  FFFF7000  000003FF   0   P   1b   Read/Write
0078  80400000  0000FFFF   0   P   1b   Execute/Read
0080  80400000  0000FFFF   0   P   1b   Read/Write
0088  00000000  00000000   0   P   1b   Read/Write
0090  00000000  00000000   0   NP  1b   Reserved
0098  00000000  00000000   0   NP  1b   Reserved
00A0  00000000  00000000   0   NP  1b   Reserved
00A8  00000000  00000000   0   NP  1b   Reserved
00B0  00000000  00000000   0   NP  1b   Reserved
00B8  00000000  00000000   0   NP  1b   Reserved
00C0  00000000  00000000   0   NP  1b   Reserved
00C8  00000000  00000000   0   NP  1b   Reserved
00D0  00000000  00000000   0   NP  1b   Reserved
00D8  00000000  00000000   0   NP  1b   Reserved
00E0  00008003  0000F100   0   NP  1b   Reserved
00E8  00000000  0000FFFF   0   P   1b   Read/Write
00F0  80827E8C  000003B7   0   P   1b   Execute-Only
00F8  00000000  0000FFFF   0   P   1b   Read/Write

                               GDT Table

 

待續,見下節……

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章