用Visual studio11在Windows8上开发驱动实现注册表监控和过滤

在Windows NT中,80386保护模式的“保护”比Windows 95中更坚固,这个“镀金的笼子”更加结实,更加难以打破。在Windows 95中,至少应用程序I/O操作是不受限制的,而在Windows NT中,我们的应用程序连这点权限都被剥夺了。在NT中几乎不太可能进入真正的ring0层。 
在Windows NT中,存在三种Device Driver:

  1.“Virtual device Driver” (VDD)。通过VDD,16位应用程序,如DOS 和Win16应用程序可以访问特定的I/O端口(注意,不是直接访问,而是要通过VDD来实现访问)。

  2.“GDI Driver”,提供显示和打印所需的GDI函数。

  3.“Kernel Mode Driver”,实现对特定硬件的操作,比如说CreateFile, CloseHandle (对于文件对象而言), ReadFile, WriteFile, DeviceIoControl 等操作。“Kernel Mode Driver”还是Windows NT中唯一可以对硬件中断和DMA进行操作的Driver。SCSI 小端口驱动和 网卡NDIS 驱动都是Kernel Mode Driver的一种特殊形式。

 

 

Visual studio11与Windows8带来格外不同的新体验

 

1.启动Vs11

用Visual studio11在Windows8上开发驱动实现注册表监控和过滤_第1张图片

2.看见满目的驱动开发模板

用Visual studio11在Windows8上开发驱动实现注册表监控和过滤_第2张图片

3.选择一个驱动模式,有内核模式与用户模式两种的驱动

用Visual studio11在Windows8上开发驱动实现注册表监控和过滤_第3张图片

 

4.创建一个驱动程序,KMDF DriverMVP

用Visual studio11在Windows8上开发驱动实现注册表监控和过滤_第4张图片

 

5.我们选择的是内核模式的驱动程序,下面是创建成功后的界面,分别是驱动程序本身,与驱动安装包

用Visual studio11在Windows8上开发驱动实现注册表监控和过滤_第5张图片

6.按下F5,选择驱动编译,

 

用Visual studio11在Windows8上开发驱动实现注册表监控和过滤_第6张图片


插入下列代码实现基于callback的注册表监控和过滤技术,请见代码分析


#include "ntifs.h"
#include "RegistryCallBack.h"
#include <ntstrsafe.h>

NTSTATUS st;
LARGE_INTEGER g_CallbackCookie;
ANSI_STRING  astr;
 
VOID UnloadDriver(PDRIVER_OBJECT DriverObject);

NTSTATUS RegistryCallback(IN PVOID CallbackContext, IN PVOID Argument1, IN PVOID Argument2);

BOOLEAN GetRegistryObjectCompleteName(PUNICODE_STRING pRegistryPath, PUNICODE_STRING pPartialRegistryPath,PVOID pRegistryObject);

NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{    
	
	DbgPrint("[RegRoutine]Loading!\n");
	
	DriverObject->DriverUnload = UnloadDriver;
		
	st = CmRegisterCallback(RegistryCallback,NULL,&g_CallbackCookie);
	if ( !NT_SUCCESS(st) )	
	{
		DbgPrint("[RegRoutine]CmRegisterCallback Failed!\n");
		return st;
	}
	DbgPrint("[RegRoutine]RegistryCallback Addr:0x%08X\n",RegistryCallback);	
	DbgPrint("[RegRoutine]Cookie.LowPart:0x%08X Cookie.HighPart:0x%08X\n",g_CallbackCookie.LowPart,g_CallbackCookie.HighPart);
    return st;
}
VOID UnloadDriver(PDRIVER_OBJECT DriverObject)
{
	CmUnRegisterCallback(g_CallbackCookie);
	DbgPrint("[RegRoutine]UnLoading!\n");
}

