1. 程式人生 > >用Visual studio2012在Windows8上開發核心驅動監視程序建立

用Visual studio2012在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 studio2012與Windows8帶來格外不同的新體驗

1.啟動Vs2012


2.看見滿目的驅動開發模板

3.選擇一個驅動模式,有核心模式與使用者模式兩種的驅動

4.建立一個驅動程式,KMDF DriverMVP

5.我們選擇的是核心模式的驅動程式,下面是建立成功後的介面,分別是驅動程式本身,與驅動安裝包

6.按下F5,選擇驅動編譯,

插入下列程式碼實現核心的程序建立

#include "ProcMon.h"
#include "../inc/ioctls.h"

//
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
//
// 全域性變數
//

PDEVICE_OBJECT	g_pDeviceObject;

//
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
//
// 函式實現
//

NTSTATUS
DriverEntry(
	IN PDRIVER_OBJECT		DriverObject,
	IN PUNICODE_STRING		RegistryPath
)
{
	NTSTATUS			Status = STATUS_SUCCESS;    
	UNICODE_STRING		ntDeviceName;
	UNICODE_STRING		dosDeviceName;
	UNICODE_STRING		ProcessEventString;
	PDEVICE_EXTENSION	deviceExtension;
	PDEVICE_OBJECT		deviceObject = NULL;
	
	KdPrint(("[ProcMon] DriverEntry: %wZ\n", RegistryPath));
	
	//
	// 建立裝置物件
	//
	RtlInitUnicodeString(&ntDeviceName, PROCMON_DEVICE_NAME_W);
	
	Status = IoCreateDevice(
						DriverObject, 
						sizeof(DEVICE_EXTENSION),		// DeviceExtensionSize
						&ntDeviceName,					// DeviceName
						FILE_DEVICE_PROCMON,			// DeviceType
						0,								// DeviceCharacteristics
						TRUE,							// Exclusive
						&deviceObject					// [OUT]
						);

	if(!NT_SUCCESS(Status))
	{
		KdPrint(("[ProcMon] IoCreateDevice Error Code = 0x%X\n", Status));
		
		return Status;
	}
	
	//
	// 設定擴充套件結構
	//
	deviceExtension = (PDEVICE_EXTENSION)deviceObject->DeviceExtension;
	
	//
	// Set up synchronization objects, state info,, etc.
	//
	deviceObject->Flags |= DO_BUFFERED_IO;
	
	//
	// 建立符號連結
	//
	RtlInitUnicodeString(&dosDeviceName, PROCMON_DOS_DEVICE_NAME_W);
	
	Status = IoCreateSymbolicLink(&dosDeviceName, &ntDeviceName);
	
	if(!NT_SUCCESS(Status))
	{
		KdPrint(("[ProcMon] IoCreateSymbolicLink Error Code = 0x%X\n", Status));

		IoDeleteDevice(deviceObject);
		
		return Status;
	}
	
	//
	// 分發IRP
	//
	DriverObject->MajorFunction[IRP_MJ_CREATE]			= ProcmonDispatchCreate;
	DriverObject->MajorFunction[IRP_MJ_CLOSE]			= ProcmonDispatchClose;
	DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]	= ProcmonDispatchDeviceControl;
	DriverObject->DriverUnload							= ProcmonUnload;
	
	//
	// 儲存裝置物件指標
	//
	g_pDeviceObject = deviceObject;

	//
	// 建立事件物件與應用層通訊
	//
	RtlInitUnicodeString(&ProcessEventString, EVENT_NAME);
	
	deviceExtension->ProcessEvent = IoCreateNotificationEvent(&ProcessEventString, &deviceExtension->hProcessHandle);
	KeClearEvent(deviceExtension->ProcessEvent);			// 非受信狀態

	//
	// 設定回撥例程
	//
	Status = PsSetCreateProcessNotifyRoutine(ProcessCallback, FALSE);

	return Status;
}

NTSTATUS
ProcmonDispatchCreate(
	IN PDEVICE_OBJECT		DeviceObject,
	IN PIRP					Irp
)
{
	NTSTATUS Status = STATUS_SUCCESS;
	
	Irp->IoStatus.Information = 0;
	
	KdPrint(("[ProcMon] IRP_MJ_CREATE\n"));
	
	Irp->IoStatus.Status = Status;
	IoCompleteRequest(Irp, IO_NO_INCREMENT);
	
	return Status;
}

NTSTATUS
ProcmonDispatchClose(
	IN PDEVICE_OBJECT		DeviceObject,
	IN PIRP					Irp
)
{
	NTSTATUS Status = STATUS_SUCCESS;
	
	Irp->IoStatus.Information = 0;
	
	KdPrint(("[ProcMon] IRP_MJ_CLOSE\n"));
	
	Irp->IoStatus.Status = Status;
	IoCompleteRequest(Irp, IO_NO_INCREMENT);
	
	return Status;
}

