用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,选择驱动编译,
#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 studio2012在Windows8上开发内核驱动监视线程创建
在Windows NT中,80386保护模式的“保护”比Windows 95中更坚固,这个“镀金的笼子”更加结实,更加难以打破.在Windows 95中,至少应用程序I/O操作是不受限制的,而在Win ...
- 用Visual studio2012在Windows8上开发内核驱动监视进程创建
在Windows NT中,80386保护模式的“保护”比Windows 95中更坚固,这个“镀金的笼子”更加结实,更加难以打破.在Windows 95中,至少应用程序I/O操作是不受限制的,而在Win ...
- 64 位 Windows 平台开发注意要点之注册表重定向
Window 系统错误代码 ERROR_SUCCESS,本博客中一律使用 NO_ERROR 代替.虽然 ERROR_SUCCESS 与 NO_ERROR 是完全等价的,都代表成功,但是后者却和其他错误 ...
- python测试开发django-35.xadmin注册表信息
前言 xadmin后台如果要对表的内容增删改查,跟之前的admin.py文件里面写注册表信息一样,需在admin.py同一级目录新建一个adminx.py的文件. 然后在adminx.py文件控制页面 ...
- A电脑的gho还原到B电脑上的驱动解决方案
近来给B笔记本做系统,我有一个gho,是A电脑的,我想直接把系统复制过去,我的这个gho有50G,里面已经配置好了java,安卓,cocos2dx的各种环境变量,安卓开发的朋友都知道这个有多恶心,我就 ...
- ArcGIS 10.2 二次开发,兼容Visual Studio 2012二次开发,完美安装教程
GIS 经常安装是常有的事,每次重装系统都要浪费大半天去安装这个.所以凑这一次安装,把这个软件重新安装的步骤整理了一下,希望对大家有所帮助.这次整理的内容的关键优点是,对常见的出错内容进行了归纳整理. ...
- 驱动开发:内核监控Register注册表回调
在笔者前一篇文章<驱动开发:内核枚举Registry注册表回调>中实现了对注册表的枚举,本章将实现对注册表的监控,不同于32位系统在64位系统中,微软为我们提供了两个针对注册表的专用内核监 ...
- Win64 驱动内核编程-15.回调监控注册表
回调监控注册表 在 WIN32 平台上,监控注册表的手段通常是 SSDT HOOK.不过用 SSDT HOOK 的方式监控注册表实在是太麻烦了,要 HOOK 一大堆函数,还要处理一些 NT6 系统有而 ...
- S3C2440上LCD驱动(FrameBuffer)实例开发讲解
一.开发环境 主 机:VMWare--Fedora 9 开发板:Mini2440--64MB Nand, Kernel:2.6.30.4 编译器:arm-linux-gcc-4.3.2 二.背景知识 ...
随机推荐
- Kubernetes——滚动更新和数据管理
k8s——滚动更新滚动更新就是一次只更新一小部分副本,更新成功之后再更新更多的副本,最终完成所有副本的更新.滚动更新最大的好处是零停机,整个更新的过程中始终有副本运行,从而保证了业务的连续性.kube ...
- Referenced file contains errors
Referenced file contains errors (file:/D:/TONG/tong/eclipse/config_/xsd/spring-context-4.2.xsd). For ...
- rsa免密钥登陆
#第一步 生成密钥,一路回车就行 ssh-keygen -t rsa #第二步 将密钥拷贝到目标服务器上,注意双引号 ssh-copy-id -i ~/.ssh/id_rsa.pub "ro ...
- windows下用libevent 开发一个echo服务
#include <stdio.h> #include <string.h> #include <errno.h> #include <iostream> ...
- 在Linux上安装Oracle服务的操作步骤
如题,将我在云服务器上安装Oracle服务的惨痛经历分享出来,期间查找的资料踩过的坑无数,希望对大家能有帮助 闲话少叙,直接开始 首先,由于服务器比较差,需要先设置swap 查看是否设置swap虚拟内 ...
- php 实现店铺装修5
/** * @title 选中蜂店装修模板样式 * @param plate_id 是 int 商品(平台或特色)装修样式ID * @param type_id 是 int 要装修商品的类型(1-平台 ...
- Redis列表类型
列表类型(list) 可以存储一个有序的字符串列表.常用的操作是向列表两端添加元素. 一个列表类型键最多能容纳2^32 -1个元素. 命令 向列表两端增加元素 LPUSH key value [val ...
- 十六 StudentManagerSystem的一些业务实现
1 删除学生的JSP实现: <%@ page language="java" contentType="text/html; charset=UTF-8" ...
- firewalld学习-zone的使用和配置
原文地址:http://www.excelib.com/article/290/show zone文件标签名词解释 target:目标,这个前面学生也已经给大家介绍过了,可以理解为默认行为,有四个可选 ...
- 洛谷P4427 [BJOI2018]求和
\(\Large\textbf{Description: } \large{一颗n个节点的树,m次询问,每次查询点i到点j的路径上所有节点点深度的k次方的和并对998244353取模(1\leq n, ...