Exemple #1
0
_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;
}
Exemple #2
0
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;
}
Exemple #3
0
_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(&registryKeyHandle, 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;
}
Exemple #4
0
_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;
}