Kernel mode2014. 6. 19. 18:36

PspCidTable 주소를 찾기 위해 PsLookupProcessByProcessId() 함수 내부를 스캔하는 방법 말고도 다른 방법이 있어 정리해본다.

(x64에서는 사용 할 수 없을 것 같다)



첫번째로 찾아야 할 정보는 nt!_KPCR(Kernel Processor Control Region) 구조체 정보이다.

각 CPU(core)마다 하나씩 가지고 있는 구조체 이며, x86과 x64에서 각각 다음과 같이 구조체를 구할 수 있다.


x86 : FS:[0x1C]

x64 : GS:[0x18]


UserMode에서는 FS레지스터를 이용하여 TEB 정보를 가져올때 사용하지만,

KernelMode에서는 TEB가 아닌 PCR 정보를 가져온다.

또한 x64에서는 FS레지스터가 아닌 GS레지스터를 사용한다는 점.


아래는 _KPCR 구조체 모습이며 각각 0x34, 0x108 위치에 KdVersionBlock값을 가지고 있다.


[x86]

1: kd> dt nt!_KPCR

   +0x000 NtTib            : _NT_TIB

   +0x000 Used_ExceptionList : Ptr32 _EXCEPTION_REGISTRATION_RECORD

   +0x004 Used_StackBase   : Ptr32 Void

   +0x008 Spare2           : Ptr32 Void

   +0x00c TssCopy          : Ptr32 Void

   +0x010 ContextSwitches  : Uint4B

   +0x014 SetMemberCopy    : Uint4B

   +0x018 Used_Self        : Ptr32 Void

   +0x01c SelfPcr          : Ptr32 _KPCR        -> FS:[0x1C]

   +0x020 Prcb             : Ptr32 _KPRCB

   +0x024 Irql             : UChar

   +0x028 IRR              : Uint4B

   +0x02c IrrActive        : Uint4B

   +0x030 IDR              : Uint4B

   +0x034 KdVersionBlock   : Ptr32 Void

   +0x038 IDT              : Ptr32 _KIDTENTRY

   +0x03c GDT              : Ptr32 _KGDTENTRY

   +0x040 TSS              : Ptr32 _KTSS

   +0x044 MajorVersion     : Uint2B

   +0x046 MinorVersion     : Uint2B

   +0x048 SetMember        : Uint4B

   +0x04c StallScaleFactor : Uint4B

   +0x050 SpareUnused      : UChar

   +0x051 Number           : UChar

   +0x052 Spare0           : UChar

   +0x053 SecondLevelCacheAssociativity : UChar

   +0x054 VdmAlert         : Uint4B

   +0x058 KernelReserved   : [14] Uint4B

   +0x090 SecondLevelCacheSize : Uint4B

   +0x094 HalReserved      : [16] Uint4B

   +0x0d4 InterruptMode    : Uint4B

   +0x0d8 Spare1           : UChar

   +0x0dc KernelReserved2  : [17] Uint4B

   +0x120 PrcbData         : _KPRCB

[x64]

0: kd> dt nt!_KPCR

   +0x000 NtTib            : _NT_TIB

   +0x000 GdtBase          : Ptr64 _KGDTENTRY64

   +0x008 TssBase          : Ptr64 _KTSS64

   +0x010 UserRsp          : Uint8B

   +0x018 Self             : Ptr64 _KPCR        -> GS:[0x18]

   +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


참고로 KdVersionBlock값은 첫번째 코어만 가지고 있다고 하며, x64는 모두 NULL값을 갖는다.

실제 KdVersionBlock값을 확인하기 위해 각각의 PCR 정보를 보자.

x86은 듀얼코어, x64는 쿼드코어 환경



[x86]

1: kd> !PCR 0

KPCR for Processor 0 at 82d38c00:

...


1: kd> !PCR 1

KPCR for Processor 1 at 807c3000:

...

          

1: kd> dt nt!_KPCR 82d38c00 KdVersionBlock

   +0x034 KdVersionBlock : 0x82d37bc0 Void

1: kd> dt nt!_KPCR 807c3000 KdVersionBlock

   +0x034 KdVersionBlock : (null) 

[x64]

0: kd> !PCR 0

KPCR for Processor 0 at fffff802218ef000:

