首页IT科技注册表监控软件(驱动开发:内核监控Register注册表回调)

注册表监控软件(驱动开发:内核监控Register注册表回调)

时间2025-07-07 12:28:44分类IT科技浏览3714
导读:在笔者前一篇文章《驱动开发:内核枚举Registry注册表回调》中实现了对注册表的枚举,本章将实现对注册表的监控,不同于32位系统在64位系统中,微软为我们提供了两个针对注册表的专用内核监控函数,通过这两个函数可以在不劫持内核API的前提下实现对注册表增加,删除,创建等事件的有效监控,注册表监视通常会通过CmRegisterCal...

在笔者前一篇文章《驱动开发:内核枚举Registry注册表回调》中实现了对注册表的枚举             ,本章将实现对注册表的监控                  ,不同于32位系统在64位系统中      ,微软为我们提供了两个针对注册表的专用内核监控函数       ,通过这两个函数可以在不劫持内核API的前提下实现对注册表增加                  ,删除            ,创建等事件的有效监控       ,注册表监视通常会通过CmRegisterCallback创建监控事件并传入自己的回调函数                   ,与该创建对应的是CmUnRegisterCallback当注册表监控结束后可用于注销回调            。

CmRegisterCallback 设置注册表回调 CmUnRegisterCallback 注销注册表回调

默认情况下CmRegisterCallback需传入三个参数            ,参数一回调函数地址,参数二空余                   ,参数三回调句柄                  ,微软定义如下                   。

// 署名权 // right to sign ones name on a piece of work // PowerBy: LyShark // Email: me@lyshark.com // 参数1:回调函数地址 // 参数2:无作用 // 参数3:回调句柄 NTSTATUS CmRegisterCallback( [in] PEX_CALLBACK_FUNCTION Function, [in, optional] PVOID Context, [out] PLARGE_INTEGER Cookie );

自定义注册表回调函数MyLySharkCallback需要保留三个参数,CallbackContext回调上下文             ,Argument1是操作类型                  ,Argument2定义详细结构体指针      。

NTSTATUS MyLySharkCallback(_In_ PVOID CallbackContext, _In_opt_ PVOID Argument1, _In_opt_ PVOID Argument2)

在自定义回调函数内Argument1则可获取到操作类型      ,类型是一个REG_NOTIFY_CLASS枚举结构             ,微软对其的具体定义如下所示            。

// 署名权 // right to sign ones name on a piece of work // PowerBy: LyShark // Email: me@lyshark.com typedef enum _REG_NOTIFY_CLASS { RegNtDeleteKey, RegNtPreDeleteKey = RegNtDeleteKey, RegNtSetValueKey, RegNtPreSetValueKey = RegNtSetValueKey, RegNtDeleteValueKey, RegNtPreDeleteValueKey = RegNtDeleteValueKey, RegNtSetInformationKey, RegNtPreSetInformationKey = RegNtSetInformationKey, RegNtRenameKey, RegNtPreRenameKey = RegNtRenameKey, RegNtEnumerateKey, RegNtPreEnumerateKey = RegNtEnumerateKey, RegNtEnumerateValueKey, RegNtPreEnumerateValueKey = RegNtEnumerateValueKey, RegNtQueryKey, RegNtPreQueryKey = RegNtQueryKey, RegNtQueryValueKey, RegNtPreQueryValueKey = RegNtQueryValueKey, RegNtQueryMultipleValueKey, RegNtPreQueryMultipleValueKey = RegNtQueryMultipleValueKey, RegNtPreCreateKey, RegNtPostCreateKey, RegNtPreOpenKey, RegNtPostOpenKey, RegNtKeyHandleClose, RegNtPreKeyHandleClose = RegNtKeyHandleClose, // // .Net only // RegNtPostDeleteKey, RegNtPostSetValueKey, RegNtPostDeleteValueKey, RegNtPostSetInformationKey, RegNtPostRenameKey, RegNtPostEnumerateKey, RegNtPostEnumerateValueKey, RegNtPostQueryKey, RegNtPostQueryValueKey, RegNtPostQueryMultipleValueKey, RegNtPostKeyHandleClose, RegNtPreCreateKeyEx, RegNtPostCreateKeyEx, RegNtPreOpenKeyEx, RegNtPostOpenKeyEx, // // new to Windows Vista // RegNtPreFlushKey, RegNtPostFlushKey, RegNtPreLoadKey, RegNtPostLoadKey, RegNtPreUnLoadKey, RegNtPostUnLoadKey, RegNtPreQueryKeySecurity, RegNtPostQueryKeySecurity, RegNtPreSetKeySecurity, RegNtPostSetKeySecurity, // // per-object context cleanup // RegNtCallbackObjectContextCleanup, // // new in Vista SP2 // RegNtPreRestoreKey, RegNtPostRestoreKey, RegNtPreSaveKey, RegNtPostSaveKey, RegNtPreReplaceKey, RegNtPostReplaceKey, MaxRegNtNotifyClass //should always be the last enum } REG_NOTIFY_CLASS;

