_Check_return_ NTSTATUS LcGetRegistryValueDWord( _In_ PUNICODE_STRING RegistryPath, _In_ PUNICODE_STRING RegistryValueName, _Out_ PULONG Value ) /*++ Summary: This function reads a REG_DWORD value from the path given. Arguments: RegistryPath - Path to the registry value to be read. RegistryValueName - Registry value name, which value to read. Value - A pointer to a ULONG variable that receives the DWORD value read. Return value: The return value is the status of the operation. --*/ { NTSTATUS status = STATUS_SUCCESS; PKEY_VALUE_PARTIAL_INFORMATION valueBuffer = NULL; PAGED_CODE(); // Other parameters will be validated in the 'LcGetRegistryValue' function. IF_FALSE_RETURN_RESULT(Value != NULL, STATUS_INVALID_PARAMETER_3); __try { NT_IF_FAIL_LEAVE(LcGetRegistryValue(RegistryPath, RegistryValueName, &valueBuffer)); // We are expecting a DWORD value. NT_IF_FALSE_LEAVE(valueBuffer->Type == REG_DWORD, STATUS_INVALID_PARAMETER); *Value = *(PULONG)&valueBuffer->Data; } __finally { if (valueBuffer != NULL) { LcFreeNonPagedBuffer(valueBuffer); } } return status; }
NTSTATUS LcFetchRemoteFile ( _In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ PUNICODE_STRING SourceFile, _In_ PUNICODE_STRING TargetFile, _In_ BOOLEAN UseCustomHandler, _Out_ PLARGE_INTEGER BytesCopied ) /*++ Summary: This function copies the remote file content to the current file object. In order for the remote file to be fetched, make sure that the network redirector device is used, i.e. the 'SourceFile' root points to the '\Device\Mup\<path>'. Arguments: FltObjects - Pointer to the 'FLT_RELATED_OBJECTS' data structure containing opaque handles to this filter, instance, its associated volume and file object. SourceFile - Path to the file to fetch content from. TargetFile - Path to the file to store content to. UseCustomHandler - Whether the file should be fetched by the user-mode client. BytesCopied - The amount of bytes copied. Return Value: The return value is the status of the operation. --*/ { NTSTATUS status = STATUS_SUCCESS; HANDLE sourceFileHandle = NULL; IO_STATUS_BLOCK statusBlock = { 0 }; FILE_STANDARD_INFORMATION standardInfo = { 0 }; FILE_END_OF_FILE_INFORMATION eofInfo = { 0 }; PAGED_CODE(); IF_FALSE_RETURN_RESULT(FltObjects != NULL, STATUS_INVALID_PARAMETER_1); IF_FALSE_RETURN_RESULT(SourceFile != NULL, STATUS_INVALID_PARAMETER_2); IF_FALSE_RETURN_RESULT(TargetFile != NULL, STATUS_INVALID_PARAMETER_3); IF_FALSE_RETURN_RESULT(BytesCopied != NULL, STATUS_INVALID_PARAMETER_5); FLT_ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); *BytesCopied = RtlConvertLongToLargeInteger(0); __try { LOG((DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL, "[LazyCopy] Fetching content from: '%wZ' -> '%wZ'\n", SourceFile, TargetFile)); if (UseCustomHandler) { NT_IF_FAIL_LEAVE(LcFetchFileInUserMode(SourceFile, TargetFile, BytesCopied)); } else { // // Open the source file and make sure it's not empty. // NT_IF_FAIL_LEAVE(LcOpenFile(SourceFile, TargetFile, &sourceFileHandle)); NT_IF_FAIL_LEAVE(ZwQueryInformationFile(sourceFileHandle, &statusBlock, &standardInfo, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation)); if (standardInfo.EndOfFile.QuadPart == 0) { // No need to copy an empty file. __leave; } // Extend the target file, so all readers that wait for the content to be copied will get the actual file size information. // Remote file system may return incorrect information, but we are doing it only for the cases, when multiple threads // try to access the same file, while we are fetching it. eofInfo.EndOfFile.QuadPart = standardInfo.EndOfFile.QuadPart; NT_IF_FAIL_LEAVE(FltSetInformationFile(FltObjects->Instance, FltObjects->FileObject, &eofInfo, sizeof(eofInfo), FileEndOfFileInformation)); // // Copy source file contents into the local (target) file. // NT_IF_FAIL_LEAVE(LcFetchFileByChunks( FltObjects, sourceFileHandle, &standardInfo.EndOfFile, BytesCopied)); } } __finally { if (sourceFileHandle != NULL) { ZwClose(sourceFileHandle); } } return status; }
_Check_return_ NTSTATUS LcGetRegistryValue( _In_ PUNICODE_STRING RegistryPath, _In_ PUNICODE_STRING RegistryValueName, _Outptr_ PKEY_VALUE_PARTIAL_INFORMATION* ValueBuffer ) /*++ Summary: This function retrieves the registry value from the path given. Caller should free the 'ValueBuffer' received using the 'LcFreeNonPagedBuffer' function. Arguments: RegistryPath - Path from where the registry value should be read. RegistryValueName - Name of the registry value to read. ValueBuffer - A pointer to a variable that receives the value content. Return value: The return value is the status of the operation. --*/ { NTSTATUS status = STATUS_SUCCESS; // Registry key handle. HANDLE registryKeyHandle = NULL; OBJECT_ATTRIBUTES attributes = { 0 }; // Buffer to read the value data into. PKEY_VALUE_PARTIAL_INFORMATION valueBuffer = NULL; ULONG valueLength = 0; PAGED_CODE(); IF_FALSE_RETURN_RESULT(NT_SUCCESS(RtlUnicodeStringValidate(RegistryPath)), STATUS_INVALID_PARAMETER_1); IF_FALSE_RETURN_RESULT(RegistryPath->Buffer != NULL, STATUS_INVALID_PARAMETER_1); IF_FALSE_RETURN_RESULT(NT_SUCCESS(RtlUnicodeStringValidate(RegistryValueName)), STATUS_INVALID_PARAMETER_2); IF_FALSE_RETURN_RESULT(RegistryValueName->Buffer != NULL, STATUS_INVALID_PARAMETER_2); IF_FALSE_RETURN_RESULT(ValueBuffer != NULL, STATUS_INVALID_PARAMETER_3); __try { // Open the registry key given. InitializeObjectAttributes(&attributes, RegistryPath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); NT_IF_FAIL_LEAVE(ZwOpenKey(®istryKeyHandle, KEY_READ, &attributes)); // Get the length of the value for proper buffer allocation. status = ZwQueryValueKey(registryKeyHandle, RegistryValueName, KeyValuePartialInformation, NULL, 0, &valueLength); if (status != STATUS_BUFFER_TOO_SMALL && status != STATUS_BUFFER_OVERFLOW) { status = STATUS_INVALID_PARAMETER; __leave; } // Allocate buffer and read value into it. NT_IF_FAIL_LEAVE(LcAllocateNonPagedBuffer((PVOID*)&valueBuffer, valueLength)); NT_IF_FAIL_LEAVE(ZwQueryValueKey(registryKeyHandle, RegistryValueName, KeyValuePartialInformation, valueBuffer, valueLength, &valueLength)); // Set the output value and set the 'valueBuffer' to NULL, so it won't be freed in the __finally block. *ValueBuffer = valueBuffer; valueBuffer = NULL; } __finally { if (registryKeyHandle != NULL) { ZwClose(registryKeyHandle); } if (valueBuffer != NULL) { LcFreeNonPagedBuffer(valueBuffer); } } return status; }
_Check_return_ NTSTATUS LcGetRegistryValueString( _In_ PUNICODE_STRING RegistryPath, _In_ PUNICODE_STRING RegistryValueName, _Out_ PUNICODE_STRING Value ) /*++ Summary: This function reads REG_MULTI_SZ or REG_SZ value from the path given. Caller should manually free the string received using the 'LcFreeUnicodeString' function. Arguments: RegistryPath - Path to the registry value to be read. RegistryValueName - Registry value name, which value to read. Value - A pointer to a unicode string that receives the value. Return value: The return value is the status of the operation. --*/ { NTSTATUS status = STATUS_SUCCESS; PKEY_VALUE_PARTIAL_INFORMATION valueBuffer = NULL; UNICODE_STRING string = { 0 }; PAGED_CODE(); // Other parameters will be validated in the 'LcGetRegistryValue' function. IF_FALSE_RETURN_RESULT(Value != NULL, STATUS_INVALID_PARAMETER_3); __try { NT_IF_FAIL_LEAVE(LcGetRegistryValue(RegistryPath, RegistryValueName, &valueBuffer)); // We are expecting REG_MULTI_SZ or REG_SZ value. NT_IF_FALSE_LEAVE(valueBuffer->Type == REG_MULTI_SZ || valueBuffer->Type == REG_SZ, STATUS_INVALID_PARAMETER); // Allocate internal string buffer and copy the value there. NT_IF_FAIL_LEAVE(LcAllocateUnicodeString(&string, (USHORT)valueBuffer->DataLength)); __analysis_assume(string.Buffer != NULL); RtlCopyMemory(string.Buffer, &valueBuffer->Data, valueBuffer->DataLength); string.Length = (USHORT)valueBuffer->DataLength - sizeof(WCHAR); // Set the output value and set the 'string.Buffer' to NULL, so it won't be freed in the __finally block. *Value = string; string.Buffer = NULL; } __finally { if (valueBuffer != NULL) { LcFreeNonPagedBuffer(valueBuffer); } if (string.Buffer != NULL) { LcFreeUnicodeString(&string); } } return status; }