用Visual studio11在Windows8上开发驱动实现注册表监控和过滤
2012-10-24 15:26
531 查看
在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的注册表监控和过滤技术,请见代码分析
在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; }
相关文章推荐
- 用Visual studio11在Windows8上开发驱动实现注册表监控和过滤
- 用Visual studio11在Windows8上开发驱动实现注册表监控和过滤
- 用Visual studio11在Windows8上开发驱动实现注册表监控和过滤
- 用Visual studio11在Windows8上开发驱动实现注册表监控和过滤
- 用Visual studio11在Windows8上开发驱动实现注册表监控和过滤
- 用Visual studio11在Windows8上开发驱动实现内存填0杀进程
- 用Visual studio11在Windows8上开发驱动实现内存填0杀进程
- 用Visual studio11在Windows8上开发驱动实现内存填0杀进程
- 用Visual studio11在Windows8上开发内核驱动隐藏注册表
- 用Visual studio11在Windows8上开发内核驱动隐藏注册表
- 开发键盘过滤驱动实现模拟按键过程中遇到的问题___续
- 驱动开发之四:NDIS过滤钩子驱动实现ip包过滤
- 开发键盘过滤驱动实现模拟按键过程中遇到的问题
- 驱动开发之四:NDIS过滤钩子驱动实现ip包过滤
- 基于Windows8与Visual Studio11开发第一个USB驱动应用程序
- 开发键盘过滤驱动实现模拟按键过程中遇到的问题
- 开发键盘过滤驱动实现模拟按键过程中遇到的问题___续
- 用Visual studio11在Windows8上开发内核枚举注册表
- 用Visual studio11在Windows8上开发内核枚举注册表
- 基于Windows8与Visual Studio11开发第一个USB驱动应用程序