Unexpected behavior with driver's pre-op callbacks

0

I'm currently developing a driver, and one of its functions is to protect registry values from being modified by users. I'm following the guidelines in this post to create a Registry Filter. Things went pretty fine, expect that it sometimes causes the system to crash

Here are parts of the code of the filter. If it detects an attempt to modify registry's value that does not come from the defined path, the operation will be blocked.

  • For registering callback functions:
PEX_CALLBACK_FUNCTION g_RegistryCallbackTable[MaxRegNtNotifyClass] = { 0 };
...
g_RegistryCallbackTable[RegNtPreRenameKey] = (PEX_CALLBACK_FUNCTION)RfPreRenameKey;
    g_RegistryCallbackTable[RegNtPreSetValueKey] = (PEX_CALLBACK_FUNCTION)RfPreSetValueKeyEx;
    g_RegistryCallbackTable[RegNtPreDeleteKey] = (PEX_CALLBACK_FUNCTION)RfPreDeleteKeyEx;
    g_RegistryCallbackTable[RegNtPreDeleteValueKey] = (PEX_CALLBACK_FUNCTION)RfPreDeleteValueKeyEx;
  • Callback functions
NTSTATUS RfRegistryCallback(__in PVOID CallbackContext, __in PVOID Argument1, __in PVOID Argument2)
{
    UNREFERENCED_PARAMETER(CallbackContext);
    UNREFERENCED_PARAMETER(Argument2);

    REG_NOTIFY_CLASS Operation = (REG_NOTIFY_CLASS)(ULONG_PTR)Argument1;
    if (!g_RegistryCallbackTable[Operation] || MY_DIR[0] == 'T')
    {
        return STATUS_SUCCESS;
    }
    return g_RegistryCallbackTable[Operation](CallbackContext, Argument1, Argument2);
}

NTSTATUS RfPreRenameKey(__in PVOID CallbackContext, __in PVOID Argument1, __in PREG_RENAME_KEY_INFORMATION CallbackData)
{
    UNREFERENCED_PARAMETER(CallbackContext);
    UNREFERENCED_PARAMETER(Argument1);
    return RfRegistryCallbackHelper(CallbackData->Object);
}

NTSTATUS RfPreSetValueKeyEx(__in PVOID CallbackContext, __in PVOID Argument1, __in PREG_SET_VALUE_KEY_INFORMATION CallbackData) {
    UNREFERENCED_PARAMETER(CallbackContext);
    UNREFERENCED_PARAMETER(Argument1);
    return RfRegistryCallbackHelper(CallbackData->Object);
}

NTSTATUS RfPreDeleteKeyEx(__in PVOID CallbackContext, __in PVOID Argument1, __in PREG_DELETE_KEY_INFORMATION CallbackData)
{
    UNREFERENCED_PARAMETER(CallbackContext);
    UNREFERENCED_PARAMETER(Argument1);
    return RfRegistryCallbackHelper(CallbackData->Object);
}

NTSTATUS RfPreDeleteValueKeyEx(__in PVOID CallbackContext, __in PVOID Argument1, __in PREG_DELETE_VALUE_KEY_INFORMATION CallbackData)
{
    UNREFERENCED_PARAMETER(CallbackContext);
    UNREFERENCED_PARAMETER(Argument1);
    return RfRegistryCallbackHelper(CallbackData->Object);
}

NTSTATUS RfRegistryCallbackHelper(__in PVOID CallBackDataObj) {

    NTSTATUS status = STATUS_SUCCESS;
    PCUNICODE_STRING pObjectName;
    status = CmCallbackGetKeyObjectID(&g_CmCookie, CallBackDataObj, NULL, &pObjectName);
    
    UNICODE_STRING UnicodeObjectName;
    RtlInitUnicodeString(&UnicodeObjectName, pObjectName->Buffer);


    if (CompareWcharWithUniStr(MY_KERNEL_REG_SVC_PATH, &UnicodeObjectName)) {
        goto BlockOper;
    }


    if (CompareWcharWithUniStr(MY_USER_REG_SVC_PATH, &UnicodeObjectName)) {
        if (isBlockUserSvcReg) {
            goto BlockOper;
        }
        return status;
    }
    goto NormalOper;

BlockOper:
    // block the operation
    DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "Driver: Modifying value in %wZ being denied!\r\n", &UnicodeObjectName);
    status = STATUS_ACCESS_DENIED;

