Сегмент GS в режиме kernel (windows x64) указывает на область управления процессором ядра ( 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
Вы можете подтвердить, что KPCR действительно указан сегментным регистром GS
, прочитав MSR (регистр, специфичный для модели) с именем IA32_GS_BASE
(значение 0xc0000101):
kd> rdmsr 0xc0000101
msr[c0000101] = fffff802`fbd73000
Как вы можете видеть, они оба указывают, в моем примере, на 0xfffff802fbd73000.
ПЦР описывается структурой 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) чрезвычайно велика: размер PCR в windows 10 x64 составляет 0x8040 байт (0x7EC0 для KPRCB).
Учитывая ваше смещение 0x2eb8 в GS (которое указывает на PCR), мы можем просто вычесть смещение KPRCB из PCR (0x180):
kd> ? 0x2eb8 - 0x180
Evaluate expression: 11576 = 00000000`00002d38
И затем проверьте, какое поле имеет смещение 0x2d38 в KPRCB:
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:
KiSystemCall64
VslpDispatchIumSyscall
Первый - это «обычный» диспетчер системных вызовов, а второй - диспетчер системных вызовов для процессов IUM (он же Trustlets).
В обеих этих функциях использование поля одинаково (пример в KiSystemCall64):
.text:0000000140187360 call r10 ; perform syscall
.text:0000000140187363
.text:0000000140187363 loc_140187363:
.text:0000000140187363 inc dword ptr gs:2EB8h ; increment syscall counter
Таким образом, это поле является просто монотонным счетчиком количества системных вызовов, которые произошли с момента загрузки системы.