[note]RegMon驱动分析笔记(一)

///////////////////////////////////////
// 
// RegMon学习与分析
// 
//////////////////////////////////////

//////////////////////////////////////
//
// 1.注册表回调机制
//
/////////////////////////////////////

应用程序通过调用NtNotifyChangeKey或NtNotifyChangeMuptipleKeys系统服务,
可以监视一个或多个注册表创建,删除和修改动作.(ring3 api 对应的是RegNotifyChangeKey)

类似的进程和线程监视的话,可以使用PsSetCreateProcessNotifyRoutine()和
PsSetCreateThreadNotifyRoutine(),这两个函数可以通过向系统注册一个
CALLBALCK 函数来监视进程/线程等操作.
(具体实现可以参考sinister的<<编写进程\线程监视器>>)

注册表的回调机制是在Windows xp中引入的.但是RegMon在Windows xp上运行时,它使用的是SSDT hook.
因为Windows xp的回调机制并没有报告所有的注册表活动.

///////////////////////////////////////
//
// 2.RegMon驱动分析
//
///////////////////////////////////////
RegMon驱动主要是通过SSDT hook,hook了那些与注册表操作相关的系统服务函数.
Hook了以下函数:
@ NtCreateKey()
@ NtDeleteKey()
@ NtEnumerateKey()
@ NtEnumerateValueKey()
@ NtFlushKey()
@ NtLoadKey()
@ NtOpenKey()
@ NtQueryKey()
@ NtQueryValueKey()
@ NtUnloadKey()
@ NtSetValueKey()
@ NtCloseKey()
要实现注册表的监控就必须hook掉这些函数.(当然也可以hook更底层的,比如Cmxxxx系列的.)

RegMon内部机理如下:
// 1. 应用程序执行与注册表有关的系统服务调用,就会调用上述那些与注册表相关的函数.
// 2. 而这些函数已经被Regmon.sys hook掉了,那么应用程序对注册表的操作,就能被RegMon捕获.

//////////////////////////////////////////////////
//
// 下面的分析有点混乱,权当笔记看..
//
/////////////////////////////////////////////////

//---------------------------------
// 1.DriverEntry()
//---------------------------------
// segment 1
// RTL_QUERY_REGISTRY_TABLE 结构定义如下:
typedef struct _RTL_QUERY_REGISTRY_TABLE {
    PRTL_QUERY_REGISTRY_ROUTINE QueryRoutine;
    ULONG Flags;
    PWSTR Name;
    PVOID EntryContext;
    ULONG DefaultType;
    PVOID DefaultData;
    ULONG DefaultLength;

} RTL_QUERY_REGISTRY_TABLE, *PRTL_QUERY_REGISTRY_TABLE;

RTL_QUERY_REGISTRY_TABLE paramTable[2];

RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE,
                            registryPath.Buffer, &paramTable[0],
                            NULL, NULL  );

// RTL_QUERY_REGISTRY_TABLE paramTable[2];
// 是一个RTL_QUERY_REGISTRY_TABLE结构的数组。
// 每个成员都包含一个Name名称项和一些其他值。
// 因为要求这种数组必须以一个“空数组”结束。
// 所以空数组就是说Name为空和QueryRoutine为空。

// The RtlQueryRegistryValues()allows the caller to
// query several values from the registry subtree with a single call.

// segment 2

1. IoCreateDevice() 创建device
2. IoCreateSymbolicLink() 创建符号链接symbolicLink
3. 设置分发函数RegmonDispatch;
4. DriverObject->DriverUnload = RegmonUnload;
5. 初始化几个KMutex,和rootkey lengths
6. 获得一个指向SSDT表的指针KeServiceTablePointers
 关于RegmonMapServiceTable()这个函数,后续奉上.
7. 获得"System"进程的NameOffset..GetProcessNameOffset(),暂时不知道用来干嘛..
8. FullPathLookaside指向一个Loskaside内存..估计是用来保存注册表路径的~
9. RegmonUpdageFilters();---后面分析
10.HookRegistry(),hook上述与注册表相关的系统服务函数.

