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
'Kernel mode' 카테고리의 다른 글
TESTSIGNING, DISABLE_INTEGRITY_CHECKS 환경 검사 (CI!g_CiOptions) (0) | 2014.09.17 |
---|---|
PspCreateProcessNotifyRoutine Maximum (0) | 2014.07.01 |
PsActiveProcessHead, HandleTableListHead (0) | 2014.05.12 |
windbg - registers are not yet known (0) | 2014.05.12 |
[펌] 커널에서 프로세스 풀패스 얻는 법 (0) | 2014.03.06 |