EX_CALLBACK_FUNCTION回调函数 (wdm.h)
筛选器驱动程序的 RegistryCallback 例程可以监视、阻止或修改注册表作。
语法
EX_CALLBACK_FUNCTION ExCallbackFunction;
NTSTATUS ExCallbackFunction(
[in] PVOID CallbackContext,
[in, optional] PVOID Argument1,
[in, optional] PVOID Argument2
)
{...}
参数
[in] CallbackContext
驱动程序在注册此 RegistryCallback 例程时作为 Context 参数传递给 CmRegisterCallback 或 CmRegisterCallbackEx 的值。
[in, optional] Argument1
一个 REG_NOTIFY_CLASS类型的值,该值标识正在执行的注册表作的类型,以及执行注册表作之前还是之后调用 RegistryCallback 例程。
[in, optional] Argument2
指向包含特定于注册表作类型的信息的结构的指针。 结构类型取决于 Argument1的 REG_NOTIFY_CLASS类型值,如下表所示。 有关哪些REG_NOTIFY_CLASS类型值可用于哪些作系统版本的信息,请参阅 REG_NOTIFY_CLASS。
从 Windows 7 开始,通知类为 RegNtPreCreateKeyEx 或 RegNtPreOpenKeyEx 时传入的实际数据结构分别是此结构的 V1 版本(REG_CREATE_KEY_INFORMATION_V1 或 REG_OPEN_KEY_INFORMATION_V1)。 检查保留成员以确定结构的版本。
版本号 | 结构名称 |
---|---|
0 | REG_CREATE_KEY_INFORMATION和REG_OPEN_KEY_INFORMATION |
1 | REG_CREATE_KEY_INFORMATION_V1和REG_OPEN_KEY_INFORMATION_V1 |
返回值
有关 RegistryCallback 例程何时应返回这些状态值的详细信息,请参阅 筛选注册表调用。
言论
若要通知注册表作,内核模式组件(如防病毒软件包的驱动程序组件)可以调用 CmRegisterCallback 或 CmRegisterCallbackEx 来注册 RegistryCallback 例程。
RegistryCallback 例程可以检查为注册表作提供的输入和输出缓冲区的内容。 注册表作可由调用用户模式注册表例程(如 RegCreateKeyEx 或 RegOpenKeyEx)或调用内核模式注册表例程的驱动程序(如 ZwCreateKey 或 ZwOpenKey)启动。 输入缓冲区 是注册表从中读取作输入数据的发起程序提供的内存缓冲区。 输出缓冲区 是由发起程序提供的缓冲区,注册表在其中写入发起程序请求的输出数据。
在调用 RegistryCallback 例程之前,内核探测(验证对齐和可访问性)Argument2 的所有成员 结构中的所有成员,这些结构指向用户模式内存中的输出缓冲区,但不捕获系统内存中的用户模式输出缓冲区。 回调例程必须将输出缓冲区的任何访问括在 尝试/( 块除外)。 如果回调例程需要将输出缓冲区指针传递给系统例程(例如,ZwOpenKey),并且缓冲区处于用户模式内存中,回调例程必须首先捕获缓冲区。
输入缓冲区的处理取决于 Windows 版本。 从 Windows 8 开始,内核将捕获系统内存中 Argument2 结构的成员指向的所有输入缓冲区,然后再调用 RegistryCallback 例程。 在 Windows 8 之前的 Windows 版本中,内核将探测 指向用户模式内存中输入缓冲区的 Argument2 的所有成员,但仅捕获系统内存中的一些缓冲区。 在这些早期版本的 Windows 中,回调例程必须将输入缓冲区的任何访问括在 尝试/,但 块除外。 此外,如果回调例程需要将输入缓冲区指针传递给系统例程(例如,ZwOpenKey),并且缓冲区处于用户模式内存中,回调例程必须首先捕获缓冲区。
下表汇总了 RegistryCallback 例程对缓冲区访问的要求。
缓冲区类型 | Windows 版本 | 传递给回调例程的缓冲区指针 | 对于直接访问的回调例程是安全的? | 安全地传递到系统例程(如 ZwOpenKey)? |
---|---|---|---|---|
用户模式输入 | Windows 8 及更高版本 | 指向捕获的数据。 | 是的 | 是的 |
用户模式输入 | Windows 7 及更早版本 | 指向捕获的数据或原始用户模式缓冲区。 | 不。 必须在 try/except 下读取。 | 不。 必须分配内核内存,在 try/except 下从原始缓冲区复制数据,并将复制的数据传递到系统例程。 |
用户模式输出 | 都 | 指向原始用户模式缓冲区。 | 不。 必须在 try/except 下写入。 | 不。 必须分配内核内存,将内核内存传递到系统例程,并在 try/except 下将结果复制回原始缓冲区。 |
内核模式输入和输出 | 都 | 指向原始内核模式缓冲区。 | 是的 | 是的 |
有关 RegistryCallback 例程和注册表筛选器驱动程序的详细信息,请参阅 筛选注册表调用。
RegistryCallback 在 IRQL = PASSIVE_LEVEL,并在执行注册表作的线程的上下文中执行。
例子
若要定义 RegistryCallback 回调例程,必须首先提供一个函数声明来标识要定义的回调例程的类型。 Windows 为驱动程序提供一组回调函数类型。 使用回调函数类型声明函数有助于 驱动程序代码分析、静态驱动程序验证程序(SDV)和其他验证工具查找错误,这是为 Windows作系统编写驱动程序的要求。
例如,若要定义名为 MyRegistryCallback
的 RegistryCallback 回调例程,请使用EX_CALLBACK_FUNCTION类型,如以下代码示例所示:
EX_CALLBACK_FUNCTION MyRegistryCallback;
然后,按如下所示实现回调例程:
_Use_decl_annotations_
NTSTATUS
MyRegistryCallback(
PVOID CallbackContext,
PVOID Argument1,
PVOID Argument2
)
{
// Function body
}
EX_CALLBACK_FUNCTION函数类型在 Wdm.h 头文件中定义。 若要在运行代码分析工具时更准确地识别错误,请务必将 Use_decl_annotations 注释添加到函数定义。 Use_decl_annotations 批注可确保使用应用于头文件中EX_CALLBACK_FUNCTION函数类型的批注。 有关函数声明要求的详细信息,请参阅 使用 WDM 驱动程序的函数角色类型来声明函数。 有关 Use_decl_annotations的信息,请参阅 批注函数行为。
要求
要求 | 价值 |
---|---|
最低支持的客户端 | 从 Windows XP 开始支持(请参阅“返回值”部分)。 |
目标平台 | 桌面 |
标头 | wdm.h (包括 Wdm.h、Ntddk.h、Ntifs.h) |
IRQL | 在PASSIVE_LEVEL调用(请参阅“备注”部分)。 |