935 lines
28 KiB
C
935 lines
28 KiB
C
/*++
|
|
|
|
Copyright (c) 1998 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
regbin.c
|
|
|
|
Abstract:
|
|
|
|
This module contains functions to check bin header and bin body consistency.
|
|
|
|
Author:
|
|
|
|
Dragos C. Sambotin (dragoss) 30-Dec-1998
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
#include "chkreg.h"
|
|
|
|
extern ULONG TotalKeyNode;
|
|
extern ULONG TotalKeyValue;
|
|
extern ULONG TotalKeyIndex;
|
|
extern ULONG TotalKeySecurity;
|
|
extern ULONG TotalValueIndex;
|
|
extern ULONG TotalUnknown;
|
|
|
|
extern ULONG CountKeyNode;
|
|
extern ULONG CountKeyValue;
|
|
extern ULONG CountKeyIndex;
|
|
extern ULONG CountKeySecurity;
|
|
extern ULONG CountValueIndex;
|
|
extern ULONG CountUnknown;
|
|
|
|
extern ULONG TotalFree;
|
|
extern ULONG FreeCount;
|
|
extern ULONG TotalUsed;
|
|
|
|
extern PUCHAR Base;
|
|
extern FILE *OutputFile;
|
|
|
|
extern HCELL_INDEX RootCell;
|
|
extern PHBIN FirstBin;
|
|
extern PHBIN MaxBin;
|
|
extern ULONG HiveLength;
|
|
|
|
extern LONG BinIndex;
|
|
extern BOOLEAN FixHive;
|
|
extern BOOLEAN SpaceUsage;
|
|
extern BOOLEAN CompactHive;
|
|
|
|
ULONG BinFreeDisplaySize[HHIVE_FREE_DISPLAY_SIZE];
|
|
ULONG BinFreeDisplayCount[HHIVE_FREE_DISPLAY_SIZE];
|
|
ULONG FreeDisplaySize[HHIVE_FREE_DISPLAY_SIZE];
|
|
ULONG FreeDisplayCount[HHIVE_FREE_DISPLAY_SIZE];
|
|
|
|
ULONG BinUsedDisplaySize[HHIVE_FREE_DISPLAY_SIZE];
|
|
ULONG BinUsedDisplayCount[HHIVE_FREE_DISPLAY_SIZE];
|
|
ULONG UsedDisplaySize[HHIVE_FREE_DISPLAY_SIZE];
|
|
ULONG UsedDisplayCount[HHIVE_FREE_DISPLAY_SIZE];
|
|
|
|
BOOLEAN ChkAllocatedCell(HCELL_INDEX Cell);
|
|
|
|
CCHAR ChkRegFindFirstSetLeft[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 ComputeFreeIndex(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 = ChkRegFindFirstSetLeft[Index] + \
|
|
HHIVE_FREE_DISPLAY_BIAS; \
|
|
} \
|
|
} \
|
|
}
|
|
|
|
BOOLEAN
|
|
ChkBinHeader(PHBIN Bin,
|
|
ULONG FileOffset,
|
|
ULONG Index
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Checks the validity of the Bin header.
|
|
The following tests are done:
|
|
1. the Size should not be bigger than the remaining of the file
|
|
2. the Size should not be smaller than HBLOCK_SIZE
|
|
3. the signature should be valid (HBIN_SIGNATURE)
|
|
4. the file offset should match the actual position in the hive file.
|
|
|
|
|
|
Arguments:
|
|
|
|
Bin - supplies a pointer to the bin to be checked.
|
|
|
|
FileOffset - provides the actual pposition within the file
|
|
|
|
Index - the index of the bin within the bin list of the hive
|
|
|
|
Return Value:
|
|
|
|
FALSE - the bin header is corrupted and was not fixed. Either this is a
|
|
critical corruption, or the /R argument was not present in the
|
|
command line.
|
|
|
|
TRUE - The bin header is OK, or it was successfully recovered.
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN bRez = TRUE;
|
|
PHCELL p;
|
|
|
|
p = (PHCELL)((PUCHAR)Bin + sizeof(HBIN));
|
|
|
|
if(Bin->Size > (HiveLength - FileOffset)) {
|
|
bRez = FALSE;
|
|
fprintf(stderr, "Size too big (%lu) in Bin header of Bin (%lu)\n",Bin->Size,Index);
|
|
if(FixHive) {
|
|
//
|
|
// REPAIR: set the actual size to HiveLength-FileOffset
|
|
//
|
|
Bin->Size = HiveLength-FileOffset;
|
|
p->Size = Bin->Size -sizeof(HBIN);
|
|
bRez = TRUE;
|
|
} else {
|
|
if(CompactHive) {
|
|
// any attempt to compact a corrupted hive will fail
|
|
CompactHive = FALSE;
|
|
fprintf(stderr, "Run chkreg /R to fix.\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
if((Bin->Size < HBLOCK_SIZE) || ((Bin->Size % HBLOCK_SIZE) != 0)) {
|
|
bRez = FALSE;
|
|
fprintf(stderr, "Size too small (%lu) in Bin header of Bin (%lu)\n",Bin->Size,Index);
|
|
if(FixHive) {
|
|
//
|
|
// REPAIR: set the actual size to minimmum possible size HBLOCK_SIZE
|
|
//
|
|
Bin->Size = HBLOCK_SIZE;
|
|
p->Size = Bin->Size -sizeof(HBIN);
|
|
|
|
bRez = TRUE;
|
|
} else {
|
|
if(CompactHive) {
|
|
// any attempt to compact a corrupted hive will fail
|
|
CompactHive = FALSE;
|
|
fprintf(stderr, "Run chkreg /R to fix.\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
if(Bin->Signature != HBIN_SIGNATURE) {
|
|
bRez = FALSE;
|
|
fprintf(stderr, "Invalid signature (%lx) in Bin header of Bin (%lu)\n",Bin->Signature,Index);
|
|
if(FixHive) {
|
|
//
|
|
// REPAIR: reset the bin signature
|
|
//
|
|
Bin->Signature = HBIN_SIGNATURE;
|
|
bRez = TRUE;
|
|
} else {
|
|
if(CompactHive) {
|
|
// any attempt to compact a corrupted hive will fail
|
|
CompactHive = FALSE;
|
|
fprintf(stderr, "Run chkreg /R to fix.\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
if(Bin->FileOffset != FileOffset) {
|
|
bRez = FALSE;
|
|
fprintf(stderr, "Actual FileOffset [%lx] and Bin FileOffset [%lx] do not match in Bin (%lu); Size = (%lx)\n",FileOffset,Bin->FileOffset,Index,Bin->Size);
|
|
if(FixHive) {
|
|
//
|
|
// REPAIR: reset the bin FileOffset
|
|
//
|
|
Bin->FileOffset = FileOffset;
|
|
bRez = TRUE;
|
|
} else {
|
|
if(CompactHive) {
|
|
// any attempt to compact a corrupted hive will fail
|
|
CompactHive = FALSE;
|
|
fprintf(stderr, "Run chkreg /R to fix.\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
return bRez;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
ChkBin(
|
|
PHBIN Bin,
|
|
ULONG IndexBin,
|
|
ULONG Starting,
|
|
double *Rate
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Steps through all of the cells in the bin. Make sure that
|
|
they are consistent with each other, and with the bin header.
|
|
Compute the usage rate for the current bin.
|
|
Add all used cells to the unknown list (candidates to lost cells).
|
|
Compute the used space and allocated cells by cell signature.
|
|
Compute the free space size and number of cells.
|
|
Test the cell size for reasonable limits. A cell should be smaller
|
|
than the containing bin and should not exceed the bin boundaries.
|
|
A cell should fit in only one contiguos bin!!!
|
|
|
|
Arguments:
|
|
|
|
Bin - supplies a pointer to the bin to be checked.
|
|
|
|
Index - the index of the bin within the bin list of the hive
|
|
|
|
Starting - starting address of the in-memory hive representation.
|
|
|
|
Rate - usage rate for this bin
|
|
|
|
Return Value:
|
|
|
|
FALSE - the bin is corrupted and was not fixed. Either this is a
|
|
critical corruption, or the /R argument was not present in the
|
|
command line.
|
|
|
|
TRUE - The bin is OK, or it was successfully recovered.
|
|
|
|
--*/
|
|
{
|
|
ULONG freespace = 0L;
|
|
ULONG allocated = 0L;
|
|
BOOLEAN bRez = TRUE;
|
|
HCELL_INDEX cellindex;
|
|
PHCELL p;
|
|
ULONG Size;
|
|
ULONG Index;
|
|
double TmpRate;
|
|
|
|
p = (PHCELL)((PUCHAR)Bin + sizeof(HBIN));
|
|
|
|
while (p < (PHCELL)((PUCHAR)Bin + Bin->Size)) {
|
|
|
|
cellindex = (HCELL_INDEX)((PUCHAR)p - Base);
|
|
|
|
if (p->Size >= 0) {
|
|
//
|
|
// It is a free cell.
|
|
//
|
|
Size = (ULONG)p->Size;
|
|
|
|
if ( (Size > Bin->Size) ||
|
|
( (PHCELL)(Size + (PUCHAR)p) >
|
|
(PHCELL)((PUCHAR)Bin + Bin->Size) )
|
|
) {
|
|
bRez = FALSE;
|
|
fprintf(stderr, "Impossible cell size in free cell (%lu) in Bin header of Bin (%lu)\n",Size,IndexBin);
|
|
if(FixHive) {
|
|
//
|
|
// REPAIR: set the cell size to the largest possible hereon (ie. Bin + Bin->Size - p ); reset the Size too!!!
|
|
//
|
|
bRez = TRUE;
|
|
p->Size = (ULONG)((PUCHAR)Bin + Bin->Size - (PUCHAR)p);
|
|
} else {
|
|
if(CompactHive) {
|
|
// any attempt to compact a corrupted hive will fail
|
|
CompactHive = FALSE;
|
|
fprintf(stderr, "Run chkreg /R to fix.\n");
|
|
}
|
|
}
|
|
}
|
|
freespace += Size;
|
|
|
|
TotalFree += Size;
|
|
FreeCount++;
|
|
|
|
if( SpaceUsage ) {
|
|
// only if we are interested in the usage map
|
|
// store the length of this free cell
|
|
ComputeFreeIndex(Index, Size);
|
|
BinFreeDisplaySize[Index] += Size;
|
|
// and increment the count of free cells of this particular size
|
|
BinFreeDisplayCount[Index]++;
|
|
}
|
|
|
|
}else{
|
|
//
|
|
// It is used cell. Check for signature
|
|
//
|
|
UCHAR *C;
|
|
USHORT Sig;
|
|
int i,j;
|
|
|
|
// All used cells are leak candidates
|
|
AddCellToUnknownList(cellindex);
|
|
|
|
Size = (ULONG)(p->Size * -1);
|
|
|
|
if ( (Size > Bin->Size) ||
|
|
( (PHCELL)(Size + (PUCHAR)p) >
|
|
(PHCELL)((PUCHAR)Bin + Bin->Size) )
|
|
) {
|
|
bRez = FALSE;
|
|
fprintf(stderr, "Impossible cell size in allocated cell (%lu) in Bin header of Bin (%lu)\n",Size,IndexBin);
|
|
if(FixHive) {
|
|
//
|
|
// REPAIR: set the cell size to the largest possible hereon (ie. Bin + Bin->Size - p ); reset the Size too!!!
|
|
//
|
|
bRez = TRUE;
|
|
p->Size = (LONG)((PUCHAR)Bin + Bin->Size - (PUCHAR)p);
|
|
// it's a used cell, remember ?
|
|
p->Size *= -1;
|
|
} else {
|
|
if(CompactHive) {
|
|
// any attempt to compact a corrupted hive will fail
|
|
CompactHive = FALSE;
|
|
fprintf(stderr, "Run chkreg /R to fix.\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
allocated += Size;
|
|
|
|
if( SpaceUsage ) {
|
|
// only if we are interested in the usage map
|
|
// store the length of this used cell
|
|
ComputeFreeIndex(Index, Size);
|
|
BinUsedDisplaySize[Index] += Size;
|
|
// and increment the count of used cells of this particular size
|
|
BinUsedDisplayCount[Index]++;
|
|
}
|
|
|
|
TotalUsed=TotalUsed+Size;
|
|
C= (UCHAR *) &(p->u.NewCell.u.UserData);
|
|
Sig=(USHORT) p->u.NewCell.u.UserData;
|
|
|
|
switch(Sig){
|
|
case CM_LINK_NODE_SIGNATURE:
|
|
printf("Link Node !\n");
|
|
TotalKeyNode=TotalKeyNode+Size;
|
|
CountKeyNode++;
|
|
break;
|
|
case CM_KEY_NODE_SIGNATURE:
|
|
{
|
|
PCM_KEY_NODE Pcan;
|
|
TotalKeyNode=TotalKeyNode+Size;
|
|
CountKeyNode++;
|
|
|
|
Pcan = (PCM_KEY_NODE)C;
|
|
|
|
if(Pcan->ValueList.Count){
|
|
PHCELL TmpP;
|
|
|
|
TmpP = (PHCELL) (Starting + Pcan->ValueList.List);
|
|
TotalValueIndex=TotalValueIndex - TmpP->Size;
|
|
CountValueIndex++;
|
|
}
|
|
|
|
}
|
|
break;
|
|
case CM_KEY_VALUE_SIGNATURE:
|
|
TotalKeyValue=TotalKeyValue+Size;
|
|
CountKeyValue++;
|
|
break;
|
|
case CM_KEY_FAST_LEAF:
|
|
case CM_KEY_HASH_LEAF:
|
|
case CM_KEY_INDEX_LEAF:
|
|
case CM_KEY_INDEX_ROOT:
|
|
TotalKeyIndex=TotalKeyIndex+Size;
|
|
CountKeyIndex++;
|
|
break;
|
|
case CM_KEY_SECURITY_SIGNATURE:
|
|
TotalKeySecurity=TotalKeySecurity+Size;
|
|
CountKeySecurity++;
|
|
break;
|
|
default:
|
|
//
|
|
// No signature, it can be data or index cells.
|
|
// Or there must be some registry leak here.
|
|
//
|
|
TotalUnknown=TotalUnknown+Size;
|
|
CountUnknown++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
p = (PHCELL)((PUCHAR)p + Size);
|
|
}
|
|
|
|
|
|
*Rate = TmpRate = (double)(((double)allocated)/((double)(allocated+freespace)));
|
|
TmpRate *= 100.00;
|
|
fprintf(OutputFile,"Bin [%5lu], usage %.2f%%\r",IndexBin,(float)TmpRate);
|
|
|
|
return bRez;
|
|
}
|
|
|
|
BOOLEAN ChkPhysicalHive()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Checks the integrity of the hive by stepping through all of the cells
|
|
in the hive. Collects and displays statistics, according to the command
|
|
line parameters.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
FALSE - the hive is corrupted and was not fixed. Either this is a
|
|
critical corruption, or the /R argument was not present in the
|
|
command line.
|
|
|
|
TRUE - The hive is OK, or it was successfully recovered.
|
|
|
|
--*/
|
|
{
|
|
|
|
ULONG Starting;
|
|
PHBIN Bin = FirstBin;
|
|
LONG Index;
|
|
ULONG FileOffset;
|
|
double Rate,RateTotal = 0.0;
|
|
BOOLEAN bRez = TRUE;
|
|
|
|
int i;
|
|
|
|
Starting=(ULONG) Bin;
|
|
Index=0;
|
|
FileOffset = 0;
|
|
|
|
for(i=0;i<HHIVE_FREE_DISPLAY_SIZE;i++) {
|
|
FreeDisplaySize[i] = 0;
|
|
FreeDisplayCount[i] = 0;
|
|
UsedDisplaySize[i] = 0;
|
|
UsedDisplayCount[i] = 0;
|
|
}
|
|
|
|
while(Bin < MaxBin){
|
|
|
|
if( SpaceUsage ) {
|
|
// only if we are interested in the usage map
|
|
for(i=0;i<HHIVE_FREE_DISPLAY_SIZE;i++) {
|
|
BinFreeDisplaySize[i] = 0;
|
|
BinFreeDisplayCount[i] = 0;
|
|
BinUsedDisplaySize[i] = 0;
|
|
BinUsedDisplayCount[i] = 0;
|
|
}
|
|
}
|
|
|
|
bRez = (bRez && ChkBinHeader(Bin,FileOffset,Index));
|
|
|
|
bRez = (bRez && ChkBin(Bin,Index,Starting,&Rate));
|
|
|
|
RateTotal += Rate;
|
|
|
|
if( SpaceUsage ) {
|
|
// only if we are interested in the usage map
|
|
if( BinIndex == Index ) {
|
|
// summary wanted for this particular bin
|
|
fprintf(OutputFile,"\nBin[%5lu] Display Map: Free Cells, Free Size\t Used Cells, Used Size\n",(ULONG)Index);
|
|
for(i=0;i<HHIVE_FREE_DISPLAY_SIZE;i++) {
|
|
fprintf(OutputFile,"Display[%2d] : %8lu , %8lu \t %8lu , %8lu \n",i,BinFreeDisplayCount[i],BinFreeDisplaySize[i],BinUsedDisplayCount[i],BinUsedDisplaySize[i]);
|
|
}
|
|
}
|
|
for(i=0;i<HHIVE_FREE_DISPLAY_SIZE;i++) {
|
|
FreeDisplaySize[i] += BinFreeDisplaySize[i];
|
|
FreeDisplayCount[i] += BinFreeDisplayCount[i];
|
|
UsedDisplaySize[i] += BinUsedDisplaySize[i];
|
|
UsedDisplayCount[i] += BinUsedDisplayCount[i];
|
|
}
|
|
}
|
|
|
|
if( Bin<MaxBin) {
|
|
FileOffset += Bin->Size;
|
|
}
|
|
|
|
Bin = (PHBIN)((ULONG)Bin + Bin->Size);
|
|
|
|
Index++;
|
|
}
|
|
|
|
RateTotal *= 100.00;
|
|
RateTotal /= (double)Index;
|
|
|
|
fprintf(OutputFile,"Number of Bins in hive: %lu \n",Index);
|
|
fprintf(OutputFile,"Total Hive space usage: %.2f%% \n",(float)RateTotal);
|
|
|
|
if( SpaceUsage ) {
|
|
// only if we are interested in the usage map
|
|
if( BinIndex == -1 ) {
|
|
// space usage display per entire hive
|
|
fprintf(OutputFile,"\nHive Display Map: Free Cells, Free Size\t\t Used Cells, Used Size\n");
|
|
for(i=0;i<HHIVE_FREE_DISPLAY_SIZE;i++) {
|
|
fprintf(OutputFile,"Display[%2d] : %8lu , %8lu \t %8lu , %8lu \n",i,FreeDisplayCount[i],FreeDisplaySize[i],UsedDisplayCount[i],UsedDisplaySize[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
return bRez;
|
|
}
|
|
|
|
ULONG
|
|
ComputeHeaderCheckSum(
|
|
PHBASE_BLOCK BaseBlock
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Compute the checksum for a hive disk header.
|
|
|
|
Arguments:
|
|
|
|
BaseBlock - supplies pointer to the header to checksum
|
|
|
|
Return Value:
|
|
|
|
the check sum.
|
|
|
|
--*/
|
|
{
|
|
ULONG sum;
|
|
ULONG i;
|
|
|
|
sum = 0;
|
|
for (i = 0; i < 127; i++) {
|
|
sum ^= ((PULONG)BaseBlock)[i];
|
|
}
|
|
if (sum == (ULONG)-1) {
|
|
sum = (ULONG)-2;
|
|
}
|
|
if (sum == 0) {
|
|
sum = 1;
|
|
}
|
|
return sum;
|
|
}
|
|
|
|
BOOLEAN
|
|
ChkBaseBlock(PHBASE_BLOCK BaseBlock,
|
|
DWORD dwFileSize)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Checks the integrity of the base block of a hive.
|
|
Eventually makes the following corrections:
|
|
1. enforce Sequence1 == Sequence2
|
|
2. recalculate the header checksum
|
|
|
|
Arguments:
|
|
|
|
BaseBlock - the BaseBlock in-memory mapped image.
|
|
|
|
dwFileSize - the actual size of the hive file
|
|
|
|
Return Value:
|
|
|
|
FALSE - the BaseBlock is corrupted and was not fixed. Either this is a
|
|
critical corruption, or the /R argument was not present in the
|
|
command line.
|
|
|
|
TRUE - The BaseBlock is OK, or it was successfully recovered.
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN bRez = TRUE;
|
|
ULONG CheckSum;
|
|
|
|
if(BaseBlock->Signature != HBASE_BLOCK_SIGNATURE) {
|
|
fprintf(stderr, "Fatal: Invalid Base Block signature (0x%lx)",BaseBlock->Signature);
|
|
bRez = FALSE;
|
|
if(FixHive) {
|
|
//
|
|
// REPAIR: reset the signature
|
|
//
|
|
fprintf(stderr, " ... unable to fix");
|
|
} else {
|
|
if(CompactHive) {
|
|
// any attempt to compact a corrupted hive will fail
|
|
CompactHive = FALSE;
|
|
}
|
|
}
|
|
fprintf(stderr, "\n");
|
|
}
|
|
|
|
if(BaseBlock->Major != HSYS_MAJOR) {
|
|
bRez = FALSE;
|
|
fprintf(stderr, "Fatal: Invalid hive file Major version (%lu)",BaseBlock->Major);
|
|
if(FixHive) {
|
|
//
|
|
// Fatal: unable to fix this
|
|
//
|
|
fprintf(stderr, " ... unable to fix");
|
|
} else {
|
|
if(CompactHive) {
|
|
// any attempt to compact a corrupted hive will fail
|
|
CompactHive = FALSE;
|
|
}
|
|
}
|
|
fprintf(stderr, "\n");
|
|
}
|
|
|
|
if(BaseBlock->Minor > HSYS_MINOR_SUPPORTED) {
|
|
bRez = FALSE;
|
|
fprintf(stderr, "Fatal: Invalid hive file Minor version (%lu)",BaseBlock->Minor);
|
|
if(FixHive) {
|
|
//
|
|
// Fatal: unable to fix this
|
|
//
|
|
fprintf(stderr, " ... unable to fix");
|
|
} else {
|
|
if(CompactHive) {
|
|
// any attempt to compact a corrupted hive will fail
|
|
CompactHive = FALSE;
|
|
}
|
|
}
|
|
fprintf(stderr, "\n");
|
|
}
|
|
|
|
if(BaseBlock->Format != HBASE_FORMAT_MEMORY) {
|
|
bRez = FALSE;
|
|
fprintf(stderr, "Fatal: Invalid hive memory format (%lu)",BaseBlock->Format);
|
|
if(FixHive) {
|
|
//
|
|
// Fatal: unable to fix this
|
|
//
|
|
fprintf(stderr, " ... unable to fix");
|
|
} else {
|
|
if(CompactHive) {
|
|
// any attempt to compact a corrupted hive will fail
|
|
CompactHive = FALSE;
|
|
}
|
|
}
|
|
fprintf(stderr, "\n");
|
|
}
|
|
|
|
if((BaseBlock->Length + HBLOCK_SIZE) > dwFileSize) {
|
|
fprintf(stderr, "Fatal: Invalid Hive file Length (%lu)",BaseBlock->Length);
|
|
bRez = FALSE;
|
|
if(FixHive) {
|
|
//
|
|
// REPAIR: unable to fix this
|
|
//
|
|
fprintf(stderr, " ... unable to fix");
|
|
} else {
|
|
if(CompactHive) {
|
|
// any attempt to compact a corrupted hive will fail
|
|
CompactHive = FALSE;
|
|
}
|
|
}
|
|
fprintf(stderr, "\n");
|
|
}
|
|
|
|
if(!bRez) {
|
|
//
|
|
// Fatal Base Block corruption; no point to continue.
|
|
//
|
|
return bRez;
|
|
}
|
|
|
|
if(BaseBlock->Sequence1 != BaseBlock->Sequence2) {
|
|
fprintf(stderr, "Sequence numbers do not match (%lu,%lu)",BaseBlock->Sequence1,BaseBlock->Sequence2);
|
|
bRez = FALSE;
|
|
if(FixHive) {
|
|
//
|
|
// REPAIR: enforce Sequence2 to Sequence1
|
|
//
|
|
bRez = TRUE;
|
|
BaseBlock->Sequence2 = BaseBlock->Sequence1;
|
|
fprintf(stderr, " ... fixed");
|
|
} else {
|
|
if(CompactHive) {
|
|
// any attempt to compact a corrupted hive will fail
|
|
CompactHive = FALSE;
|
|
fprintf(stderr, "\nRun chkreg /R to fix.");
|
|
}
|
|
}
|
|
fprintf(stderr, "\n");
|
|
}
|
|
|
|
CheckSum = ComputeHeaderCheckSum(BaseBlock);
|
|
if(BaseBlock->CheckSum != CheckSum) {
|
|
fprintf(stderr, "Invalid Base Block CheckSum (0x%lx)",BaseBlock->CheckSum);
|
|
bRez = FALSE;
|
|
if(FixHive) {
|
|
//
|
|
// REPAIR: reset the signature
|
|
//
|
|
bRez = TRUE;
|
|
BaseBlock->CheckSum = CheckSum;
|
|
fprintf(stderr, " ... fixed");
|
|
} else {
|
|
if(CompactHive) {
|
|
// any attempt to compact a corrupted hive will fail
|
|
CompactHive = FALSE;
|
|
fprintf(stderr, "\nRun chkreg /R to fix.");
|
|
}
|
|
}
|
|
fprintf(stderr, "\n");
|
|
}
|
|
|
|
return bRez;
|
|
}
|
|
|
|
BOOLEAN
|
|
ChkSecurityDescriptors( )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Walks the list of security descriptors present in the hive and passes
|
|
each security descriptor to RtlValidSecurityDescriptor.
|
|
Also checks the validity of the FLink <==> BLink relationship between cells.
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE - All security descriptors are valid
|
|
FALSE - At least one security descriptor is invalid, and/or cannot be fixed
|
|
|
|
--*/
|
|
|
|
{
|
|
PCM_KEY_NODE RootNode;
|
|
PCM_KEY_SECURITY SecurityCell;
|
|
HCELL_INDEX ListAnchor;
|
|
HCELL_INDEX NextCell;
|
|
HCELL_INDEX LastCell;
|
|
BOOLEAN bRez = TRUE;
|
|
|
|
// check/fix the root cell (is allocated?)
|
|
ChkAllocatedCell(RootCell);
|
|
|
|
RootNode = (PCM_KEY_NODE) GetCell(RootCell);
|
|
ListAnchor = NextCell = RootNode->Security;
|
|
|
|
do {
|
|
// is the next cell allocated?
|
|
ChkAllocatedCell(NextCell);
|
|
|
|
SecurityCell = (PCM_KEY_SECURITY) GetCell(NextCell);
|
|
|
|
if (SecurityCell->Signature != CM_KEY_SECURITY_SIGNATURE) {
|
|
bRez = FALSE;
|
|
fprintf(stderr, "Fatal: Invalid signature (0x%lx) in Security cell 0x%lx ",SecurityCell->Signature,NextCell);
|
|
if(FixHive) {
|
|
//
|
|
// REPAIR:
|
|
// FATAL: Mismatched signature cannot be fixed. Unable to fix this.
|
|
//
|
|
fprintf(stderr, " ... unable to fix");
|
|
} else {
|
|
if(CompactHive) {
|
|
// any attempt to compact a corrupted hive will fail
|
|
CompactHive = FALSE;
|
|
}
|
|
}
|
|
fprintf(stderr, "\n");
|
|
return bRez;
|
|
}
|
|
|
|
if (NextCell != ListAnchor) {
|
|
//
|
|
// Check to make sure that our Blink points to where we just
|
|
// came from.
|
|
//
|
|
if (SecurityCell->Blink != LastCell) {
|
|
fprintf(stderr, "Invalid backward link in security cell (0x%lx)",NextCell);
|
|
if(FixHive) {
|
|
//
|
|
// REPAIR: reset the link
|
|
//
|
|
SecurityCell->Blink = LastCell;
|
|
fprintf(stderr, " ... fixed");
|
|
} else {
|
|
bRez = FALSE;
|
|
if(CompactHive) {
|
|
// any attempt to compact a corrupted hive will fail
|
|
CompactHive = FALSE;
|
|
fprintf(stderr, "\nRun chkreg /R to fix.");
|
|
}
|
|
}
|
|
fprintf(stderr, "\n");
|
|
}
|
|
}
|
|
|
|
if (!RtlValidSecurityDescriptor(&SecurityCell->Descriptor)) {
|
|
bRez = FALSE;
|
|
fprintf(stderr, "Invalid security descriptor in Security cell 0x%lx ",NextCell);
|
|
if(FixHive) {
|
|
//
|
|
// REPAIR: remove the cell from the list and delete it!
|
|
//
|
|
PCM_KEY_SECURITY Before = (PCM_KEY_SECURITY) GetCell(SecurityCell->Blink);
|
|
PCM_KEY_SECURITY After = (PCM_KEY_SECURITY) GetCell(SecurityCell->Flink);
|
|
if( Before != After ) {
|
|
// make sure the list will not remain empty
|
|
Before->Flink = SecurityCell->Flink;
|
|
After->Blink = SecurityCell->Blink;
|
|
}
|
|
FreeCell(NextCell);
|
|
NextCell = SecurityCell->Flink;
|
|
fprintf(stderr, " ... deleted");
|
|
} else {
|
|
bRez = FALSE;
|
|
if(CompactHive) {
|
|
// any attempt to compact a corrupted hive will fail
|
|
CompactHive = FALSE;
|
|
fprintf(stderr, "\nRun chkreg /R to fix.");
|
|
}
|
|
}
|
|
fprintf(stderr, "\n");
|
|
} else {
|
|
// validate the next one
|
|
LastCell = NextCell;
|
|
NextCell = SecurityCell->Flink;
|
|
}
|
|
} while ( NextCell != ListAnchor );
|
|
|
|
return bRez;
|
|
}
|
|
|
|
BOOLEAN
|
|
ChkSecurityCellInList(HCELL_INDEX Security)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Searches the specified cell within the security descriptors list
|
|
|
|
Arguments:
|
|
|
|
Security - Provides the current cell
|
|
|
|
Return Value:
|
|
|
|
TRUE - the current cell was found in the security list
|
|
FALSE - the current cell is not present in the security list and it couldn't be added.
|
|
|
|
--*/
|
|
{
|
|
PCM_KEY_NODE RootNode;
|
|
PCM_KEY_SECURITY SecurityCell;
|
|
PCM_KEY_SECURITY SecurityCellCurrent;
|
|
PCM_KEY_SECURITY SecurityCellAfter;
|
|
HCELL_INDEX ListAnchor;
|
|
HCELL_INDEX NextCell;
|
|
BOOLEAN bRez = TRUE;
|
|
|
|
RootNode = (PCM_KEY_NODE) GetCell(RootCell);
|
|
ListAnchor = NextCell = RootNode->Security;
|
|
|
|
do {
|
|
|
|
if( NextCell == Security) {
|
|
// found it!
|
|
return bRez;
|
|
}
|
|
|
|
SecurityCell = (PCM_KEY_SECURITY) GetCell(NextCell);
|
|
|
|
NextCell = SecurityCell->Flink;
|
|
} while ( NextCell != ListAnchor );
|
|
|
|
// cell not found; try to fix it
|
|
bRez = FALSE;
|
|
fprintf(stderr, "Security Cell (0x%lx) not in security descriptors list",Security);
|
|
if(FixHive) {
|
|
//
|
|
// REPAIR: Add the security cell at the begining of the list
|
|
//
|
|
bRez = TRUE;
|
|
SecurityCell = (PCM_KEY_SECURITY) GetCell(ListAnchor);
|
|
SecurityCellCurrent = (PCM_KEY_SECURITY) GetCell(Security);
|
|
SecurityCellAfter = (PCM_KEY_SECURITY) GetCell(SecurityCell->Flink);
|
|
|
|
// restore the connections
|
|
SecurityCellCurrent->Flink = SecurityCell->Flink;
|
|
SecurityCellCurrent->Blink = ListAnchor;
|
|
SecurityCell->Flink = Security;
|
|
SecurityCellAfter->Blink = Security;
|
|
fprintf(stderr, " ... security cell added to the list");
|
|
} else {
|
|
if(CompactHive) {
|
|
// any attempt to compact a corrupted hive will fail
|
|
CompactHive = FALSE;
|
|
fprintf(stderr, "\nRun chkreg /R to fix.");
|
|
}
|
|
}
|
|
fprintf(stderr, "\n");
|
|
|
|
return bRez;
|
|
}
|