Windows对象句柄回调 (Object Handle Callbacks)
对象句柄回调直接介入Windows对象管理器的工作流程,它允许我们在其它进程对进程、线程、桌面对象进行操作的前后执行自定义的回调函数。
关键函数
对象句柄回调的关键函数是ObRegisterCallbacks:
cpp
NTSTATUS ObRegisterCallbacks(
[in] POB_CALLBACK_REGISTRATION CallbackRegistration, // 指向 OB_CALLBACK_REGISTRATION 结构体
[out] PVOID *RegistrationHandle // 返回的注册句柄,用于卸载
);
OB_CALLBACK_REGISTRATION结构体
这是注册信息的"根"结构,包含了所有注册的总体信息。
cpp
typedef struct _OB_CALLBACK_REGISTRATION {
USHORT Version; // 必须设置为 OB_FLT_REGISTRATION_VERSION
USHORT OperationRegistrationCount; // 下面 OperationRegistration 数组的元素个数
UNICODE_STRING Altitude; // 驱动程序的"高度",用于确定回调的优先级
PVOID RegistrationContext; // 驱动定义的上下文,会传递给回调函数
POB_OPERATION_REGISTRATION OperationRegistration; // 指向一个结构体数组
} OB_CALLBACK_REGISTRATION, *POB_CALLBACK_REGISTRATION;
Altitude 字段:这是一个关键的Unicode字符串,它决定了当多个驱动同时注册回调时,你的回调函数被调用的顺序。数值越高,优先级也越高,其 PreOperation 回调会更早被调用,PostOperation 回调会更晚被调用。
OB_OPERATION_REGISTRATION结构体
这个结构体用于指定你要监控的具体对象类型、操作类型以及对应的回调函数。
cpp
typedef struct _OB_OPERATION_REGISTRATION {
POBJECT_TYPE *ObjectType; // 对象类型: PsProcessType 或 PsThreadType 等
OB_OPERATION Operations; // 操作类型: OB_OPERATION_HANDLE_CREATE 或 DUPLICATE
POB_PRE_OPERATION_CALLBACK PreOperation; // 操作前回调函数指针
POB_POST_OPERATION_CALLBACK PostOperation; // 操作后回调函数指针
} OB_OPERATION_REGISTRATION, *POB_OPERATION_REGISTRATION;
- ObjectType:指定要监控的对象类型,通常是 PsProcessType(进程)或 PsThreadType(线程)。
- Operations:指定要拦截的操作,可以是 OB_OPERATION_HANDLE_CREATE(创建句柄)或 OB_OPERATION_HANDLE_DUPLICATE(复制句柄)。
示例代码
下面这份代码用于防止notepad.exe进程被关闭:
cpp
/*
* 这份代码用于测试ObRegisterCallbacks内核回调函数
*
* 该份代码的作用是避免notepad.exe被终止
*/
#include <wdm.h>
#include <ntstrsafe.h>
EXTERN_C NTKERNELAPI UCHAR* PsGetProcessImageFileName(IN PEPROCESS Process);
// 保存ObRegisterCallbacks返回的注册句柄,卸载时需要
PVOID g_registrationHandle = nullptr;
// 该函数在每一次进程句柄创建或者复制之前被调用
OB_PREOP_CALLBACK_STATUS ObPreCallback(
PVOID RegistrationContext,
POB_PRE_OPERATION_INFORMATION OperationInformation
);
void DriverUnload(PDRIVER_OBJECT pDrvObj)
{
// 注册成功,需要卸载
if (g_registrationHandle != nullptr)
{
ObUnRegisterCallbacks(g_registrationHandle);
g_registrationHandle = nullptr;
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL,
"[ObCallback] Callback unregistered.\n");
}
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL,
"Uninstall driver\n");
}
EXTERN_C NTSTATUS DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath)
{
pDrvObj->DriverUnload = DriverUnload;
// 定义操作注册结构,告诉系统我们要监控什么对象和什么操作
OB_OPERATION_REGISTRATION opReg = { 0 };
opReg.ObjectType = PsProcessType;
opReg.Operations = OB_OPERATION_HANDLE_CREATE;
opReg.PreOperation = ObPreCallback;
opReg.PostOperation = nullptr;
// 定义回调注册结构
OB_CALLBACK_REGISTRATION cbReg = { 0 };
cbReg.Version = OB_FLT_REGISTRATION_VERSION;
cbReg.OperationRegistrationCount = 1;
RtlInitUnicodeString(&cbReg.Altitude, L"600000");
cbReg.RegistrationContext = nullptr;
cbReg.OperationRegistration = &opReg;
// 注册回调
NTSTATUS status = ObRegisterCallbacks(&cbReg, &g_registrationHandle);
if (!NT_SUCCESS(status))
{
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL,
"ObRegisterCallbacks failed with status 0x%X\n",status);
return status;
}
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL,
"ObRegisterCallbacks successfully\n");
return STATUS_SUCCESS;
}
OB_PREOP_CALLBACK_STATUS ObPreCallback(
PVOID RegistrationContext,
POB_PRE_OPERATION_INFORMATION OperationInformation
)
{
// 只对进程对象感兴趣,虽然注册的时候指定了类型,这里是为了确保安全
if (OperationInformation->ObjectType != *PsProcessType)
{
return OB_PREOP_SUCCESS;
}
PEPROCESS targetProcess = (PEPROCESS)OperationInformation->Object;
if (!targetProcess)
{
return OB_PREOP_SUCCESS;
}
PCHAR processName = (PCHAR)PsGetProcessImageFileName(targetProcess);
if (!processName)
{
return OB_PREOP_SUCCESS;
}
// 检查是否为notepad.exe
if (_stricmp(processName, "notepad.exe") != 0)
{
return OB_PREOP_SUCCESS;
}
// 检查操作类型
if (OperationInformation->Operation == OB_OPERATION_HANDLE_CREATE ||
OperationInformation->Operation == OB_OPERATION_HANDLE_DUPLICATE)
{
// 检查请求的访问掩码中包含的权限是否包含终止权限
ACCESS_MASK desireAccess =
OperationInformation->Parameters->CreateHandleInformation.DesiredAccess;
// 只检查创建句柄,大部分终止操作是通过OpenProcess产生
if (OperationInformation->Operation == OB_OPERATION_HANDLE_CREATE)
{
ACCESS_MASK desire =
OperationInformation->Parameters->CreateHandleInformation.DesiredAccess;
if (desire & 0x0001)
{
// 拒绝该操作,返回访问被拒绝
DbgPrintEx(DPFLTR_IHVDRIVER_ID,DPFLTR_INFO_LEVEL,
"[ObCallback] Blocked attempt to open notepad.exe \
with TERMINATE access.\n");
OperationInformation->Parameters->
CreateHandleInformation.DesiredAccess = 0; // 清空权限
return OB_PREOP_SUCCESS;
}
}
}
return OB_PREOP_SUCCESS;
}
为了避免运行驱动时出现权限不足的报错,我们需要在项目属性中的链接器选项页面中,添加/INTEGRITYCHECK:
