现在的位置: 首页 > 综合 > 正文

Windows XP/2003 系统调用(一)

2014年02月28日 ⁄ 综合 ⁄ 共 6122字 ⁄ 字号 评论关闭

 今天在这里主要想了解一下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

待续,见下节……

抱歉!评论已关闭.