VOID CMAPI HvpFreeHiveBins( PHHIVE Hive) { ULONG i; PHBIN Bin; ULONG Storage; for (Storage = Stable; Storage < HTYPE_COUNT; Storage++) { Bin = NULL; for (i = 0; i < Hive->Storage[Storage].Length; i++) { if (Hive->Storage[Storage].BlockList[i].BinAddress == (ULONG_PTR)NULL) continue; if (Hive->Storage[Storage].BlockList[i].BinAddress != (ULONG_PTR)Bin) { Bin = (PHBIN)Hive->Storage[Storage].BlockList[i].BinAddress; Hive->Free((PHBIN)Hive->Storage[Storage].BlockList[i].BinAddress, 0); } Hive->Storage[Storage].BlockList[i].BinAddress = (ULONG_PTR)NULL; Hive->Storage[Storage].BlockList[i].BlockAddress = (ULONG_PTR)NULL; } if (Hive->Storage[Storage].Length) Hive->Free(Hive->Storage[Storage].BlockList, 0); } }
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; }
VOID CMAPI HvFree( PHHIVE RegistryHive) { if (!RegistryHive->ReadOnly) { /* Release hive bitmap */ if (RegistryHive->DirtyVector.Buffer) { RegistryHive->Free(RegistryHive->DirtyVector.Buffer, 0); } HvpFreeHiveBins(RegistryHive); /* Free the BaseBlock */ if (RegistryHive->BaseBlock) { RegistryHive->Free(RegistryHive->BaseBlock, 0); RegistryHive->BaseBlock = NULL; } } }
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; }
NTSTATUS CMAPI HvpInitializeMemoryHive( PHHIVE Hive, PVOID ChunkBase) { SIZE_T BlockIndex; PHBIN Bin, NewBin; ULONG i; ULONG BitmapSize; PULONG BitmapBuffer; SIZE_T ChunkSize; ChunkSize = ((PHBASE_BLOCK)ChunkBase)->Length; DPRINT("ChunkSize: %lx\n", ChunkSize); if (ChunkSize < sizeof(HBASE_BLOCK) || !HvpVerifyHiveHeader((PHBASE_BLOCK)ChunkBase)) { DPRINT1("Registry is corrupt: ChunkSize %lu < sizeof(HBASE_BLOCK) %lu, " "or HvpVerifyHiveHeader() failed\n", ChunkSize, (SIZE_T)sizeof(HBASE_BLOCK)); return STATUS_REGISTRY_CORRUPT; } Hive->BaseBlock = Hive->Allocate(sizeof(HBASE_BLOCK), FALSE, TAG_CM); if (Hive->BaseBlock == NULL) { return STATUS_NO_MEMORY; } RtlCopyMemory(Hive->BaseBlock, ChunkBase, sizeof(HBASE_BLOCK)); /* * Build a block list from the in-memory chunk and copy the data as * we go. */ Hive->Storage[Stable].Length = (ULONG)(ChunkSize / HV_BLOCK_SIZE); Hive->Storage[Stable].BlockList = Hive->Allocate(Hive->Storage[Stable].Length * sizeof(HMAP_ENTRY), FALSE, TAG_CM); if (Hive->Storage[Stable].BlockList == NULL) { DPRINT1("Allocating block list failed\n"); Hive->Free(Hive->BaseBlock, 0); return STATUS_NO_MEMORY; } for (BlockIndex = 0; BlockIndex < Hive->Storage[Stable].Length; ) { Bin = (PHBIN)((ULONG_PTR)ChunkBase + (BlockIndex + 1) * HV_BLOCK_SIZE); if (Bin->Signature != HV_BIN_SIGNATURE || (Bin->Size % HV_BLOCK_SIZE) != 0) { DPRINT1("Invalid bin at BlockIndex %lu, Signature 0x%x, Size 0x%x\n", (unsigned long)BlockIndex, (unsigned)Bin->Signature, (unsigned)Bin->Size); Hive->Free(Hive->BaseBlock, 0); Hive->Free(Hive->Storage[Stable].BlockList, 0); return STATUS_REGISTRY_CORRUPT; } NewBin = Hive->Allocate(Bin->Size, TRUE, TAG_CM); if (NewBin == NULL) { Hive->Free(Hive->BaseBlock, 0); Hive->Free(Hive->Storage[Stable].BlockList, 0); return STATUS_NO_MEMORY; } Hive->Storage[Stable].BlockList[BlockIndex].BinAddress = (ULONG_PTR)NewBin; Hive->Storage[Stable].BlockList[BlockIndex].BlockAddress = (ULONG_PTR)NewBin; RtlCopyMemory(NewBin, Bin, Bin->Size); if (Bin->Size > HV_BLOCK_SIZE) { for (i = 1; i < Bin->Size / HV_BLOCK_SIZE; i++) { Hive->Storage[Stable].BlockList[BlockIndex + i].BinAddress = (ULONG_PTR)NewBin; Hive->Storage[Stable].BlockList[BlockIndex + i].BlockAddress = ((ULONG_PTR)NewBin + (i * HV_BLOCK_SIZE)); } } BlockIndex += Bin->Size / HV_BLOCK_SIZE; } if (HvpCreateHiveFreeCellList(Hive)) { HvpFreeHiveBins(Hive); Hive->Free(Hive->BaseBlock, 0); return STATUS_NO_MEMORY; } BitmapSize = ROUND_UP(Hive->Storage[Stable].Length, sizeof(ULONG) * 8) / 8; BitmapBuffer = (PULONG)Hive->Allocate(BitmapSize, TRUE, TAG_CM); if (BitmapBuffer == NULL) { HvpFreeHiveBins(Hive); Hive->Free(Hive->BaseBlock, 0); return STATUS_NO_MEMORY; } RtlInitializeBitMap(&Hive->DirtyVector, BitmapBuffer, BitmapSize * 8); RtlClearAllBits(&Hive->DirtyVector); return STATUS_SUCCESS; }