要实现监控系统线程和进程,并实现对指定线程和进程的保护,在 32 位系统上可以使用 HOOK 技术,HOOK 相关的函数来实现。但是,到了 64 位平台上,就不能继续按常规的 HOOK 方法去实现了。
好在 Windows 给我们提供了 ObRegisterCallbacks 内核函数来注册系统回调,可以用来注册系统线程回调,监控系统的线程创建、退出等情况,而且还能进行控制;也可以用来注册系统进程回调,可以监控系统的进程创建、退出等情况,而且也能进行控制。这使得我们实现保护指定线程、进程不被结束,提供了可能。
现在,我就对程序的实现过程和原理进行整理,形成文档,分享给大家。
函数介绍
ObRegisterCallbacks 函数
注册线程、进程和桌面句柄操作的回调函数。
函数声明
NTSTATUS ObRegisterCallbacks(_In_ POB_CALLBACK_REGISTRATION CallBackRegistration,_Out_ PVOID *RegistrationHandle);参数
- CallBackRegistration [in]
指向指定回调例程列表和其他注册信息的OB_CALLBACK_REGISTRATION结构的指针。- RegistrationHandle [out]
指向变量的指针,该变量接收一个标识已注册的回调例程集合的值。 调用者将此值传递给ObUnRegisterCallbacks例程以注销该回调集。返回值
- 成功,则返回 STATUS_SUCCESS,否则,返回其它 NTSTATUS 错误码。
备注
- 驱动程序必须在卸载之前注销所有回调例程。 您可以通过调用ObUnRegisterCallbacks例程来注销回调例程。
OB_CALLBACK_REGISTRATION 结构体
typedef struct _OB_CALLBACK_REGISTRATION {USHORT Version;USHORT OperationRegistrationCount;UNICODE_STRING Altitude;PVOID RegistrationContext;OB_OPERATION_REGISTRATION *OperationRegistration;} OB_CALLBACK_REGISTRATION, *POB_CALLBACK_REGISTRATION;成员
- Version
请求的对象回调注册版本。 驱动程序应指定OB_FLT_REGISTRATION_VERSION。- OperationRegistrationCount
OperationRegistration数组中的条目数。- Altitude
指定驱动程序Altitude的Unicode字符串。一定要存在,不能置为空 NULL,可以任意指定。- RegistrationContext
当回调例程运行时,系统将RegistrationContext值传递给回调例程。 该值的含义是由驱动程序自定义的。- OperationRegistration
指向OB_OPERATION_REGISTRATION结构数组的指针。 每个结构指定ObjectPreCallback和ObjectPostCallback回调例程以及调用例程的操作类型。
OB_OPERATION_REGISTRATION 结构体
typedef struct _OB_OPERATION_REGISTRATION {POBJECT_TYPE *ObjectType;OB_OPERATION Operations;POB_PRE_OPERATION_CALLBACK PreOperation;POB_POST_OPERATION_CALLBACK PostOperation;} OB_OPERATION_REGISTRATION, *POB_OPERATION_REGISTRATION;成员
- ObjectType
指向触发回调例程的对象类型的指针。 指定以下值之一:
用于进程句柄操作的PsProcessType
线程句柄操作的PsThreadType
用于桌面句柄操作的ExDesktopObjectType。 此值在Windows 10中受支持,而不在早期版本的操作系统中。- Operations
指定以下一个或多个标志:
OB_OPERATION_HANDLE_CREATE
一个新的进程,线程或桌面句柄已被打开或将被打开。
OB_OPERATION_HANDLE_DUPLICATE
进程,线程或桌面句柄已被或将被复制。- PreOperation
指向ObjectPreCallback例程的指针。 在请求的操作发生之前,系统调用此例程。- PostOperation
指向ObjectPostCallback例程的指针。 在请求的操作发生后,系统调用此例程。
IoThreadToProcess 函数
返回指向指定线程的进程的指针。
函数声明
PEPROCESS IoThreadToProcess(_In_ PETHREAD Thread);参数
- Thread[in]
- 要返回进程的指定线程对象。
返回值
- 返回线程对象对应的进程对象的指针。
PsGetProcessId 函数
返回与指定进程关联的进程标识符(进程ID)。
函数声明
HANDLE PsGetProcessId(_In_ PEPROCESS Process);参数
Process[in]
指向进程对象结构的指针。
返回值
- 返回进程ID。
实现原理
破解 ObRegisterCallbacks 函数的使用限制
第一种方法
在讲解怎么使用 ObRegisterCallbacks 函数来注册系统线程、进程回调的之前,先来讲解下 Windows 对这个函数做的限制:驱动程序必须有数字签名才能使用此函数。不过国外的黑客对此限制很不满,通过逆向 ObRegisterCallbacks,找到了
破解这个限制的方法。经研究,内核通过 MmVerifyCallbackFunction 验证此回调
是否合法, 但此函数只是简单的验证了一下 DriverObject->DriverSection->Flags 的值是不是为 0x20:
nt!MmVerifyCallbackFunction+0x75:fffff800`01a66865 f6406820 test byte ptr [rax+68h],20hfffff800`01a66869 0f45fd cmovne edi,ebp
所以破解方法非常简单,只要把 DriverObject->DriverSection->Flags 的值按位或 0x20 即可。其中,DriverSection 是指向 LDR_DATA_TABLE_ENTRY 结构的值,要注意该结构在 32 位和 64 位系统下的定义。
// 注意32位与64位的对齐大小
// 注意32位与64位的对齐大小
#ifndef _WIN64
#pragma pack(1) &nb

本文详细介绍了如何在64位Windows系统上利用ObRegisterCallbacks函数注册线程和进程回调,以实现对指定线程和进程的保护。首先,讨论了32位系统上HOOK技术的局限性,然后详细阐述了ObRegisterCallbacks的使用,包括结构体OB_CALLBACK_REGISTRATION和OB_OPERATION_REGISTRATION的初始化,以及回调函数的设置。接着,文章讲解了两种绕过签名检查的方法,一种是编程方式,另一种是设置链接器标志。在实现原理部分,解释了如何在回调函数中修改权限来阻止线程或进程结束。最后,提供了线程和进程回调函数的示例代码,展示了如何判断并保护目标线程或进程。

6212

被折叠的 条评论
为什么被折叠?