NormalOper:
    return status;
}

When I analyze the bug with WinDbg, I notice that the errors often raise when some application try to modify or delete value/fields in registry. However, this happens occasionally, not everytime when other program do this unexpected behavior. Therefore, it's very difficult to determine exactly what happened.

Here is a sample checklog from WinDbg. It varies everytime the bug appears, but always stuck here:

*******************************************************************************
*                                                                             *
*                        Bugcheck Analysis                                    *
*                                                                             *
*******************************************************************************

PAGE_FAULT_IN_NONPAGED_AREA (50)
Invalid system memory was referenced.  This cannot be protected by try-except.
Typically the address is just plain bad or it is pointing at freed memory.
Arguments:
Arg1: ffffae05a4bfb000, memory referenced.
Arg2: 0000000000000000, value 0 = read operation, 1 = write operation.
Arg3: fffff80126e06473, If non-zero, the instruction address which referenced the bad memory
    address.
Arg4: 0000000000000000, (reserved)

Debugging Details:
------------------


KEY_VALUES_STRING: 1

    Key  : Analysis.CPU.Sec
    Value: 9

    Key  : Analysis.DebugAnalysisProvider.CPP
    Value: Create: 8007007e on DESKTOP-CV3A9R4

    Key  : Analysis.DebugData
    Value: CreateObject

    Key  : Analysis.DebugModel
    Value: CreateObject

    Key  : Analysis.Elapsed.Sec
    Value: 274

    Key  : Analysis.Memory.CommitPeak.Mb
    Value: 123

    Key  : Analysis.System
    Value: CreateObject


BUGCHECK_CODE:  50

BUGCHECK_P1: ffffae05a4bfb000

BUGCHECK_P2: 0

BUGCHECK_P3: fffff80126e06473

BUGCHECK_P4: 0

READ_ADDRESS:  ffffae05a4bfb000 Paged pool

MM_INTERNAL_CODE:  0

PROCESS_NAME:  ngen.exe

TRAP_FRAME:  fffffa8174b105c0 -- (.trap 0xfffffa8174b105c0)
NOTE: The trap frame does not contain all registers.
Some register values may be zeroed or incorrect.
rax=00000000000003b0 rbx=0000000000000000 rcx=fffffa8174b10780
rdx=ffffae05a4bfa8a0 rsi=0000000000000000 rdi=0000000000000000
rip=fffff80126e06473 rsp=fffffa8174b10758 rbp=fffffa8174b10b80
 r8=fffff801248cd180  r9=ffff848bd6c672e8 r10=0000000000000000
r11=fffffa8174b106b8 r12=0000000000000000 r13=0000000000000000
r14=0000000000000000 r15=0000000000000000
iopl=0         nv up ei pl nz ac pe nc
nt!RtlInitUnicodeString+0x23:
fffff801`26e06473 66833c4200      cmp     word ptr [rdx+rax*2],0 ds:ffffae05`a4bfb000=????
Resetting default scope

