Windows对象句柄回调 (Object Handle Callbacks)

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:

相关推荐
阿昭L13 天前
记一次符号类型不一致导致的链接错误
windows内核
阿昭L2 个月前
Windows内核事件通知机制
windows·windows内核
阿昭L2 个月前
通过KiSystemServiceUser获取SSDT基址
逆向工程·windows内核·ssdt
阿昭L2 个月前
Windows键盘过滤
windows·驱动开发·windows内核·过滤驱动
阿昭L2 个月前
通过cr3读写进程内存
保护模式·windows内核
阿昭L2 个月前
调试CreateProcess
windows·进程·逆向工程·windows内核
阿昭L4 个月前
调试Windows11启动过程
windows·uefi·windows内核
LittleFishC4 个月前
08_长调用与短调用
c语言·汇编·逆向·windows内核
阿昭L5 个月前
NT驱动程序和WDM驱动程序
驱动开发·windows内核