通過ObRegisterCallbacks學習對象監控與反對象監控
VSole2021-11-23 16:23:57
簡介
實現環境:WIN7 X86。
要實現的目標:對進程對象和線程對象實現監控來保護目標進程不被任務管理器關掉。
對象監控
在Windows中可以通過ObRegisterCallbacks來設置對象監控,該函數的定義如下:
NTSTATUS ObRegisterCallbacks( IN POB_CALLBACK_REGISTRATION CallBackRegistration, OUT PVOID *RegistrationHandle);

OB_CALLBACK_REGISTRATION結構體的定義如下:
typedef struct _OB_CALLBACK_REGISTRATION { __in USHORT Version; __in USHORT OperationRegistrationCount; __in UNICODE_STRING Altitude; __in PVOID RegistrationContext; __in OB_OPERATION_REGISTRATION *OperationRegistration;} OB_CALLBACK_REGISTRATION, *POB_CALLBACK_REGISTRATION;

OB_OPERATION_REGISTRATION結構體定義如下:
typedef struct _OB_OPERATION_REGISTRATION { __in POBJECT_TYPE *ObjectType; __in OB_OPERATION Operations; __in POB_PRE_OPERATION_CALLBACK PreOperation; __in POB_POST_OPERATION_CALLBACK PostOperation;} OB_OPERATION_REGISTRATION, *POB_OPERATION_REGISTRATION;

ObjectPreCallback和ObjectPostCallback的定義如下,它們的參數是一樣的,只是返回值不同。
OB_PREOP_CALLBACK_STATUS ObjectPreCallback( __in PVOID RegistrationContext, __in POB_PRE_OPERATION_INFORMATION OperationInformation); VOID ObjectPostCallback( __in PVOID RegistrationContext, __in POB_POST_OPERATION_INFORMATION OperationInformation );

最后在介紹一個函數,它可以根據線程對象獲得進程對象。該函數的定義如下:
PEPROCESS IoThreadToProcess( IN PETHREAD Thread);
根據以上內容就可以實現對進程的保護,具體代碼如下:
#include
#define PROCESS_NAME "demo.exe" // 要保護的進程名#define PROCESS_TERMINATE 0x0001
typedef struct _KLDR_DATA_TABLE_ENTRY{ LIST_ENTRY InLoadOrderModuleList; LIST_ENTRY InMemoryOrderModuleList; LIST_ENTRY InInitializationOrderModuleList; PVOID DllBase; PVOID EntryPoint; UINT32 SizeOfImage; UNICODE_STRING FullDllName; UNICODE_STRING BaseDllName; UINT32 Flags; USHORT LoadCount; USHORT TlsIndex; LIST_ENTRY HashLinks; PVOID SectionPointer; UINT32 CheckSum; UINT32 TimeDateStamp; PVOID LoadedImports; PVOID EntryPointActivationContext; PVOID PatchInformation;} KLDR_DATA_TABLE_ENTRY, *PKLDR_DATA_TABLE_ENTRY;
// 未導出函數聲明PUCHAR PsGetProcessImageFileName(PEPROCESS pEProcess);VOID DriverUnload(IN PDRIVER_OBJECT driverObject);BOOLEAN IsProtectProcess(PEPROCESS pEProcess); // 判斷是否是要保護的進程NTSTATUS SetProcessCallback(); // 設置進程回調函數NTSTATUS SetThreadCallback(); // 設置線程回調函數OB_PREOP_CALLBACK_STATUS ProcessPreCall(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION pObPreOperationInfo); // 進程回調函數OB_PREOP_CALLBACK_STATUS ThreadPreCall(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION pObPreOperationInfo); // 線程回調函數
// 進程回調對象句柄HANDLE g_obProcessHandle;// 線程回調對象句柄HANDLE g_obThreadHandle;
NTSTATUS DriverEntry(IN PDRIVER_OBJECT driverObject, IN PUNICODE_STRING registryPath){ NTSTATUS status = STATUS_SUCCESS; PKLDR_DATA_TABLE_ENTRY pLdrData = NULL;
DbgPrint("驅動加載完成\r"); pLdrData = (PKLDR_DATA_TABLE_ENTRY)driverObject->DriverSection; pLdrData->Flags = pLdrData->Flags | 0x20;
if (NT_SUCCESS(SetProcessCallback())) { DbgPrint("進程回調函數設置完成\r"); }
if (NT_SUCCESS(SetThreadCallback())) { DbgPrint("線程回調函數設置完成\r"); }exit: driverObject->DriverUnload = DriverUnload; return STATUS_SUCCESS;}
NTSTATUS SetProcessCallback(){ NTSTATUS status = STATUS_SUCCESS; OB_CALLBACK_REGISTRATION obCallbackReg = { 0 }; OB_OPERATION_REGISTRATION obOperationReg = { 0 };
RtlZeroMemory(&obCallbackReg, sizeof(obCallbackReg)); RtlZeroMemory(&obOperationReg, sizeof(obOperationReg));
//設置OB_OPERATION_REGISTRATION obOperationReg.ObjectType = PsProcessType; obOperationReg.Operations = OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE; obOperationReg.PreOperation = (POB_PRE_OPERATION_CALLBACK)(&ProcessPreCall);
//設置OB_CALLBACK_REGISTRATION obCallbackReg.Version = ObGetFilterVersion(); obCallbackReg.OperationRegistrationCount = 1; obCallbackReg.RegistrationContext = NULL; RtlInitUnicodeString(&obCallbackReg.Altitude, L"1900"); obCallbackReg.OperationRegistration = &obOperationReg;
status = ObRegisterCallbacks(&obCallbackReg, &g_obProcessHandle); if (!NT_SUCCESS(status)) { DbgPrint("ObRegisterCallbacks Error 0x%X\r", status); }
return status;}
OB_PREOP_CALLBACK_STATUS ProcessPreCall(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION pObPreOperationInfo){ PEPROCESS pEProcess = NULL;
// 判斷對象類型 if (*PsProcessType != pObPreOperationInfo->ObjectType) { goto exit; }
// 獲取進程結構體對象 pEProcess = (PEPROCESS)pObPreOperationInfo->Object; if (IsProtectProcess(pEProcess)) // 是否是要保護的進程 { // 判斷操作類型是創建句柄還是復制句柄 if (pObPreOperationInfo->Operation == OB_OPERATION_HANDLE_CREATE) { //是否具有關閉進程的權限,有的話刪掉它 if (pObPreOperationInfo->Parameters->CreateHandleInformation.OriginalDesiredAccess & PROCESS_TERMINATE) { pObPreOperationInfo->Parameters->CreateHandleInformation.DesiredAccess &= ~PROCESS_TERMINATE; } } else if (pObPreOperationInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE) { //是否具有關閉進程的權限,有的話刪掉它 if (pObPreOperationInfo->Parameters->DuplicateHandleInformation.DesiredAccess & PROCESS_TERMINATE) { pObPreOperationInfo->Parameters->DuplicateHandleInformation.DesiredAccess &= ~PROCESS_TERMINATE; } } }exit: return OB_PREOP_SUCCESS;}
NTSTATUS SetThreadCallback(){ NTSTATUS status = STATUS_SUCCESS; OB_CALLBACK_REGISTRATION obCallbackReg = { 0 }; OB_OPERATION_REGISTRATION obOperationReg = { 0 };
RtlZeroMemory(&obCallbackReg, sizeof(OB_CALLBACK_REGISTRATION)); RtlZeroMemory(&obOperationReg, sizeof(OB_OPERATION_REGISTRATION));
// 設置 OB_OPERATION_REGISTRATION obOperationReg.ObjectType = PsThreadType; obOperationReg.Operations = OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE; obOperationReg.PreOperation = (POB_PRE_OPERATION_CALLBACK)(&ThreadPreCall);
// 設置 OB_CALLBACK_REGISTRATION obCallbackReg.Version = ObGetFilterVersion(); obCallbackReg.OperationRegistrationCount = 1; obCallbackReg.RegistrationContext = NULL; RtlInitUnicodeString(&obCallbackReg.Altitude, L"1900"); obCallbackReg.OperationRegistration = &obOperationReg;
// 注冊回調函數 status = ObRegisterCallbacks(&obCallbackReg, &g_obThreadHandle); if (!NT_SUCCESS(status)) { DbgPrint("ObRegisterCallbacks Error[0x%X]", status); return status; }
return status;}
// 線程回調函數OB_PREOP_CALLBACK_STATUS ThreadPreCall(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION pObPreOperationInfo){ PEPROCESS pEProcess = NULL;
// 判斷對象類型 if (*PsThreadType != pObPreOperationInfo->ObjectType) { return OB_PREOP_SUCCESS; } // 獲取線程對應的進程 PEPROCESS pEProcess = IoThreadToProcess((PETHREAD)pObPreOperationInfo->Object); // 判斷是否是要保護的進程, 若是, 則拒絕結束線程 if (IsProtectProcess(pEProcess)) { // 判斷操作類型是創建句柄還是復制句柄 if (pObPreOperationInfo->Operation == OB_OPERATION_HANDLE_CREATE) { //是否具有關閉線程的權限,有的話刪掉它 if (pObPreOperationInfo->Parameters->CreateHandleInformation.OriginalDesiredAccess & PROCESS_TERMINATE) { pObPreOperationInfo->Parameters->CreateHandleInformation.DesiredAccess &= ~PROCESS_TERMINATE; } } else if (pObPreOperationInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE) { //是否具有關閉線程的權限,有的話刪掉它 if (pObPreOperationInfo->Parameters->DuplicateHandleInformation.DesiredAccess & PROCESS_TERMINATE) { pObPreOperationInfo->Parameters->DuplicateHandleInformation.DesiredAccess &= ~PROCESS_TERMINATE; } } }
return OB_PREOP_SUCCESS;}
BOOLEAN IsProtectProcess(PEPROCESS pEProcess){ BOOLEAN bRet = FALSE; PUCHAR pProcName = PsGetProcessImageFileName(pEProcess); // 獲取要保護的進程名
if (pProcName) { if (strcmp(pProcName, PROCESS_NAME) == 0) { bRet = TRUE; } }
return bRet;}
VOID DriverUnload(IN PDRIVER_OBJECT driverObject){ // 刪除進程回調 if (g_obProcessHandle) { ObUnRegisterCallbacks(g_obProcessHandle); g_obProcessHandle = NULL; }
// 卸載線程回調 if (NULL != g_obThreadHandle) { ObUnRegisterCallbacks(g_obThreadHandle); g_obThreadHandle = NULL; }
DbgPrint("驅動卸載完成\r");}
反對象監控
系統設置的對象回調函數會存儲在一個名頭CallbackList表頭的雙向鏈表里,它存儲著系統上所有ObRegisterCallbacks對象回調地址,包括操作前和操作后的回調函數地址以及對象回調句柄信息。CallbackList雙向鏈表的結構定義如下:
#pragma pack(1)typedef struct _OB_CALLBACK{ LIST_ENTRY ListEntry; ULONGLONG Unknown; HANDLE ObHandle; PVOID ObTypeAddr; PVOID PreCall; PVOID PostCall;}OB_CALLBACK, *POB_CALLBACK;#pragma pack()