其中对于注册表最常用的监控项为以下几种类型                  ,当然为了实现监控则我们必须要使用之前      ,如果使用之后则只能起到监视而无法做到监控的目的                   。

RegNtPreCreateKey 创建注册表之前 RegNtPreOpenKey 打开注册表之前 RegNtPreDeleteKey 删除注册表之前 RegNtPreDeleteValueKey 删除键值之前 RegNtPreSetValueKey 修改注册表之前

如果需要实现监视则       ,首先CmRegisterCallback注册一个自定义回调                  ,当有消息时则触发MyLySharkCallback其内部获取到lOperateType操作类型            ,并通过switch选择不同的处理例程       ,每个处理例程都通过GetFullPath得到注册表完整路径                   ,并打印出来            ,这段代码实现如下      。

// 署名权 // right to sign ones name on a piece of work // PowerBy: LyShark // Email: me@lyshark.com #include <ntifs.h> #include <windef.h> // 未导出函数声明 pEProcess -> PID PUCHAR PsGetProcessImageFileName(PEPROCESS pEProcess); NTSTATUS ObQueryNameString( _In_ PVOID Object, _Out_writes_bytes_opt_(Length) POBJECT_NAME_INFORMATION ObjectNameInfo, _In_ ULONG Length, _Out_ PULONG ReturnLength ); // 注册表回调Cookie LARGE_INTEGER g_liRegCookie; // 获取注册表完整路径 BOOLEAN GetFullPath(PUNICODE_STRING pRegistryPath, PVOID pRegistryObject) { // 判断数据地址是否有效 if ((FALSE == MmIsAddressValid(pRegistryObject)) || (NULL == pRegistryObject)) { return FALSE; } // 申请内存 ULONG ulSize = 512; PVOID lpObjectNameInfo = ExAllocatePool(NonPagedPool, ulSize); if (NULL == lpObjectNameInfo) { return FALSE; } // 获取注册表路径 ULONG ulRetLen = 0; NTSTATUS status = ObQueryNameString(pRegistryObject, (POBJECT_NAME_INFORMATION)lpObjectNameInfo, ulSize, &ulRetLen); if (!NT_SUCCESS(status)) { ExFreePool(lpObjectNameInfo); return FALSE; } // 复制 RtlCopyUnicodeString(pRegistryPath, (PUNICODE_STRING)lpObjectNameInfo); // 释放内存 ExFreePool(lpObjectNameInfo); return TRUE; } // 注册表回调函数 NTSTATUS MyLySharkCallback(_In_ PVOID CallbackContext, _In_opt_ PVOID Argument1, _In_opt_ PVOID Argument2) { NTSTATUS status = STATUS_SUCCESS; UNICODE_STRING ustrRegPath; // 获取操作类型 LONG lOperateType = (REG_NOTIFY_CLASS)Argument1; // 申请内存 ustrRegPath.Length = 0; ustrRegPath.MaximumLength = 1024 * sizeof(WCHAR); ustrRegPath.Buffer = ExAllocatePool(NonPagedPool, ustrRegPath.MaximumLength); if (NULL == ustrRegPath.Buffer) { return status; } RtlZeroMemory(ustrRegPath.Buffer, ustrRegPath.MaximumLength); // 判断操作 switch (lOperateType) { // 创建注册表之前 case RegNtPreCreateKey: { // 获取注册表路径 GetFullPath(&ustrRegPath, ((PREG_CREATE_KEY_INFORMATION)Argument2)->RootObject); DbgPrint("[创建注册表][%wZ][%wZ]\n", &ustrRegPath, ((PREG_CREATE_KEY_INFORMATION)Argument2)->CompleteName); break; } // 打开注册表之前 case RegNtPreOpenKey: { // 获取注册表路径 GetFullPath(&ustrRegPath, ((PREG_CREATE_KEY_INFORMATION)Argument2)->RootObject); DbgPrint("[打开注册表][%wZ][%wZ]\n", &ustrRegPath, ((PREG_CREATE_KEY_INFORMATION)Argument2)->CompleteName); break; } // 删除键之前 case RegNtPreDeleteKey: { // 获取注册表路径 GetFullPath(&ustrRegPath, ((PREG_DELETE_KEY_INFORMATION)Argument2)->Object); DbgPrint("[删除键][%wZ] \n", &ustrRegPath); break; } // 删除键值之前 case RegNtPreDeleteValueKey: { // 获取注册表路径 GetFullPath(&ustrRegPath, ((PREG_DELETE_VALUE_KEY_INFORMATION)Argument2)->Object); DbgPrint("[删除键值][%wZ][%wZ] \n", &ustrRegPath, ((PREG_DELETE_VALUE_KEY_INFORMATION)Argument2)->ValueName); // 获取当前进程, 即操作注册表的进程 PEPROCESS pEProcess = PsGetCurrentProcess(); if (NULL != pEProcess) { UCHAR *lpszProcessName = PsGetProcessImageFileName(pEProcess); if (NULL != lpszProcessName) { DbgPrint("进程 [%s] 删除了键值对 \n", lpszProcessName); } } break; } // 修改键值之前 case RegNtPreSetValueKey: { // 获取注册表路径 GetFullPath(&ustrRegPath, ((PREG_SET_VALUE_KEY_INFORMATION)Argument2)->Object); DbgPrint("[修改键值][%wZ][%wZ] \n", &ustrRegPath, ((PREG_SET_VALUE_KEY_INFORMATION)Argument2)->ValueName); break; } default: break; } // 释放内存 if (NULL != ustrRegPath.Buffer) { ExFreePool(ustrRegPath.Buffer); ustrRegPath.Buffer = NULL; } return status; } VOID UnDriver(PDRIVER_OBJECT driver) { DbgPrint(("Uninstall Driver Is OK \n")); // 注销当前注册表回调 if (0 < g_liRegCookie.QuadPart) { CmUnRegisterCallback(g_liRegCookie); } } NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath) { DbgPrint(("hello lyshark.com \n")); // 设置注册表回调 NTSTATUS status = CmRegisterCallback(MyLySharkCallback, NULL, &g_liRegCookie); if (!NT_SUCCESS(status)) { g_liRegCookie.QuadPart = 0; return status; } Driver->DriverUnload = UnDriver; return STATUS_SUCCESS; }

