BOOLEAN CMAPI HvpVerifyHiveHeader( PHBASE_BLOCK BaseBlock) { if (BaseBlock->Signature != HV_SIGNATURE || BaseBlock->Major != HSYS_MAJOR || BaseBlock->Minor < HSYS_MINOR || BaseBlock->Type != HFILE_TYPE_PRIMARY || BaseBlock->Format != HBASE_FORMAT_MEMORY || BaseBlock->Cluster != 1 || BaseBlock->Sequence1 != BaseBlock->Sequence2 || HvpHiveHeaderChecksum(BaseBlock) != BaseBlock->CheckSum) { DPRINT1("Verify Hive Header failed: \n"); DPRINT1(" Signature: 0x%x, expected 0x%x; Major: 0x%x, expected 0x%x\n", BaseBlock->Signature, HV_SIGNATURE, BaseBlock->Major, HSYS_MAJOR); DPRINT1(" Minor: 0x%x is not >= 0x%x; Type: 0x%x, expected 0x%x\n", BaseBlock->Minor, HSYS_MINOR, BaseBlock->Type, HFILE_TYPE_PRIMARY); DPRINT1(" Format: 0x%x, expected 0x%x; Cluster: 0x%x, expected 1\n", BaseBlock->Format, HBASE_FORMAT_MEMORY, BaseBlock->Cluster); DPRINT1(" Sequence: 0x%x, expected 0x%x; Checksum: 0x%x, expected 0x%x\n", BaseBlock->Sequence1, BaseBlock->Sequence2, HvpHiveHeaderChecksum(BaseBlock), BaseBlock->CheckSum); return FALSE; } return TRUE; }
NTSTATUS CMAPI HvpCreateHive( PHHIVE RegistryHive, PCUNICODE_STRING FileName OPTIONAL) { PHBASE_BLOCK BaseBlock; ULONG Index; BaseBlock = RegistryHive->Allocate(sizeof(HBASE_BLOCK), FALSE, TAG_CM); if (BaseBlock == NULL) return STATUS_NO_MEMORY; RtlZeroMemory(BaseBlock, sizeof(HBASE_BLOCK)); BaseBlock->Signature = HV_SIGNATURE; BaseBlock->Major = HSYS_MAJOR; BaseBlock->Minor = HSYS_MINOR; BaseBlock->Type = HFILE_TYPE_PRIMARY; BaseBlock->Format = HBASE_FORMAT_MEMORY; BaseBlock->Cluster = 1; BaseBlock->RootCell = HCELL_NIL; BaseBlock->Length = 0; BaseBlock->Sequence1 = 1; BaseBlock->Sequence2 = 1; /* Copy the 31 last characters of the hive file name if any */ if (FileName) { if (FileName->Length / sizeof(WCHAR) <= HIVE_FILENAME_MAXLEN) { RtlCopyMemory(BaseBlock->FileName, FileName->Buffer, FileName->Length); } else { RtlCopyMemory(BaseBlock->FileName, FileName->Buffer + FileName->Length / sizeof(WCHAR) - HIVE_FILENAME_MAXLEN, HIVE_FILENAME_MAXLEN * sizeof(WCHAR)); } /* NULL-terminate */ BaseBlock->FileName[HIVE_FILENAME_MAXLEN] = L'\0'; } BaseBlock->CheckSum = HvpHiveHeaderChecksum(BaseBlock); RegistryHive->BaseBlock = BaseBlock; for (Index = 0; Index < 24; Index++) { RegistryHive->Storage[Stable].FreeDisplay[Index] = HCELL_NIL; RegistryHive->Storage[Volatile].FreeDisplay[Index] = HCELL_NIL; } return STATUS_SUCCESS; }
BOOLEAN HvIsInPlaceBaseBlockValid ( _In_ PHBASE_BLOCK BaseBlock ) { ULONG HiveLength, HeaderSum; BOOLEAN Valid; /* Assume failure */ Valid = FALSE; /* Check for incorrect signature, type, version, or format */ if ((BaseBlock->Signature == 'fger') && (BaseBlock->Type == 0) && (BaseBlock->Major <= 1) && (BaseBlock->Minor <= 5) && (BaseBlock->Minor >= 3) && (BaseBlock->Format == 1)) { /* Check for invalid hive size */ HiveLength = BaseBlock->Length; if (HiveLength) { /* Check for misaligned or too large hive size */ if (!(HiveLength & 0xFFF) && HiveLength <= 0x7FFFE000) { /* Check for invalid header checksum */ HeaderSum = HvpHiveHeaderChecksum(BaseBlock); if (HeaderSum == BaseBlock->CheckSum) { /* All good */ Valid = TRUE; } } } } /* Return validity */ return Valid; }
static BOOLEAN CMAPI HvpWriteHive( PHHIVE RegistryHive, BOOLEAN OnlyDirty) { ULONG FileOffset; ULONG BlockIndex; ULONG LastIndex; PVOID BlockPtr; BOOLEAN Success; ASSERT(RegistryHive->ReadOnly == FALSE); ASSERT(RegistryHive->BaseBlock->Length == RegistryHive->Storage[Stable].Length * HV_BLOCK_SIZE); DPRINT("HvpWriteHive called\n"); if (RegistryHive->BaseBlock->Sequence1 != RegistryHive->BaseBlock->Sequence2) { return FALSE; } /* Update first update counter and CheckSum */ RegistryHive->BaseBlock->Type = HFILE_TYPE_PRIMARY; RegistryHive->BaseBlock->Sequence1++; RegistryHive->BaseBlock->CheckSum = HvpHiveHeaderChecksum(RegistryHive->BaseBlock); /* Write hive block */ FileOffset = 0; Success = RegistryHive->FileWrite(RegistryHive, HFILE_TYPE_PRIMARY, &FileOffset, RegistryHive->BaseBlock, sizeof(HBASE_BLOCK)); if (!Success) { return FALSE; } BlockIndex = 0; while (BlockIndex < RegistryHive->Storage[Stable].Length) { if (OnlyDirty) { LastIndex = BlockIndex; BlockIndex = RtlFindSetBits(&RegistryHive->DirtyVector, 1, BlockIndex); if (BlockIndex == ~0U || BlockIndex < LastIndex) { break; } } BlockPtr = (PVOID)RegistryHive->Storage[Stable].BlockList[BlockIndex].BlockAddress; FileOffset = (BlockIndex + 1) * HV_BLOCK_SIZE; /* Write hive block */ Success = RegistryHive->FileWrite(RegistryHive, HFILE_TYPE_PRIMARY, &FileOffset, BlockPtr, HV_BLOCK_SIZE); if (!Success) { return FALSE; } BlockIndex++; } Success = RegistryHive->FileFlush(RegistryHive, HFILE_TYPE_PRIMARY, NULL, 0); if (!Success) { DPRINT("FileFlush failed\n"); } /* Update second update counter and CheckSum */ RegistryHive->BaseBlock->Sequence2++; RegistryHive->BaseBlock->CheckSum = HvpHiveHeaderChecksum(RegistryHive->BaseBlock); /* Write hive block */ FileOffset = 0; Success = RegistryHive->FileWrite(RegistryHive, HFILE_TYPE_PRIMARY, &FileOffset, RegistryHive->BaseBlock, sizeof(HBASE_BLOCK)); if (!Success) { return FALSE; } Success = RegistryHive->FileFlush(RegistryHive, HFILE_TYPE_PRIMARY, NULL, 0); if (!Success) { DPRINT("FileFlush failed\n"); } return TRUE; }
static BOOLEAN CMAPI HvpWriteLog( PHHIVE RegistryHive) { ULONG FileOffset; ULONG BufferSize; ULONG BitmapSize; PUCHAR Buffer; PUCHAR Ptr; ULONG BlockIndex; ULONG LastIndex; PVOID BlockPtr; BOOLEAN Success; UNIMPLEMENTED; return TRUE; ASSERT(RegistryHive->ReadOnly == FALSE); ASSERT(RegistryHive->BaseBlock->Length == RegistryHive->Storage[Stable].Length * HV_BLOCK_SIZE); DPRINT("HvpWriteLog called\n"); if (RegistryHive->BaseBlock->Sequence1 != RegistryHive->BaseBlock->Sequence2) { return FALSE; } BitmapSize = RegistryHive->DirtyVector.SizeOfBitMap; BufferSize = HV_LOG_HEADER_SIZE + sizeof(ULONG) + BitmapSize; BufferSize = ROUND_UP(BufferSize, HV_BLOCK_SIZE); DPRINT("Bitmap size %lu buffer size: %lu\n", BitmapSize, BufferSize); Buffer = RegistryHive->Allocate(BufferSize, TRUE, TAG_CM); if (Buffer == NULL) { return FALSE; } /* Update first update counter and CheckSum */ RegistryHive->BaseBlock->Type = HFILE_TYPE_LOG; RegistryHive->BaseBlock->Sequence1++; RegistryHive->BaseBlock->CheckSum = HvpHiveHeaderChecksum(RegistryHive->BaseBlock); /* Copy hive header */ RtlCopyMemory(Buffer, RegistryHive->BaseBlock, HV_LOG_HEADER_SIZE); Ptr = Buffer + HV_LOG_HEADER_SIZE; RtlCopyMemory(Ptr, "DIRT", 4); Ptr += 4; RtlCopyMemory(Ptr, RegistryHive->DirtyVector.Buffer, BitmapSize); /* Write hive block and block bitmap */ FileOffset = 0; Success = RegistryHive->FileWrite(RegistryHive, HFILE_TYPE_LOG, &FileOffset, Buffer, BufferSize); RegistryHive->Free(Buffer, 0); if (!Success) { return FALSE; } /* Write dirty blocks */ FileOffset = BufferSize; BlockIndex = 0; while (BlockIndex < RegistryHive->Storage[Stable].Length) { LastIndex = BlockIndex; BlockIndex = RtlFindSetBits(&RegistryHive->DirtyVector, 1, BlockIndex); if (BlockIndex == ~0U || BlockIndex < LastIndex) { break; } BlockPtr = (PVOID)RegistryHive->Storage[Stable].BlockList[BlockIndex].BlockAddress; /* Write hive block */ Success = RegistryHive->FileWrite(RegistryHive, HFILE_TYPE_LOG, &FileOffset, BlockPtr, HV_BLOCK_SIZE); if (!Success) { return FALSE; } BlockIndex++; FileOffset += HV_BLOCK_SIZE; } Success = RegistryHive->FileSetSize(RegistryHive, HFILE_TYPE_LOG, FileOffset, FileOffset); if (!Success) { DPRINT("FileSetSize failed\n"); return FALSE; } /* Flush the log file */ Success = RegistryHive->FileFlush(RegistryHive, HFILE_TYPE_LOG, NULL, 0); if (!Success) { DPRINT("FileFlush failed\n"); } /* Update second update counter and CheckSum. */ RegistryHive->BaseBlock->Sequence2++; RegistryHive->BaseBlock->CheckSum = HvpHiveHeaderChecksum(RegistryHive->BaseBlock); /* Write hive header again with updated sequence counter. */ FileOffset = 0; Success = RegistryHive->FileWrite(RegistryHive, HFILE_TYPE_LOG, &FileOffset, RegistryHive->BaseBlock, HV_LOG_HEADER_SIZE); if (!Success) { return FALSE; } /* Flush the log file */ Success = RegistryHive->FileFlush(RegistryHive, HFILE_TYPE_LOG, NULL, 0); if (!Success) { DPRINT("FileFlush failed\n"); } return TRUE; }