NTSTATUS 
  RegistryCallback(
    IN PVOID  CallbackContext,
    IN PVOID  Argument1,
    IN PVOID  Argument2 
    )
{
	int type;
	BOOLEAN exception = FALSE;
	BOOLEAN registryEventIsValid = FALSE;
	UNICODE_STRING registryPath;
	UCHAR* registryData = NULL;
	ULONG registryDataLength = 0;
	ULONG registryDataType = 0;
	
	registryPath.Length = 0;
	registryPath.MaximumLength = NTSTRSAFE_UNICODE_STRING_MAX_CCH * sizeof(WCHAR);
	registryPath.Buffer = ExAllocatePoolWithTag(NonPagedPool, registryPath.MaximumLength, 'ConT');
	
	if(registryPath.Buffer == NULL)
	{
		DbgPrint("[RegRoutine]Allocate registryPath failed!\n");
		return STATUS_SUCCESS;
	}
	
	type = (REG_NOTIFY_CLASS)Argument1;
	
	try
	{
		switch(type)
		{
			case RegNtPostCreateKey:
			{	
				PREG_POST_CREATE_KEY_INFORMATION createKey = (PREG_POST_CREATE_KEY_INFORMATION)Argument2;
				if( NT_SUCCESS(createKey->Status) || createKey->Status == STATUS_PENDING ) //创建注册表项状态为成功和未决的都记录一下
				{
					PVOID* registryObject = createKey->Object;
					registryEventIsValid = GetRegistryObjectCompleteName(®istryPath, createKey->CompleteName,*registryObject);
					if ( registryEventIsValid )
					{
						RtlUnicodeStringToAnsiString(&astr,®istryPath,TRUE);
						DbgPrint("[RegCreated]KeyName:%s!\n",astr.Buffer);
						
						//如果创建的是自启动项,则警告一下
						if ( strstr(astr.Buffer,"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run") )
						{
							DbgPrint("[RegCreated]Forbin!\n");
							DbgPrint("[RegCreated]ForbinKeyName:%s!\n",astr.Buffer);
							RtlFreeAnsiString(&astr);
						}
						RtlFreeAnsiString(&astr);
					}
					else
						DbgPrint("[RegCreated]Get Key Name Failed!\n");
				}
				
			}
				break;
			//使用PreCreateKey可以阻止key的创建,但是能够作为判断依据的只有一个key的CompleteName,无法得到完整路径来判断
			case RegNtPreCreateKey:
			{
				PREG_PRE_CREATE_KEY_INFORMATION createKey = (PREG_PRE_CREATE_KEY_INFORMATION)Argument2;
				RtlCopyUnicodeString(®istryPath,createKey->CompleteName);
				RtlUnicodeStringToAnsiString(&astr,®istryPath,TRUE);
				DbgPrint("[RegRoutine]PreCreate:%s!\n",astr.Buffer);
				if ( !strcmp(astr.Buffer,"新项 #1") )
						{
							DbgPrint("[RegRoutine]Forbin!\n");
							DbgPrint("[RegRoutine]ForbinKeyName:%s!\n",astr.Buffer);
							RtlFreeAnsiString(&astr);
							return STATUS_INVALID_PARAMETER;
						}
				RtlFreeAnsiString(&astr);
			}
				break;
			case RegNtDeleteKey:
			{
				PREG_DELETE_KEY_INFORMATION deleteKey = (PREG_DELETE_KEY_INFORMATION)Argument2;
				registryEventIsValid = GetRegistryObjectCompleteName(®istryPath, NULL, deleteKey->Object);
				
				if ( registryEventIsValid )
					{
						RtlUnicodeStringToAnsiString(&astr,®istryPath,TRUE);
						DbgPrint("[RegDeletedKey]KeyName:%s!\n",astr.Buffer);
						if ( !strcmp(astr.Buffer,"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run\\ljh00001") )
						{
							DbgPrint("[RegDeletedKey]Forbin!\n");
							DbgPrint("[RegDeletedKey]ForbinKeyName:%s!\n");
							RtlFreeAnsiString(&astr);
							return STATUS_INVALID_PARAMETER;
						}
						RtlFreeAnsiString(&astr);
					}
					
			}
				break;
			case RegNtSetValueKey:
			{
				PREG_SET_VALUE_KEY_INFORMATION setvalue = (PREG_SET_VALUE_KEY_INFORMATION)Argument2;
				
				if( MmIsAddressValid(setvalue->ValueName) )
				{
					registryEventIsValid = GetRegistryObjectCompleteName(®istryPath, NULL, setvalue->Object);
				
					if ( registryEventIsValid )
					{
						RtlUnicodeStringToAnsiString(&astr,®istryPath,TRUE);
						DbgPrint("[RegSetValue]ValueParentPath:%s!\n",astr.Buffer);
						RtlFreeAnsiString(&astr);
					}
					RtlUnicodeStringToAnsiString(&astr,setvalue->ValueName,TRUE);
					DbgPrint("[RegSetValue]ValueName:%s!\n",astr.Buffer);
					RtlFreeAnsiString(&astr);
					//输出设置的键值的数据类型和大小,如果类型是REG_SZ则data是一个unicode_string,而数据大小为buffer长度
					//加上4字节长度的length和MaxLength再加上2个字节的结尾00的长度
					DbgPrint("[RegSetValue]ValueDataType:%X,DataSize:%X\n",setvalue->Type,setvalue->DataSize);
					if ( setvalue->Type == 1 ) //Type为REG_SZ,其它类型的数据暂时忽略 
					{
						DbgPrint("[RegSetValue]Data:%ws\n",setvalue->Data);
					}
				}
				
			}
				break;
			case RegNtDeleteValueKey:
			{
				PREG_DELETE_VALUE_KEY_INFORMATION deletevalue = (PREG_DELETE_VALUE_KEY_INFORMATION)Argument2;
				
				if( MmIsAddressValid(deletevalue->ValueName) )
				{
					registryEventIsValid = GetRegistryObjectCompleteName(®istryPath, NULL, deletevalue->Object);
				
					if ( registryEventIsValid )
					{
						RtlUnicodeStringToAnsiString(&astr,®istryPath,TRUE);
						DbgPrint("[RegDelValue]ValueParentPath:%s!\n",astr.Buffer);
						RtlFreeAnsiString(&astr);
					}
					RtlUnicodeStringToAnsiString(&astr,deletevalue->ValueName,TRUE);
					DbgPrint("[RegDelValue]ValueName:%s!\n",astr.Buffer);
					if ( !strcmp(astr.Buffer,"ljh00001") )
						{
							DbgPrint("[RegDelValue]Forbin!\n");
							DbgPrint("[RegDelValue]ForbinKeyName:%s!\n");
							RtlFreeAnsiString(&astr);
							return STATUS_INVALID_PARAMETER;
						}
					RtlFreeAnsiString(&astr);
				}
				
			}
				break;
			case RegNtRenameKey:
			{
				PREG_RENAME_KEY_INFORMATION renamevalue = (PREG_RENAME_KEY_INFORMATION)Argument2;
				
				if( MmIsAddressValid(renamevalue->NewName) )
				{
					registryEventIsValid = GetRegistryObjectCompleteName(®istryPath, NULL, renamevalue->Object);
				
					if ( registryEventIsValid )
					{
						RtlUnicodeStringToAnsiString(&astr,®istryPath,TRUE);
						DbgPrint("[RegRenameKey]KeyPath:%s!\n",astr.Buffer);
						RtlFreeAnsiString(&astr);
					}
					RtlUnicodeStringToAnsiString(&astr,renamevalue->NewName,TRUE);
					DbgPrint("[RegRenameKey]KeyName:%s!\n",astr.Buffer);
					RtlFreeAnsiString(&astr);
				}
				
			}
				break;
			default:
				break;
		}
	} 
	except( EXCEPTION_EXECUTE_HANDLER ) 
	{
		DbgPrint("[RegRoutine]Catch a Expection!\n");
		exception = TRUE;
		registryEventIsValid = FALSE;
	}
	
	if(registryPath.Buffer != NULL)
	{
		ExFreePoolWithTag(registryPath.Buffer, 'ConT');
	}
	return STATUS_SUCCESS;
}