STACK_TEXT:  
fffffa81`74b0fb68 fffff801`27111e92 : fffffa81`74b0fcd0 fffff801`26f7c550 fffff801`26c00000 00000000`00000000 : nt!DbgBreakPointWithStatus
fffffa81`74b0fb70 fffff801`27111476 : fffff801`00000003 fffffa81`74b0fcd0 fffff801`2700a6c0 00000000`00000050 : nt!KiBugCheckDebugBreak+0x12
fffffa81`74b0fbd0 fffff801`26ff5887 : 00000000`00000000 00000000`00000000 000129da`00000010 ffffae05`a4bfb000 : nt!KeBugCheck2+0x946
fffffa81`74b102e0 fffff801`2701eb6b : 00000000`00000050 ffffae05`a4bfb000 00000000`00000000 fffffa81`74b105c0 : nt!KeBugCheckEx+0x107
fffffa81`74b10320 fffff801`26e0c960 : ffffae05`00000000 00000000`00000000 fffffa81`74b10640 00000000`00000000 : nt!MiSystemFault+0x1f435b
fffffa81`74b10420 fffff801`2700395e : 00000000`00000000 fffff801`279225e0 00000000`00000000 ffffae05`99ebb6e0 : nt!MmAccessFault+0x400
fffffa81`74b105c0 fffff801`26e06473 : fffff801`261f3189 fffffa81`74b109a0 fffff801`27226e30 fffffa81`74b109a0 : nt!KiPageFault+0x35e
fffffa81`74b10758 fffff801`261f3189 : fffffa81`74b109a0 fffff801`27226e30 fffffa81`74b109a0 ffffae05`9df87d48 : nt!RtlInitUnicodeString+0x23
fffffa81`74b10760 fffff801`27226808 : fffffa81`74b109a0 ffffae05`a4bfa890 00000000`00000000 00000000`00000000 : mydriver!RfRegistryCallbackHelper+0x5d [E:\MyWork\Projects\Endpoint\drivers\driver\regfltr_cbs.c @ 80] 
fffffa81`74b107a0 fffff801`27218e54 : 0000006f`00000001 fffffa81`74b109a0 00000000`00000000 ffffae05`a49be101 : nt!CmpCallCallBacksEx+0x1c8
fffffa81`74b108b0 fffff801`270071b5 : 00000000`0001000f 00000000`00000000 00000000`00000000 00000000`00000000 : nt!NtSetValueKey+0x5f4
fffffa81`74b10a90 00007ffe`9fc6cba4 : 00007ffe`9d924008 000001cb`1059ba30 00007ffe`0000000d 00000000`000001a8 : nt!KiSystemServiceCopyEnd+0x25
0000006f`001edf68 00007ffe`9d924008 : 000001cb`1059ba30 00007ffe`0000000d 00000000`000001a8 000001cb`1059dd20 : ntdll!NtSetValueKey+0x14
0000006f`001edf70 00007ffe`9d923da2 : 00000000`00000000 00007ffe`00000000 0000006f`00000003 000001cb`1055c5e0 : KERNELBASE!LocalBaseRegSetValue+0x13c
0000006f`001ee000 00007ffe`83821f0e : 00000000`000005e4 0000006f`001ee100 000001cb`105c5070 00000186`00000003 : KERNELBASE!RegSetValueExW+0x142
0000006f`001ee090 00000000`000005e4 : 0000006f`001ee100 000001cb`105c5070 00000186`00000003 000001cb`1055c5e0 : mscorsvc!CSimpleRegWrapper::RegistryKey::WriteVal+0x84
0000006f`001ee098 0000006f`001ee100 : 000001cb`105c5070 00000186`00000003 000001cb`1055c5e0 000001cb`00000118 : 0x5e4
0000006f`001ee0a0 000001cb`105c5070 : 00000186`00000003 000001cb`1055c5e0 000001cb`00000118 000001cb`105c5070 : 0x0000006f`001ee100
0000006f`001ee0a8 00000186`00000003 : 000001cb`1055c5e0 000001cb`00000118 000001cb`105c5070 00007ffe`83824e71 : 0x000001cb`105c5070
0000006f`001ee0b0 000001cb`1055c5e0 : 000001cb`00000118 000001cb`105c5070 00007ffe`83824e71 00000000`00000000 : 0x00000186`00000003
0000006f`001ee0b8 000001cb`00000118 : 000001cb`105c5070 00007ffe`83824e71 00000000`00000000 00007ffe`83821ec0 : 0x000001cb`1055c5e0
0000006f`001ee0c0 000001cb`105c5070 : 00007ffe`83824e71 00000000`00000000 00007ffe`83821ec0 00000000`00000000 : 0x000001cb`00000118
0000006f`001ee0c8 00007ffe`83824e71 : 00000000`00000000 00007ffe`83821ec0 00000000`00000000 00000000`00000000 : 0x000001cb`105c5070
0000006f`001ee0d0 00000000`00000000 : 00007ffe`83821ec0 00000000`00000000 00000000`00000000 000001cb`105c4e00 : mscorsvc!Configuration::BinarySerializeLogicalImageList+0x3be


FAULTING_SOURCE_LINE:  E:\MyWork\Projects\Endpoint\drivers\driver\regfltr_cbs.c

FAULTING_SOURCE_FILE:  E:\MyWork\Projects\Endpoint\drivers\driver\regfltr_cbs.c

FAULTING_SOURCE_LINE_NUMBER:  80