如果想要獲取進程回調的雙向鏈表信息,可以從*PsProcessType中獲取。要獲得線程回調的雙向鏈表信息,可以從*PsThreadType中獲取。
*PsProcessType和*PsThreadType的數據結構類型為POBJECT_TYPE,定義如下:
typedef struct _OBJECT_TYPE{ LIST_ENTRY TypeList; // _LIST_ENTRY UNICODE_STRING Name; // _UNICODE_STRING PVOID DefaultObject; // Ptr64 Void UCHAR Index; // UChar ULONG TotalNumberOfObjects; // Uint4B ULONG TotalNumberOfHandles; // Uint4B ULONG HighWaterNumberOfObjects; // Uint4B ULONG HighWaterNumberOfHandles; // Uint4B OBJECT_TYPE_INITIALIZER TypeInfo; // _OBJECT_TYPE_INITIALIZER EX_PUSH_LOCK TypeLock; // _EX_PUSH_LOCK ULONG Key; // Uint4B LIST_ENTRY CallbackList; // _LIST_ENTRY}OBJECT_TYPE, *POBJECT_TYPE;
最后一個成員CallbackList就是雙向鏈表表頭。
而倒數第四個成員的類型為OBJECT_TYPE_INITIALIZER,它的定義如下:
typedef struct _OBJECT_TYPE_INITIALIZER{ USHORT Length; // Uint2B UCHAR ObjectTypeFlags; // UChar ULONG ObjectTypeCode; // Uint4B ULONG InvalidAttributes; // Uint4B GENERIC_MAPPING GenericMapping; // _GENERIC_MAPPING ULONG ValidAccessMask; // Uint4B ULONG RetainAccess; // Uint4B POOL_TYPE PoolType; // _POOL_TYPE ULONG DefaultPagedPoolCharge; // Uint4B ULONG DefaultNonPagedPoolCharge; // Uint4B PVOID DumpProcedure; // Ptr64 void PVOID OpenProcedure; // Ptr64 long PVOID CloseProcedure; // Ptr64 void PVOID DeleteProcedure; // Ptr64 void PVOID ParseProcedure; // Ptr64 long PVOID SecurityProcedure; // Ptr64 long PVOID QueryNameProcedure; // Ptr64 long PVOID OkayToCloseProcedure; // Ptr64 unsigned char#if (NTDDI_VERSION >= NTDDI_WINBLUE) // Win8.1 ULONG WaitObjectFlagMask; // Uint4B USHORT WaitObjectFlagOffset; // Uint2B USHORT WaitObjectPointerOffset; // Uint2B#endif}OBJECT_TYPE_INITIALIZER, *POBJECT_TYPE_INITIALIZER;
所以可以從*PsProcessType和*PsThreadType中獲得鏈表頭,然后遍歷鏈表找到對應的句柄對象在調用ObUnRegisterCallbacks將回調刪除,具體代碼如下:
#include #include #pragma pack(1)typedef struct _OBJECT_TYPE_INITIALIZER{ USHORT Length; // Uint2B UCHAR ObjectTypeFlags; // UChar ULONG ObjectTypeCode; // Uint4B ULONG InvalidAttributes; // Uint4B GENERIC_MAPPING GenericMapping; // _GENERIC_MAPPING ULONG ValidAccessMask; // Uint4B ULONG RetainAccess; // Uint4B POOL_TYPE PoolType; // _POOL_TYPE ULONG DefaultPagedPoolCharge; // Uint4B ULONG DefaultNonPagedPoolCharge; // Uint4B PVOID DumpProcedure; // Ptr64 void PVOID OpenProcedure; // Ptr64 long PVOID CloseProcedure; // Ptr64 void PVOID DeleteProcedure; // Ptr64 void PVOID ParseProcedure; // Ptr64 long PVOID SecurityProcedure; // Ptr64 long PVOID QueryNameProcedure; // Ptr64 long PVOID OkayToCloseProcedure; // Ptr64 unsigned char#if (NTDDI_VERSION >= NTDDI_WINBLUE) // Win8.1 ULONG WaitObjectFlagMask; // Uint4B USHORT WaitObjectFlagOffset; // Uint2B USHORT WaitObjectPointerOffset; // Uint2B#endif}OBJECT_TYPE_INITIALIZER, *POBJECT_TYPE_INITIALIZER; typedef struct _OBJECT_TYPE{ LIST_ENTRY TypeList; // _LIST_ENTRY UNICODE_STRING Name; // _UNICODE_STRING PVOID DefaultObject; // Ptr64 Void UCHAR Index; // UChar ULONG TotalNumberOfObjects; // Uint4B ULONG TotalNumberOfHandles; // Uint4B ULONG HighWaterNumberOfObjects; // Uint4B ULONG HighWaterNumberOfHandles; // Uint4B OBJECT_TYPE_INITIALIZER TypeInfo; // _OBJECT_TYPE_INITIALIZER EX_PUSH_LOCK TypeLock; // _EX_PUSH_LOCK ULONG Key; // Uint4B LIST_ENTRY CallbackList; // _LIST_ENTRY}OBJECT_TYPE, *POBJECT_TYPE; typedef struct _OB_CALLBACK{ LIST_ENTRY ListEntry; ULONGLONG Unknown; HANDLE ObHandle; PVOID ObTypeAddr; PVOID PreCall; PVOID PostCall;}OB_CALLBACK, *POB_CALLBACK;#pragma pack() VOID DriverUnload(IN PDRIVER_OBJECT driverObject);BOOLEAN RemoveProcessObCallback();BOOLEAN RemoveThreadObCallback(); NTSTATUS DriverEntry(IN PDRIVER_OBJECT driverObject, IN PUNICODE_STRING registryPath){ NTSTATUS status = STATUS_SUCCESS; if (RemoveProcessObCallback()) { DbgPrint("刪除進程回調成功\r"); } else { DbgPrint("刪除進程回調失敗\r"); } if (RemoveThreadObCallback()) { DbgPrint("刪除線程回調成功\r"); } else { DbgPrint("刪除線程回調失敗\r"); }exit: driverObject->DriverUnload = DriverUnload; return STATUS_SUCCESS;} BOOLEAN RemoveThreadObCallback(){ BOOLEAN bRet = TRUE; LIST_ENTRY CallbackList = ((POBJECT_TYPE)(*PsProcessType))->CallbackList; // 獲取線程表頭 POB_CALLBACK pObCallback = NULL; pObCallback = (POB_CALLBACK)CallbackList.Flink; do{ if (!MmIsAddressValid(pObCallback)) { bRet = FALSE; break; } if (pObCallback->ObHandle) { ObUnRegisterCallbacks(pObCallback->ObHandle); DbgPrint("刪除回調函數成功,函數地址:0x%X\r", pObCallback->PreCall); } } while (CallbackList.Flink != (PLIST_ENTRY)pObCallback); return bRet;} BOOLEAN RemoveProcessObCallback(){ BOOLEAN bRet = TRUE; POB_CALLBACK pObCallback = NULL; LIST_ENTRY CallbackList = ((POBJECT_TYPE)(*PsProcessType))->CallbackList; // 獲取設置進程對象回調函數的雙向鏈表表頭 pObCallback = (POB_CALLBACK)CallbackList.Flink; do{ if (!MmIsAddressValid(pObCallback)) { bRet = FALSE; break; } if (pObCallback->ObHandle) { ObUnRegisterCallbacks(pObCallback->ObHandle); DbgPrint("刪除回調成功,函數地址為:0x%X\r", pObCallback->PreCall); } pObCallback = (POB_CALLBACK)pObCallback->ListEntry.Flink; }while (CallbackList.Flink != (PLIST_ENTRY)pObCallback); return bRet;} VOID DriverUnload(IN PDRIVER_OBJECT driverObject){ DbgPrint("驅動卸載完成\r");}
運行結果
設置回調以后想要關閉進程就會失敗:

將回調刪除以后就可以正常關閉進程:

VSole
網絡安全專家