...


0: kd> !PCR 1

KPCR for Processor 1 at ffffd0019cf5c000:

...


0: kd> !PCR 2

KPCR for Processor 2 at ffffd0019cfd5000:

...


0: kd> !PCR 3

KPCR for Processor 3 at ffffd0019cf00000:

...

          

0: kd> dt nt!_KPCR fffff802218ef000 KdVersionBlock

   +0x108 KdVersionBlock : (null) 

0: kd> dt nt!_KPCR ffffd0019cf5c000 KdVersionBlock

   +0x108 KdVersionBlock : (null) 

0: kd> dt nt!_KPCR ffffd0019cfd5000 KdVersionBlock

   +0x108 KdVersionBlock : (null) 

0: kd> dt nt!_KPCR ffffd0019cf00000 KdVersionBlock

   +0x108 KdVersionBlock : (null) 


보는것처럼 x64의 PCR에는 KdVersionBlock 값이 전부 NULL이다.

다른 방법으로 해당 값을 구할 수 있지 않을까하여 열심히 찾아보았지만, 찾을 수가 없었다.


그리고 KdVersionBlock값은 nt!_DBGKD_GET_VERSION64라는 구조체 형태로 전환해 볼 수 있다.


1: kd> dt nt!_DBGKD_GET_VERSION64

   +0x000 MajorVersion     : Uint2B

   +0x002 MinorVersion     : Uint2B

   +0x004 ProtocolVersion  : UChar

   +0x005 KdSecondaryVersion : UChar

   +0x006 Flags            : Uint2B

   +0x008 MachineType      : Uint2B

   +0x00a MaxPacketType    : UChar

   +0x00b MaxStateChange   : UChar

   +0x00c MaxManipulate    : UChar

   +0x00d Simulation       : UChar

   +0x00e Unused           : [1] Uint2B

   +0x010 KernBase         : Uint8B

   +0x018 PsLoadedModuleList : Uint8B

   +0x020 DebuggerDataList : Uint8B



익숙한 PsLoadedModuleList 데이터가 보인다.

KdVersionBlock를 이용하여 PsLoadedModuleList값도 구할 수 있을 것 같은데 아직 확인을 못해봤다.

그리고 PspCidTable 값을 구하기 위해 사용되는 DebuggerDataList라는 데이터가 있다.

이 DebuggerDataList는 _KDDEBUGGER_DATA64라는 구조체로 전환 할 수 있다.


typedef struct _DBGKD_DEBUG_DATA_HEADER64

{

LIST_ENTRY64    List;

ULONG           OwnerTag;   //"KDBG"

ULONG           Size;

}DBGKD_DEBUG_DATA_HEADER64, *PDBGKD_DEBUG_DATA_HEADER64;


typedef struct _KDDEBUGGER_DATA64 

{

DBGKD_DEBUG_DATA_HEADER64 Header;

ULONG64   KernBase;

ULONG64   BreakpointWithStatus;       // address of breakpoint

ULONG64   SavedContext;

USHORT    ThCallbackStack;            // offset in thread data

USHORT    NextCallback;               // saved pointer to next callback frame

USHORT    FramePointer;               // saved frame pointer

USHORT    PaeEnabled:1;

ULONG64   KiCallUserMode;             // kernel routine

ULONG64   KeUserCallbackDispatcher;

ULONG64   PsLoadedModuleList;

ULONG64   PsActiveProcessHead;

ULONG64   PspCidTable;

ULONG64   ExpSystemResourcesList;

ULONG64   ExpPagedPoolDescriptor;

ULONG64   ExpNumberOfPagedPools;

...

}KDDEBUGGER_DATA64, *PKDDEBUGGER_DATA64;



드디어 PspCidTable값이 나왔다.

XP에서 8.1까지 해당 값을 확인 할 수 있었으며,

x64의 경우는 KdVersionBlock값이 전부 NULL이라 이 방법으로는 확인하지 못했다.


아래는 샘플 코드.




[참조]

https://code.google.com/p/qpopt/source/browse/trunk/other/eagleeyes/driver/helper.c?r=40

http://scdetective.googlecode.com/svn/trunk/ScDetective_Driver/ScDetective/Process/Process.c



Posted by hswang