基于ObRegisterCallbacks实现的线程和进程监控及其保护

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

要实现监控系统线程和进程,并实现对指定线程和进程的保护,在 32 位系统上可以使用 HOOK 技术,HOOK 相关的函数来实现。但是,到了 64 位平台上,就不能继续按常规的 HOOK 方法去实现了。

好在 Windows 给我们提供了 ObRegisterCallbacks 内核函数来注册系统回调,可以用来注册系统线程回调,监控系统的线程创建、退出等情况,而且还能进行控制;也可以用来注册系统进程回调,可以监控系统的进程创建、退出等情况,而且也能进行控制。这使得我们实现保护指定线程、进程不被结束,提供了可能。

现在,我就对程序的实现过程和原理进行整理,形成文档,分享给大家。

函数介绍

ObRegisterCallbacks 函数

注册线程、进程和桌面句柄操作的回调函数。

函数声明

 
  1. NTSTATUS ObRegisterCallbacks(
  2. _In_ POB_CALLBACK_REGISTRATION CallBackRegistration,
  3. _Out_ PVOID *RegistrationHandle
  4. );

参数

  • CallBackRegistration [in]
    指向指定回调例程列表和其他注册信息的OB_CALLBACK_REGISTRATION结构的指针。
  • RegistrationHandle [out]
    指向变量的指针,该变量接收一个标识已注册的回调例程集合的值。 调用者将此值传递给ObUnRegisterCallbacks例程以注销该回调集。

返回值

  • 成功,则返回 STATUS_SUCCESS,否则,返回其它 NTSTATUS 错误码。

备注

  • 驱动程序必须在卸载之前注销所有回调例程。 您可以通过调用ObUnRegisterCallbacks例程来注销回调例程。

OB_CALLBACK_REGISTRATION 结构体

 
  1. typedef struct _OB_CALLBACK_REGISTRATION {
  2. USHORT Version;
  3. USHORT OperationRegistrationCount;
  4. UNICODE_STRING Altitude;
  5. PVOID RegistrationContext;
  6. OB_OPERATION_REGISTRATION *OperationRegistration;
  7. } 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 结构体

 
  1. typedef struct _OB_OPERATION_REGISTRATION {
  2. POBJECT_TYPE *ObjectType;
  3. OB_OPERATION Operations;
  4. POB_PRE_OPERATION_CALLBACK PreOperation;
  5. POB_POST_OPERATION_CALLBACK PostOperation;
  6. } 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 函数

返回指向指定线程的进程的指针。

函数声明

 
  1. PEPROCESS IoThreadToProcess(
  2. _In_ PETHREAD Thread
  3. );

参数

  • Thread[in]
  • 要返回进程的指定线程对象。

返回值

  • 返回线程对象对应的进程对象的指针。

PsGetProcessId 函数

返回与指定进程关联的进程标识符(进程ID)。

函数声明

 
  1. HANDLE PsGetProcessId(
  2. _In_ PEPROCESS Process
  3. );

参数

  • Process[in]

    指向进程对象结构的指针。

返回值

  • 返回进程ID。

实现原理

破解 ObRegisterCallbacks 函数的使用限制

第一种方法

在讲解怎么使用 ObRegisterCallbacks 函数来注册系统线程、进程回调的之前,先来讲解下 Windows 对这个函数做的限制:驱动程序必须有数字签名才能使用此函数。不过国外的黑客对此限制很不满,通过逆向 ObRegisterCallbacks,找到了
破解这个限制的方法。经研究,内核通过 MmVerifyCallbackFunction 验证此回调
是否合法, 但此函数只是简单的验证了一下 DriverObject->DriverSection->Flags 的值是不是为 0x20:

 
  1. nt!MmVerifyCallbackFunction+0x75:
  2. fffff800`01a66865 f6406820 test byte ptr [rax+68h],20h
  3. fffff800`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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cosmoslife

你的鼓励将是我最大的创作动力。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值