在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;
}
~~~
- 前言
- Visual Studio 11開發指南(1) Visual Studio 11簡介與新特性
- Visual Studio 11開發指南(2) Visual Studio 11放棄宏處理
- Visual Studio 11開發指南(3)Visual Studio 11開發SharePoint 2011程序
- Visual Studio 11開發指南(4)Visual Studio 11編程語言發展
- Visual Studio 11開發指南(5)Visual Studio 11 IDE增強
- Visual Studio 11開發指南(6)Visual Studio 11平臺改進
- Visual Studio 11開發指南(7)NET 4.5的改善
- Visual Studio 11開發指南(8)Visual C++ 11新特色
- Visual Studio 11開發指南(9)Visual C++ 新功能體驗
- Visual Studio 11開發指南(10)Visual C++11 IDE 新功能體驗
- Visual Studio 11開發指南(11)Visual Studio 11調試游戲
- Visual Studio 11開發指南(12)Visual Studio 11可視化多核多線程編程的行為
- Visual Studio 11開發指南(13)C++11語言新特性
- Visual Studio 11開發指南(14)C++11---C++/ CX設計
- Visual Studio 11開發指南(15)C++11單元測試
- Visual Studio 11開發指南(16)C++11更新-多線程和異步操作管理
- Visual Studio 11開發指南(17)C++11更新- Lambda表達式
- Visual Studio 11開發指南(18)C++11更新-自動矢量器使用
- Visual Studio 11開發指南(19)C++11更新-并行模式庫和代理庫
- 在 C++ 中使用 PPL 進行異步編程
- 基于VisualStudio11開發Windows8的Metro sample講解(1)MessageBox
- Visual C++ 11 中新的并發功能
- 基于Windows8與Visual Studio2012開發內核隱藏注冊表
- 基于VC++2012在Windows8上實現文件隱藏
- 實現諾基亞 lumia Windows phone 的手機通話記錄截取
- 最短代碼實現windows8下的下載器-下載安裝執行一體化
- 用Visual studio2012在Windows8上開發內核驅動監視線程創建
- 用Visual studio2012在Windows8上開發內核驅動監視進程創建
- 基于Windows8與Visual Studio2012實現殺毒通用模塊
- 用Visual studio2012在Windows8上開發內核中隱藏進程
- 用Visual studio11在Windows8上開發內核枚舉注冊表
- 用Visual studio11在Windows8上開發內核驅動隱藏注冊表
- 用Visual studio11在Windows8上開發驅動實現注冊表監控和過濾
- 用Visual studio11在Windows8上開發驅動實現內存填0殺進程
- 【CSDN2012年度博客之星】喜歡本博客的讀者,投票贈送《visual C++2010開發權威指南》電子稿--感謝支持 ~(截至到2012年12月30日)
- 今天在清華圖書館看到我的杰作,感慨萬千,而我要歸零一切 !
- use Visual studio2012 developing kernel driver monitor thread creation on Windows8
- To kernel driver monitoring process developed in Windows8 create using Visual studio2012
- Under Windows8 kernel mode development NDIS application-NDIS Filter explain
- use Visual studio2012 development kernel to hidden process on Windows8