驅動開發:內核註冊並監控對象回調
- 2022 年 10 月 24 日
- 筆記
- Windows 內核安全開發, Windows 內核驅動開發
在筆者上一篇文章《驅動開發:內核枚舉進程與執行緒ObCall回調》
簡單介紹了如何枚舉系統中已經存在的進程與執行緒
回調,本章LyShark
將通過對象回調實現對進程執行緒的句柄
監控,在內核中提供了ObRegisterCallbacks
回調,使用這個內核回調
函數,可註冊一個對象
回調,不過目前該函數只能
監控進程與執行緒句柄操作,通過監控進程或執行緒句柄,可實現保護指定進程執行緒不被終止的目的。
由於目前對象回調
只能監控進程與執行緒,而這個監控是通過ObjectType
這麼一個成員控制的,如果成員是PsProcessType
則代表監控進程,反之PsThreadType
則是監控執行緒,無論監控進程還是執行緒都調用ObRegisterCallbacks
這個函數來完成註冊。
函數ObRegisterCallbacks
其微軟對他的定義是這樣的,用戶傳入OB_OPERATION_REGISTRATION
結構,以及OB_CALLBACK_REGISTRATION
回調結構,其中PreOperation
則是傳入的回調函數,也是最重要的,其次是ObjectType
指定成進程回調。
NTSTATUS ObRegisterCallbacks(
[in] POB_CALLBACK_REGISTRATION CallbackRegistration,
[out] PVOID *RegistrationHandle
);
首先來實現一個檢測的案例,註冊一個進程回調對象MyLySharkComObjectCallBack
,通過ObRegisterCallbacks
註冊的回調只需要傳入一個填充好的OB_CALLBACK_REGISTRATION
回調結構體,以及一個全局句柄即可,這個全局句柄的作用僅僅只是在程式結束時,調用ObUnRegisterCallbacks
卸載監控而已,實現程式碼如下所示。
// 署名權
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: [email protected]
#include <ntddk.h>
#include <ntstrsafe.h>
PVOID Globle_Object_Handle;
// 繞過簽名檢測
void BypassCheckSign(PDRIVER_OBJECT pDriverObj)
{
typedef struct _LDR_DATA
{
struct _LIST_ENTRY InLoadOrderLinks;
struct _LIST_ENTRY InMemoryOrderLinks;
struct _LIST_ENTRY InInitializationOrderLinks;
VOID* DllBase;
VOID* EntryPoint;
ULONG32 SizeOfImage;
UINT8 _PADDING0_[0x4];
struct _UNICODE_STRING FullDllName;
struct _UNICODE_STRING BaseDllName;
ULONG32 Flags;
}LDR_DATA, *PLDR_DATA;
PLDR_DATA ldr;
ldr = (PLDR_DATA)(pDriverObj->DriverSection);
ldr->Flags |= 0x20;
}
// 自定義回調
OB_PREOP_CALLBACK_STATUS MyLySharkComObjectCallBack(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION OperationInformation)
{
DbgPrint("[lyshark] 執行回調函數... \n");
return STATUS_SUCCESS;
}
VOID UnDriver(PDRIVER_OBJECT driver)
{
ObUnRegisterCallbacks(Globle_Object_Handle);
DbgPrint("回調卸載完成... \n");
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
DbgPrint("hello lyshark.com \n");
BypassCheckSign(Driver);
OB_OPERATION_REGISTRATION Base; // 回調函數結構體
OB_CALLBACK_REGISTRATION CallbackReg; // 回調函數
CallbackReg.RegistrationContext = NULL; // 註冊上下文(你回調函數返回參數)
CallbackReg.Version = OB_FLT_REGISTRATION_VERSION; // 註冊回調版本
CallbackReg.OperationRegistration = &Base; // 回調結構體
CallbackReg.OperationRegistrationCount = 1; // 操作計數(下鉤數量)
RtlUnicodeStringInit(&CallbackReg.Altitude, L"600000"); // 長度
Base.ObjectType = PsProcessType; // 進程操作類型.此處為進程操作
Base.Operations = OB_OPERATION_HANDLE_CREATE; // 操作句柄創建
Base.PreOperation = MyLySharkComObjectCallBack; // 你自己的回調函數
Base.PostOperation = NULL;
// 註冊回調
if (ObRegisterCallbacks(&CallbackReg, &Globle_Object_Handle))
{
DbgPrint("[lyshark message] 回調註冊成功...");
}
Driver->DriverUnload = UnDriver;
return STATUS_SUCCESS;
}
當驅動程式被載入以後,一旦有進程運行則會執行我們自己的MyLySharkComObjectCallBack
回調,而在回調函數內則可以執行任意功能,運行如下所示。
如上所示只是演示基本的回調申請流程,回調函數通常需要包含兩個值,其一RegistrationContext
用於標註上下文,其二POB_PRE_OPERATION_INFORMATION
則用於標註進程或者執行緒創建的資訊結構體。
OB_PREOP_CALLBACK_STATUS MyLySharkComObjectCallBack(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION OperationInformation)
那麼如何實現攔截進程啟動
這個功能呢,我們可以在回調函數中寫入以下程式碼進行攔截。
- CreateHandleInformation.DesiredAccess 將打開句柄的許可權清零
- CreateHandleInformation.OriginalDesiredAccess 判斷是否終止
if (pOperationInformation->Operation == OB_OPERATION_HANDLE_CREATE)
{
DbgPrint("lyshark.exe 進程打開 \n");
pOperationInformation->Parameters->CreateHandleInformation.DesiredAccess=0;
if ((pOperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess & PROCESS_TERMINATE) == PROCESS_TERMINATE)
{
pOperationInformation->Parameters->CreateHandleInformation.DesiredAccess &= ~PROCESS_TERMINATE;
}
}
攔截進程創建核心程式碼如下所示。
// 署名權
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: [email protected]
#include <ntddk.h>
#include <ntstrsafe.h>
#define PROCESS_TERMINATE 0x1
// 導出兩個API
NTKERNELAPI PEPROCESS IoThreadToProcess(PETHREAD Thread);
NTKERNELAPI char* PsGetProcessImageFileName(PEPROCESS Process);
// 全局句柄
PVOID Globle_Object_Handle = NULL;
// 繞過簽名檢測
void BypassCheckSign(PDRIVER_OBJECT pDriverObj)
{
typedef struct _LDR_DATA
{
struct _LIST_ENTRY InLoadOrderLinks;
struct _LIST_ENTRY InMemoryOrderLinks;
struct _LIST_ENTRY InInitializationOrderLinks;
VOID* DllBase;
VOID* EntryPoint;
ULONG32 SizeOfImage;
UINT8 _PADDING0_[0x4];
struct _UNICODE_STRING FullDllName;
struct _UNICODE_STRING BaseDllName;
ULONG32 Flags;
}LDR_DATA, *PLDR_DATA;
PLDR_DATA ldr;
ldr = (PLDR_DATA)(pDriverObj->DriverSection);
ldr->Flags |= 0x20;
}
// 判斷是否是需要保護的進程
BOOLEAN CheckProcess(PEPROCESS eprocess)
{
char *Name = PsGetProcessImageFileName(eprocess);
if (!_stricmp("lyshark.exe", Name))
return TRUE;
else
return FALSE;
}
// 進程回調
OB_PREOP_CALLBACK_STATUS MyLySharkProcessObjectCallBack(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION pOperationInformation)
{
HANDLE pid;
// 只取出進程回調
if (pOperationInformation->ObjectType != *PsProcessType)
{
return OB_PREOP_SUCCESS;
}
// 得到所有進程的ID
pid = PsGetProcessId((PEPROCESS)pOperationInformation->Object);
// DbgPrint("進程PID= %ld \n", pid);
UNREFERENCED_PARAMETER(RegistrationContext);
// 驗證是否是需要的進程
if (CheckProcess((PEPROCESS)pOperationInformation->Object))
{
// 創建句柄
if (pOperationInformation->Operation == OB_OPERATION_HANDLE_CREATE)
{
DbgPrint("lyshark.exe 進程打開事件 \n");
pOperationInformation->Parameters->CreateHandleInformation.DesiredAccess=0;
if ((pOperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess & PROCESS_TERMINATE) == PROCESS_TERMINATE)
{
DbgPrint("[LyShark Message] 攔截進程打開 \n");
pOperationInformation->Parameters->CreateHandleInformation.DesiredAccess &= ~PROCESS_TERMINATE;
}
}
// 複製句柄
if (pOperationInformation->Operation == OB_OPERATION_HANDLE_DUPLICATE)
{
DbgPrint("lyshark.exe 進程被關閉 \n");
pOperationInformation->Parameters->DuplicateHandleInformation.DesiredAccess=0;
if ((pOperationInformation->Parameters->DuplicateHandleInformation.OriginalDesiredAccess & PROCESS_TERMINATE) == PROCESS_TERMINATE)
{
pOperationInformation->Parameters->DuplicateHandleInformation.DesiredAccess &= ~PROCESS_TERMINATE;
}
}
}
return OB_PREOP_SUCCESS;
}
VOID UnDriver(PDRIVER_OBJECT driver)
{
ObUnRegisterCallbacks(Globle_Object_Handle);
DbgPrint("回調卸載完成... \n");
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
DbgPrint("hello lyshark.com \n");
BypassCheckSign(Driver);
OB_OPERATION_REGISTRATION ob_process_callback;
OB_CALLBACK_REGISTRATION op_process_operation;
memset(&ob_process_callback, 0, sizeof(ob_process_callback));
ob_process_callback.ObjectType = PsProcessType;
ob_process_callback.Operations = OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE;
ob_process_callback.PreOperation = MyLySharkProcessObjectCallBack;
ob_process_callback.PostOperation = NULL;
RtlUnicodeStringInit(&op_process_operation.Altitude, L"600000");
op_process_operation.RegistrationContext = NULL;
op_process_operation.Version = OB_FLT_REGISTRATION_VERSION;
op_process_operation.OperationRegistration = &ob_process_callback;
op_process_operation.OperationRegistrationCount = 1;
// 註冊進程回調
if (ObRegisterCallbacks(&op_process_operation, &Globle_Object_Handle))
{
DbgPrint("進程回調註冊成功...");
}
Driver->DriverUnload = UnDriver;
return STATUS_SUCCESS;
}
載入這個驅動,當有進程被創建時,則首先判斷是否是lyshark.exe
如果是則直接禁止打開,也就是終止掉。
同理進程可以被攔截,那麼如果增加更多的過濾條件,則執行緒
同樣可以被攔截,攔截執行緒程式碼如下所示。
// 署名權
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: [email protected]
#include <ntddk.h>
#include <ntstrsafe.h>
#define THREAD_TERMINATE2 0x1
// 導出兩個API
NTKERNELAPI PEPROCESS IoThreadToProcess(PETHREAD Thread);
NTKERNELAPI char* PsGetProcessImageFileName(PEPROCESS Process);
// 全局句柄
PVOID Globle_Object_Handle = NULL;
// 繞過簽名檢測
void BypassCheckSign(PDRIVER_OBJECT pDriverObj)
{
typedef struct _LDR_DATA
{
struct _LIST_ENTRY InLoadOrderLinks;
struct _LIST_ENTRY InMemoryOrderLinks;
struct _LIST_ENTRY InInitializationOrderLinks;
VOID* DllBase;
VOID* EntryPoint;
ULONG32 SizeOfImage;
UINT8 _PADDING0_[0x4];
struct _UNICODE_STRING FullDllName;
struct _UNICODE_STRING BaseDllName;
ULONG32 Flags;
}LDR_DATA, *PLDR_DATA;
PLDR_DATA ldr;
ldr = (PLDR_DATA)(pDriverObj->DriverSection);
ldr->Flags |= 0x20;
}
// 判斷是否是需要保護的進程
BOOLEAN CheckProcess(PEPROCESS eprocess)
{
char *Name = PsGetProcessImageFileName(eprocess);
if (!_stricmp("lyshark.exe", Name))
return TRUE;
else
return FALSE;
}
// 執行緒回調
OB_PREOP_CALLBACK_STATUS MyThreadObjectCallBack(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION pOperationInformation)
{
PEPROCESS ep;
PETHREAD et;
HANDLE pid;
// 執行緒過濾
if (pOperationInformation->ObjectType != *PsThreadType)
{
return OB_PREOP_SUCCESS;
}
et = (PETHREAD)pOperationInformation->Object;
ep = IoThreadToProcess(et);
pid = PsGetProcessId(ep);
// DbgPrint("執行緒PID= %ld | TID= %ld \n", pid, PsGetThreadId(et));
UNREFERENCED_PARAMETER(RegistrationContext);
if (CheckProcess(ep))
{
if (pOperationInformation->Operation == OB_OPERATION_HANDLE_CREATE)
{
pOperationInformation->Parameters->CreateHandleInformation.DesiredAccess=0;
if ((pOperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess & THREAD_TERMINATE2) == THREAD_TERMINATE2)
{
DbgPrint("[LyShark] 攔截lyshark.exe進程內 %d 執行緒創建 \n", PsGetThreadId(et));
pOperationInformation->Parameters->CreateHandleInformation.DesiredAccess &= ~THREAD_TERMINATE2;
}
}
if (pOperationInformation->Operation == OB_OPERATION_HANDLE_DUPLICATE)
{
pOperationInformation->Parameters->DuplicateHandleInformation.DesiredAccess=0;
if ((pOperationInformation->Parameters->DuplicateHandleInformation.OriginalDesiredAccess & THREAD_TERMINATE2) == THREAD_TERMINATE2)
{
pOperationInformation->Parameters->DuplicateHandleInformation.DesiredAccess &= ~THREAD_TERMINATE2;
}
}
}
return OB_PREOP_SUCCESS;
}
VOID UnDriver(PDRIVER_OBJECT driver)
{
ObUnRegisterCallbacks(Globle_Object_Handle);
DbgPrint("回調卸載完成... \n");
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
DbgPrint("hello lyshark.com \n");
BypassCheckSign(Driver);
OB_OPERATION_REGISTRATION ob_thread_callback;
OB_CALLBACK_REGISTRATION op_thread_operation;
memset(&ob_thread_callback, 0, sizeof(ob_thread_callback));
ob_thread_callback.ObjectType = PsThreadType;
ob_thread_callback.Operations = OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE;
ob_thread_callback.PreOperation = MyThreadObjectCallBack;
ob_thread_callback.PostOperation = NULL;
RtlUnicodeStringInit(&op_thread_operation.Altitude, L"600001");
op_thread_operation.RegistrationContext = NULL;
op_thread_operation.Version = OB_FLT_REGISTRATION_VERSION;
op_thread_operation.OperationRegistration = &ob_thread_callback;
op_thread_operation.OperationRegistrationCount = 1;
// 註冊進程回調
if (ObRegisterCallbacks(&op_thread_operation, &Globle_Object_Handle))
{
DbgPrint("進程回調註冊成功...");
}
Driver->DriverUnload = UnDriver;
return STATUS_SUCCESS;
}
這段驅動載入後,如果有新執行緒被創建,則會被攔截並列印輸出,效果圖如下。
參考文獻
//www.cnblogs.com/ciyze0101/p/5468175.html