【问题标题】:What does inc dword ptr gs : [] doing here?inc dword ptr gs : [] 在这里做什么?
【发布时间】:2018-10-16 14:06:04
【问题描述】:

在使用 WinDbg 调试 windows 内核时,

我发现以下行: inc dword ptr gs : [2EB8h]

谁能解释一下这是什么意思? (英特尔语法、x86、Windows-10)

【问题讨论】:

  • TIB 也称为thread environment block。奇怪的是,x64 TEB(为 Windows 10 更新)的描述仅上升到 0x1828。鉴于这是一个硬编码地址(即不是从某个 tib 变量加载的),听起来 gs 段中存储了其他东西。或者 geoffchappell 并没有他想象的那么完整?

标签: windows assembly x86-64 windbg dword


【解决方案1】:

kernel 模式 (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

您可以通过读取名为IA32_GS_BASE(其值为0xc0000101)的MSR(模型特定寄存器)来确认KPCR确实由GS段寄存器指向:

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 //points to the _KPRCB member at 0x180
   +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 (0x180) 中减去 KPRCB 偏移量:

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

第一个是“普通”系统调用调度程序,而第二个是IUM processes(又名 Trustlets)的系统调用调度程序。

在这两个函数中,字段的使用完全相同(以 KiSystemCall64 为例):

.text:0000000140187360    call    r10 ; perform syscall
.text:0000000140187363
.text:0000000140187363 loc_140187363:
.text:0000000140187363    inc     dword ptr gs:2EB8h ; increment syscall counter

所以这个字段只是一个单调计数器,用于记录自系统启动以来发生的系统调用次数。

【讨论】:

  • @Nietsa KeSystemCalls 用于初始化 Process->Cookie,但它在 win7 中的 600 范围内,如果你说它在 Windows 10 中为 2d38,它已经前进了很多距离: )
【解决方案2】:

此答案只是 Nietsa 答案的扩展 除了被用来创建进程->cookie
poi(nt!KiProcessorBlock) 结构中的 KeSystemCalls 成员

kd> ?? @@masm(poi(nt!KiProcessorBlock)) == @$prcb
bool true
kd> ? @$pcr
Evaluate expression: -2104316928 = 8292ac00
kd> ? @$pcr+120
Evaluate expression: -2104316640 = 8292ad20
kd> ? @$prcb
Evaluate expression: -2104316640 = 8292ad20
kd> ? poi(nt!KiProcessorBlock)
Evaluate expression: -2104316640 = 8292ad20

还用于为

提供性能计数器值

“\system\System Calls/sec”数据

C:\>powershell -c "&{get-counter -counter \"\System\System Calls/sec\"}"

Timestamp                 CounterSamples
                          144196.186791101

如果有人遵循 pdh api

s = PdhCollectQueryData(hQuery); 

可以观察到使用 SYSTEM_INFO_CLASS 2 == SystemPerformanceInformation 对 NtQueryInformationSystem 的调用导致内核端的 nt!ExpQuerySystemInformation 填充来自 KPRCB 的信息

kd> # \+590h nt!ExpQuerySystemInformation l 600
nt!ExpQuerySystemInformation+0x57f:
82a01d73 038290050000    add     eax,dword ptr [edx+590h]

kd> ?? #FIELD_OFFSET(nt!_KPRCB , KeSystemCalls)
long 0n1424

kd> ? 0n1424
Evaluate expression: 1424 = 00000590  <<<< (windows 7 sp2 32 bit )

【讨论】:

  • 嘿@blabb!非常感谢您的评论。你的发现做得很好,这真的很有趣。你有我的 +1 :)
猜你喜欢
  • 2014-10-28
  • 2013-03-05
  • 1970-01-01
  • 2014-03-02
  • 1970-01-01
  • 2011-01-28
  • 2012-03-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多