FAULTING_SOURCE_CODE:  
    76:     RtlInitUnicodeString(&UnicodeObjectName, pObjectName->Buffer);
    77: 
    78:     // check if target registry key is belong to our protection registry path
    79: 
>   80:     if (CompareWcharWithUniStr(MY_KERNEL_REG_SVC_PATH, &UnicodeObjectName)) {
    81:         goto BlockOper;
    82:     }
    83: 
    84:     if (CompareWcharWithUniStr(MY_USER_REG_SVC_PATH, &UnicodeObjectName)) {
    85:         if (isBlockUserSvcReg) {


SYMBOL_NAME:  mydriver!RfRegistryCallbackHelper+5d

MODULE_NAME: mydriver

IMAGE_NAME:  mydriver.sys

STACK_COMMAND:  .thread ; .cxr ; kb

BUCKET_ID_FUNC_OFFSET:  5d

FAILURE_BUCKET_ID:  AV_R_INVALID_mydriver!RfRegistryCallbackHelper

OS_VERSION:  10.0.19041.1

BUILDLAB_STR:  vb_release

OSPLATFORM_TYPE:  x64

OSNAME:  Windows 10

FAILURE_ID_HASH:  {22eeb165-1a3b-01b0-0915-474fa8d2e7b3}

Followup:     MachineOwner
---------

It seems like the bug appears everytimes the driver runs to the line that check the registry path (as shown above). The log said that the system fails due to a read from a no-data (not null) paged pool memory, but I had allocated both MY_KERNEL_REG_SVC_PATH and MY_USER_REG_SVC_PATH as non-paged pool memory, which must stay until the computer shut down, and they all have data at first.

I'll be very appreciated for any help.

Edit: Part of the code for initializing variables:

PWCHAR MY_KERNEL_REG_SVC_PATH = NULL;
PWCHAR MY_USER_REG_SVC_PATH = NULL;

WCHAR BACKUP_MY_KERNEL_SVC[FILEPATH_SIZE] = L"\\REGISTRY\\MACHINE\\SYSTEM\\ControlSet001\\Services\\mykrnl";
WCHAR BACKUP_MY_USER_SVC[FILEPATH_SIZE] = L"\\REGISTRY\\MACHINE\\SYSTEM\\ControlSet001\\Services\\mysvc";

NTSTATUS AllocateLists() {

    // initiliaze protection kernel registry
    if (MY_KERNEL_REG_SVC_PATH != NULL) {
        ExFreePoolWithTag(MY_KERNEL_REG_SVC_PATH, TD_MY_KERNEL_REG_SVC_PATH);
    }
    MY_KERNEL_REG_SVC_PATH = ExAllocatePoolWithTag(NonPagedPool, sizeof(WCHAR) * FILEPATH_SIZE, TD_MY_KERNEL_REG_SVC_PATH);
    if (MY_KERNEL_REG_SVC_PATH == NULL)
    {
        DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "Endpoint Driver: DriverEntry: Cannot allocate memory for protection kernel registry\r\n");
        goto Exit;
    }
    swprintf_s(MY_KERNEL_REG_SVC_PATH, FILEPATH_SIZE, BACKUP_MY_KERNEL_SVC);
    DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "Endpoint Driver: DriverEntry: protection registry: %S\r\n", MY_KERNEL_REG_SVC_PATH);

    // initiliaze protection user registry
    if (MY_USER_REG_SVC_PATH != NULL) {
        ExFreePoolWithTag(MY_USER_REG_SVC_PATH, TD_MY_USER_REG_SVC_PATH);
    }
    MY_USER_REG_SVC_PATH = ExAllocatePoolWithTag(NonPagedPool, sizeof(WCHAR) * FILEPATH_SIZE, TD_MY_USER_REG_SVC_PATH);
    if (MY_USER_REG_SVC_PATH == NULL)
    {
        DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "Endpoint Driver: DriverEntry: Cannot allocate memory for protection user registry\r\n");
        goto Exit;
    }
    swprintf_s(MY_USER_REG_SVC_PATH, FILEPATH_SIZE, BACKUP_MY_USER_SVC);

Exit:
    return STATUS_MEMORY_NOT_ALLOCATED;
}
c++
filter
registry
driver
asked on Stack Overflow Jan 3, 2021 by Margaret Nguyen • edited Jan 4, 2021 by Margaret Nguyen

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0