592 lines
13 KiB
C
592 lines
13 KiB
C
/*++
|
||
|
||
Copyright (c) 1992 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
regext.c
|
||
|
||
Abstract:
|
||
|
||
Kernel debugger extensions useful for the registry
|
||
|
||
Author:
|
||
|
||
John Vert (jvert) 7-Sep-1993
|
||
|
||
Environment:
|
||
|
||
Loaded as a kernel debugger extension
|
||
|
||
Revision History:
|
||
|
||
John Vert (jvert) 7-Sep-1993
|
||
created
|
||
|
||
--*/
|
||
#include "cmp.h"
|
||
#include <windef.h>
|
||
#include <ntkdexts.h>
|
||
#include <stdlib.h>
|
||
#include <stdio.h>
|
||
|
||
HIVE_LIST_ENTRY HiveList[8];
|
||
|
||
ULONG TotalPages;
|
||
ULONG TotalPresentPages;
|
||
|
||
ULONG TotalKcbs;
|
||
ULONG TotalKcbName;
|
||
|
||
BOOLEAN SavePages;
|
||
BOOLEAN RestorePages;
|
||
FILE *TempFile;
|
||
|
||
PNTKD_OUTPUT_ROUTINE lpPrint;
|
||
PNTKD_GET_EXPRESSION lpGetExpressionRoutine;
|
||
PNTKD_GET_SYMBOL lpGetSymbolRoutine;
|
||
PNTKD_CHECK_CONTROL_C lpCheckControlCRoutine;
|
||
PNTKD_READ_VIRTUAL_MEMORY lpReadMem;
|
||
|
||
void
|
||
poolDumpHive(
|
||
IN PCMHIVE Hive
|
||
);
|
||
|
||
VOID
|
||
poolDumpMap(
|
||
IN ULONG Length,
|
||
IN PHMAP_DIRECTORY Map
|
||
);
|
||
|
||
void
|
||
dumpHiveFromFile(
|
||
IN FILE *File
|
||
);
|
||
|
||
VOID
|
||
kcbWorker(
|
||
IN PCM_KEY_CONTROL_BLOCK pKcb
|
||
);
|
||
|
||
VOID
|
||
pool(
|
||
DWORD dwCurrentPc,
|
||
PNTKD_EXTENSION_APIS lpExtensionApis,
|
||
LPSTR lpArgumentString
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Goes through all the paged pool allocated to registry space and
|
||
determines which pages are present and which are not.
|
||
|
||
Called as:
|
||
|
||
!regext.pool [s|r]
|
||
|
||
s Save list of registry pages to temporary file
|
||
r Restore list of registry pages from temp. file
|
||
|
||
Arguments:
|
||
|
||
CurrentPc - Supplies the current pc at the time the extension is
|
||
called.
|
||
|
||
lpExtensionApis - Supplies the address of the functions callable
|
||
by this extension.
|
||
|
||
lpArgumentString - Supplies the pattern and expression for this
|
||
command.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PLIST_ENTRY pCmpHiveListHead;
|
||
PLIST_ENTRY pNextHiveList;
|
||
HIVE_LIST_ENTRY *pHiveListEntry;
|
||
ULONG BytesRead;
|
||
PCMHIVE CmHive;
|
||
|
||
lpPrint = lpExtensionApis->lpOutputRoutine;
|
||
lpGetExpressionRoutine = lpExtensionApis->lpGetExpressionRoutine;
|
||
lpGetSymbolRoutine = lpExtensionApis->lpGetSymbolRoutine;
|
||
lpCheckControlCRoutine = lpExtensionApis->lpCheckControlCRoutine;
|
||
lpReadMem = lpExtensionApis->lpReadVirtualMemRoutine;
|
||
|
||
if (toupper(lpArgumentString[0])=='S') {
|
||
SavePages = TRUE;
|
||
} else {
|
||
SavePages = FALSE;
|
||
}
|
||
if (toupper(lpArgumentString[0])=='R') {
|
||
RestorePages = TRUE;
|
||
} else {
|
||
RestorePages = FALSE;
|
||
}
|
||
|
||
//
|
||
// Go get the hivelist.
|
||
//
|
||
memset(HiveList,0,sizeof(HiveList));
|
||
pHiveListEntry = (PHIVE_LIST_ENTRY)(lpGetExpressionRoutine)("CmpMachineHiveList");
|
||
if (pHiveListEntry != NULL) {
|
||
(lpReadMem)(pHiveListEntry,
|
||
HiveList,
|
||
sizeof(HiveList),
|
||
&BytesRead);
|
||
}
|
||
|
||
//
|
||
// First go and get the hivelisthead
|
||
//
|
||
pCmpHiveListHead = (PLIST_ENTRY)(lpGetExpressionRoutine)("CmpHiveListHead");
|
||
if (pCmpHiveListHead==NULL) {
|
||
(lpPrint)("CmpHiveListHead couldn't be read\n");
|
||
return;
|
||
}
|
||
|
||
(lpReadMem)(&pCmpHiveListHead->Flink,
|
||
&pNextHiveList,
|
||
sizeof(pNextHiveList),
|
||
&BytesRead);
|
||
if (BytesRead != sizeof(pNextHiveList)) {
|
||
(lpPrint)("Couldn't read first Flink (%lx) of CmpHiveList\n",
|
||
&pCmpHiveListHead->Flink);
|
||
return;
|
||
}
|
||
|
||
TotalPages = TotalPresentPages = 0;
|
||
|
||
if (SavePages) {
|
||
TempFile = fopen("regext.dat","w+");
|
||
if (TempFile==NULL) {
|
||
(lpPrint)("Couldn't create regext.dat for write\n");
|
||
return;
|
||
}
|
||
} else if (RestorePages) {
|
||
TempFile = fopen("regext.dat","r");
|
||
if (TempFile==NULL) {
|
||
(lpPrint)("Couldn't open regext.dat for read\n");
|
||
return;
|
||
}
|
||
}
|
||
|
||
if (RestorePages) {
|
||
dumpHiveFromFile(TempFile);
|
||
} else {
|
||
while (pNextHiveList != pCmpHiveListHead) {
|
||
CmHive = CONTAINING_RECORD(pNextHiveList, CMHIVE, HiveList);
|
||
poolDumpHive(CmHive);
|
||
|
||
(lpReadMem)(&pNextHiveList->Flink,
|
||
&pNextHiveList,
|
||
sizeof(pNextHiveList),
|
||
&BytesRead);
|
||
if (BytesRead != sizeof(pNextHiveList)) {
|
||
(lpPrint)("Couldn't read Flink (%lx) of %lx\n",
|
||
&pCmpHiveListHead->Flink,pNextHiveList);
|
||
break;
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
(lpPrint)("Total pages present = %d / %d\n",
|
||
TotalPresentPages,
|
||
TotalPages);
|
||
|
||
if (SavePages || RestorePages) {
|
||
fclose(TempFile);
|
||
}
|
||
}
|
||
|
||
void
|
||
poolDumpHive(
|
||
IN PCMHIVE pHive
|
||
)
|
||
{
|
||
CMHIVE CmHive;
|
||
ULONG BytesRead;
|
||
WCHAR FileName[HBASE_NAME_ALLOC/2 + 1];
|
||
ULONG i;
|
||
|
||
(lpPrint)("\ndumping hive at %lx ",pHive);
|
||
(lpReadMem)(pHive,
|
||
&CmHive,
|
||
sizeof(CmHive),
|
||
&BytesRead);
|
||
|
||
if (BytesRead < sizeof(CmHive)) {
|
||
(lpPrint)("\tRead %lx bytes from %lx\n",BytesRead,pHive);
|
||
return;
|
||
}
|
||
|
||
(lpReadMem)(&CmHive.Hive.BaseBlock->FileName,
|
||
FileName,
|
||
sizeof(FileName),
|
||
&BytesRead);
|
||
|
||
if (BytesRead < sizeof(FileName)) {
|
||
wcscpy(FileName, L"UNKNOWN");
|
||
} else {
|
||
if (FileName[0]==L'\0') {
|
||
wcscpy(FileName, L"NONAME");
|
||
} else {
|
||
FileName[HBASE_NAME_ALLOC/2]=L'\0';
|
||
}
|
||
}
|
||
|
||
(lpPrint)("(%ws)\n",FileName);
|
||
|
||
(lpPrint)(" %d KCBs open\n",CmHive.KcbCount);
|
||
(lpPrint)(" Stable Length = %lx\n",CmHive.Hive.Storage[Stable].Length);
|
||
if (SavePages) {
|
||
fprintf(TempFile,
|
||
"%ws %d %d\n",
|
||
FileName,
|
||
CmHive.Hive.Storage[Stable].Length,
|
||
CmHive.Hive.Storage[Volatile].Length);
|
||
}
|
||
poolDumpMap(CmHive.Hive.Storage[Stable].Length,
|
||
CmHive.Hive.Storage[Stable].Map);
|
||
|
||
(lpPrint)(" Volatile Length = %lx\n",CmHive.Hive.Storage[Volatile].Length);
|
||
poolDumpMap(CmHive.Hive.Storage[Volatile].Length,
|
||
CmHive.Hive.Storage[Volatile].Map);
|
||
|
||
}
|
||
|
||
VOID
|
||
poolDumpMap(
|
||
IN ULONG Length,
|
||
IN PHMAP_DIRECTORY Map
|
||
)
|
||
{
|
||
ULONG Tables;
|
||
ULONG MapSlots;
|
||
ULONG i;
|
||
ULONG BytesRead;
|
||
HMAP_DIRECTORY MapDirectory;
|
||
PHMAP_TABLE MapTable;
|
||
HMAP_ENTRY MapEntry;
|
||
ULONG Garbage;
|
||
ULONG Present=0;
|
||
|
||
if (Length==0) {
|
||
return;
|
||
}
|
||
|
||
MapSlots = Length / HBLOCK_SIZE;
|
||
Tables = 1+ ((MapSlots-1) / HTABLE_SLOTS);
|
||
|
||
//
|
||
// read in map directory
|
||
//
|
||
(lpReadMem)(Map,
|
||
&MapDirectory,
|
||
Tables * sizeof(PHMAP_TABLE),
|
||
&BytesRead);
|
||
if (BytesRead < (Tables * sizeof(PHMAP_TABLE))) {
|
||
(lpPrint)("Only read %lx/%lx bytes from %lx\n",
|
||
BytesRead,
|
||
Tables * sizeof(PHMAP_TABLE),
|
||
Map);
|
||
return;
|
||
|
||
}
|
||
|
||
//
|
||
// check out each map entry
|
||
//
|
||
for (i=0; i<MapSlots; i++) {
|
||
|
||
MapTable = MapDirectory.Directory[i/HTABLE_SLOTS];
|
||
|
||
(lpReadMem)(&(MapTable->Table[i%HTABLE_SLOTS]),
|
||
&MapEntry,
|
||
sizeof(HMAP_ENTRY),
|
||
&BytesRead);
|
||
if (BytesRead < sizeof(HMAP_ENTRY)) {
|
||
(lpPrint)(" can't read HMAP_ENTRY at %lx\n",
|
||
&(MapTable->Table[i%HTABLE_SLOTS]));
|
||
}
|
||
|
||
if (SavePages) {
|
||
fprintf(TempFile, "%lx\n",MapEntry.BlockAddress);
|
||
|
||
}
|
||
|
||
//
|
||
// probe the HBLOCK
|
||
//
|
||
(lpReadMem)(MapEntry.BlockAddress,
|
||
&Garbage,
|
||
sizeof(ULONG),
|
||
&BytesRead);
|
||
if (BytesRead > 0) {
|
||
++Present;
|
||
}
|
||
}
|
||
(lpPrint)(" %d/%d pages present\n",
|
||
Present,
|
||
MapSlots);
|
||
|
||
TotalPages += MapSlots;
|
||
TotalPresentPages += Present;
|
||
|
||
}
|
||
|
||
void
|
||
dumpHiveFromFile(
|
||
IN FILE *File
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Takes a list of the registry hives and pages from a file and
|
||
checks to see how many of the pages are in memory.
|
||
|
||
The format of the file is as follows
|
||
hivename stablelength volatilelength
|
||
stable page address
|
||
stable page address
|
||
.
|
||
.
|
||
.
|
||
volatile page address
|
||
volatile page address
|
||
.
|
||
.
|
||
.
|
||
hivename stablelength volatilelength
|
||
.
|
||
.
|
||
.
|
||
|
||
|
||
Arguments:
|
||
|
||
File - Supplies a file.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
CHAR Hivename[33];
|
||
ULONG StableLength;
|
||
ULONG VolatileLength;
|
||
ULONG Page;
|
||
ULONG i;
|
||
ULONG NumFields;
|
||
ULONG Garbage;
|
||
ULONG Present;
|
||
ULONG Total;
|
||
ULONG BytesRead;
|
||
|
||
while (!feof(File)) {
|
||
NumFields = fscanf(File,"%s %d %d\n",
|
||
Hivename,
|
||
&StableLength,
|
||
&VolatileLength);
|
||
if (NumFields != 3) {
|
||
(lpPrint)("fscanf returned %d\n",NumFields);
|
||
return;
|
||
}
|
||
|
||
(lpPrint)("\ndumping hive %s\n",Hivename);
|
||
(lpPrint)(" Stable Length = %lx\n",StableLength);
|
||
Present = 0;
|
||
Total = 0;
|
||
while (StableLength > 0) {
|
||
fscanf(File, "%lx\n",&Page);
|
||
(lpReadMem)(Page,
|
||
&Garbage,
|
||
sizeof(ULONG),
|
||
&BytesRead);
|
||
if (BytesRead > 0) {
|
||
++Present;
|
||
}
|
||
++Total;
|
||
StableLength -= HBLOCK_SIZE;
|
||
}
|
||
if (Total > 0) {
|
||
(lpPrint)(" %d/%d stable pages present\n",
|
||
Present,Total);
|
||
}
|
||
TotalPages += Total;
|
||
TotalPresentPages += Present;
|
||
|
||
(lpPrint)(" Volatile Length = %lx\n",VolatileLength);
|
||
Present = 0;
|
||
Total = 0;
|
||
while (VolatileLength > 0) {
|
||
fscanf(File, "%lx\n",&Page);
|
||
(lpReadMem)(Page,
|
||
&Garbage,
|
||
sizeof(ULONG),
|
||
&BytesRead);
|
||
if (BytesRead > 0) {
|
||
++Present;
|
||
}
|
||
++Total;
|
||
VolatileLength -= HBLOCK_SIZE;
|
||
}
|
||
if (Total > 0) {
|
||
(lpPrint)(" %d/%d volatile pages present\n",
|
||
Present,Total);
|
||
}
|
||
|
||
TotalPages += Total;
|
||
TotalPresentPages += Present;
|
||
}
|
||
|
||
}
|
||
|
||
void
|
||
kcb(
|
||
DWORD dwCurrentPc,
|
||
PNTKD_EXTENSION_APIS lpExtensionApis,
|
||
LPSTR lpArgumentString
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Walks the kcb tree and prints the names of keys which have
|
||
outstanding kcbs
|
||
|
||
Called as:
|
||
|
||
!regext.kcb
|
||
|
||
Arguments:
|
||
|
||
CurrentPc - Supplies the current pc at the time the extension is
|
||
called.
|
||
|
||
lpExtensionApis - Supplies the address of the functions callable
|
||
by this extension.
|
||
|
||
lpArgumentString - Supplies the pattern and expression for this
|
||
command.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PCM_KEY_CONTROL_BLOCK pKCB;
|
||
PCM_KEY_CONTROL_BLOCK Root;
|
||
ULONG BytesRead;
|
||
|
||
lpPrint = lpExtensionApis->lpOutputRoutine;
|
||
lpGetExpressionRoutine = lpExtensionApis->lpGetExpressionRoutine;
|
||
lpGetSymbolRoutine = lpExtensionApis->lpGetSymbolRoutine;
|
||
lpCheckControlCRoutine = lpExtensionApis->lpCheckControlCRoutine;
|
||
lpReadMem = lpExtensionApis->lpReadVirtualMemRoutine;
|
||
|
||
Root = (PCM_KEY_CONTROL_BLOCK)(lpGetExpressionRoutine)("CmpKeyControlBlockRoot");
|
||
if (Root == NULL) {
|
||
(lpPrint)("Couldn't find address of CmpKeyControlBlockRoot\n");
|
||
return;
|
||
}
|
||
(lpReadMem)(Root,
|
||
&pKCB,
|
||
sizeof(pKCB),
|
||
&BytesRead);
|
||
|
||
if (BytesRead < sizeof(pKCB)) {
|
||
(lpPrint)("Couldn't get pKCB from CmpKeyControlBlockRoot\n");
|
||
}
|
||
|
||
TotalKcbs = 0;
|
||
TotalKcbName = 0;
|
||
kcbWorker(pKCB);
|
||
|
||
(lpPrint)("%d KCBs\n",TotalKcbs);
|
||
(lpPrint)("%d total bytes of FullNames\n",TotalKcbName);
|
||
|
||
}
|
||
|
||
VOID
|
||
kcbWorker(
|
||
IN PCM_KEY_CONTROL_BLOCK pKcb
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
recursive worker for walking the kcb tree.
|
||
|
||
Arguments:
|
||
|
||
pKcb - Supplies pointer to kcb.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
CM_KEY_CONTROL_BLOCK kcb;
|
||
ULONG BytesRead;
|
||
WCHAR *Buffer;
|
||
|
||
++TotalKcbs;
|
||
(lpReadMem)(pKcb,
|
||
&kcb,
|
||
sizeof(kcb),
|
||
&BytesRead);
|
||
if (BytesRead < sizeof(kcb)) {
|
||
(lpPrint)("Can't read kcb at %lx\n",pKcb);
|
||
return;
|
||
}
|
||
TotalKcbName += kcb.FullName.Length;
|
||
|
||
if (kcb.Left != NULL) {
|
||
kcbWorker(kcb.Left);
|
||
}
|
||
|
||
(lpPrint)("%d - ",kcb.RefCount);
|
||
|
||
Buffer = malloc(kcb.FullName.Length);
|
||
if (Buffer != NULL) {
|
||
(lpReadMem)(kcb.FullName.Buffer,
|
||
Buffer,
|
||
kcb.FullName.Length,
|
||
&BytesRead);
|
||
|
||
kcb.FullName.Length = BytesRead;
|
||
kcb.FullName.Buffer = Buffer;
|
||
|
||
(lpPrint)(" %wZ\n",&kcb.FullName);
|
||
free(Buffer);
|
||
|
||
} else {
|
||
(lpPrint)(" ??? \n");
|
||
}
|
||
|
||
if (kcb.Right != NULL) {
|
||
kcbWorker(kcb.Right);
|
||
}
|
||
|
||
|
||
}
|
||
|