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.
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;
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;
}
User contributions licensed under CC BY-SA 3.0