亚洲国产第一_开心网五月色综合亚洲_日本一级特黄特色大片免费观看_久久久久久久久久免观看

Hello! 歡迎來到小浪云!


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


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

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

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

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

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

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

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

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

代碼語言:JavaScript代碼運行次數:0運行復制

// 參數1:回調函數地址// 參數2:無作用// 參數3:回調句柄NTSTATUS CmRegisterCallback(  [in]           PEX_CALLBACK_FUNCTION Function,  [in, optional] PVOID                 Context,  [out]          PLARGE_INTEGER        Cookie);

自定義注冊表回調函數MyLySharkCallback需要保留三個參數,CallbackContext回調上下文,Argument1是操作類型,Argument2定義詳細結構體指針。

代碼語言:javascript代碼運行次數:0運行復制

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

在自定義回調函數內Argument1則可獲取到操作類型,類型是一個REG_NOTIFY_CLASS枚舉結構,微軟對其的具體定義如下所示。

代碼語言:javascript代碼運行次數:0運行復制

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

代碼語言:javascript代碼運行次數:0運行復制

#include <ntifs.h>#include <windef.h>// 未導出函數聲明 pEProcess -&gt; PIDPUCHAR PsGetProcessImageFileName(PEPROCESS pEProcess);NTSTATUS ObQueryNameString(    _In_ PVOID Object,    _Out_writes_bytes_opt_(Length) POBJECT_NAME_INFORMATION ObjectNameInfo,    _In_ ULONG Length,    _Out_ PULONG ReturnLength    );// 注冊表回調CookieLARGE_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, &amp;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(&amp;ustrRegPath, ((PREG_CREATE_KEY_INFORMATION)Argument2)-&gt;RootObject);        DbgPrint("[創建注冊表][%wZ][%wZ] ", &amp;ustrRegPath, ((PREG_CREATE_KEY_INFORMATION)Argument2)-&gt;CompleteName);        break;    }    // 打開注冊表之前    case RegNtPreOpenKey:    {        // 獲取注冊表路徑        GetFullPath(&amp;ustrRegPath, ((PREG_CREATE_KEY_INFORMATION)Argument2)-&gt;RootObject);        DbgPrint("[打開注冊表][%wZ][%wZ] ", &amp;ustrRegPath, ((PREG_CREATE_KEY_INFORMATION)Argument2)-&gt;CompleteName);        break;    }    // 刪除鍵之前    case RegNtPreDeleteKey:    {        // 獲取注冊表路徑        GetFullPath(&amp;ustrRegPath, ((PREG_DELETE_KEY_INFORMATION)Argument2)-&gt;Object);        DbgPrint("[刪除鍵][%wZ]  ", &amp;ustrRegPath);        break;    }    // 刪除鍵值之前    case RegNtPreDeleteValueKey:    {        // 獲取注冊表路徑        GetFullPath(&amp;ustrRegPath, ((PREG_DELETE_VALUE_KEY_INFORMATION)Argument2)-&gt;Object);        DbgPrint("[刪除鍵值][%wZ][%wZ]  ", &amp;ustrRegPath, ((PREG_DELETE_VALUE_KEY_INFORMATION)Argument2)-&gt;ValueName);        // 獲取當前進程, 即操作注冊表的進程        PEPROCESS pEProcess = PsGetCurrentProcess();        if (NULL != pEProcess)        {            UCHAR *lpszProcessName = PsGetProcessImageFileName(pEProcess);            if (NULL != lpszProcessName)            {                DbgPrint("進程 [%s] 刪除了鍵值對  ", lpszProcessName);            }        }        break;    }    // 修改鍵值之前    case RegNtPreSetValueKey:    {        // 獲取注冊表路徑        GetFullPath(&amp;ustrRegPath, ((PREG_SET_VALUE_KEY_INFORMATION)Argument2)-&gt;Object);        DbgPrint("[修改鍵值][%wZ][%wZ]  ", &amp;ustrRegPath, ((PREG_SET_VALUE_KEY_INFORMATION)Argument2)-&gt;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  "));    // 注銷當前注冊表回調    if (0 DriverUnload = UnDriver;    return STATUS_SUCCESS;}</windef.h></ntifs.h>

運行驅動程序,則會輸出當前系統中所有針對注冊表的操作,如下圖所示。

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

如上的代碼只能實現注冊表項的監視,而如果需要監控則需要在回調函數MyLySharkCallback判斷,如果指定注冊表項是需要保護的則直接返回status = STATUS_access_DENIED;從而達到保護注冊表的目的,核心代碼如下所示。

代碼語言:javascript代碼運行次數:0運行復制

// 反注冊表刪除回調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(&amp;ustrRegPath, ((PREG_DELETE_VALUE_KEY_INFORMATION)Argument2)-&gt;Object);        DbgPrint("[刪除鍵值][%wZ][%wZ] ", &amp;ustrRegPath, ((PREG_DELETE_VALUE_KEY_INFORMATION)Argument2)-&gt;ValueName);        // 如果要刪除指定注冊表項則拒絕        PWCH pszRegister = L"REGISTRYMACHINESOFTWARElyshark";        if (wcscmp(ustrRegPath.Buffer, pszRegister) == 0)        {            DbgPrint("[lyshark] 注冊表項刪除操作已被攔截!  ");            // 拒絕操作            status = STATUS_ACCESS_DENIED;        }        break;    }    default:        break;    }    // 釋放內存    if (NULL != ustrRegPath.Buffer)    {        ExFreePool(ustrRegPath.Buffer);        ustrRegPath.Buffer = NULL;    }    return status;}

運行驅動程序,然后我們嘗試刪除LySharkHKEY_LOCAL_MACHINESOFTWARElyshark里面的子項,則會提示如下信息。

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

當然這里的RegNtPreDeleteValueKey是指的刪除操作,如果將其替換成RegNtPreSetValueKey,那么只有當注冊表被創建才會攔截,此時就會變成攔截創建。

代碼語言:javascript代碼運行次數:0運行復制

// 攔截創建操作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(&amp;ustrRegPath, ((PREG_DELETE_VALUE_KEY_INFORMATION)Argument2)-&gt;Object);        // 攔截創建        PWCH pszRegister = L"REGISTRYMACHINESOFTWARElyshark";        if (wcscmp(ustrRegPath.Buffer, pszRegister) == 0)        {            DbgPrint("[lyshark] 注冊表項創建操作已被攔截!  ");            status = STATUS_ACCESS_DENIED;        }        break;    }    default:        break;    }    // 釋放內存    if (NULL != ustrRegPath.Buffer)    {        ExFreePool(ustrRegPath.Buffer);        ustrRegPath.Buffer = NULL;    }    return status;}

加載驅動保護,然后我們嘗試在LySharkHKEY_LOCAL_MACHINESOFTWARElyshark里面創建一個子項,則會提示創建失敗。

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

相關閱讀