7.5 Windows驅動開發:監控Register注冊表回調

在筆者前一篇文章《內核枚舉Registry注冊表回調》中實現了對注冊表的枚舉,本章將實現對注冊表的監控,不同于32位系統在64位系統中,微軟為我們提供了兩個針對注冊表的專用內核監控函數,通過這兩個函數可以在不劫持內核API的前提下實現對注冊表增加,刪除,創建等事件的有效監控,注冊表監視通常會通過CmRegisterCallback創建監控事件并傳入自己的回調函數,與該創建對應的是CmUnRegisterCallback當注冊表監控結束后可用于注銷回調。

CmRegisterCallback和CmUnRegisterCallback是Windows操作系統提供的兩個內核API函數,用于注冊和取消注冊注冊表回調函數。

注冊表回調函數是一種內核回調函數,它可以用于監視和攔截系統中的注冊表操作,例如鍵值的創建、修改和刪除等。當有相關操作發生時,操作系統會調用注冊的注冊表回調函數,并將操作相關的信息傳遞給回調函數。

CmRegisterCallback函數用于注冊注冊表回調函數,而CmUnRegisterCallback函數則用于取消注冊已經注冊的回調函數。開發者可以在注冊表回調函數中執行自定義的邏輯,例如記錄日志、過濾敏感數據、或者阻止某些操作。

需要注意的是,注冊表回調函數的注冊和取消注冊必須在內核模式下進行,并且需要開發者有一定的內核開發經驗。同時,注冊表回調函數也需要遵守一些約束條件,例如不能阻塞或掛起進程或線程的創建或訪問,不能調用一些內核API函數等。

內核監控Register注冊表回調在安全軟件、系統監控和調試工具等領域有著廣泛的應用。開發者可以利用這個機制來監視和攔截系統中的注冊表操作,以保護系統安全。

  • CmRegisterCallback 設置注冊表回調
  • CmUnRegisterCallback 注銷注冊表回調

默認情況下CmRegisterCallback需傳入三個參數,參數一回調函數地址,參數二空余,參數三回調句柄,微軟定義如下。

// 參數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枚舉結構,微軟對其的具體定義如下所示。

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得到注冊表完整路徑,并打印出來,這段代碼實現如下。

#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 \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";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里面的子項,則會提示如下信息。

當然這里的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";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里面創建一個子項,則會提示創建失敗。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/167335.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/167335.shtml
英文地址,請注明出處:http://en.pswp.cn/news/167335.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

數組方法reduce的基礎用法和奇怪的用法

Array.prototype.reduce 是 JavaScript 數組方法之一&#xff0c;用于累積數組的各個值&#xff0c;將其簡化為單個值。下面是一些基礎用法和一些可能被認為奇怪或不太常見的用法&#xff1a; 基礎用法&#xff1a; 數組求和&#xff1a; const numbers [1, 2, 3, 4, 5]; c…

Android runtime層是如何通過縮減代碼來縮減內存的

文章目錄 前言&#xff1a;Android 在設備上改進內存的秘密優化編譯器101代碼大小改進消除寫入障礙隱式暫停檢查合并回調其他優化改進代碼下沉循環優化消除死代碼 – SimplifyAlwaysThrows加載存儲消除 – 使用 try catch 塊加載存儲消除 – 使用釋放/獲取操作新的內聯啟發式不…

遞歸回溯剪枝-子集

LCR 079. 子集 - 力扣&#xff08;LeetCode&#xff09; 方法一 1. 決策樹&#xff1a;對于決策樹&#xff0c;思考的角度不同&#xff0c;畫出的決策樹也會不同&#xff0c;這道題可以從兩個角度來畫決策樹。 2. 考慮全局變量的使用&#xff1a; 使用全局變量 List<List&…

Python 基礎【五】--數據類型-序列【2023.11.24】

1.定義 Python 中的序列是一塊可存放多個值的連續內存空間&#xff0c;所有值按一定順序排列&#xff0c;每個值所在位置都有一個編號&#xff0c;稱其為索引&#xff0c;我們可以通過索引訪問其對應值。 list1 [Google, Runoob, 1997, 2000] list2 [1, 2, 3, 4, 5 ] list3…

馬克思主義基本原理課后題答案

吐血整理馬原word版課后題答案&#xff0c;大家可以自行修改&#xff0c;持續更新中... 【限于篇幅原因&#xff0c;需要的同學可以點贊收藏后&#x1f44d;&#xff0c;掃碼下方的公眾號&#xff0c;回復相應關鍵詞&#xff08;馬原&#xff09;自行領取?~】

【05】ES6:函數的擴展

一、函數參數的默認值 ES6 允許為函數的參數設置默認值&#xff0c;即直接寫在參數定義的后面。 1、基本用法 默認值的生效條件 不傳參數&#xff0c;或者明確的傳遞 undefined 作為參數&#xff0c;只有這兩種情況下&#xff0c;默認值才會生效。 注意&#xff1a;null 就…

react的開發中關于圖片的知識

React是一個流行的JavaScript庫&#xff0c;用于構建用戶界面。在React開發中&#xff0c;圖片是一個非常重要的元素&#xff0c;可以用于美化界面和展示內容。本篇博客將詳細講解React中關于圖片的知識。 1. React中使用圖片 在React中使用圖片非常簡單&#xff0c;只需要使…

