windows-nt/Source/XPSP1/NT/base/ntos/config/cmkd/cmkd.c
2020-09-26 16:20:57 +08:00

2084 lines
55 KiB
C

/*++
Copyright (c) 1999 Microsoft Corporation
Module Name:
cmkd.c
Abstract:
Kernel debugger extensions useful for the registry
Starting point: regext.c (jvert)
Author:
Dragos C. Sambotin (dragoss) 5-May-1999
Environment:
Loaded as a kernel debugger extension
Revision History:
Dragos C. Sambotin (dragoss) 5-May-1999
created
Dragos C. Sambotin (dragoss) 06-March-2000
moved to cm directory; ported to new windbg format
--*/
#include "cmp.h"
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <ntos.h>
#include <zwapi.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <windef.h>
#include <windows.h>
#include <ntverp.h>
#include <imagehlp.h>
#include <memory.h>
#include <wdbgexts.h>
#include <stdlib.h>
#include <stdio.h>
EXT_API_VERSION ApiVersion = { 3, 5, EXT_API_VERSION_NUMBER, 0 };
WINDBG_EXTENSION_APIS ExtensionApis;
USHORT SavedMajorVersion;
USHORT SavedMinorVersion;
HIVE_LIST_ENTRY HiveList[8];
ULONG TotalPages;
ULONG TotalPresentPages;
ULONG TotalKcbs;
ULONG TotalKcbName;
BOOLEAN SavePages;
BOOLEAN RestorePages;
FILE *TempFile;
#define ExitIfCtrlC() if (CheckControlC()) return
#define BreakIfCtrlC() if (CheckControlC()) break
VOID
WinDbgExtensionDllInit(
PWINDBG_EXTENSION_APIS lpExtensionApis,
USHORT MajorVersion,
USHORT MinorVersion
)
{
ExtensionApis = *lpExtensionApis;
SavedMajorVersion = MajorVersion;
SavedMinorVersion = MinorVersion;
return;
}
DllInit(
HANDLE hModule,
DWORD dwReason,
DWORD dwReserved
)
{
UNREFERENCED_PARAMETER( hModule );
UNREFERENCED_PARAMETER( dwReserved );
switch (dwReason) {
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
case DLL_PROCESS_ATTACH:
break;
}
return TRUE;
}
DECLARE_API( version )
{
#if DBG
PCHAR DebuggerType = "Checked";
#else
PCHAR DebuggerType = "Free";
#endif
UNREFERENCED_PARAMETER( args );
UNREFERENCED_PARAMETER( dwProcessor );
UNREFERENCED_PARAMETER( dwCurrentPc );
UNREFERENCED_PARAMETER( hCurrentThread );
UNREFERENCED_PARAMETER( hCurrentProcess );
dprintf( "%s Extension dll for Build %d debugging %s kernel for Build %d\n",
DebuggerType,
VER_PRODUCTBUILD,
SavedMajorVersion == 0x0c ? "Checked" : "Free",
SavedMinorVersion
);
}
VOID
CheckVersion(
VOID
)
{
#if DBG
if ((SavedMajorVersion != 0x0c) || (SavedMinorVersion != VER_PRODUCTBUILD)) {
dprintf("\r\n*** Extension DLL(%d Checked) does not match target system(%d %s)\r\n\r\n",
VER_PRODUCTBUILD, SavedMinorVersion, (SavedMajorVersion==0x0f) ? "Free" : "Checked" );
}
#else
if ((SavedMajorVersion != 0x0f) || (SavedMinorVersion != VER_PRODUCTBUILD)) {
dprintf("\r\n*** Extension DLL(%d Free) does not match target system(%d %s)\r\n\r\n",
VER_PRODUCTBUILD, SavedMinorVersion, (SavedMajorVersion==0x0f) ? "Free" : "Checked" );
}
#endif
}
LPEXT_API_VERSION
ExtensionApiVersion(
VOID
)
{
return &ApiVersion;
}
USHORT
GetKcbName(
ULONG_PTR KcbAddr,
PWCHAR NameBuffer,
ULONG BufferSize
)
/*++
Routine Description:
Takes a kcb and dump its complete name.
Arguments:
KcbAddr - Address of key control block.
NameBuffer - The Name buffer to fill in the name.
BufferSize - Size of Buffer.
Return Value:
Size of Name String.
--*/
{
WCHAR Name[ 256 ];
CM_KEY_CONTROL_BLOCK TmpKcb;
ULONG_PTR TmpKcbAddr;
CM_NAME_CONTROL_BLOCK NameBlock;
ULONG_PTR NameBlockAddr;
DWORD BytesRead;
USHORT Length;
USHORT TotalLength;
USHORT size;
USHORT i;
USHORT BeginPosition;
WCHAR *w1, *w2;
WCHAR *BufferEnd;
UCHAR *u2;
//
// Calculate the total string length.
//
TotalLength = 0;
TmpKcbAddr = KcbAddr;
while (TmpKcbAddr) {
ExitIfCtrlC() 0;
if( !ReadMemory(TmpKcbAddr,
&TmpKcb,
sizeof(TmpKcb),
&BytesRead) ) {
dprintf("Could not read KCB: 1\n");
return (0);
}
NameBlockAddr = (ULONG_PTR) TmpKcb.NameBlock;
if(!ReadMemory(NameBlockAddr,
&NameBlock,
sizeof(NameBlock),
&BytesRead)) {
dprintf("Could not read NCB: 2\n");
return (0);
}
if (NameBlock.Compressed) {
Length = NameBlock.NameLength * sizeof(WCHAR);
} else {
Length = NameBlock.NameLength;
}
TotalLength += Length;
//
// Add the sapce for OBJ_NAME_PATH_SEPARATOR;
//
TotalLength += sizeof(WCHAR);
TmpKcbAddr = (ULONG_PTR) TmpKcb.ParentKcb;
}
BufferEnd = &(NameBuffer[BufferSize/sizeof(WCHAR) - 1]);
if (TotalLength < BufferSize) {
NameBuffer[TotalLength/sizeof(WCHAR)] = UNICODE_NULL;
} else {
*BufferEnd = UNICODE_NULL;
}
//
// Now fill the name into the buffer.
//
TmpKcbAddr = KcbAddr;
BeginPosition = TotalLength;
while (TmpKcbAddr) {
ExitIfCtrlC() 0;
//
// Read the information.
//
if(!ReadMemory(TmpKcbAddr,
&TmpKcb,
sizeof(TmpKcb),
&BytesRead) ) {
dprintf("Could not read KCB: 3\n");
return (0);
}
NameBlockAddr = (ULONG_PTR) TmpKcb.NameBlock;
if(!ReadMemory(NameBlockAddr,
&NameBlock,
sizeof(NameBlock),
&BytesRead) ) {
dprintf("Could not read NCB: 4\n");
return (0);
}
if(!ReadMemory(NameBlockAddr + FIELD_OFFSET(CM_NAME_CONTROL_BLOCK, Name),
Name,
NameBlock.NameLength,
&BytesRead) ) {
dprintf("Could not read Name BUFFER: 5\n");
return (0);
}
//
// Calculate the begin position of each subkey. Then fill in the char.
//
//
if (NameBlock.Compressed) {
BeginPosition -= (NameBlock.NameLength + 1) * sizeof(WCHAR);
w1 = &(NameBuffer[BeginPosition/sizeof(WCHAR)]);
if (w1 < BufferEnd) {
*w1 = OBJ_NAME_PATH_SEPARATOR;
}
w1++;
u2 = (UCHAR *) &(Name[0]);
for (i=0; i<NameBlock.NameLength; i++) {
if (w1 < BufferEnd) {
*w1 = (WCHAR)(*u2);
} else {
break;
}
w1++;
u2++;
}
} else {
BeginPosition -= (NameBlock.NameLength + sizeof(WCHAR));
w1 = &(NameBuffer[BeginPosition/sizeof(WCHAR)]);
if (w1 < BufferEnd) {
*w1 = OBJ_NAME_PATH_SEPARATOR;
}
w1++;
w2 = Name;
for (i=0; i<NameBlock.NameLength; i=i+sizeof(WCHAR)) {
if (w1 < BufferEnd) {
*w1 = *w2;
} else {
break;
}
w1++;
w2++;
}
}
TmpKcbAddr = (ULONG_PTR) TmpKcb.ParentKcb;
}
// dprintf("\n%5d, %ws\n", TotalLength, NameBuffer);
return (TotalLength);
}
DECLARE_API( childlist )
{
DWORD Count;
ULONG64 RecvAddr;
ULONG_PTR Addr;
DWORD BytesRead;
USHORT u;
CM_KEY_INDEX Index;
USHORT Signature; // also type selector
HCELL_INDEX Cell;
UCHAR NameHint[5];
sscanf(args,"%I64lX",&RecvAddr);
Addr = (ULONG_PTR)RecvAddr;
if(!ReadMemory(Addr,
&Index,
sizeof(Index),
&BytesRead) ) {
dprintf("\tCould not read index\n");
return;
} else {
Addr+= 2*sizeof(USHORT);
Signature = Index.Signature;
Count = Index.Count;
if(Count > 100) {
Count = 100;
}
if( Signature == CM_KEY_INDEX_ROOT ) {
dprintf("Index is a CM_KEY_INDEX_ROOT, %u elements\n",Count);
for( u=0;u<Count;u++) {
if( !ReadMemory(Addr,
&Cell,
sizeof(Cell),
&BytesRead) ) {
dprintf("\tCould not read Index[%u]\n",u);
} else {
dprintf(" Index[%u] = %lx\n",u,(ULONG)Cell);
}
Addr += sizeof(Cell);
}
} else if( Signature == CM_KEY_FAST_LEAF ) {
dprintf("Index is a CM_KEY_FAST_LEAF, %u elements\n",Count);
dprintf("Index[ ] %8s %s\n","Cell","Hint");
for( u=0;u<Count;u++) {
if( !ReadMemory(Addr,
&Cell,
sizeof(Cell),
&BytesRead) ) {
dprintf("\tCould not read Index[%u]\n",u);
} else {
dprintf(" Index[%2u] = %8lx",u,(ULONG)Cell);
Addr += sizeof(Cell);
if( !ReadMemory(Addr,
NameHint,
4*sizeof(UCHAR),
&BytesRead) ) {
dprintf("\tCould not read Index[%u]\n",u);
} else {
NameHint[4] = 0;
dprintf(" %s\n",NameHint);
}
}
Addr += 4*sizeof(UCHAR);
}
} else {
dprintf("Index is a CM_KEY_INDEX_LEAF, %u elements\n",Count);
dprintf("CM_KEY_INDEX_LEAF not yet implemented\n");
}
}
return;
}
DECLARE_API( kcb )
/*++
Routine Description:
Dumps the name when given a KCB address
Called as:
!regkcb KCB_Address
Arguments:
args - Supplies the address of the KCB.
Return Value:
.
--*/
{
WCHAR KeyName[ 256 ];
ULONG64 RecvAddr;
ULONG_PTR KcbAddr;
CM_KEY_CONTROL_BLOCK Kcb;
DWORD BytesRead;
CM_INDEX_HINT_BLOCK IndexHint;
sscanf(args,"%I64lX",&RecvAddr);
KcbAddr = (ULONG_PTR)RecvAddr;
if( !ReadMemory(KcbAddr,
&Kcb,
sizeof(Kcb),
&BytesRead) ) {
dprintf("Could not read Kcb\n");
return;
} else {
if(GetKcbName(KcbAddr, KeyName, sizeof(KeyName))) {
dprintf("Key : %ws\n", KeyName);
} else {
dprintf("Could not read key name\n");
return;
}
dprintf("RefCount : %lx\n", Kcb.RefCount);
dprintf("Attrib :");
if (Kcb.ExtFlags & CM_KCB_KEY_NON_EXIST) {
dprintf(" Fake,");
}
if (Kcb.Delete) {
dprintf(" Deleted,");
}
if (Kcb.Flags & KEY_SYM_LINK) {
dprintf(" Symbolic,");
}
if (Kcb.Flags & KEY_VOLATILE) {
dprintf(" Volatile");
} else {
dprintf(" Stable");
}
KcbAddr = (ULONG_PTR)Kcb.ParentKcb;
dprintf("\n");
dprintf("Parent : 0x%p\n", KcbAddr);
dprintf("KeyHive : 0x%p\n", Kcb.KeyHive);
dprintf("KeyCell : 0x%lx [cell index]\n", Kcb.KeyCell);
dprintf("TotalLevels : %u\n", Kcb.TotalLevels);
dprintf("DelayedCloseIndex: %u\n", Kcb.DelayedCloseIndex);
dprintf("MaxNameLen : 0x%lx\n", Kcb.KcbMaxNameLen);
dprintf("MaxValueNameLen : 0x%lx\n", Kcb.KcbMaxValueNameLen);
dprintf("MaxValueDataLen : 0x%lx\n", Kcb.KcbMaxValueDataLen);
dprintf("LastWriteTime : 0x%8lx:0x%8lx\n", Kcb.KcbLastWriteTime.HighPart,Kcb.KcbLastWriteTime.LowPart);
dprintf("KeyBodyListHead : 0x%p 0x%p\n", Kcb.KeyBodyListHead.Flink, Kcb.KeyBodyListHead.Blink);
dprintf("SubKeyCount : ");
if( !(Kcb.ExtFlags & CM_KCB_INVALID_CACHED_INFO) ) {
if (Kcb.ExtFlags & CM_KCB_NO_SUBKEY ) {
dprintf("0");
} else if (Kcb.ExtFlags & CM_KCB_SUBKEY_ONE ) {
dprintf("1");
} else if (Kcb.ExtFlags & CM_KCB_SUBKEY_HINT ) {
if( !ReadMemory((ULONG_PTR)Kcb.IndexHint,
&IndexHint,
sizeof(IndexHint),
&BytesRead) ) {
dprintf("Could not read Kcb\n");
return;
} else {
dprintf("%lu",IndexHint.Count);
}
} else {
dprintf("%lu",Kcb.SubKeyCount);
}
} else {
dprintf("hint not valid");
}
dprintf("\n");
}
return;
}
DECLARE_API( knode )
/*++
Routine Description:
Dumps the name when given a KCB address
Called as:
!knode KNode_Address
Arguments:
args - Supplies the address of the CM_KEY_NODE.
Return Value:
.
--*/
{
char KeyName[ 256 ];
ULONG64 RecvAddr;
ULONG_PTR KnAddr;
CM_KEY_NODE KNode;
DWORD BytesRead;
sscanf(args,"%I64lX",&RecvAddr);
KnAddr = (ULONG_PTR)RecvAddr;
if( !ReadMemory(KnAddr,
&KNode,
sizeof(KNode),
&BytesRead) ) {
dprintf("Could not read KeyNode\n");
return;
} else {
KnAddr += FIELD_OFFSET(CM_KEY_NODE, Name);
if( KNode.Signature == CM_KEY_NODE_SIGNATURE) {
dprintf("Signature: CM_KEY_NODE_SIGNATURE (kn)\n");
} else if(KNode.Signature == CM_LINK_NODE_SIGNATURE) {
dprintf("Signature: CM_LINK_NODE_SIGNATURE (kl)\n");
} else {
dprintf("Invalid Signature %u\n",KNode.Signature);
}
ReadMemory(KnAddr,
KeyName,
KNode.NameLength,
&BytesRead);
KeyName[KNode.NameLength] = '\0';
dprintf("Name : %s\n", KeyName);
dprintf("ParentCell : 0x%lx\n", KNode.Parent);
dprintf("Security : 0x%lx [cell index]\n", KNode.Security);
dprintf("Class : 0x%lx [cell index]\n", KNode.Class);
dprintf("Flags : 0x%lx\n", KNode.Flags);
dprintf("MaxNameLen : 0x%lx\n", KNode.MaxNameLen);
dprintf("MaxClassLen : 0x%lx\n", KNode.MaxClassLen);
dprintf("MaxValueNameLen : 0x%lx\n", KNode.MaxValueNameLen);
dprintf("MaxValueDataLen : 0x%lx\n", KNode.MaxValueDataLen);
dprintf("LastWriteTime : 0x%8lx:0x%8lx\n", KNode.LastWriteTime.HighPart,KNode.LastWriteTime.LowPart);
if(!(KNode.Flags&KEY_HIVE_ENTRY)) {
dprintf("SubKeyCount[Stable ]: 0x%lx\n", KNode.SubKeyCounts[Stable]);
dprintf("SubKeyLists[Stable ]: 0x%lx\n", KNode.SubKeyLists[Stable]);
dprintf("SubKeyCount[Volatile]: 0x%lx\n", KNode.SubKeyCounts[Volatile]);
dprintf("SubKeyLists[Volatile]: 0x%lx\n", KNode.SubKeyLists[Volatile]);
dprintf("ValueList.Count : 0x%lx\n", KNode.ValueList.Count);
dprintf("ValueList.List : 0x%lx\n", KNode.ValueList.List);
}
}
return;
}
//
// Cell Procedures
//
ULONG_PTR
MyHvpGetCellPaged(
PHHIVE Hive,
HCELL_INDEX Cell
)
/*++
Routine Description:
Returns the memory address for the specified Cell. Will never
return failure, but may assert. Use HvIsCellAllocated to check
validity of Cell.
This routine should never be called directly, always call it
via the HvGetCell() macro.
This routine provides GetCell support for hives with full maps.
It is the normal version of the routine.
Arguments:
Hive - supplies a pointer to the hive control structure for the
hive of interest
Cell - supplies HCELL_INDEX of cell to return address for
Return Value:
Address of Cell in memory. Assert or BugCheck if error.
--*/
{
ULONG Type;
ULONG Table;
ULONG Block;
ULONG Offset;
PHCELL pcell;
PHMAP_ENTRY Map;
HMAP_TABLE MapTable;
HMAP_DIRECTORY DirMap;
ULONG Tables;
ULONG_PTR lRez;
DWORD BytesRead;
ULONG_PTR BlockAddress;
HCELL hcell;
ASSERT(Hive->Signature == HHIVE_SIGNATURE);
ASSERT(Cell != HCELL_NIL);
ASSERT(Hive->Flat == FALSE);
ASSERT((Cell & (HCELL_PAD(Hive)-1))==0);
Type = HvGetCellType(Cell);
Table = (Cell & HCELL_TABLE_MASK) >> HCELL_TABLE_SHIFT;
Block = (Cell & HCELL_BLOCK_MASK) >> HCELL_BLOCK_SHIFT;
Offset = (Cell & HCELL_OFFSET_MASK);
ASSERT((Cell - (Type * HCELL_TYPE_MASK)) < Hive->Storage[Type].Length);
//
// read in map directory
//
ReadMemory((DWORD_PTR)Hive->Storage[Type].Map,
&DirMap,
sizeof(DirMap),
&BytesRead);
ReadMemory((DWORD_PTR)DirMap.Directory[Table],
&MapTable,
sizeof(MapTable),
&BytesRead);
Map = &(MapTable.Table[Block]);
BlockAddress = (ULONG_PTR)Map->BlockAddress;
pcell = (PHCELL)((ULONG_PTR)(BlockAddress) + Offset);
lRez = (ULONG_PTR)pcell;
if (USE_OLD_CELL(Hive)) {
return lRez + sizeof(LONG) + sizeof(ULONG);
//return (struct _CELL_DATA *)&(hcell.u.OldCell.u.UserData);
} else {
return lRez + sizeof(LONG);
//return (struct _CELL_DATA *)&(hcell.u.NewCell.u.UserData);
}
}
ULONG_PTR
MyHvpGetCellFlat(
PHHIVE Hive,
HCELL_INDEX Cell
)
/*++
Routine Description:
Returns the memory address for the specified Cell. Will never
return failure, but may assert. Use HvIsCellAllocated to check
validity of Cell.
This routine should never be called directly, always call it
via the HvGetCell() macro.
This routine provides GetCell support for read only hives with
single allocation flat images. Such hives do not have cell
maps ("page tables"), instead, we compute addresses by
arithmetic against the base image address.
Such hives cannot have volatile cells.
Arguments:
Hive - supplies a pointer to the hive control structure for the
hive of interest
Cell - supplies HCELL_INDEX of cell to return address for
Return Value:
Address of Cell in memory. Assert or BugCheck if error.
--*/
{
PUCHAR base;
PHCELL pcell;
HBASE_BLOCK BaseBlock;
ULONG_PTR lRez;
DWORD BytesRead;
ASSERT(Hive->Signature == HHIVE_SIGNATURE);
ASSERT(Cell != HCELL_NIL);
ASSERT(Hive->Flat == TRUE);
ASSERT(HvGetCellType(Cell) == Stable);
ASSERT(Cell >= sizeof(HBIN));
ReadMemory((DWORD_PTR)Hive->BaseBlock,
&BaseBlock,
sizeof(BaseBlock),
&BytesRead);
ASSERT(Cell < BaseBlock.Length);
ASSERT((Cell & 0x7)==0);
//
// Address is base of Hive image + Cell
//
base = (PUCHAR)(Hive->BaseBlock) + HBLOCK_SIZE;
pcell = (PHCELL)(base + Cell);
lRez = (ULONG_PTR)pcell;
if (USE_OLD_CELL(Hive)) {
return lRez + sizeof(LONG) + sizeof(ULONG);
//return (struct _CELL_DATA *)&(pcell->u.OldCell.u.UserData);
} else {
return lRez + sizeof(LONG);
//return (struct _CELL_DATA *)&(pcell->u.NewCell.u.UserData);
}
}
DECLARE_API( cellindex )
/*++
Routine Description:
Dumps the name when given a KCB address
Called as:
!cellindex HiveAddr HCELL_INDEX
Arguments:
args - Supplies the address of the HCELL_INDEX.
Return Value:
.
--*/
{
ULONG64 RecvAddr;
DWORD IdxAddr;
ULONG_PTR HiveAddr;
DWORD BytesRead;
HCELL_INDEX cell;
CMHIVE CmHive;
ULONG_PTR pcell;
sscanf(args,"%I64lX %lx",&RecvAddr,&IdxAddr);
HiveAddr = (ULONG_PTR)RecvAddr;
cell = IdxAddr;
if( !ReadMemory(HiveAddr,
&CmHive,
sizeof(CmHive),
&BytesRead) ) {
dprintf("\tRead %lx bytes from %lx\n",BytesRead,HiveAddr);
return;
}
if(CmHive.Hive.Flat) {
pcell = MyHvpGetCellFlat(&(CmHive.Hive),cell);
} else {
pcell = MyHvpGetCellPaged(&(CmHive.Hive),cell);
}
dprintf("pcell: %p\n",pcell);
}
DECLARE_API( kvalue )
/*++
Routine Description:
Dumps the name when given a KCB address
Called as:
!kvalue KValue_Address
Arguments:
args - Supplies the address of the CM_KEY_NODE.
Return Value:
.
--*/
{
char ValName[ 256 ];
ULONG64 RecvAddr;
ULONG_PTR ValAddr;
CM_KEY_VALUE KVal;
DWORD BytesRead;
sscanf(args,"%I64lX",&RecvAddr);
ValAddr = (ULONG_PTR)RecvAddr;
if( !ReadMemory(ValAddr,
&KVal,
sizeof(KVal),
&BytesRead) ) {
dprintf("Could not read KeyValue\n");
return;
} else {
ValAddr += FIELD_OFFSET(CM_KEY_VALUE, Name);
if( KVal.Signature == CM_KEY_VALUE_SIGNATURE) {
dprintf("Signature: CM_KEY_VALUE_SIGNATURE (kv)\n");
} else {
dprintf("Invalid Signature %lx\n",KVal.Signature);
}
if(KVal.Flags & VALUE_COMP_NAME) {
ReadMemory(ValAddr,
ValName,
KVal.NameLength,
&BytesRead);
ValName[KVal.NameLength] = '\0';
dprintf("Name : %s {compressed}\n", ValName);
}
dprintf("DataLength: %lx\n", KVal.DataLength);
dprintf("Data : %lx [cell index]\n", KVal.Data);
dprintf("Type : %lx\n", KVal.Type);
}
return;
}
DECLARE_API( kbody )
/*++
Routine Description:
displays a CM_KEY_BODY
Called as:
!kbody KBody_Address
Arguments:
args - Supplies the address of the CM_KEY_BODY.
Return Value:
.
--*/
{
ULONG64 RecvAddr;
ULONG_PTR KBodyAddr;
CM_KEY_BODY KBody;
DWORD BytesRead;
sscanf(args,"%I64lX",&RecvAddr);
KBodyAddr = (ULONG_PTR)RecvAddr;
if( !ReadMemory(KBodyAddr,
&KBody,
sizeof(KBody),
&BytesRead) ) {
dprintf("Could not read KeyBody\n");
return;
} else {
if( KBody.Type == KEY_BODY_TYPE) {
dprintf("Type : KEY_BODY_TYPE\n");
} else {
dprintf("Invalid Type %lx\n",KBody.Type);
}
dprintf("KCB : %p\n", KBody.KeyControlBlock);
dprintf("NotifyBlock : %p\n", KBody.NotifyBlock);
dprintf("Process : %p\n", KBody.Process);
dprintf("KeyBodyList : %p %p\n", KBody.KeyBodyList.Flink, KBody.KeyBodyList.Blink);
}
return;
}
DECLARE_API( hashindex )
/*++
Routine Description:
display the index for the convkey
Called as:
!hashindex conv_key
Arguments:
args - convkey.
Return Value:
.
--*/
{
ULONG ConvKey;
ULONG CmpHashTableSize = 2048;
ULONG_PTR Address;
ULONG_PTR CmpCacheTable,CmpNameCacheTable;
DWORD BytesRead;
sscanf(args,"%lx",&ConvKey);
dprintf("Hash Index[%8lx] : %lx\n",ConvKey,GET_HASH_INDEX(ConvKey));
Address = GetExpression("CmpCacheTable");
if( !ReadMemory(Address,
&CmpCacheTable,
sizeof(CmpCacheTable),
&BytesRead) ) {
dprintf("Could not read CmpCacheTable\n");
} else {
dprintf("CmpCacheTable : %p\n",CmpCacheTable);
}
Address = GetExpression("CmpNameCacheTable");
if( !ReadMemory(Address,
&CmpNameCacheTable,
sizeof(CmpNameCacheTable),
&BytesRead) ) {
dprintf("Could not read CmpNameCacheTable\n");
} else {
dprintf("CmpNameCacheTable : %p\n",CmpNameCacheTable);
}
return;
}
DECLARE_API( openkeys )
/*++
Routine Description:
dumps open subkeys for the specified hive
Called as:
!openkeys hive
if hive is 0, dump all KCBs
Arguments:
args - convkey.
Return Value:
.
--*/
{
ULONG CmpHashTableSize = 2048;
ULONG_PTR Address;
ULONG_PTR CmpCacheTable,CmpNameCacheTable;
DWORD BytesRead;
ULONG64 RecvAddr;
ULONG_PTR HiveAddr;
ULONG i;
ULONG_PTR Current;
ULONG KcbNumber = 0;
ULONG Offset = FIELD_OFFSET(CM_KEY_CONTROL_BLOCK, KeyHash);
CM_KEY_HASH KeyHash;
WCHAR KeyName[ 512 ];
sscanf(args,"%I64lX",&RecvAddr);
HiveAddr = (ULONG_PTR)RecvAddr;
Address = GetExpression("CmpCacheTable");
if( !ReadMemory(Address,
&CmpCacheTable,
sizeof(CmpCacheTable),
&BytesRead) ) {
dprintf("\nCould not read CmpCacheTable\n");
} else {
dprintf("\nCmpCacheTable : %p\n",CmpCacheTable);
}
Address = GetExpression("CmpNameCacheTable");
if( !ReadMemory(Address,
&CmpNameCacheTable,
sizeof(CmpNameCacheTable),
&BytesRead) ) {
dprintf("Could not read CmpNameCacheTable\n\n");
} else {
dprintf("CmpNameCacheTable : %p\n\n",CmpNameCacheTable);
}
dprintf("List of open KCBs:\n\n");
for (i=0; i<CmpHashTableSize; i++) {
Address = CmpCacheTable + i* sizeof(PCM_KEY_HASH);
ReadMemory(Address,
&Current,
sizeof(Current),
&BytesRead);
while (Current) {
ExitIfCtrlC();
ReadMemory(Current,
&KeyHash,
sizeof(KeyHash),
&BytesRead);
if( (HiveAddr == 0) || (HiveAddr == (ULONG_PTR)KeyHash.KeyHive) ) {
KcbNumber++;
dprintf("%p",Current-Offset);
if (BytesRead < sizeof(KeyHash)) {
dprintf("Could not read KeyHash at %p\n",Current);
break;
} else {
if(GetKcbName(Current-Offset, KeyName, sizeof(KeyName))) {
dprintf(" : %ws\n", KeyName);
} else {
dprintf("Could not read key name\n");
}
}
}
Current = (ULONG_PTR)KeyHash.NextHash;
}
}
dprintf("\nTotal of %lu KCBs opened\n",KcbNumber);
return;
}
DECLARE_API( baseblock )
/*++
Routine Description:
displays the base block structure
Called as:
!baseblock address
Arguments:
args - convkey.
Return Value:
.
--*/
{
HBASE_BLOCK BaseBlock;
ULONG_PTR BaseAddr;
DWORD BytesRead;
PWCHAR FileName;
ULONG64 RecvAddr;
sscanf(args,"%I64lX",&RecvAddr);
BaseAddr = (ULONG_PTR)RecvAddr;
if( !ReadMemory(BaseAddr,
&BaseBlock,
sizeof(BaseBlock),
&BytesRead) ) {
dprintf("\tRead %lx bytes from %p\n",BytesRead,BaseAddr);
return;
}
if( BaseBlock.Signature == HBASE_BLOCK_SIGNATURE ) {
dprintf("Signature: HBASE_BLOCK_SIGNATURE\n");
} else {
dprintf("Signature: %lx\n",BaseBlock.Signature);
}
FileName = (PWCHAR)&(BaseBlock.FileName);
FileName[HBASE_NAME_ALLOC/sizeof(WCHAR)] = 0;
dprintf("FileName : %ws\n",FileName);
dprintf("Sequence1: %lx\n",BaseBlock.Sequence1);
dprintf("Sequence2: %lx\n",BaseBlock.Sequence2);
dprintf("TimeStamp: %lx %lx\n",BaseBlock.TimeStamp.HighPart,BaseBlock.TimeStamp.LowPart);
dprintf("Major : %lx\n",BaseBlock.Major);
dprintf("Minor : %lx\n",BaseBlock.Minor);
switch(BaseBlock.Type) {
case HFILE_TYPE_PRIMARY:
dprintf("Type : HFILE_TYPE_PRIMARY\n");
break;
case HFILE_TYPE_LOG:
dprintf("Type : HFILE_TYPE_LOG\n");
break;
case HFILE_TYPE_EXTERNAL:
dprintf("Type : HFILE_TYPE_EXTERNAL\n");
break;
default:
dprintf("Type : %lx\n",BaseBlock.Type);
break;
}
if( BaseBlock.Format == HBASE_FORMAT_MEMORY ) {
dprintf("Format : HBASE_FORMAT_MEMORY\n");
} else {
dprintf("Format : %lx\n",BaseBlock.Format);
}
dprintf("RootCell : %lx\n",BaseBlock.RootCell);
dprintf("Length : %lx\n",BaseBlock.Length);
dprintf("Cluster : %lx\n",BaseBlock.Cluster);
dprintf("CheckSum : %lx\n",BaseBlock.CheckSum);
}
DECLARE_API( findkcb )
/*++
Routine Description:
finds a kcb given the full path
Called as:
!findkcb \REGISTRY\MACHINE\foo
Arguments:
args - convkey.
Return Value:
.
--*/
{
ULONG CmpHashTableSize = 2048;
ULONG_PTR Address;
ULONG_PTR CmpCacheTable,CmpNameCacheTable;
DWORD BytesRead;
ULONG i,j,Count;
ULONG_PTR Current;
ULONG Offset = FIELD_OFFSET(CM_KEY_CONTROL_BLOCK, KeyHash);
CM_KEY_HASH KeyHash;
WCHAR KeyName[ 512 ];
UCHAR AnsiFullKeyName[ 512 ];
WCHAR FullKeyName[ 512 ];
PWCHAR Dest;
ULONG ConvKey = 0;
sscanf(args,"%s",AnsiFullKeyName);
for( Count=0;AnsiFullKeyName[Count];Count++) {
FullKeyName[Count] = (WCHAR)AnsiFullKeyName[Count];
if( FullKeyName[Count] != OBJ_NAME_PATH_SEPARATOR ) {
ConvKey = 37 * ConvKey + (ULONG) RtlUpcaseUnicodeChar(FullKeyName[Count]);
}
}
FullKeyName[Count] = UNICODE_NULL;
//dprintf("\nFullKeyName :%ws %\n",FullKeyName);
Address = GetExpression("CmpCacheTable");
if( !ReadMemory(Address,
&CmpCacheTable,
sizeof(CmpCacheTable),
&BytesRead) ) {
dprintf("\nCould not read CmpCacheTable\n");
return;
}
Address = GetExpression("CmpNameCacheTable");
if( !ReadMemory(Address,
&CmpNameCacheTable,
sizeof(CmpNameCacheTable),
&BytesRead) ) {
dprintf("Could not read CmpNameCacheTable\n\n");
return;
}
i = GET_HASH_INDEX(ConvKey);
//for (i=0; i<CmpHashTableSize; i++) {
Address = CmpCacheTable + i* sizeof(PCM_KEY_HASH);
ReadMemory(Address,
&Current,
sizeof(Current),
&BytesRead);
while (Current) {
ExitIfCtrlC();
if( !ReadMemory(Current,
&KeyHash,
sizeof(KeyHash),
&BytesRead) ) {
dprintf("Could not read KeyHash at %lx\n",Current);
break;
} else {
if(GetKcbName(Current-Offset, KeyName, sizeof(KeyName))) {
for(j=0;KeyName[j] != UNICODE_NULL;j++);
if( (j == Count) && (_wcsnicmp(FullKeyName,KeyName,Count) == 0) ) {
dprintf("\nFound KCB = %lx :: %ws\n\n",Current-Offset,KeyName);
return;
}
dprintf("Along the path - KCB = %lx :: %ws\n",Current-Offset,KeyName);
} else {
continue;
}
}
Current = (ULONG_PTR)KeyHash.NextHash;
}
//}
dprintf("\nSorry %ws is not cached \n\n",FullKeyName);
return;
}
DECLARE_API( seccache )
/*++
Routine Description:
displays the base block structure
Called as:
!seccache <HiveAddr>
Arguments:
args - convkey.
Return Value:
.
--*/
{
CMHIVE CmHive;
ULONG64 RecvAddr;
ULONG_PTR HiveAddr;
DWORD BytesRead;
PWCHAR FileName;
CM_KEY_SECURITY_CACHE_ENTRY SecurityCacheEntry;
ULONG i;
ULONG Tmp;
sscanf(args,"%I64lX",&RecvAddr);
HiveAddr = (ULONG_PTR)RecvAddr;
if( !ReadMemory(HiveAddr,
&CmHive,
sizeof(CmHive),
&BytesRead) ) {
dprintf("\tRead %lx bytes from %p\n",BytesRead,HiveAddr);
return;
}
if( CmHive.Hive.Signature != HHIVE_SIGNATURE ) {
dprintf("Invalid Hive signature: %lx\n",CmHive.Hive.Signature);
return;
}
Tmp = CmHive.SecurityCacheSize;
dprintf("SecurityCacheSize = : 0x%lx\n",Tmp);
Tmp = CmHive.SecurityCount;
dprintf("SecurityCount = : 0x%lx\n",Tmp);
Tmp = CmHive.SecurityHitHint;
dprintf("SecurityHitHint = : 0x%lx\n",Tmp);
HiveAddr = (ULONG_PTR)CmHive.SecurityCache;
dprintf("SecurityCache = : 0x%p\n\n",HiveAddr);
dprintf("[Entry No.] [Security Cell] [Security Cache]\n",CmHive.SecurityHitHint);
for( i=0;i<CmHive.SecurityCount;i++) {
ExitIfCtrlC();
if( !ReadMemory(HiveAddr,
&SecurityCacheEntry,
sizeof(SecurityCacheEntry),
&BytesRead) ) {
dprintf("\tCould not read entry %lu \n",i);
continue;
}
dprintf("%[%8lu] 0x%8lx 0x%p\n",i,SecurityCacheEntry.Cell,SecurityCacheEntry.CachedSecurity);
HiveAddr += sizeof(SecurityCacheEntry);
}
}
DECLARE_API( viewlist )
/*++
Routine Description:
dumps all the views mapped/pinned for the specified hive
Called as:
!viewlist <HiveAddr>
Arguments:
args - hive.
Return Value:
.
--*/
{
CMHIVE CmHive;
CM_VIEW_OF_FILE CmView;
ULONG_PTR HiveAddr;
DWORD BytesRead;
USHORT Nr;
ULONG Offset;
ULONG_PTR ViewAddr;
ULONG_PTR Tmp;
ULONG64 RecvAddr;
sscanf(args,"%I64lX",&RecvAddr);
HiveAddr = (ULONG_PTR)RecvAddr;
if( !ReadMemory(HiveAddr,
&CmHive,
sizeof(CmHive),
&BytesRead) ) {
dprintf("\tRead %lx bytes from %p\n",BytesRead,HiveAddr);
return;
}
if( CmHive.Hive.Signature != HHIVE_SIGNATURE ) {
dprintf("Invalid Hive signature: %lx\n",CmHive.Hive.Signature);
return;
}
Nr = CmHive.PinnedViews;
dprintf("%4u Pinned Views ; PinViewListHead = %p %p\n",Nr,(ULONG_PTR)CmHive.PinViewListHead.Flink,(ULONG_PTR)CmHive.PinViewListHead.Blink);
if( Nr ) {
dprintf("--------------------------------------------------------------------------------------------------------------\n");
dprintf("| ViewAddr |FileOffset| Size |ViewAddress| Bcb | LRUViewList | PinViewList | UseCount |\n");
dprintf("--------------------------------------------------------------------------------------------------------------\n");
ViewAddr = (ULONG_PTR)CmHive.PinViewListHead.Flink;
Offset = FIELD_OFFSET(CM_VIEW_OF_FILE, PinViewList);
for(;Nr;Nr--) {
ViewAddr -= Offset;
if( !ReadMemory(ViewAddr,
&CmView,
sizeof(CmView),
&BytesRead) ) {
dprintf("error reading view at %lx\n",ViewAddr);
break;
}
Tmp = ViewAddr;
dprintf("| %p ",Tmp);
dprintf("| %8lx ",CmView.FileOffset);
dprintf("| %8lx ",CmView.Size);
Tmp = (ULONG_PTR)CmView.ViewAddress;
dprintf("| %p ",Tmp);
Tmp = (ULONG_PTR)CmView.Bcb;
dprintf("| %p ",Tmp);
Tmp = (ULONG_PTR)CmView.LRUViewList.Flink;
dprintf("| %p",Tmp);
Tmp = (ULONG_PTR)CmView.LRUViewList.Blink;
dprintf(" %p ",Tmp);
Tmp = (ULONG_PTR)CmView.PinViewList.Flink;
dprintf("| %p",Tmp);
Tmp = (ULONG_PTR)CmView.PinViewList.Blink;
dprintf(" %p |",Tmp);
dprintf(" %8lx |\n",CmView.UseCount);
ViewAddr = (ULONG_PTR)CmView.PinViewList.Flink;
}
dprintf("--------------------------------------------------------------------------------------------------------------\n");
}
dprintf("\n");
Nr = CmHive.MappedViews;
dprintf("%4u Mapped Views ; LRUViewListHead = %p %p\n",Nr,(ULONG_PTR)CmHive.LRUViewListHead.Flink,(ULONG_PTR)CmHive.LRUViewListHead.Blink);
if( Nr ) {
dprintf("--------------------------------------------------------------------------------------------------------------\n");
dprintf("| ViewAddr |FileOffset| Size |ViewAddress| Bcb | LRUViewList | PinViewList | UseCount |\n");
dprintf("--------------------------------------------------------------------------------------------------------------\n");
ViewAddr = (ULONG_PTR)CmHive.LRUViewListHead.Flink;
Offset = FIELD_OFFSET(CM_VIEW_OF_FILE, LRUViewList);
for(;Nr;Nr--) {
ViewAddr -= Offset;
if( !ReadMemory(ViewAddr,
&CmView,
sizeof(CmView),
&BytesRead) ) {
dprintf("error reading view at %lx\n",ViewAddr);
break;
}
Tmp = ViewAddr;
dprintf("| %p ",Tmp);
dprintf("| %8lx ",CmView.FileOffset);
dprintf("| %8lx ",CmView.Size);
Tmp = (ULONG_PTR)CmView.ViewAddress;
dprintf("| %p ",Tmp);
Tmp = (ULONG_PTR)CmView.Bcb;
dprintf("| %p ",Tmp);
Tmp = (ULONG_PTR)CmView.LRUViewList.Flink;
dprintf("| %p",Tmp);
Tmp = (ULONG_PTR)CmView.LRUViewList.Blink;
dprintf(" %p ",Tmp);
Tmp = (ULONG_PTR)CmView.PinViewList.Flink;
dprintf("| %p",Tmp);
Tmp = (ULONG_PTR)CmView.PinViewList.Blink;
dprintf(" %8lx |",Tmp);
dprintf(" %8lx |\n",CmView.UseCount);
ViewAddr = (ULONG_PTR)CmView.LRUViewList.Flink;
}
dprintf("--------------------------------------------------------------------------------------------------------------\n");
}
dprintf("\n");
}
DECLARE_API( hivelist )
/*++
Routine Description:
dumps all the hives in the system
Called as:
!hivelist
Arguments:
Return Value:
.
--*/
{
CMHIVE CmHive;
ULONG_PTR HiveAddr;
ULONG_PTR AnchorAddr;
DWORD BytesRead;
ULONG Offset;
ULONG_PTR Tmp;
LIST_ENTRY CmpHiveListHead;
HBASE_BLOCK BaseBlock;
PWCHAR FileName;
AnchorAddr = GetExpression("CmpHiveListHead");
if( !ReadMemory(AnchorAddr,
&CmpHiveListHead,
sizeof(CmpHiveListHead),
&BytesRead)) {
dprintf("\ncannot read CmpHiveListHead\n");
return;
}
Offset = FIELD_OFFSET(CMHIVE, HiveList);
HiveAddr = (ULONG_PTR)CmpHiveListHead.Flink;
dprintf("-------------------------------------------------------------------------------------------------------------\n");
dprintf("| HiveAddr |Stable Length|Stable Map|Volatile Length|Volatile Map|MappedViews|PinnedViews|U(Cnt)| BaseBlock | FileName \n");
dprintf("-------------------------------------------------------------------------------------------------------------\n");
while( HiveAddr != AnchorAddr ) {
ExitIfCtrlC();
HiveAddr -= Offset;
if( !ReadMemory(HiveAddr,
&CmHive,
sizeof(CmHive),
&BytesRead) ) {
dprintf("cannot read hive at %lx\n",HiveAddr);
return;
}
if( CmHive.Hive.Signature != HHIVE_SIGNATURE ) {
dprintf("Invalid Hive signature: %lx\n",CmHive.Hive.Signature);
return;
}
Tmp = HiveAddr;
dprintf("| %p ",Tmp);
dprintf("| %8lx ",CmHive.Hive.Storage[0].Length);
Tmp = (ULONG_PTR)CmHive.Hive.Storage[0].Map;
dprintf("| %p ",Tmp);
dprintf("| %8lx ",CmHive.Hive.Storage[1].Length);
Tmp = (ULONG_PTR)CmHive.Hive.Storage[1].Map;
dprintf("| %p ",Tmp);
dprintf("| %8u ",CmHive.MappedViews);
dprintf("| %8u ",CmHive.PinnedViews);
dprintf("| %5u",CmHive.UseCount);
Tmp = (ULONG_PTR)CmHive.Hive.BaseBlock;
dprintf("| %p |",Tmp);
if( !ReadMemory(Tmp,
&BaseBlock,
sizeof(BaseBlock),
&BytesRead) ) {
dprintf(" could not read baseblock\n");
} else {
FileName = (PWCHAR)&(BaseBlock.FileName);
FileName[HBASE_NAME_ALLOC/sizeof(WCHAR)] = 0;
dprintf(" %ws\n",FileName);
}
HiveAddr = (ULONG_PTR)CmHive.HiveList.Flink;
}
dprintf("-------------------------------------------------------------------------------------------------------------\n");
dprintf("\n");
}
DECLARE_API( freebins )
/*++
Routine Description:
dumps all the free bins for the specified hive
Called as:
!freebins <HiveAddr>
Arguments:
args - hive.
Return Value:
.
--*/
{
HHIVE Hive;
ULONG_PTR HiveAddr;
DWORD BytesRead;
ULONG Offset;
ULONG_PTR BinAddr;
ULONG_PTR AnchorAddr;
ULONG_PTR Tmp;
USHORT Nr = 0;
FREE_HBIN FreeBin;
ULONG64 RecvAddr;
sscanf(args,"%I64lX",&RecvAddr);
HiveAddr = (ULONG_PTR)RecvAddr;
if( !ReadMemory(HiveAddr,
&Hive,
sizeof(Hive),
&BytesRead) ) {
dprintf("\tRead %lx bytes from %p\n",BytesRead,HiveAddr);
return;
}
if( Hive.Signature != HHIVE_SIGNATURE ) {
dprintf("Invalid Hive signature: %lx\n",Hive.Signature);
return;
}
Offset = FIELD_OFFSET(FREE_HBIN, ListEntry);
dprintf("Stable Storage ... \n");
dprintf("-------------------------------------------------------------------\n");
dprintf("| Address |FileOffset| Size | Flags | Flink | Blink |\n");
dprintf("-------------------------------------------------------------------\n");
Nr = 0;
AnchorAddr = HiveAddr + FIELD_OFFSET(HHIVE,Storage) + 5*sizeof(ULONG) + HHIVE_FREE_DISPLAY_SIZE*sizeof(RTL_BITMAP);
BinAddr = (ULONG_PTR)Hive.Storage[0].FreeBins.Flink;
while(BinAddr != AnchorAddr ) {
ExitIfCtrlC();
BinAddr -= Offset;
if( !ReadMemory(BinAddr,
&FreeBin,
sizeof(FreeBin),
&BytesRead)) {
dprintf("error reading FreeBin at %lx\n",BinAddr);
break;
}
Tmp = BinAddr;
dprintf("| %p ",Tmp);
dprintf("| %8lx ",FreeBin.FileOffset);
dprintf("| %8lx ",FreeBin.Size);
dprintf("| %8lx ",FreeBin.Flags);
Tmp = (ULONG_PTR)FreeBin.ListEntry.Flink;
dprintf("| %p ",Tmp);
Tmp = (ULONG_PTR)FreeBin.ListEntry.Blink;
dprintf("| %p |\n",Tmp);
BinAddr = (ULONG_PTR)FreeBin.ListEntry.Flink;
Nr++;
}
dprintf("-------------------------------------------------------------------\n");
dprintf("%4u FreeBins\n",Nr);
dprintf("\n");
dprintf("Volatile Storage ... \n");
dprintf("-------------------------------------------------------------------\n");
dprintf("| Address |FileOffset| Size | Flags | Flink | Blink |\n");
dprintf("-------------------------------------------------------------------\n");
Nr = 0;
AnchorAddr += (7*sizeof(ULONG) + HHIVE_FREE_DISPLAY_SIZE*sizeof(RTL_BITMAP));
BinAddr = (ULONG_PTR)Hive.Storage[1].FreeBins.Flink;
while(BinAddr != AnchorAddr ) {
ExitIfCtrlC();
BinAddr -= Offset;
if( !ReadMemory(BinAddr,
&FreeBin,
sizeof(FreeBin),
&BytesRead) ) {
dprintf("error reading FreeBin at %lx\n",BinAddr);
break;
}
Tmp = BinAddr;
dprintf("| %p ",Tmp);
dprintf("| %8lx ",FreeBin.FileOffset);
dprintf("| %8lx ",FreeBin.Size);
dprintf("| %8lx ",FreeBin.Flags);
Tmp = (ULONG_PTR)FreeBin.ListEntry.Flink;
dprintf("| %p ",Tmp);
Tmp = (ULONG_PTR)FreeBin.ListEntry.Blink;
dprintf("| %p |\n",Tmp);
BinAddr = (ULONG_PTR)FreeBin.ListEntry.Flink;
Nr++;
}
dprintf("-------------------------------------------------------------------\n");
dprintf("%4u FreeBins\n",Nr);
dprintf("\n");
}
DECLARE_API( dirtyvector )
/*++
Routine Description:
displays the dirty vector of the hive
Called as:
!dirtyvector <HiveAddr>
Arguments:
args - convkey.
Return Value:
.
--*/
{
HHIVE Hive;
ULONG_PTR HiveAddr;
DWORD BytesRead;
ULONG i;
ULONG_PTR Tmp;
ULONG SizeOfBitmap;
ULONG DirtyBuffer;
ULONG_PTR DirtyBufferAddr;
ULONG Mask;
ULONG BitsPerULONG;
ULONG BitsPerBlock;
ULONG64 RecvAddr;
sscanf(args,"%I64lX",&RecvAddr);
HiveAddr = (ULONG_PTR)RecvAddr;
if( !ReadMemory(HiveAddr,
&Hive,
sizeof(Hive),
&BytesRead)) {
dprintf("\tRead %lx bytes from %lx\n",BytesRead,HiveAddr);
return;
}
if( Hive.Signature != HHIVE_SIGNATURE ) {
dprintf("Invalid Hive signature: %lx\n",Hive.Signature);
return;
}
dprintf("HSECTOR_SIZE = %lx\n",HSECTOR_SIZE);
dprintf("HBLOCK_SIZE = %lx\n",HBLOCK_SIZE);
dprintf("PAGE_SIZE = %lx\n",PAGE_SIZE);
dprintf("\n");
dprintf("DirtyAlloc = : 0x%lx\n",Hive.DirtyAlloc);
dprintf("DirtyCount = : 0x%lx\n",Hive.DirtyCount);
Tmp = (ULONG_PTR)Hive.DirtyVector.Buffer;
dprintf("Buffer = : 0x%p\n",Tmp);
dprintf("\n");
SizeOfBitmap = Hive.DirtyVector.SizeOfBitMap;
DirtyBufferAddr = (ULONG_PTR)Hive.DirtyVector.Buffer;
BitsPerULONG = 8*sizeof(ULONG);
BitsPerBlock = HBLOCK_SIZE / HSECTOR_SIZE;
dprintf(" Address 32k 32k");
for(i=0;i<SizeOfBitmap;i++) {
ExitIfCtrlC();
if( !(i%(2*BitsPerULONG ) ) ){
dprintf("\n 0x%8lx ",i*HSECTOR_SIZE);
}
if( !(i%BitsPerBlock) ) {
dprintf(" ");
}
if( !(i%BitsPerULONG) ) {
//
// fetch in a new DWORD
//
if( !ReadMemory(DirtyBufferAddr,
&DirtyBuffer,
sizeof(DirtyBuffer),
&BytesRead)) {
dprintf("\tRead %lx bytes from %lx\n",BytesRead,DirtyBufferAddr);
return;
}
DirtyBufferAddr += sizeof(ULONG);
dprintf("\t");
}
Mask = ((DirtyBuffer >> (i%BitsPerULONG)) & 0x1);
//Mask <<= (BitsPerULONG - (i%BitsPerULONG) - 1);
//Mask &= DirtyBuffer;
dprintf("%s",Mask?"1":"0");
}
dprintf("\n\n");
}
CCHAR CmKDFindFirstSetLeft[256] = {
0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7};
#define CmKDComputeIndex(Index, Size) \
{ \
Index = (Size >> HHIVE_FREE_DISPLAY_SHIFT) - 1; \
if (Index >= HHIVE_LINEAR_INDEX ) { \
\
/* \
** Too big for the linear lists, compute the exponential \
** list. \
*/ \
\
if (Index > 255) { \
/* \
** Too big for all the lists, use the last index. \
*/ \
Index = HHIVE_FREE_DISPLAY_SIZE-1; \
} else { \
Index = CmKDFindFirstSetLeft[Index] + \
HHIVE_FREE_DISPLAY_BIAS; \
} \
} \
}
DECLARE_API( freecells )
/*++
Routine Description:
displays the free cells map in a bin
Called as:
!freecells <BinAddr>
Arguments:
args - convkey.
Return Value:
.
--*/
{
ULONG_PTR BinAddr;
ULONG Offset;
ULONG_PTR CurrentAddr;
LONG Current;
HBIN Bin;
ULONG Index;
ULONG CurrIndex;
DWORD BytesRead;
ULONG NrOfCellsPerIndex;
ULONG NrOfCellsTotal;
ULONG TotalFreeSize;
ULONG64 RecvAddr;
sscanf(args,"%I64lX",&RecvAddr);
BinAddr = (ULONG_PTR)RecvAddr;
if( !ReadMemory(BinAddr,
&Bin,
sizeof(Bin),
&BytesRead)) {
dprintf("\tRead %lx bytes from %lx\n",BytesRead,BinAddr);
return;
}
if( Bin.Signature != HBIN_SIGNATURE ) {
dprintf("\tInvalid Bin signature %lx \n",Bin.Signature);
return;
}
dprintf("Bin Offset = 0x%lx Size = 0x%lx\n",Bin.FileOffset,Bin.Size);
NrOfCellsTotal = 0;
TotalFreeSize = 0;
for(CurrIndex = 0;CurrIndex<HHIVE_FREE_DISPLAY_SIZE;CurrIndex++) {
dprintf("\n FreeDisplay[%2lu] :: ",CurrIndex);
NrOfCellsPerIndex = 0;
Offset = sizeof(Bin);
while( Offset < Bin.Size ) {
ExitIfCtrlC();
CurrentAddr = BinAddr + Offset;
if( !ReadMemory(CurrentAddr,
&Current,
sizeof(Current),
&BytesRead) ) {
dprintf("\tRead %lx bytes from %lx\n",BytesRead,CurrentAddr);
return;
}
if(Current>0) {
//
// free cell
//
CmKDComputeIndex(Index, Current);
if( Index == CurrIndex ) {
//
// dum it here as this is the right index
//
NrOfCellsTotal++;
NrOfCellsPerIndex++;
TotalFreeSize += Current;
dprintf(" %lx [%lx]",Offset,Current);
if( !(NrOfCellsPerIndex % 8) && ((Offset + Current) < Bin.Size) ) {
dprintf("\n");
}
}
} else {
Current *= -1;
}
Offset += Current;
}
}
dprintf("\nTotal: FreeCells = %lu, FreeSpace = 0x%lx BinUsage = %.2f%%\n",NrOfCellsTotal,TotalFreeSize,
(float)(((float)(Bin.Size-sizeof(Bin)-TotalFreeSize)/(float)(Bin.Size-sizeof(Bin)))*100.00)
);
}
DECLARE_API( freehints )
/*++
Routine Description:
displays the freehints information for the hive
Called as:
!freehints <HiveAddr>
Arguments:
args - convkey.
Return Value:
.
--*/
{
HHIVE Hive;
ULONG_PTR HiveAddr;
DWORD BytesRead;
ULONG i;
ULONG DisplayCount;
ULONG StorageCount;
ULONG SizeOfBitmap;
ULONG DirtyBuffer;
ULONG_PTR DirtyBufferAddr;
ULONG Mask;
ULONG BitsPerULONG;
ULONG BitsPerBlock;
ULONG BitsPerLine;
ULONG64 RecvAddr;
sscanf(args,"%I64lX %lu %lu",&RecvAddr,&StorageCount,&DisplayCount);
HiveAddr = (ULONG_PTR)RecvAddr;
if( !ReadMemory(HiveAddr,
&Hive,
sizeof(Hive),
&BytesRead) ) {
dprintf("\tRead %lx bytes from %lx\n",BytesRead,HiveAddr);
return;
}
if( Hive.Signature != HHIVE_SIGNATURE ) {
dprintf("Invalid Hive signature: %lx\n",Hive.Signature);
return;
}
dprintf("HSECTOR_SIZE = %lx\n",HSECTOR_SIZE);
dprintf("HBLOCK_SIZE = %lx\n",HBLOCK_SIZE);
dprintf("PAGE_SIZE = %lx\n",PAGE_SIZE);
dprintf("\n");
BitsPerULONG = 8*sizeof(ULONG);
BitsPerBlock = 0x10000 / HBLOCK_SIZE; // 64k blocks
BitsPerLine = 0x40000 / HBLOCK_SIZE; // 256k lines (vicinity reasons)
SizeOfBitmap = Hive.Storage[StorageCount].Length / HBLOCK_SIZE;
DirtyBufferAddr = (ULONG_PTR)Hive.Storage[StorageCount].FreeDisplay[DisplayCount].Buffer;
dprintf("Storage = %s , FreeDisplay[%lu]: \n",StorageCount?"Volatile":"Stable",DisplayCount);
dprintf("\n%8s %16s %16s %16s %16s","Address","64K (0x10000)","64K (0x10000)","64K (0x10000)","64K (0x10000)");
for(i=0;i<SizeOfBitmap;i++) {
ExitIfCtrlC();
if( !(i%BitsPerLine) ){
dprintf("\n 0x%8lx ",i*HBLOCK_SIZE);
}
if( !(i%BitsPerBlock) ) {
dprintf(" ");
}
if( !(i%BitsPerULONG) ) {
//
// fetch in a new DWORD
//
if( !ReadMemory(DirtyBufferAddr,
&DirtyBuffer,
sizeof(DirtyBuffer),
&BytesRead) ) {
dprintf("\tRead %lx bytes from %lx\n",BytesRead,DirtyBufferAddr);
return;
}
DirtyBufferAddr += sizeof(ULONG);
}
Mask = ((DirtyBuffer >> (i%BitsPerULONG)) & 0x1);
//Mask <<= (BitsPerULONG - (i%BitsPerULONG) - 1);
//Mask &= DirtyBuffer;
dprintf("%s",Mask?"1":"0");
}
dprintf("\n\n");
}
DECLARE_API( help )
/*++
Routine Description:
Called as:
!help
Arguments:
Return Value:
.
--*/
{
dprintf("\nkcb\t\t<kcb_address>\n"); //OK, moved to kdexts
dprintf("knode\t\t<knode_address>\n");//OK, moved to kdexts
dprintf("kbody\t\t<kbody_address>\n");//OK, moved to kdexts
dprintf("kvalue\t\t<kvalue_address>\n");//OK, moved to kdexts
dprintf("cellindex\t<HiveAddr> <HCELL_INDEX>\n"); //OK, moved to kdexts
dprintf("childlist\t<address>\n");// not worth moving, never used it
dprintf("hashindex\t<ConvKey>\n");//OK, moved to kdexts
dprintf("openkeys\t<HiveAddr|0>\n");//OK, moved to kdexts
dprintf("baseblock\t<BaseBlockAddr>\n");//OK, moved to kdexts
dprintf("findkcb\t\t<FullKeyPath>\n");//OK, moved to kdexts
dprintf("seccache\t<HiveAddr>\n");//OK, moved to kdexts
dprintf("viewlist\t<HiveAddr>\n");//OK, moved to kdexts
dprintf("hivelist\n");//OK, moved to kdexts
dprintf("freebins\t<HiveAddr>\n");//OK, moved to kdexts
dprintf("dirtyvector\t<HiveAddr>\n");//OK, moved to kdexts
dprintf("freecells\t<BinAddr>\n");//OK, moved to kdexts
dprintf("freehints\t<HiveAddr> <Storage> <Display>\n");//OK, moved to kdexts
dprintf("help\t\tThis screen\n\n");
return;
}