在笔者前一篇文章《驱动开发:内核枚举Registry注册表回调》
中实现了对注册表的枚举,本章将实现对注册表的监控,不同于32位系统在64位系统中,微软为我们提供了两个针对注册表的专用内核监控函数,通过这两个函数可以在不劫持内核API的前提下实现对注册表增加,删除,创建等事件的有效监控,注册表监视通常会通过CmRegisterCallback
创建监控事件并传入自己的回调函数,与该创建对应的是CmUnRegisterCallback
当注册表监控结束后可用于注销回调。
- CmRegisterCallback 设置注册表回调
- CmUnRegisterCallback 注销注册表回调
默认情况下CmRegisterCallback
需传入三个参数,参数一回调函数地址,参数二空余,参数三回调句柄,微软定义如下。
// 署名权
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com
// 参数1:回调函数地址
// 参数2:无作用
// 参数3:回调句柄
NTSTATUS CmRegisterCallback(
[in] PEX_CALLBACK_FUNCTION Function,
[in, optional] PVOID Context,
[out] PLARGE_INTEGER Cookie
);
自定义注册表回调函数MyLySharkCallback
需要保留三个参数,CallbackContext
回调上下文,Argument1
是操作类型,Argument2
定义详细结构体指针。
NTSTATUS MyLySharkCallback(_In_ PVOID CallbackContext, _In_opt_ PVOID Argument1, _In_opt_ PVOID Argument2)
在自定义回调函数内Argument1
则可获取到操作类型,类型是一个REG_NOTIFY_CLASS
枚举结构,微软对其的具体定义如下所示。
// 署名权
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com
typedef enum _REG_NOTIFY_CLASS {
RegNtDeleteKey,
RegNtPreDeleteKey = RegNtDeleteKey,
RegNtSetValueKey,
RegNtPreSetValueKey = RegNtSetValueKey,
RegNtDeleteva lueKey,
RegNtPreDeleteva lueKey = RegNtDeleteva lueKey,
RegNtSetInformationKey,
RegNtPreSetInformationKey = RegNtSetInformationKey,
RegNtRenameKey,
RegNtPreRenameKey = RegNtRenameKey,
RegNtEnumerateKey,
RegNtPreEnumerateKey = RegNtEnumerateKey,
RegNtEnumerateva lueKey,
RegNtPreEnumerateva lueKey = RegNtEnumerateva lueKey,
RegNtQueryKey,
RegNtPreQueryKey = RegNtQueryKey,
RegNtQueryValueKey,
RegNtPreQueryValueKey = RegNtQueryValueKey,
RegNtQueryMultipleva lueKey,
RegNtPreQueryMultipleva lueKey = RegNtQueryMultipleva lueKey,
RegNtPreCreateKey,
RegNtPostCreateKey,
RegNtPreOpenKey,
RegNtPostOpenKey,
RegNtKeyHandleClose,
RegNtPreKeyHandleClose = RegNtKeyHandleClose,
//
// .Net only
//
RegNtPostDeleteKey,
RegNtPostSetValueKey,
RegNtPostDeleteva lueKey,
RegNtPostSetInformationKey,
RegNtPostRenameKey,
RegNtPostEnumerateKey,
RegNtPostEnumerateva lueKey,
RegNtPostQueryKey,
RegNtPostQueryValueKey,
RegNtPostQueryMultipleva lueKey,
RegNtPostKeyHandleClose,
RegNtPreCreateKeyEx,
RegNtPostCreateKeyEx,
RegNtPreOpenKeyEx,
RegNtPostOpenKeyEx,
//
// new to Windows Vista
//
RegNtPreFlushKey,
RegNtPostFlushKey,
RegNtPreLoadKey,
RegNtPostLoadKey,
RegNtPreUnLoadKey,
RegNtPostUnLoadKey,
RegNtPreQueryKeySecurity,
RegNtPostQueryKeySecurity,
RegNtPreSetKeySecurity,
RegNtPostSetKeySecurity,
//
// per-object context cleanup
//
RegNtCallbackObjectContextCleanup,
//
// new in Vista SP2
//
RegNtPreRestoreKey,
RegNtPostRestoreKey,
RegNtPreSaveKey,
RegNtPostSaveKey,
RegNtPreReplaceKey,
RegNtPostReplaceKey,
MaxRegNtNotifyClass //should always be the last enum
} REG_NOTIFY_CLASS;
其中对于注册表最常用的监控项为以下几种类型,当然为了实现监控则我们必须要使用之前,如果使用之后则只能起到监视而无法做到监控的目的。
- RegNtPreCreateKey 创建注册表之前
- RegNtPreOpenKey 打开注册表之前
- RegNtPreDeleteKey 删除注册表之前
- RegNtPreDeleteva lueKey 删除键值之前
- RegNtPreSetValueKey 修改注册表之前
如果需要实现监视则,首先CmRegisterCallback
注册一个自定义回调,当有消息时则触发MyLySharkCallback
其内部获取到lOperateType
操作类型,并通过switch
选择不同的处理例程,每个处理例程都通过GetFullPath
得到注册表完整路径,并打印出来,这段代码实现如下。
// 署名权
// right to sign one's name on a piece of wor