zoukankan      html  css  js  c++  java
  • 用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

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

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

     

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

     

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

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

     


    插入下列代码实现基于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;
    }
    
    
    	


  • 相关阅读:
    查询程序,统计文件每个单词出现几次,对应的出现在哪一行
    适配器 STL
    非关联容器|hash|unordered_map/multimap,unordered_set/multiset
    函数对象
    ACM-ICPC 2018 徐州赛区网络预赛 J. Maze Designer (最大生成树+LCA求节点距离)
    D. Connected Components Croc Champ 2013
    [Educational Codeforces Round 63 ] D. Beautiful Array (思维+DP)
    C. Vasily the Bear and Sequence Codeforces 336C(枚举,思维)
    Vasya and Beautiful Arrays CodeForces
    D. Happy Tree Party CodeForces 593D【树链剖分,树边权转点权】
  • 原文地址:https://www.cnblogs.com/new0801/p/6177696.html
Copyright © 2011-2022 走看看