内核回调函数
本文提供了 Windows 内核导出的所有 API 的完整列表,用于驱动程序写入注册由内核组件在各种情况下调用的回调例程。这些例程中的大多数都记录在 Windows 驱动程序工具包 (WDK) 中,但其中一些供内置驱动程序使用。未文档化的函数进行了简要描述,而此处仅列出了已文档化的函数以供参考。
已文档化函数
CmRegisterCallbackEx() |
ExAllocateTimer() |
ExInitializeWorkItem() |
ExRegisterCallback() |
FsRtlRegisterFileSystemFilterCallbacks() |
IoInitializeThreadedDpcRequest() |
IoQueueWorkItem() |
IoRegisterBootDriverCallback() |
IoRegisterContainerNotification() |
IoRegisterFsRegistrationChangeEx() |
IoRegisterFsRegistrationChangeMountAware() |
IoRegisterPlugPlayNotification() |
IoSetCompletionRoutineEx() |
IoWMISetNotificationCallback() |
KeExpandKernelStackAndCalloutEx() |
KeInitializeApc() |
KeInitializeDpc() |
KeRegisterBugCheckCallback() |
KeRegisterBugCheckReasonCallback() |
KeRegisternmiCallback() |
KeRegisterProcessorChangeCallback() |
KeRegisterProcessorChangeCallback() |
ObRegisterCallbacks() |
PoRegisterDeviceNotify() |
PoRegisterPowerSettingCallback() |
PsCreateSystemThread() |
PsSetCreateProcessNotifyRoutineEx() |
PsSetCreateThreadNotifyRoutine() |
PsSetLoadImageNotifyRoutine() |
SeRegisterLogonSessionTerminatedRoutine() |
TmEnableCallbacks() |
未文档化函数
DbgSetDebugPrintCallback() 安装或删除调用方提供的回调函数,每当调用 DbgPrint()、KdPrint() 及其变化形式都会调用该函数,从而使他们能够访问格式化的调试输出缓冲区。当系统不在内核调试器的控制下运行时,并且用户希望检查 DbgPrint 的外部,这很有用。SysInternals 的 DbgView 工具使用此 API 来捕获和显示内核组件的输出。多个调用方可以安装回调,所有这些回调都存储在一个双链表中,其头部位于RtlpDebugPrintCallbackList。RtlpDebugPrintCallbackLock 上的锁保护此列表。RtlpDebugPrintCallbacksActive 中的返回值确定是否有任何驱动程序安装了此类回调。此功能的原型在 WDK 中可用,如下所示:
VOID (*PDEBUG_PRINT_CALLBACK) (
_In_ PSTRING Output,
_In_ ULONG ComponentId,
_In_ ULONG Level );
NTSTATUS DbgSetDebugPrintCallback (
_In_ PDEBUG_PRINT_CALLBACK DebugPrintCallback,
_In_ BOOLEAN Enable );
IoRegisterPriorityCallback() 由存储 I/O 驱动程序(如 classpnp.sys)用于注册回调(例如 CLASSPNP!ClassIoBoostPriority),用于通知驱动程序有关驱动程序当前拥有的 IRP 中的 I/O 优先级更改。线程的 I/O 优先级得到提升,以缓解涉及具有不同 I/O 优先级的线程的优先级反转问题。Windows Internals 书籍第 6 版在第 8 章中对此进行了描述。回调存储在数组 IopUpdatePriorityCallbackRoutine[] 中,该数组最多可以容纳 8 个回调。IoBoostThreadIoPriority 负责进行回调。此函数的原型(如下所示)在 WDK 中不可用:
VOID (*PIO_PRIORITY_CALLBACK) (
_In_ PDRIVER_OBJECT DriverObject,
_In_ PDEVICE_OBJECT DeviceObject,
_In_ PETHREAD Thread,
_In_ IO_PRIORITY_HINT PriorityHint );
NTSTATUS IoRegisterPriorityCallback (
_In_ PDRIVER_OBJECT DriverObject,
_In_ PIO_PRIORITY_CALLBACK Callback );
VOID IoUnregisterPriorityCallback (
_In_ PDRIVER_OBJECT DriverObject );
PoRegisterCoalescingCallback() 被 Cache Manager、Configuration Manager 和 NTFS 等调用方用来注册 I/O 合并通知。回调函数存储在一个数组 PopIssueCoalescingNotification[] 中,该数组最多可以容纳 8 个这样的回调。系统将通知已注册的调用方切换其 I/O 合并状态或在系统空闲状态期间刷新挂起的 I/O 操作,以便可以向下旋转磁盘。函数 PopIssueCoalescingNotification 执行 I/O 合并通知。此函数的原型(如下所示)在 WDK 中不可用:
VOID (*PPO_COALESCING_CALLBACK) (
_In_ ULONG Reason,
_In_ PDEVICE_OBJECT DeviceObject,
_In_ PVOID Context );
NTSTATUS PoRegisterCoalescingCallback (
_In_ PPO_COALESCING_CALLBACK Callback,
_In_ BOOLEAN ClientOrSrever,
_Out_ PVOID* Handle,
_In_ PVOID Context );
VOID PoUnregisterCoalescingCallback (
_In_ PVOID Handle);
PsSetLegoNotifyRoutine() 用于注册一个在线程终止期间由内核调用的例程。KTHREAD 结构包含一个名为 LegoData 的指针大小的字段,系统中的单个内核组件可以使用该字段来存储每个线程的数据。这在功能上类似于用户模式线程本地存储 (TLS),但仅限于每个线程一个插槽。内核模式驱动程序可以动态分配特定于线程的上下文,并将其存储在 KTHREAD 中。LegoData,根据需要检索它,然后在乐高通知例程中释放它。PsSetLegoNotifyRoutine() 注册的回调存储在内核全局 PspLegoNotifyRoutine 中。使调用方能够访问 KTHREAD。LegoData 在不了解 KTHREAD 布局的情况下,PsSetLegoNotifyRoutine() 返回 KTHREAD 的偏移量。调用方可用于直接访问内容的 LegoData 字段。此函数的原型(如下所示)在 WDK 中不可用:
VOID (*PLEGO_NOTIFY_ROUTINE)(
_In_ PKTHREAD Thread );
ULONG PsSetLegoNotifyRoutine(
_In_ PLEGO_NOTIFY_ROUTINE Routine );
SeRegisterImageVerificationCallback() 被反恶意软件驱动程序(如内置的 Windows Defender 驱动程序 (WdFilter.sys) 用于注册回调(例如 WdFilter!MpImageVerificationCallback),每次将驱动程序映像加载到内存中时都会调用它。SeValidateImageHeader() 将工作项例程 SepImageVerificationCallbackWorker() 排队,该例程负责调用所有已注册的图像验证回调。图像验证回调以这种延迟方式调用,以免在验证图像时阻塞驱动程序加载过程。在此回调中,驱动程序读取BDCB_IMAGE_INFORMATION中捕获的信息,并使用自己的专有算法来确定通过将新的驱动程序映像加载到内存中并随后采取适当的操作,系统状态是否可能受到威胁。SeUnregisterImageVerificationCallback() 用于注销回调。此功能的原型在 WDK 中可用,如下所示:
VOID (*PSE_IMAGE_VERIFICATION_CALLBACK_FUNCTION) (
_In_opt_ PVOID CallbackContext,
_In_ SE_IMAGE_TYPE ImageType,
_Inout_ PBDCB_IMAGE_INFORMATION ImageInformation );
NTSTATUS SeRegisterImageVerificationCallback (
_In_ SE_IMAGE_TYPE ImageType,
_In_ SE_IMAGE_VERIFICATION_CALLBACK_TYPE CallbackType,
_In_ PSE_IMAGE_VERIFICATION_CALLBACK_FUNCTION CallbackFunction,
_In_opt_ PVOID CallbackContext,
_Reserved_ SE_IMAGE_VERIFICATION_CALLBACK_TOKEN Token,
_Out_ PVOID* CallbackHandle );
VOID SeUnregisterImageVerificationCallback (
_In_ PVOID CallbackHandle );