|
|
/*++
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); }
}
|