运行驱动程序,则会输出当前系统中所有针对注册表的操作                   ,如下图所示      。

如上的代码只能实现注册表项的监视                  ,而如果需要监控则需要在回调函数MyLySharkCallback判断,如果指定注册表项是需要保护的则直接返回status = STATUS_ACCESS_DENIED;从而达到保护注册表的目的             ,核心代码如下所示                   。

// 反注册表删除回调 NTSTATUS MyLySharkCallback(_In_ PVOID CallbackContext, _In_opt_ PVOID Argument1, _In_opt_ PVOID Argument2) { NTSTATUS status = STATUS_SUCCESS; UNICODE_STRING ustrRegPath; // 获取操作类型 LONG lOperateType = (REG_NOTIFY_CLASS)Argument1; ustrRegPath.Length = 0; ustrRegPath.MaximumLength = 1024 * sizeof(WCHAR); ustrRegPath.Buffer = ExAllocatePool(NonPagedPool, ustrRegPath.MaximumLength); if (NULL == ustrRegPath.Buffer) { return status; } RtlZeroMemory(ustrRegPath.Buffer, ustrRegPath.MaximumLength); // 判断操作 switch (lOperateType) { // 删除键值之前 case RegNtPreDeleteValueKey: { // 获取注册表路径 GetFullPath(&ustrRegPath, ((PREG_DELETE_VALUE_KEY_INFORMATION)Argument2)->Object); DbgPrint("[删除键值][%wZ][%wZ]\n", &ustrRegPath, ((PREG_DELETE_VALUE_KEY_INFORMATION)Argument2)->ValueName); // 如果要删除指定注册表项则拒绝 PWCH pszRegister = L"\\REGISTRY\\MACHINE\\SOFTWARE\\lyshark.com"; if (wcscmp(ustrRegPath.Buffer, pszRegister) == 0) { DbgPrint("[lyshark] 注册表项删除操作已被拦截! \n"); // 拒绝操作 status = STATUS_ACCESS_DENIED; } break; } default: break; } // 释放内存 if (NULL != ustrRegPath.Buffer) { ExFreePool(ustrRegPath.Buffer); ustrRegPath.Buffer = NULL; } return status; }

