前言
注册表是windows的重要数据库,存放了很多重要的信息以及一些应用的设置,对注册表进行监控并防止篡改是十分有必要的。在64位系统下微软提供了CmRegisterCallback
这个回调函数来实时监控注册表的操作,那么既然这里微软提供了这么一个方便的接口,病毒木马自然也会利用,这里我们就来探究其实现的原理和如何利用这个回调函数进行对抗
CmRegisterCallback
要想更好的进行对抗,就是深入底层去看这个函数到底做了什么事情,无论是监控还是反监控,这样我们才能够更好的进行利用
首先我们去msdn里面看一下它的结构
NTSTATUS CmRegisterCallback(
[in] PEX_CALLBACK_FUNCTION Function,
[in, optional] PVOID Context,
[out] PLARGE_INTEGER Cookie
);
image-20220501100957527.png
第一个参数指向RegistryCallback
,它这里其实是通过EX_CALLBACK_FUNCTION
这个回调函数实现,结构如下
EX_CALLBACK_FUNCTION ExCallbackFunction;
NTSTATUS ExCallbackFunction(
[in] PVOID CallbackContext,
[in, optional] PVOID Argument1,
[in, optional] PVOID Argument2
)
{...}
image-20220501101203532.png
主要是看第三个参数,REG_NOTIFY_CLASS
结构如下
typedef enum _REG_NOTIFY_CLASS {
RegNtDeleteKey,
RegNtPreDeleteKey = RegNtDeleteKey,
RegNtSetValueKey,
RegNtPreSetValueKey = RegNtSetValueKey,
RegNtDeleteValueKey,
RegNtPreDeleteValueKey = RegNtDeleteValueKey,
RegNtSetInformationKey,
RegNtPreSetInformationKey = RegNtSetInformationKey,
RegNtRenameKey,
RegNtPreRenameKey = RegNtRenameKey,
RegNtEnumerateKey,
RegNtPreEnumerateKey = RegNtEnumerateKey,
RegNtEnumerateValueKey,
RegNtPreEnumerateValueKey = RegNtEnumerateValueKey,
RegNtQueryKey,
RegNtPreQueryKey = RegNtQueryKey,
RegNtQueryValueKey,
RegNtPreQueryValueKey = RegNtQueryValueKey,
RegNtQueryMultipleValueKey,
RegNtPreQueryMultipleValueKey = RegNtQueryMultipleValueKey,
RegNtPreCreateKey,
RegNtPostCreateKey,
RegNtPreOpenKey,
RegNtPostOpenKey,
RegNtKeyHandleClose,
RegNtPreKeyHandleClose = RegNtKeyHandleClose,
//
// .Net only
//
RegNtPostDeleteKey,
RegNtPostSetValueKey,
RegNtPostDeleteValueKey,
RegNtPostSetInformationKey,
RegNtPostRenameKey,
RegNtPostEnumerateKey,
RegNtPostEnumerateValueKey,
RegNtPostQueryKey,
RegNtPostQueryValueKey,
RegNtPostQueryMultipleValueKey,
RegNtPostKeyHandleClose,
RegNtPreCreateKeyEx,
RegNtPostCreateKeyEx,
RegNtPreOpenKeyEx,
RegNtPostOpenKeyEx,
//
//
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 创建注册表 对应的
Argument2
为PREG_CREATE_KEY_INFORMATION
-
• RegNtPreOpenKey 打开注册表 对应的
Argument2
为PREG_CREATE_KEY_INFORMATION
-
• RegNtPreDeleteKey 删除键 对应的
Argument2
为PREG_DELETE_KEY_INFORMATION
-
• RegNtPreDeleteValueKey 删除键值 对应的
Argument2
为PREG_DELETE_VALUE_KEY_INFORMATION
-
• RegNtPreSetValueKey 修改键值 对应的
Argument2
为PREG_SET_VALUE_KEY_INFORMATION
这里RegNtPreCreateKey
和RegNtPreOpenKey
的Argument2
都是使用到PREG_CREATE_KEY_INFORMATION
这个结构体,我们看下结构
其中两个关键的参数就是CompleteName
表示指向路径的指针,以及RootObject
表示指向注册表项的指针
typedef struct _REG_CREATE_KEY_INFORMATION {
PUNICODE_STRING CompleteName; // IN
PVOID RootObject; // IN
PVOID ObjectType;
ULONG CreateOptions;
PUNICODE_