如何获取触发注册表过滤驱动回调的进程ID?
获取注册表过滤回调中触发操作的进程ID的可行方案
核心逻辑说明
你之前通过注册表键句柄获取进程的思路存在偏差:键的句柄属于首次打开该键的进程,而非当前执行操作的进程,因此无法得到正确的触发PID。正确的思路是从回调的执行上下文或回调参数中直接关联发起操作的进程。
两种可靠实现方式
方法一:直接获取当前进程上下文(常规场景)
绝大多数注册表操作的回调会在发起操作的进程上下文中执行,此时可直接调用内核API获取当前进程:
NTSTATUS RegistryCallback( _In_ PVOID CallbackContext, _In_ PVOID Argument1, _In_ PVOID Argument2 ) { UNREFERENCED_PARAMETER(CallbackContext); UNREFERENCED_PARAMETER(Argument1); UNREFERENCED_PARAMETER(Argument2); // 获取发起操作的进程对象 PEPROCESS targetProcess = PsGetCurrentProcess(); // 转换为PID HANDLE targetPid = PsGetProcessId(targetProcess); // 调试输出PID(可根据需求替换为业务逻辑) DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "Registry operation from PID: %lu\n", (ULONG)targetPid); return STATUS_SUCCESS; }
方法二:通过线程ID关联进程(严谨场景)
若回调可能运行在系统线程上下文(如异步注册表操作),可从回调参数中取出发起操作的线程ID,通过线程关联到所属进程:
NTSTATUS RegistryCallback( _In_ PVOID CallbackContext, _In_ PVOID Argument1, _In_ PVOID Argument2 ) { UNREFERENCED_PARAMETER(CallbackContext); REG_NOTIFY_CLASS notifyClass = (REG_NOTIFY_CLASS)Argument1; PREG_PRE_OPERATION_INFORMATION preOpInfo = NULL; PETHREAD targetThread = NULL; NTSTATUS status = STATUS_SUCCESS; // 针对预操作类型解析参数(根据监控需求扩展操作类型) if (notifyClass == RegNtPreDeleteKey || notifyClass == RegNtPreSetValueKey || notifyClass == RegNtPreCreateKeyEx) { preOpInfo = (PREG_PRE_OPERATION_INFORMATION)Argument2; // 通过线程ID查找线程对象 status = PsLookupThreadByThreadId(preOpInfo->ThreadId, &targetThread); if (NT_SUCCESS(status)) { // 从线程对象获取所属进程 PEPROCESS targetProcess = PsGetThreadProcess(targetThread); HANDLE targetPid = PsGetProcessId(targetProcess); DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "Registry operation from PID: %lu\n", (ULONG)targetPid); // 释放线程对象引用,避免内存泄漏 ObDereferenceObject(targetThread); } } // 你的过滤拦截逻辑... return status; }
关键注意事项
- 使用
PsLookupThreadByThreadId后必须调用ObDereferenceObject释放线程对象,防止内核内存泄漏。 - 确保回调函数中对
Argument2的类型解析正确,不同REG_NOTIFY_CLASS对应的参数结构体不同(预操作对应REG_PRE_OPERATION_INFORMATION,后操作对应REG_POST_OPERATION_INFORMATION)。
内容的提问来源于stack exchange,提问作者anitarazafi
相关产品推荐
相关产品推荐

