415 lines
11 KiB
C
415 lines
11 KiB
C
/*++
|
|
|
|
Copyright (c) 1998 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
regmain.c
|
|
|
|
Abstract:
|
|
|
|
Main module. Data definitions.
|
|
|
|
Author:
|
|
|
|
Dragos C. Sambotin (dragoss) 30-Dec-1998
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "chkreg.h"
|
|
|
|
// check the hive structure.
|
|
BOOLEAN CheckHive = TRUE;
|
|
|
|
// compact the hive.
|
|
BOOLEAN CompactHive = FALSE;
|
|
|
|
// check for lost space (marked as used but not reffered).
|
|
BOOLEAN LostSpace = FALSE;
|
|
|
|
// repair damaged hives.
|
|
BOOLEAN FixHive = FALSE;
|
|
|
|
// repair damaged hives.
|
|
BOOLEAN SpaceUsage = FALSE;
|
|
|
|
// maximum level to dump
|
|
ULONG MaxLevel = 0;
|
|
|
|
// bin to examine space display
|
|
LONG BinIndex = -1;
|
|
|
|
// the hive file name
|
|
TCHAR *Hive = NULL;
|
|
|
|
// the root of the hive
|
|
HCELL_INDEX RootCell;
|
|
|
|
// Usage string
|
|
char *Usage="\
|
|
Checks a hive file and perform repairs, compacts or displays a status report.\n\n\
|
|
CHKREG /F <filename[.<LOG>]> [/H] [/D [<level>] [/S [<bin>]] [/C] [/L] [/R]\n\n\
|
|
<filename> FileName of hive to be analyzed\n\
|
|
/H This manual\n\
|
|
/D [<level>] Dump subkeys up to level <level>. If level is not\n\
|
|
specified, dumps the entire hive. No checks are done\n\
|
|
when dumping.\n\
|
|
/S [<bin>] Displays space usage for the bin <bin>. When bin is\n\
|
|
not specified, displays usage for the entire hive.\n\
|
|
/C Compacts the hive. Bad hives cannot be compacted.\n\
|
|
The compacted hive will be written to <filename>.BAK\n\
|
|
/L Lost space detection.\n\
|
|
/R Repair the hive.\n\
|
|
";
|
|
|
|
// Lost Space Warning
|
|
char *LostSpaceWarning="\n\
|
|
WARNING : Lost space detection may take a while. Are you sure you want this (y/n)?";
|
|
|
|
// Starting address of the in-memory maped hive image
|
|
PUCHAR Base;
|
|
|
|
// LostCells list used for lost space detection
|
|
UNKNOWN_LIST LostCells[FRAGMENTATION];
|
|
|
|
// OutputFile : future changes may use it to write the results to a file rather than to stdout
|
|
FILE *OutputFile;
|
|
|
|
#define NAME_BUFFERSIZE 2000
|
|
|
|
UNICODE_STRING KeyName;
|
|
WCHAR NameBuffer[NAME_BUFFERSIZE];
|
|
|
|
// Miscelaneous variables used fo data statistics
|
|
ULONG TotalKeyNode=0;
|
|
ULONG TotalKeyValue=0;
|
|
ULONG TotalKeyIndex=0;
|
|
ULONG TotalKeySecurity=0;
|
|
ULONG TotalValueIndex=0;
|
|
ULONG TotalUnknown=0;
|
|
|
|
ULONG CountKeyNode=0;
|
|
ULONG CountKeyValue=0;
|
|
ULONG CountKeyIndex=0;
|
|
ULONG CountKeySecurity=0;
|
|
ULONG CountValueIndex=0;
|
|
ULONG CountUnknown=0;
|
|
|
|
ULONG CountKeyNodeCompacted=0;
|
|
|
|
ULONG TotalFree=0;
|
|
ULONG FreeCount=0;
|
|
ULONG TotalUsed=0;
|
|
|
|
PHBIN FirstBin;
|
|
PHBIN MaxBin;
|
|
ULONG HiveLength;
|
|
|
|
#define OPTION_MODE 0
|
|
#define FILE_MODE 1
|
|
#define LEVEL_MODE 2
|
|
#define BIN_MODE 3
|
|
|
|
VOID
|
|
ChkDumpLogFile( PHBASE_BLOCK BaseBlock,ULONG Length );
|
|
|
|
VOID
|
|
ParseArgs (
|
|
int argc,
|
|
char *argv[]
|
|
)
|
|
{
|
|
|
|
char *p;
|
|
int i;
|
|
|
|
// specified what should we expect from the command line
|
|
int iMode = OPTION_MODE;
|
|
|
|
for(i=0;i<argc;i++) {
|
|
p = argv[i];
|
|
if ( *p == '/' || *p == '-' ) {
|
|
// option mode
|
|
p++;
|
|
iMode = OPTION_MODE;
|
|
while ((*p != '\0') && (*p != ' ')) {
|
|
switch (*p) {
|
|
case 'h':
|
|
case 'H':
|
|
case '?':
|
|
fprintf(stderr, "%s\n", Usage);
|
|
ExitProcess(1);
|
|
break;
|
|
case 'f':
|
|
case 'F':
|
|
iMode = FILE_MODE;
|
|
break;
|
|
case 'd':
|
|
case 'D':
|
|
iMode = LEVEL_MODE;
|
|
// when not specified, dump at least 100 levels
|
|
MaxLevel = 100;
|
|
CheckHive = FALSE;
|
|
break;
|
|
case 's':
|
|
case 'S':
|
|
SpaceUsage = TRUE;
|
|
iMode = BIN_MODE;
|
|
break;
|
|
case 'c':
|
|
case 'C':
|
|
p++;
|
|
CompactHive = TRUE;
|
|
break;
|
|
case 'l':
|
|
case 'L':
|
|
p++;
|
|
LostSpace = TRUE;
|
|
break;
|
|
case 'r':
|
|
case 'R':
|
|
p++;
|
|
FixHive = TRUE;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if( iMode != OPTION_MODE ) {
|
|
// break the loop; ignore the rest of the current argv
|
|
break;
|
|
}
|
|
} // while
|
|
} else {
|
|
switch(iMode) {
|
|
case FILE_MODE:
|
|
Hive = argv[i];
|
|
break;
|
|
case LEVEL_MODE:
|
|
MaxLevel = (ULONG) atol(argv[i]);
|
|
break;
|
|
case BIN_MODE:
|
|
BinIndex = (LONG) atol(argv[i]);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
__cdecl
|
|
main(
|
|
int argc,
|
|
char *argv[]
|
|
)
|
|
{
|
|
ULONG FileIndex;
|
|
HANDLE myFileHandle, myMMFHandle;
|
|
LPBYTE myMMFViewHandle;
|
|
BYTE lowChar, hiChar, modVal;
|
|
DWORD dwFileSize;
|
|
ULONG Index,Index2;
|
|
|
|
PHBASE_BLOCK PHBaseBlock;
|
|
PHBIN NewBins;
|
|
ULONG Offset;
|
|
ULONG CellCount;
|
|
ULONG SizeCount;
|
|
|
|
REG_USAGE TotalUsage;
|
|
DWORD dwHiveFileAccess = GENERIC_READ;
|
|
DWORD flHiveViewProtect = PAGE_READONLY;
|
|
DWORD dwHiveViewAccess = FILE_MAP_READ;
|
|
ParseArgs( argc, argv );
|
|
|
|
if (!Hive) {
|
|
fprintf(stderr, "\nMust provide a hive name !!!\n\n");
|
|
fprintf(stderr, "%s\n", Usage);
|
|
ExitProcess(-1);
|
|
}
|
|
|
|
if(LostSpace) {
|
|
// are you sure you want lost cells detection? It may take a while!
|
|
int chLost;
|
|
fprintf(stdout, "%s",LostSpaceWarning);
|
|
fflush(stdin);
|
|
chLost = getchar();
|
|
if( (chLost != 'y') && (chLost != 'Y') ) {
|
|
// he changed his mind
|
|
LostSpace = FALSE;
|
|
}
|
|
fprintf(stderr, "\n");
|
|
}
|
|
|
|
if( FixHive ) {
|
|
dwHiveFileAccess |= GENERIC_WRITE;
|
|
flHiveViewProtect = PAGE_READWRITE;
|
|
dwHiveViewAccess = FILE_MAP_WRITE;
|
|
}
|
|
/* Create temporary file for mapping. */
|
|
if ((myFileHandle = CreateFile (Hive, dwHiveFileAccess,
|
|
0 , NULL, OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL))
|
|
== (HANDLE) INVALID_HANDLE_VALUE) /* Bad handle */ {
|
|
fprintf(stderr,"Could not create file %s\n", Hive);
|
|
exit(-1);
|
|
}
|
|
|
|
// Get the size of the file. I am assuming here that the
|
|
// file is smaller than 4 GB.
|
|
dwFileSize = GetFileSize(myFileHandle, NULL);
|
|
|
|
/* If we get here, we managed to name and create a temp file. Now we need
|
|
to create a mapping */
|
|
|
|
myMMFHandle = CreateFileMapping (myFileHandle, NULL, flHiveViewProtect,
|
|
0, dwFileSize, NULL);
|
|
if (myMMFHandle == (HANDLE) INVALID_HANDLE_VALUE) {
|
|
fprintf(stderr,"Could not map file %s\n", Hive);
|
|
exit(-1);
|
|
}
|
|
|
|
/* So we've mapped the file. Now try to map a view */
|
|
|
|
myMMFViewHandle = (LPBYTE) MapViewOfFile (myMMFHandle, dwHiveViewAccess, 0, 0, dwFileSize);
|
|
if (!myMMFViewHandle) {
|
|
fprintf(stderr,"Could not map view of file %s error = %lx\n", Hive,(ULONG)GetLastError());
|
|
exit(-1);
|
|
}
|
|
|
|
/* Now we have a view. Read through it */
|
|
|
|
PHBaseBlock = (PHBASE_BLOCK) myMMFViewHandle;
|
|
|
|
if( strstr(Hive,".LOG") != NULL ) {
|
|
// dumping log file
|
|
ChkDumpLogFile(PHBaseBlock,MaxLevel);
|
|
} else {
|
|
/*
|
|
if (PHBaseBlock->Minor < 4) {
|
|
fprintf(stderr,"Hive version %d is too old, must be 3 or later\n", PHBaseBlock->Minor);
|
|
ExitProcess(-1);
|
|
}
|
|
*/
|
|
// Initialization stuff
|
|
for(Index =0;Index<FRAGMENTATION;Index++) {
|
|
LostCells[Index].Count = 0;
|
|
for(Index2 = 0;Index2<SUBLISTS;Index2++) {
|
|
LostCells[Index].List[Index2] = NULL;
|
|
}
|
|
}
|
|
|
|
RootCell = PHBaseBlock->RootCell;
|
|
|
|
OutputFile = stdout;
|
|
Base = (PUCHAR)(PHBaseBlock) + HBLOCK_SIZE;
|
|
|
|
Offset=HBLOCK_SIZE;
|
|
HiveLength = PHBaseBlock->Length;
|
|
|
|
MaxBin= (PHBIN) (Base + HiveLength);
|
|
FirstBin = (PHBIN) (Base);
|
|
|
|
KeyName.Buffer = NameBuffer;
|
|
KeyName.MaximumLength = NAME_BUFFERSIZE;
|
|
|
|
ChkBaseBlock(PHBaseBlock,dwFileSize);
|
|
|
|
ChkSecurityDescriptors();
|
|
|
|
ChkPhysicalHive();
|
|
|
|
if (MaxLevel) {
|
|
fprintf(stdout,"%6s,%6s,%7s,%10s, %s\n",
|
|
"Keys",
|
|
"Values",
|
|
"Cells",
|
|
"Size",
|
|
"SubKeys");
|
|
}
|
|
|
|
DumpChkRegistry(0, 0, PHBaseBlock->RootCell,HCELL_NIL,&TotalUsage);
|
|
|
|
if(LostSpace) {
|
|
// clear the dirt on the screen
|
|
fprintf(OutputFile,"\r \n");
|
|
}
|
|
|
|
DumpUnknownList();
|
|
FreeUnknownList();
|
|
|
|
fprintf(OutputFile,"\nSUMMARY: \n");
|
|
fprintf(OutputFile,"%15s,%15s, %s\n",
|
|
"Cells",
|
|
"Size",
|
|
"Category");
|
|
|
|
fprintf(OutputFile,"%15lu,%15lu, Keys\n",
|
|
CountKeyNode,
|
|
TotalKeyNode
|
|
);
|
|
fprintf(OutputFile,"%15lu,%15lu, Values\n",
|
|
CountKeyValue,
|
|
TotalKeyValue
|
|
);
|
|
fprintf(OutputFile,"%15lu,%15lu, Key Index\n",
|
|
CountKeyIndex,
|
|
TotalKeyIndex
|
|
);
|
|
fprintf(OutputFile,"%15lu,%15lu, Value Index\n",
|
|
CountValueIndex,
|
|
TotalValueIndex
|
|
);
|
|
fprintf(OutputFile,"%15lu,%15lu, Security\n",
|
|
CountKeySecurity,
|
|
TotalKeySecurity
|
|
);
|
|
fprintf(OutputFile,"%15lu,%15lu, Data\n",
|
|
CountUnknown - CountValueIndex,
|
|
TotalUnknown - TotalValueIndex
|
|
);
|
|
|
|
fprintf(OutputFile,"%15lu,%15lu, Free\n",
|
|
FreeCount,
|
|
TotalFree
|
|
);
|
|
|
|
CellCount = CountKeyNode +
|
|
CountKeyValue +
|
|
CountKeyIndex +
|
|
CountKeySecurity +
|
|
CountUnknown +
|
|
FreeCount;
|
|
|
|
SizeCount = TotalKeyNode +
|
|
TotalKeyValue +
|
|
TotalKeyIndex +
|
|
TotalKeySecurity +
|
|
TotalUnknown +
|
|
TotalFree;
|
|
|
|
fprintf(OutputFile,"%15lu,%15lu, %s\n",
|
|
CellCount,
|
|
SizeCount,
|
|
"Total Hive");
|
|
|
|
fprintf(OutputFile,"\n%15lu compacted keys (all related cells in the same view)\n",CountKeyNodeCompacted);
|
|
|
|
}
|
|
|
|
UnmapViewOfFile(myMMFViewHandle);
|
|
CloseHandle(myMMFHandle);
|
|
CloseHandle(myFileHandle);
|
|
|
|
if(CompactHive) {
|
|
DoCompactHive();
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|