binhive.c
来自「一个类似windows」· C语言 代码 · 共 1,660 行 · 第 1/3 页
C
1,660 行
/*
* FreeLoader
*
* Copyright (C) 2001 Rex Jolliff
* Copyright (C) 2001 Eric Kohl
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <freeldr.h>
#define NDEBUG
#include <debug.h>
#define REG_HIVE_ID 0x66676572 /* "regf" */
#define REG_BIN_ID 0x6e696268 /* "hbin" */
#define REG_KEY_CELL_ID 0x6b6e
#define REG_HASH_TABLE_BLOCK_ID 0x666c
#define REG_VALUE_CELL_ID 0x6b76
#define REG_BLOCK_SIZE 4096
#define REG_HBIN_DATA_OFFSET 32
#define REG_INIT_BLOCK_LIST_SIZE 32
#define REG_INIT_HASH_TABLE_SIZE 3
#define REG_EXTEND_HASH_TABLE_SIZE 4
#define REG_VALUE_LIST_CELL_MULTIPLE 4
#define ABS_VALUE(V) (((V) < 0) ? -(V) : (V))
/* BLOCK_OFFSET = offset in file after header block */
typedef ULONG BLOCK_OFFSET, *PBLOCK_OFFSET;
/* header for registry hive file : */
typedef struct _HIVE_HEADER
{
/* Hive identifier "regf" (0x66676572) */
ULONG BlockId;
/* Update counter */
ULONG UpdateCounter1;
/* Update counter */
ULONG UpdateCounter2;
/* When this hive file was last modified */
ULONGLONG DateModified;
/* Registry format major version (1) */
ULONG MajorVersion;
/* Registry format minor version (3)
Version 3 added fast indexes, version 5 has large value optimizations */
ULONG MinorVersion;
/* Registry file type (0 - Primary, 1 - Log) */
ULONG Type;
/* Registry format (1 is the only defined value so far) */
ULONG Format;
/* Offset into file from the byte after the end of the base block.
If the hive is volatile, this is the actual pointer to the KEY_CELL */
BLOCK_OFFSET RootKeyOffset;
/* Size of each hive block ? */
ULONG BlockSize;
/* (1?) */
ULONG Unused7;
/* Name of hive file */
WCHAR FileName[48];
ULONG Reserved[99];
/* Checksum of first 0x200 bytes */
ULONG Checksum;
} __attribute__((packed)) HIVE_HEADER, *PHIVE_HEADER;
typedef struct _BIN_HEADER
{
/* Bin identifier "hbin" (0x6E696268) */
ULONG HeaderId;
/* Block offset of this bin */
BLOCK_OFFSET BinOffset;
/* Size in bytes, multiple of the block size (4KB) */
ULONG BinSize;
ULONG Reserved[2];
/* When this bin was last modified */
ULONGLONG DateModified;
/* ? (In-memory only) */
ULONG MemAlloc;
} __attribute__((packed)) HBIN, *PHBIN;
typedef struct _CELL_HEADER
{
/* <0 if used, >0 if free */
LONG CellSize;
} __attribute__((packed)) CELL_HEADER, *PCELL_HEADER;
typedef struct _KEY_CELL
{
/* Size of this cell */
LONG CellSize;
/* Key cell identifier "kn" (0x6b6e) */
USHORT Id;
/* Flags */
USHORT Flags;
/* Time of last flush */
ULONGLONG LastWriteTime; /* FILETIME */
/* ? */
ULONG UnUsed1;
/* Block offset of parent key cell */
BLOCK_OFFSET ParentKeyOffset;
/* Count of sub keys for the key in this key cell */
ULONG NumberOfSubKeys;
/* ? */
ULONG UnUsed2;
/* Block offset of has table for FIXME: subkeys/values? */
BLOCK_OFFSET HashTableOffset;
/* ? */
ULONG UnUsed3;
/* Count of values contained in this key cell */
ULONG NumberOfValues;
/* Block offset of VALUE_LIST_CELL */
BLOCK_OFFSET ValueListOffset;
/* Block offset of security cell */
BLOCK_OFFSET SecurityKeyOffset;
/* Block offset of registry key class */
BLOCK_OFFSET ClassNameOffset;
/* ? */
ULONG Unused4[5];
/* Size in bytes of key name */
USHORT NameSize;
/* Size of class name in bytes */
USHORT ClassSize;
/* Name of key (not zero terminated) */
CHAR Name[0];
} __attribute__((packed)) KEY_CELL, *PKEY_CELL;
/* KEY_CELL.Type constants */
#define REG_LINK_KEY_CELL_TYPE 0x10
#define REG_KEY_NAME_PACKED 0x20
#define REG_ROOT_KEY_CELL_TYPE 0x0c
// hash record :
// HashValue=four letters of value's name
typedef struct _HASH_RECORD
{
BLOCK_OFFSET KeyOffset;
ULONG HashValue;
} __attribute__((packed)) HASH_RECORD, *PHASH_RECORD;
typedef struct _HASH_TABLE_CELL
{
LONG CellSize;
USHORT Id;
USHORT HashTableSize;
HASH_RECORD Table[0];
} __attribute__((packed)) HASH_TABLE_CELL, *PHASH_TABLE_CELL;
typedef struct _VALUE_LIST_CELL
{
LONG CellSize;
BLOCK_OFFSET ValueOffset[0];
} __attribute__((packed)) VALUE_LIST_CELL, *PVALUE_LIST_CELL;
typedef struct _VALUE_CELL
{
LONG CellSize;
USHORT Id; // "kv"
USHORT NameSize; // length of Name
ULONG DataSize; // length of datas in the cell pointed by DataOffset
BLOCK_OFFSET DataOffset;// datas are here if high bit of DataSize is set
ULONG DataType;
USHORT Flags;
USHORT Unused1;
CHAR Name[0]; /* warning : not zero terminated */
} __attribute__((packed)) VALUE_CELL, *PVALUE_CELL;
/* VALUE_CELL.Flags constants */
#define REG_VALUE_NAME_PACKED 0x0001
/* VALUE_CELL.DataSize mask constants */
#define REG_DATA_SIZE_MASK 0x7FFFFFFF
#define REG_DATA_IN_OFFSET 0x80000000
typedef struct _DATA_CELL
{
LONG CellSize;
CHAR Data[0];
} __attribute__((packed)) DATA_CELL, *PDATA_CELL;
typedef struct _REGISTRY_HIVE
{
ULONG FileSize;
PHIVE_HEADER HiveHeader;
ULONG BlockListSize;
PHBIN *BlockList;
ULONG FreeListSize;
ULONG FreeListMax;
PCELL_HEADER *FreeList;
BLOCK_OFFSET *FreeListOffset;
} REGISTRY_HIVE, *PREGISTRY_HIVE;
static PVOID MbBase = NULL;
static ULONG MbSize = 0;
/* FUNCTIONS ****************************************************************/
static VOID
InitMbMemory (PVOID ChunkBase)
{
MbBase = ChunkBase;
MbSize = 0;
}
static PVOID
AllocateMbMemory (ULONG MemSize)
{
PVOID CurBase;
CurBase = MbBase;
MbBase = (PVOID)((ULONG)MbBase + MemSize);
MbSize += MemSize;
return CurBase;
}
static VOID
FreeMbMemory (VOID)
{
MbSize = 0;
}
static ULONG
GetMbAllocatedSize (VOID)
{
return MbSize;
}
static VOID
CmiCreateDefaultHiveHeader (PHIVE_HEADER Header)
{
assert(Header);
memset (Header, 0, REG_BLOCK_SIZE);
Header->BlockId = REG_HIVE_ID;
Header->UpdateCounter1 = 0;
Header->UpdateCounter2 = 0;
Header->DateModified = 0;
Header->MajorVersion = 1;
Header->MinorVersion = 3;
Header->Type = 0;
Header->Format = 1;
Header->Unused7 = 1;
Header->RootKeyOffset = -1;
Header->BlockSize = REG_BLOCK_SIZE;
Header->Checksum = 0;
}
static VOID
CmiCreateDefaultBinCell (PHBIN BinCell)
{
assert(BinCell);
memset (BinCell, 0, REG_BLOCK_SIZE);
BinCell->HeaderId = REG_BIN_ID;
BinCell->DateModified = 0ULL;
BinCell->BinSize = REG_BLOCK_SIZE;
}
static VOID
CmiCreateDefaultRootKeyCell (PKEY_CELL RootKeyCell, PCWSTR KeyName)
{
PWCHAR BaseKeyName;
ULONG NameSize;
ULONG CellSize;
ULONG i;
BOOL Packable = TRUE;
assert (RootKeyCell);
BaseKeyName = wcsrchr(KeyName, L'\\') + 1;
NameSize = wcslen(BaseKeyName);
for (i = 0; i < NameSize; i++)
{
if (KeyName[i] & 0xFF00)
{
Packable = FALSE;
NameSize *= sizeof(WCHAR);
break;
}
}
CellSize = ROUND_UP(sizeof(KEY_CELL) + NameSize, 16);
memset (RootKeyCell, 0, CellSize);
RootKeyCell->CellSize = -CellSize;
RootKeyCell->Id = REG_KEY_CELL_ID;
RootKeyCell->Flags = REG_ROOT_KEY_CELL_TYPE;
RootKeyCell->LastWriteTime = 0ULL;
RootKeyCell->ParentKeyOffset = 0;
RootKeyCell->NumberOfSubKeys = 0;
RootKeyCell->HashTableOffset = -1;
RootKeyCell->NumberOfValues = 0;
RootKeyCell->ValueListOffset = -1;
RootKeyCell->SecurityKeyOffset = 0;
RootKeyCell->ClassNameOffset = -1;
RootKeyCell->NameSize = NameSize;
RootKeyCell->ClassSize = 0;
if (Packable)
{
for(i = 0; i < NameSize; i++)
{
((PCHAR)RootKeyCell->Name)[i] = BaseKeyName[i];
}
RootKeyCell->Flags |= REG_KEY_NAME_PACKED;
}
else
{
memcpy (RootKeyCell->Name, BaseKeyName, NameSize);
}
}
static PREGISTRY_HIVE
CmiCreateHive (PCWSTR KeyName)
{
PREGISTRY_HIVE Hive;
PCELL_HEADER FreeCell;
PKEY_CELL RootKeyCell;
PHBIN BinCell;
Hive = (PREGISTRY_HIVE) MmAllocateMemory (sizeof(REGISTRY_HIVE));
if (Hive == NULL)
{
return NULL;
}
memset (Hive, 0, sizeof(REGISTRY_HIVE));
DbgPrint((DPRINT_REGISTRY, "Hive %x\n", Hive));
/* Create hive beader (aka 'base block') */
Hive->HiveHeader = (PHIVE_HEADER) AllocateMbMemory (REG_BLOCK_SIZE);
if (Hive->HiveHeader == NULL)
{
MmFreeMemory (Hive);
return NULL;
}
CmiCreateDefaultHiveHeader(Hive->HiveHeader);
Hive->FileSize = REG_BLOCK_SIZE;
/* Allocate block list */
Hive->BlockListSize = 1;
Hive->BlockList = MmAllocateMemory (sizeof(PHBIN) * Hive->BlockListSize);
if (Hive->BlockList == NULL)
{
MmFreeMemory (Hive);
return NULL;
}
/* Allocate free cell list */
Hive->FreeListMax = 32;
Hive->FreeList = MmAllocateMemory(sizeof(PCELL_HEADER) * Hive->FreeListMax);
if (Hive->FreeList == NULL)
{
MmFreeMemory (Hive->BlockList);
MmFreeMemory (Hive);
return NULL;
}
Hive->FreeListOffset = MmAllocateMemory(sizeof(BLOCK_OFFSET) * Hive->FreeListMax);
if (Hive->FreeListOffset == NULL)
{
MmFreeMemory (Hive->FreeList);
MmFreeMemory (Hive->BlockList);
MmFreeMemory (Hive);
return NULL;
}
/* Allocate first bin */
Hive->BlockList[0] = (PHBIN) AllocateMbMemory (REG_BLOCK_SIZE);
if (Hive->BlockList[0] == NULL)
{
MmFreeMemory (Hive->FreeListOffset);
MmFreeMemory (Hive->FreeList);
MmFreeMemory (Hive->BlockList);
MmFreeMemory (Hive);
return NULL;
}
Hive->FileSize += REG_BLOCK_SIZE;
/* Init first bin */
BinCell = (PHBIN)Hive->BlockList[0];
CmiCreateDefaultBinCell(BinCell);
BinCell->BinOffset = 0;
/* Init root key cell */
RootKeyCell = (PKEY_CELL)((ULONG)BinCell + REG_HBIN_DATA_OFFSET);
CmiCreateDefaultRootKeyCell(RootKeyCell, KeyName);
Hive->HiveHeader->RootKeyOffset = REG_HBIN_DATA_OFFSET;
/* Init free cell */
FreeCell = (PCELL_HEADER)((ULONG)RootKeyCell - RootKeyCell->CellSize);
FreeCell->CellSize = REG_BLOCK_SIZE - (REG_HBIN_DATA_OFFSET - RootKeyCell->CellSize);
Hive->FreeList[0] = FreeCell;
Hive->FreeListOffset[0] = REG_HBIN_DATA_OFFSET - RootKeyCell->CellSize;
Hive->FreeListSize++;
return Hive;
}
static VOID
CmiCleanupHive(PREGISTRY_HIVE Hive, BOOL Release)
{
MmFreeMemory (Hive->FreeListOffset);
MmFreeMemory (Hive->FreeList);
MmFreeMemory (Hive->BlockList);
MmFreeMemory (Hive);
if (Release)
{
FreeMbMemory ();
}
}
static PHBIN
CmiGetBin (PREGISTRY_HIVE Hive,
BLOCK_OFFSET BlockOffset)
{
ULONG BlockIndex;
if (BlockOffset == (ULONG) -1)
return NULL;
BlockIndex = BlockOffset / REG_BLOCK_SIZE;
if (BlockIndex >= Hive->BlockListSize)
return NULL;
return Hive->BlockList[BlockIndex];
}
static BOOL
CmiMergeFree(PREGISTRY_HIVE RegistryHive,
PCELL_HEADER FreeBlock,
BLOCK_OFFSET FreeOffset)
{
BLOCK_OFFSET BlockOffset;
BLOCK_OFFSET BinOffset;
ULONG BlockSize;
ULONG BinSize;
PHBIN Bin;
ULONG i;
DbgPrint((DPRINT_REGISTRY, "CmiMergeFree(Block %lx Offset %lx Size %lx) called\n",
FreeBlock, FreeOffset, FreeBlock->CellSize));
Bin = CmiGetBin (RegistryHive, FreeOffset);
if (Bin == NULL)
return FALSE;
DbgPrint((DPRINT_REGISTRY, "Bin %p\n", Bin));
BinOffset = Bin->BinOffset;
BinSize = Bin->BinSize;
DbgPrint((DPRINT_REGISTRY, "Bin %p Offset %lx Size %lx\n", Bin, BinOffset, BinSize));
for (i = 0; i < RegistryHive->FreeListSize; i++)
{
BlockOffset = RegistryHive->FreeListOffset[i];
BlockSize = RegistryHive->FreeList[i]->CellSize;
if (BlockOffset > BinOffset &&
BlockOffset < BinOffset + BinSize)
{
DbgPrint((DPRINT_REGISTRY, "Free block: Offset %lx Size %lx\n",
BlockOffset, BlockSize));
if ((i < (RegistryHive->FreeListSize - 1)) &&
(BlockOffset + BlockSize == FreeOffset) &&
(FreeOffset + FreeBlock->CellSize == RegistryHive->FreeListOffset[i + 1]))
{
DbgPrint((DPRINT_REGISTRY, "Merge current block with previous and next block\n"));
RegistryHive->FreeList[i]->CellSize +=
(FreeBlock->CellSize + RegistryHive->FreeList[i + 1]->CellSize);
FreeBlock->CellSize = 0;
RegistryHive->FreeList[i + 1]->CellSize = 0;
if ((i + 2) < RegistryHive->FreeListSize)
{
memmove (&RegistryHive->FreeList[i + 1],
&RegistryHive->FreeList[i + 2],
sizeof(RegistryHive->FreeList[0])
* (RegistryHive->FreeListSize - i - 2));
memmove (&RegistryHive->FreeListOffset[i + 1],
&RegistryHive->FreeListOffset[i + 2],
sizeof(RegistryHive->FreeListOffset[0])
* (RegistryHive->FreeListSize - i - 2));
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?