BOOLEAN GetRegistryObjectCompleteName(PUNICODE_STRING pRegistryPath, PUNICODE_STRING pPartialRegistryPath, PVOID pRegistryObject)
{
	BOOLEAN foundCompleteName = FALSE;
	BOOLEAN partial = FALSE;
	NTSTATUS status;
	ULONG returnedLength;
	PUNICODE_STRING pObjectName = NULL;
	//判断object的有效性
	if( (!MmIsAddressValid(pRegistryObject)) || (pRegistryObject == NULL) )
	{
		DbgPrint("[RegRoutine]pRegistryObject Invalid!\n");
		return FALSE;
	}
	//使用ObQueryNameString来得到object对应的名称
	status = ObQueryNameString(pRegistryObject, (POBJECT_NAME_INFORMATION)pObjectName, 0, &returnedLength );
	if(status == STATUS_INFO_LENGTH_MISMATCH)	//第一次传的buffer长度为0,ObQueryNameString返回的结果必定是缓冲区大小不足
	{
		pObjectName = ExAllocatePoolWithTag(NonPagedPool, returnedLength, 'ConT'); //申请内存
		if ( pObjectName == NULL ) //申请内存失败则返回FALSE
		{
			DbgPrint("[RegRoutine]AllocatePool Failed!\n");
			return FALSE;
		}
		//查询名称
		status = ObQueryNameString(pRegistryObject, (POBJECT_NAME_INFORMATION)pObjectName, returnedLength, &returnedLength );
		if(NT_SUCCESS(status))
		{
			RtlUnicodeStringCopy(pRegistryPath, pObjectName);	//拷贝名称
			foundCompleteName = TRUE;
		}
		ExFreePoolWithTag(pObjectName, 'ConT');	//无论查询是否成功都应该释放内存 	
	}

	return foundCompleteName;
}


	


你可能感兴趣的:(用Visual studio11在Windows8上开发驱动实现注册表监控和过滤)