【Web題】狼追兔問題

&#x1f49d;&#x1f49d;&#x1f49d;歡迎來到我的博客&#xff0c;很高興能夠在這里和您見面&#xff01;希望您在這里可以感受到一份輕松愉快的氛圍&#xff0c;不僅可以獲得有趣的內容和知識&#xff0c;也可以暢所欲言、分享您的想法和見解。 推薦:kwan 的首頁,持續學…

解決Resolving Android Dependencies問題

無論是谷歌的Admob&#xff0c;還是Unity的Level play&#xff0c; 在windows&#xff08;win10, win11&#xff09;下&#xff0c;都出現了resolving android dependencies 報錯并且卡住的問題&#xff0c;如圖: 主要錯誤&#xff0c;是找不到這個gradlew.bat文件。 在指定位置…

什么是單元測試?

什么是單元測試 單元測試是軟件開發中的一種測試方法&#xff0c;旨在驗證各個軟件組件或模塊的功能正確性。在敏捷開發環境中&#xff0c;單元測試尤為重要&#xff0c;因為它有助于確保代碼的質量和穩定性。下面是一些關于單元測試的關鍵點&#xff1a; 定義&#xff1a;單元…

力扣每日一題-統計和小于目標的下標對數目-2023.11.24

力扣每日一題&#xff1a;統計和小于目標的下標對數目 開篇 今天這道力扣打卡題寫得我好狼狽&#xff0c;一開始思路有點問題&#xff0c;后面就是對自己的代碼到處縫縫補補&#xff0c;最后蒙混過關。只能分享一下大佬的代碼&#xff0c;然后我幫大家分享代碼的思路。 題目鏈…

大模型能否生成搜索引擎的未來?

文&#xff5c;郝 鑫 編&#xff5c;劉雨琦 ChatGPT火爆之前&#xff0c;水面下&#xff0c;也有中國公司也在朝著智能助手的方向努力。夸克便是其中之一。在GPT風靡科技圈后&#xff0c;國內就開始陸續冒出一些大模型廠商。對當時夸克而言&#xff0c;做大模型毋庸置疑&am…

django(千鋒教育)

創建一個django項目 官網下載python最新版本 配置到環境變量中 打開intlij編輯器 創建django項目 安裝django&#xff1a;pip install django 創建django項目: django-admin startproject django01 創建djangoAPP&#xff1a;python manage.py startapp App 啟動&#xff1a…

設置定時自動請求測試_自動定時循環發送http_post請求---postman工作筆記001

其實就是創建接口文件夾的時候,有個monitor collection 用來監聽接口執行情況,這里就可以設置 可以看到多久執行一次對吧,這里可以設置每幾分鐘執行一次,一共執行多少次等等 但是這里要說明一下,如果需要使用monitor功能,必須需要登錄, 所以如果這里點擊monitor collection…

媒體增加日活量的有效策略

隨著數字媒體的蓬勃發展&#xff0c;提高日活量成為媒體平臺追求的重要目標之一。日活量的增加不僅意味著更廣泛的影響力&#xff0c;還能為媒體平臺帶來更多的商業機會。以下是一些有效的策略&#xff0c;可幫助媒體提高日活量&#xff1a; admaoyan貓眼聚合 內容優質化&#…

**QT與目標板聯合調試_斷點仿真**

原文地址: https://blog.csdn.net/u012851408/article/details/86715626

仙女麻麻看過來~這是不是你們在找的外套?

分享女兒的秋冬穿搭 時尚與美觀兼具的毛毛外套 洋氣百搭不挑人穿 誰穿對都好看系列 經典寬松版型 不臃腫對身材包容性很強 小編墻裂推薦哦&#xff01;&#xff01;

NFT Insider115:The Sandbox開設元宇宙Diorama快閃店,?YGG Web3 游戲峰會已開幕

引言&#xff1a;NFT Insider由NFT收藏組織WHALE Members、BeepCrypto聯合出品&#xff0c;濃縮每周NFT新聞&#xff0c;為大家帶來關于NFT最全面、最新鮮、最有價值的訊息。每期周報將從NFT市場數據&#xff0c;藝術新聞類&#xff0c;游戲新聞類&#xff0c;虛擬世界類&#…

RevCol:可逆的柱狀神經網絡

文章目錄 摘要1、簡介2、方法2.1、Multi-LeVEl ReVERsible Unit2.2、可逆列架構2.2.1、MACRo設計2.2.2、MicRo 設計 2.3、中間監督 3、實驗部分3.1、圖像分類3.2、目標檢測3.3、語義分割3.4、與SOTA基礎模型的系統級比較3.5、更多分析實驗3.5.1、可逆列架構的性能提升3.5.2、可…

貴金屬交易指南:如何在市場中獲利?

貴金屬市場一直以來都是投資者追逐利潤的熱門選擇&#xff0c;然而&#xff0c;貴金屬市場波動較大&#xff0c;在市場中獲利并非易事。想要成功&#xff0c;需要理解市場動態和采取適當的策略。萬洲金業將為您提供一些實用的貴金屬交易指南&#xff0c;幫助您在市場中獲利。 …