NTSTATUS
ProcmonDispatchDeviceControl(
	IN PDEVICE_OBJECT		DeviceObject,
	IN PIRP					Irp
)
{
	NTSTATUS			Status = STATUS_SUCCESS;
	PIO_STACK_LOCATION	irpStack;
	PDEVICE_EXTENSION	deviceExtension;
	ULONG				inBufLength, outBufLength;
	ULONG				ioControlCode;
	PCALLBACK_INFO		pCallbackInfo;
	
	// 獲取當前裝置棧
	irpStack = IoGetCurrentIrpStackLocation(Irp);
	deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
	
	// 提取資訊
	pCallbackInfo = Irp->AssociatedIrp.SystemBuffer;
	inBufLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
	outBufLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
	ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;

	// 處理不同的IOCTL
	switch (ioControlCode)
	{
	case IOCTL_PROC_MON:
		{
			KdPrint(("[ProcMon] IOCTL: 0x%X", ioControlCode));

			if (outBufLength >= sizeof(PCALLBACK_INFO))
			{
				pCallbackInfo->hParentId = deviceExtension->hParentId;
				pCallbackInfo->hProcessId = deviceExtension->hProcessId;
				pCallbackInfo->bCreate = deviceExtension->bCreate;

				Irp->IoStatus.Information = outBufLength;
			} 
			break;
		}
		
	default:
		{
			Status = STATUS_INVALID_PARAMETER;
			Irp->IoStatus.Information = 0;
			
			KdPrint(("[ProcMon] Unknown IOCTL: 0x%X (%04X,%04X)", \
					ioControlCode, DEVICE_TYPE_FROM_CTL_CODE(ioControlCode), \
					IoGetFunctionCodeFromCtlCode(ioControlCode)));
			
			break;
		}
	}
	
	Irp->IoStatus.Status = Status;
	IoCompleteRequest(Irp, IO_NO_INCREMENT);	
	
	return Status;
}

VOID
ProcmonUnload(
	IN PDRIVER_OBJECT		DriverObject
)
{
	UNICODE_STRING dosDeviceName;
	
	//
	// Free any resources
	//

	// 解除安裝回撥例程
	PsSetCreateProcessNotifyRoutine(ProcessCallback, TRUE);
	
	//
	// Delete the symbolic link
	//
	
	RtlInitUnicodeString(&dosDeviceName, PROCMON_DOS_DEVICE_NAME_W);
	
	IoDeleteSymbolicLink(&dosDeviceName);
	
	//
	// Delete the device object
	//
	
	IoDeleteDevice(DriverObject->DeviceObject);
	
	KdPrint(("[ProcMon] Unloaded"));
}

VOID
ProcessCallback(
	IN HANDLE				ParentId,			// 父程序ID
	IN HANDLE				ProcessId,			// 發生事件的程序ID
	IN BOOLEAN				Create				// 程序是建立還是終止
)
{
	PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION)g_pDeviceObject->DeviceExtension;

	deviceExtension->hParentId = ParentId;
	deviceExtension->hProcessId = ProcessId;
	deviceExtension->bCreate = Create;

	// 觸發事件,通知應用程式
	KeSetEvent(deviceExtension->ProcessEvent, 0, FALSE);
	KeClearEvent(deviceExtension->ProcessEvent);
}

//
//////////////////////////////////////////////////////////////////////////


ring3實現應用層的呼叫,搞定程序建立的監視

#include "windows.h"
#include "winioctl.h"
#include "stdio.h"
#include "../inc/ioctls.h"

#define SYMBOL_LINK "\\\\.\\ProcMon"
//#define SYMBOL_LINK "\\\\.\\slNTProcDrv"

int main()
{
	CALLBACK_INFO cbkinfo, cbktemp = {0};

	// 開啟驅動裝置物件
	HANDLE hDriver = ::CreateFile(
							SYMBOL_LINK,
							GENERIC_READ | GENERIC_WRITE,
							0,
							NULL,
							OPEN_EXISTING,
							FILE_ATTRIBUTE_NORMAL,
							NULL);
	if (hDriver == INVALID_HANDLE_VALUE)
	{
		printf("開啟驅動裝置物件失敗!\n");

		return -1;
	}
	
	// 開啟核心事件物件
	HANDLE hProcessEvent = ::OpenEventW(SYNCHRONIZE, FALSE, EVENT_NAME);

	while (::WaitForSingleObject(hProcessEvent, INFINITE))
	{
		DWORD	dwRet;
		BOOL	bRet;

		bRet = ::DeviceIoControl(
							hDriver,
							IOCTL_PROC_MON,
							NULL,
							0,
							&cbkinfo,
							sizeof(cbkinfo),
							&dwRet,
							NULL);

		if (bRet)
		{
			if (cbkinfo.hParentId != cbktemp.hParentId || \
				cbkinfo.hProcessId != cbktemp.hProcessId || \
				cbkinfo.bCreate != cbktemp.bCreate)
			{
				if (cbkinfo.bCreate)
				{
					printf("有程序被建立,PID = %d\n", cbkinfo.hProcessId);
				} 
				else
				{
					printf("有程序被終止,PID = %d\n", cbkinfo.hProcessId);
				}

				cbktemp = cbkinfo;
			}
		} 
		else
		{
			printf("\n獲取程序資訊失敗!\n");
			break;
		}
	}

	::CloseHandle(hDriver);

	return 0;
}