lkd> dd KdversionBlock
8054c038
0a28000f 00020006 030c014c 0000002d
8054c048
804d7000 ffffffff 8055a420 ffffffff
WinDbg understands a variable called KdVersionBlock
and tells us that it begins at location 8054c038. This value is the value of i1
in our program. The KdVersionBlock is stored at address 0x0ffdff034. We set
variable I to this value and then use a * to pick up the value of the
KdVersionBlock variable.
We add an offset 0x80 to get a value of 8054c0b8.
lkd> dd 8054c0b8
8054c0b8 805605e0
00000000 80562a08 00000000
The value stored here is the address of the
PspCidTable 805605e0.
r.c
#include <ntddk.h>
#include <stdio.h>
#define DWORD long
struct NonExported
{
DWORD KernelBase;
DWORD KiCallUserMode;
DWORD PsActiveProcessHead;
DWORD PsLoadedModuleList;
DWORD PspCidTable;
DWORD ExpNumberOfPagedPools;
DWORD ObpRootDirectoryObject;
DWORD ObpTypeObjectType;
DWORD MmSystemCacheStart;
DWORD MmSystemCacheEnd;
DWORD MmSystemCacheWs;
DWORD MmPfnDatabase;
};
typedef ULONG *LPDWORD;
#define GetAddress( x ) (*(LPDWORD)((*(LPDWORD)0x0ffdff034) + (ULONG)(x)))
void GetNonExportedVariables(struct NonExported
*Table )
{
Table->KernelBase = GetAddress( 0x40 );
Table->KiCallUserMode = GetAddress( 0x60 );
Table->PsActiveProcessHead = GetAddress( 0x78 );
Table->PsLoadedModuleList = GetAddress( 0x70 );
Table->PspCidTable = GetAddress( 0x80 );
Table->ExpNumberOfPagedPools = GetAddress( 0x98
);
Table->ObpRootDirectoryObject = GetAddress( 0xC0
);
Table->ObpTypeObjectType = GetAddress( 0xC8 );
Table->MmSystemCacheStart = GetAddress( 0xD0 );
Table->MmSystemCacheEnd = GetAddress( 0xD8 );
Table->MmSystemCacheWs = GetAddress( 0xE0 );
Table->MmPfnDatabase = GetAddress( 0xE8 );
}
VOID OnUnload(PDRIVER_OBJECT DriverObject )
{
DbgPrint("Unload5");
}
NTSTATUS DriverEntry(PDRIVER_OBJECT
d,PUNICODE_STRING r)
{
struct NonExported NPVars;
long i,i1,i2,i3;
GetNonExportedVariables( &NPVars );
DbgPrint( "KernelBase = 0x%X PspCidTable =
0x%X", NPVars.KernelBase, NPVars.PspCidTable);
i = 0x0ffdff034;
i1 = *(long *)i;
i2 = i1 + 0x80;
i3 = *(long *)i2;
DbgPrint("i=%x i1=%x i2=%x
i3=%x",i,i1,i2,i3);
d->DriverUnload
= OnUnload;
return STATUS_SUCCESS;
}
KernelBase = 0x804D7000 PspCidTable = 0x805605E0
i=ffdff034 i1=8054c038 i2=8054c0b8 i3=805605e0
Unload5
The KdVersionBlock is actually a pointer to a
structure called KDDEBUGGER_DATA32. The KdVersionBlock
field in turn is a part of the Process Control Region
structure.
typedef struct _KDDEBUGGER_DATA32 {
DBGKD_DEBUG_DATA_HEADER32 Header;
ULONG KernBase;
ULONG BreakpointWithStatus; // address of breakpoint
ULONG SavedContext;
USHORT ThCallbackStack; // offset in thread data
USHORT NextCallback; // saved pointer to next callback frame
USHORT FramePointer; // saved frame pointer
USHORT PaeEnabled:1;
ULONG KiCallUserMode; // kernel routine
ULONG KeUserCallbackDispatcher; // address in ntdll
ULONG PsLoadedModuleList;
ULONG PsActiveProcessHead;
ULONG PspCidTable;
ULONG ExpSystemResourcesList;
ULONG ExpPagedPoolDescriptor;
ULONG ExpNumberOfPagedPools;
[...]
ULONG KdPrintCircularBuffer;
ULONG KdPrintCircularBufferEnd;
ULONG KdPrintWritePointer;
ULONG KdPrintRolloverCount;
ULONG MmLoadedUserImageList;
} KDDEBUGGER_DATA32, *PKDDEBUGGER_DATA32;
Thus in our code we assume that the Process Control
Region starts somewhere and at 0x0ffdff034 is a pointer to the kdVersionBlock
which is a pointer to the above debugger data32 structure. I is a pointer to
the PCR region where the KdVersionBlock pointer is stored, i1 is the
KdVersionBlock pointer, i2 is 80 bytes within the debugger structure and i3 is
where the PspCidTable starts.
lkd> !pcr
KPCR for Processor 0 at ffdff000:
The pcr or Process Control Block extension tells us
that it starts at ffdff000. 34 from the start is found the KdVersionBlock
field.
lkd> dd ffdff034
ffdff034
8054c038 8003f400 8003f000 80042000
We thus assume the value of the pcr and from there
we an get at the KdVersionBlock and then the PspCidTable.