运行驱动程序                  ,然后我们尝试删除\\LyShark\HKEY_LOCAL_MACHINE\SOFTWARE\lyshark.com里面的子项      ,则会提示如下信息             。

当然这里的RegNtPreDeleteValueKey是指的删除操作             ,如果将其替换成RegNtPreSetValueKey                  ,那么只有当注册表被创建才会拦截      ,此时就会变成拦截创建      。

// 拦截创建操作 NTSTATUS MyLySharkCallback(_In_ PVOID CallbackContext, _In_opt_ PVOID Argument1, _In_opt_ PVOID Argument2) { NTSTATUS status = STATUS_SUCCESS; UNICODE_STRING ustrRegPath; // 获取操作类型 LONG lOperateType = (REG_NOTIFY_CLASS)Argument1; // 申请内存 ustrRegPath.Length = 0; ustrRegPath.MaximumLength = 1024 * sizeof(WCHAR); ustrRegPath.Buffer = ExAllocatePool(NonPagedPool, ustrRegPath.MaximumLength); if (NULL == ustrRegPath.Buffer) { return status; } RtlZeroMemory(ustrRegPath.Buffer, ustrRegPath.MaximumLength); // 判断操作 switch (lOperateType) { // 修改键值之前 case RegNtPreSetValueKey: { // 获取注册表路径 GetFullPath(&ustrRegPath, ((PREG_DELETE_VALUE_KEY_INFORMATION)Argument2)->Object); // 拦截创建 PWCH pszRegister = L"\\REGISTRY\\MACHINE\\SOFTWARE\\lyshark.com"; if (wcscmp(ustrRegPath.Buffer, pszRegister) == 0) { DbgPrint("[lyshark] 注册表项创建操作已被拦截! \n"); status = STATUS_ACCESS_DENIED; } break; } default: break; } // 释放内存 if (NULL != ustrRegPath.Buffer) { ExFreePool(ustrRegPath.Buffer); ustrRegPath.Buffer = NULL; } return status; }

加载驱动保护       ,然后我们尝试在\\LyShark\HKEY_LOCAL_MACHINE\SOFTWARE\lyshark.com里面创建一个子项                  ,则会提示创建失败                  。

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
vuexmind思维导图(vue使用jsMind(思维导图))