Windows内核回调
字数 955 2025-08-22 12:23:30
Windows内核回调机制详解
内核回调概述
Windows内核回调机制为驱动程序提供了一种在满足特定条件时请求和提供通知的常规方法。MSDN中提供了多种内核回调函数,主要包括:
- 进程创建/销毁通知
- 线程创建/销毁通知
- 模块加载通知
- 对象操作回调
进程回调
PsSetCreateProcessNotifyRoutine
NTSTATUS PsSetCreateProcessNotifyRoutine(
_In_ PCREATE_PROCESS_NOTIFY_ROUTINE NotifyRoutine,
_In_ BOOLEAN Remove
);
参数说明:
NotifyRoutine: 回调函数指针Remove: TRUE表示移除回调,FALSE表示注册回调
回调函数原型:
VOID TestRoutine(
_In_ HANDLE ParentId,
_In_ HANDLE ProcessId,
_In_ BOOLEAN Create
);
示例代码:
VOID TestRoutine(
_In_ HANDLE ParentId,
_In_ HANDLE ProcessId,
_In_ BOOLEAN Create
) {
if (Create) {
DbgPrint("PID: %d, ID: %d, Create", ParentId, ProcessId);
} else {
DbgPrint("PID: %d, ID: %d, Remove", ParentId, ProcessId);
}
}
NTSTATUS UnloadDriver(PDRIVER_OBJECT DriverObject) {
PsSetCreateProcessNotifyRoutine((PCREATE_PROCESS_NOTIFY_ROUTINE)TestRoutine, TRUE);
DbgPrint("Unload!");
}
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) {
PsSetCreateProcessNotifyRoutine((PCREATE_PROCESS_NOTIFY_ROUTINE)TestRoutine, FALSE);
DriverObject->DriverUnload = UnloadDriver;
return STATUS_SUCCESS;
}
PsSetCreateProcessNotifyRoutineEx
增强版进程回调函数,提供更多信息:
VOID TestRoutine(
_Inout_ PEPROCESS Process,
_In_ HANDLE ProcessId,
_Inout_opt_ PPS_CREATE_NOTIFY_INFO CreateInfo
) {
if (CreateInfo) {
DbgPrint("ID: %d, Create", ProcessId);
} else {
DbgPrint("ID: %d, Remove", ProcessId);
}
}
注意:要使PsSetCreateProcessNotifyRoutineEx正常工作,需要修改驱动模块的Flags:
PLDR_DATA_TABLE_ENTRY ldr = (PLDR_DATA_TABLE_ENTRY)((ULONG_PTR)DriverObject->DriverSection);
ldr->Flags |= 0x20; // LDRP_IMAGE_INTEGRITY_FORCED
线程回调
PsSetCreateThreadNotifyRoutine
NTSTATUS PsSetCreateThreadNotifyRoutine(
_In_ PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine
);
NTSTATUS PsRemoveCreateThreadNotifyRoutine(
_In_ PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine
);
模块回调
PsSetLoadImageNotifyRoutine
NTSTATUS PsSetLoadImageNotifyRoutine(
_In_ PLOAD_IMAGE_NOTIFY_ROUTINE NotifyRoutine
);
NTSTATUS PsRemoveLoadImageNotifyRoutine(
_In_ PLOAD_IMAGE_NOTIFY_ROUTINE NotifyRoutine
);
回调函数原型:
VOID TestRoutine(
_In_opt_ PUNICODE_STRING FullImageName,
_In_ HANDLE ProcessId, // pid into which image is being mapped
_In_ PIMAGE_INFO ImageInfo
);
阻止驱动加载示例
通过修改模块入口点代码实现阻止驱动加载:
VOID TestRoutine(
_In_opt_ PUNICODE_STRING FullImageName,
_In_ HANDLE ProcessId,
_In_ PIMAGE_INFO ImageInfo
) {
if (ImageInfo->SystemModeImage) {
PIMAGE_NT_HEADERS pNtHeader = NULL;
PIMAGE_DOS_HEADER pDosHeader = NULL;
PULONG Entry = NULL;
KIRQL kirql = DisableCR0WriteProtection();
pDosHeader = (PIMAGE_DOS_HEADER)(ULONG_PTR)ImageInfo->ImageBase;
pNtHeader = (PIMAGE_NT_HEADERS)((ULONG_PTR)ImageInfo->ImageBase + pDosHeader->e_lfanew);
Entry = (ULONG_PTR)ImageInfo->ImageBase + pNtHeader->OptionalHeader.AddressOfEntryPoint;
DbgPrint("%x\n", Entry);
memcpy(Entry, DieEntry, 32);
EnableCR0WriteProtection(kirql);
}
}
// 关闭写保护函数
KIRQL DisableCR0WriteProtection() {
KIRQL irql = KeRaiseIrqlToDpcLevel();
UINT64 cr0 = __readcr0();
cr0 &= 0xfffffffffffeffff;
__writecr0(cr0);
_disable();
return irql;
}
// 恢复写保护函数
void EnableCR0WriteProtection(KIRQL irql) {
UINT64 cr0 = __readcr0();
cr0 |= 0x10000;
_enable();
__writecr0(cr0);
KeLowerIrql(irql);
}
// 用于替换的入口点函数
NTSTATUS DieEntry(IN PDRIVER_OBJECT MyDriver, IN PUNICODE_STRING RegistryPath) {
return STATUS_UNSUCCESSFUL;
}
对象回调
对象类型结构
struct _OBJECT_TYPE {
struct _LIST_ENTRY TypeList; //0x0
struct _UNICODE_STRING Name; //0x8
VOID* DefaultObject; //0x10
UCHAR Index; //0x14
ULONG TotalNumberOfObjects; //0x18
ULONG TotalNumberOfHandles; //0x1c
ULONG HighWaterNumberOfObjects; //0x20
ULONG HighWaterNumberOfHandles; //0x24
struct _OBJECT_TYPE_INITIALIZER TypeInfo; //0x28
struct _EX_PUSH_LOCK TypeLock; //0x78
ULONG Key; //0x7c
struct _LIST_ENTRY CallbackList; //0x80
};
关键成员:
TypeInfo: 对象类型初始化信息CallbackList: 回调函数列表
对象类型初始化器
struct _OBJECT_TYPE_INITIALIZER {
USHORT Length; //0x0
union {
UCHAR ObjectTypeFlags; //0x2
struct {
UCHAR CaseInsensitive : 1; //0x2
UCHAR UnnamedObjectsOnly : 1; //0x2
UCHAR UseDefaultObject : 1; //0x2
UCHAR SecurityRequired : 1; //0x2
UCHAR MaintainHandleCount : 1; //0x2
UCHAR MaintainTypeList : 1; //0x2
UCHAR SupportsObjectCallbacks : 1; //0x2
};
};
// ... 其他成员
};
SupportsObjectCallbacks位决定了CallbackList是否启用。如果为0,则不启用回调列表。
ObRegisterCallbacks
NTSTATUS ObRegisterCallbacks(
_In_ POB_CALLBACK_REGISTRATION CallbackRegistration,
_Outptr_ PVOID* RegistrationHandle
);
相关结构体:
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;
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;
对象回调示例
PVOID RegistrationHandle = NULL;
NTSTATUS UnloadDriver(PDRIVER_OBJECT DriverObject) {
if (RegistrationHandle) {
ObUnRegisterCallbacks(RegistrationHandle);
}
DbgPrint("Unload!");
}
OB_PREOP_CALLBACK_STATUS TestRoutine(
_In_ PVOID RegistrationContext,
_Inout_ POB_PRE_OPERATION_INFORMATION OperationInformation
) {
DbgPrint("111\n");
return OB_PREOP_SUCCESS;
}
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) {
// 修改Flags使回调生效
PLDR_DATA_TABLE_ENTRY ldr = (PLDR_DATA_TABLE_ENTRY)DriverObject->DriverSection;
ldr->Flags |= 0x20;
OB_OPERATION_REGISTRATION obOpreationRegistration = {0};
OB_CALLBACK_REGISTRATION obCbRegistration = {0};
obOpreationRegistration.ObjectType = *PsProcessType;
obOpreationRegistration.Operations = OB_OPERATION_HANDLE_CREATE;
obOpreationRegistration.PreOperation = TestRoutine;
obCbRegistration.Version = ObGetFilterVersion();
UNICODE_STRING altitude = {0};
RtlInitUnicodeString(&altitude, "114514");
obCbRegistration.Altitude = altitude;
obCbRegistration.OperationRegistrationCount = 1;
obCbRegistration.RegistrationContext = NULL;
obCbRegistration.OperationRegistration = &obOpreationRegistration;
ObRegisterCallbacks(&obCbRegistration, &RegistrationHandle);
DriverObject->DriverUnload = UnloadDriver;
return STATUS_SUCCESS;
}
保护特定进程示例
OB_PREOP_CALLBACK_STATUS TestRoutine(
_In_ PVOID RegistrationContext,
_Inout_ POB_PRE_OPERATION_INFORMATION OperationInformation
) {
if (OperationInformation->Object) {
pEPROCESS pEprocess = (pEPROCESS)(OperationInformation->Object);
if (_stricmp("calc.exe", pEprocess->ImageFileName) == 0) {
DbgPrint("Done!\n");
// 移除所有访问权限
OperationInformation->Parameters->CreateHandleInformation.DesiredAccess = 0;
}
}
return OB_PREOP_SUCCESS;
}
回调操作信息结构
typedef struct _OB_PRE_OPERATION_INFORMATION {
_In_ OB_OPERATION Operation;
union {
_In_ ULONG Flags;
struct {
_In_ ULONG KernelHandle : 1;
_In_ ULONG Reserved : 31;
};
};
_In_ PVOID Object;
_In_ POBJECT_TYPE ObjectType;
_Out_ PVOID CallContext;
_In_ POB_PRE_OPERATION_PARAMETERS Parameters;
} OB_PRE_OPERATION_INFORMATION, *POB_PRE_OPERATION_INFORMATION;
成员说明:
Operation: 触发回调的操作类型(创建或dump)KernelHandle: 是否是内核调用的Object: 被操作的对象ObjectType: 对象类型CallContext: 回调参数Parameters: 描述当前操作的具体参数,可用于设置权限等
总结
Windows内核回调机制提供了强大的系统监控和干预能力,可以用于:
- 监控进程、线程创建和销毁
- 监控模块加载
- 拦截和处理对象操作
- 实现系统保护和安全监控
使用时需要注意:
- 某些回调需要修改驱动模块Flags才能正常工作
- 内核内存操作需要处理CR0写保护
- 回调函数应尽可能高效,避免影响系统性能
- 卸载驱动时要正确移除所有注册的回调