答案 0 :(得分:2)
内核模式(Windows x64)中的GS段指向内核处理器控制区域( KPCR )。
您可以使用!pcr
命令转储它:
kd> !pcr
KPCR for Processor 0 at fffff802fbd73000:
Major 1 Minor 1
NtTib.ExceptionList: fffff802fd6d8000
NtTib.StackBase: fffff802fd6d9070
NtTib.StackLimit: 0000000000b0e968
NtTib.SubSystemTib: fffff802fbd73000
NtTib.Version: 00000000fbd73180
NtTib.UserPointer: fffff802fbd737f0
NtTib.SelfTib: 000000007f005000
SelfPcr: 0000000000000000
Prcb: fffff802fbd73180
Irql: 0000000000000000
IRR: 0000000000000000
IDR: 0000000000000000
InterruptMode: 0000000000000000
IDT: 0000000000000000
GDT: 0000000000000000
TSS: 0000000000000000
CurrentThread: ffffe001e41a3080
NextThread: 0000000000000000
IdleThread: fffff802fbde9740
DpcQueue: Unable to read nt!_KDPC_DATA.DpcListHead.Flink @ fffff802fbd75f00
通过读取名为GS
的MSR(模型特定寄存器)(值为0xc0000101),您可以确认IA32_GS_BASE
段寄存器确实指向了KPCR:
kd> rdmsr 0xc0000101
msr[c0000101] = fffff802`fbd73000
正如你所看到的,在我的例子中,他们都指向0xfffff802fbd73000。
PCR由KPCR
结构描述:
kd> dt nt!_kpcr
+0x000 NtTib : _NT_TIB
+0x000 GdtBase : Ptr64 _KGDTENTRY64
+0x008 TssBase : Ptr64 _KTSS64
+0x010 UserRsp : Uint8B
+0x018 Self : Ptr64 _KPCR
+0x020 CurrentPrcb : Ptr64 _KPRCB
+0x028 LockArray : Ptr64 _KSPIN_LOCK_QUEUE
+0x030 Used_Self : Ptr64 Void
+0x038 IdtBase : Ptr64 _KIDTENTRY64
+0x040 Unused : [2] Uint8B
+0x050 Irql : UChar
+0x051 SecondLevelCacheAssociativity : UChar
+0x052 ObsoleteNumber : UChar
+0x053 Fill0 : UChar
+0x054 Unused0 : [3] Uint4B
+0x060 MajorVersion : Uint2B
+0x062 MinorVersion : Uint2B
+0x064 StallScaleFactor : Uint4B
+0x068 Unused1 : [3] Ptr64 Void
+0x080 KernelReserved : [15] Uint4B
+0x0bc SecondLevelCacheSize : Uint4B
+0x0c0 HalReserved : [16] Uint4B
+0x100 Unused2 : Uint4B
+0x108 KdVersionBlock : Ptr64 Void
+0x110 Unused3 : Ptr64 Void
+0x118 PcrAlign1 : [24] Uint4B
+0x180 Prcb : _KPRCB
正如您所看到的,KPCR结构的最后一个字段是另一个名为KPRCB
(代表内核处理器控制块)的结构(不指针,但结构本身)偏移量0x180。
这是这个结构的开始:
kd> dt nt!_kprcb
+0x000 MxCsr : Uint4B
+0x004 LegacyNumber : UChar
+0x005 ReservedMustBeZero : UChar
+0x006 InterruptRequest : UChar
+0x007 IdleHalt : UChar
+0x008 CurrentThread : Ptr64 _KTHREAD
+0x010 NextThread : Ptr64 _KTHREAD
+0x018 IdleThread : Ptr64 _KTHREAD
+0x020 NestingLevel : UChar
+0x021 ClockOwner : UChar
+0x022 PendingTickFlags : UChar
+0x022 PendingTick : Pos 0, 1 Bit
+0x022 PendingBackupTick : Pos 1, 1 Bit
+0x023 IdleState : UChar
+0x024 Number : Uint4B
...
为了简洁,上面的输出被截断,因为这个结构(以及PCR)非常大:windows 10 x64中PCR的大小是0x8040字节(KPRCB为0x7EC0)。
考虑到GS中的0x2eb8偏移(指向PCR),我们可以从PCR中减去KPRCB偏移量(0x180):
kd> ? 0x2eb8 - 0x180
Evaluate expression: 11576 = 00000000`00002d38
然后检查哪个字段位于KPRCB中的偏移量0x2d38:
0: kd> .shell -ci "dt nt!_kprcb" findstr /i 0x2d38
+0x2d38 KeSystemCalls : Uint4B
(注意:您只需dt nt!_kprcb
并查看偏移量0x2d38)。
因此,示例中的递增字段名为KeSystemCalls
,是一个32位字段(Uint4B
),如代码所示。
字段用法
在IDA反汇编程序(ntoskrnel.exe windows 10 - x64)中搜索,我们在0x2eb8值上有2次点击:
KiSystemCall64
VslpDispatchIumSyscall
第一个是"正常" syscall调度程序,而第二个调度程序是IUM processes(aka Trustlets)的系统调度程序。
在这两个函数中,字段的使用完全相同(KiSystemCall64中的示例):
.text:0000000140187360 call r10 ; perform syscall
.text:0000000140187363
.text:0000000140187363 loc_140187363:
.text:0000000140187363 inc dword ptr gs:2EB8h ; increment syscall counter
因此,该字段只是一个单调计数器,用于表示自系统启动以来发生的系统调用次数。