//----------------------------------------------
// 2. HookRegistry()和UnHookRegistry()函数分析
//------------------------------------------------
"HookRegistry()的功能是实现函数的hook,主要是通过"
"SYSCALL_INDEX()宏和HOOK_SYSCALL()宏实现的"

"UnHookRegistry()是实现函数钩子的卸载,即unhook,通过
"SYSCALL_INDEX()宏和UNHOOK_SYSCALL()宏实现的"

SYSCALL_INDEX宏采用Zw*函数地址并返回它在SSDT中相应的索引号.
#define SYSCALL_INDEX(_Function) *(PULONG)((PUCHAR)_Function+1)
"实现原理:内核中所有Zw*函数都以操作码 mov eax,ULONG,起始其中ULONG是
"系统调用在SSDT的索引号.通过将该函数的第二字节看作ULONG类型,这些宏能够得到该
"函数的索引号."

HOOK_SYSCALL和UNHOOK_SYSCALL采用被钩住的Zw*函数的地址,获取其索引号,并自动将
SSDT中该索引的相应地址与_HOOK函数地址进行交换.

/////////////////////////////////////////////////////////
//
// HookRegXXXX()函数的实现
//
////////////////////////////////////////////////////////

//---------------------------------------------------
// 1. NtOpenKey() 和 HookRegOpenKey()
//---------------------------------------------------
NTSTATUS
  ZwOpenKey(
    OUT PHANDLE  KeyHandle,
    IN ACCESS_MASK  DesiredAccess,
    IN POBJECT_ATTRIBUTES  ObjectAttributes
    );
NtOpenKey()实现的是打开一个存在的Registry Key,并返回它的一个句柄hKey;

由于Regmon实现的功能是获得操作注册表应用程序的相关信息.
故必须从ObjectAttributes中获得..所以HookRegOpenKey()实现的功能
也就是过滤ObjectAttributes,从中获得相关信息,传送到内存缓冲区,最后传递给
RegMon GUI程序.显示出来. 然后也会调用原始的NtOpenKey()函数.

NTSTATUS
NTAPI
HookRegOpenKey(
    IN OUT PHANDLE pHandle,
    IN ACCESS_MASK ReqAccess,
    IN POBJECT_ATTRIBUTES pOpenInfo
    )
// GetFullName()获得一个key值的全路径,返回在fullname中.
GetFullName( pOpenInfo->RootDirectory, pOpenInfo->ObjectName, fullname );
// 调用原始的NtOpenKey()函数;
ntstatus = RealRegOpenKey( pHandle, ReqAccess, pOpenInfo );
//后续有一些关于hash table 的,暂时放下~
@ RegmonFreeHashEntry()  // 从 hash table 移除
@ RegmonLogHash()   // 加进hash table 中
@ LogRecord()    // 输出类似信息
//"System:4 OpenKey HKLM\Software\Primax\Mouse Suite 98\Productivity Utility
// NOTFOUND"

//---------------------------------------------------
// 2. NtCreateKey() 和 HookRegCreateKey()
//---------------------------------------------------
实现方式和上面介绍的HookRegOpenKey()是一致的.这里就不赘述了.

//---------------------------------------------------
// 3. NtCloseKey() 和 HookRegCloseKey()
//---------------------------------------------------
由于NtCloseKey()值接受一个参数hKey,所以在
HookRegCloseKey()中需要使用原始的NtQueryKey()函数.
来获取更多关于该hKey的信息.传入给NtQueryKey()的是KEY_BASIC_INFORMATION

//--------------------------------------------------
// 4.  HookRegFlushKey()
//  5.  HookRegDeleteKey()
// 6.  HookRegDeleteValueKey()
// 7.  HookRegSetValueKey()
// 8.  HookRegEnumerateKey()
// 9.  HookRegQueryKey()
// 10.  HookRegSetValueKey()
//   .......
//--------------------------------------------------
这些函数实现方式与上面介绍的,大同小异,基本一致.
需要注意的几个函数是:
@ AppendRegValueData()  // 获取更多关于RegValue的信息.
@ AppendKeyInformation() // 获取更多关于Key的信息

//-------------------------------------------------
//

 

posted @ 2010-11-12 22:37  Tbit  阅读(1260)  评论(0编辑  收藏  举报