1. 程式人生 > >EXE和SYS通訊MiniFilter基於事件方式

EXE和SYS通訊MiniFilter基於事件方式

#ifndef _HEADER_HEAD_FILE
#define _HEADER_HEAD_FILE
#pragma once
#include <ntifs.h>
#include <ntddk.h>
#include <fltKernel.h>  
#include <Ntstrsafe.h>  

#ifndef MAX_PATH
#define MAX_PATH	260
#endif



NTKERNELAPI UCHAR * PsGetProcessImageFileName(__in PEPROCESS Process);



//驅動控制程式碼
#define IOCTL_START CTL_CODE(FILE_DEVICE_UNKNOWN, 0x810,METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_STOP CTL_CODE(FILE_DEVICE_UNKNOWN, 0x811,METHOD_BUFFERED, FILE_ANY_ACCESS)




NTSTATUS PtUnload(__in FLT_FILTER_UNLOAD_FLAGS Flags);

NTSTATUS PtInstanceQueryTeardown(__in PCFLT_RELATED_OBJECTS FltObjects, __in FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags);

CONST FLT_REGISTRATION FilterRegistration = {
	sizeof(FLT_REGISTRATION),         //  Size  
	FLT_REGISTRATION_VERSION,           //  Version  
	0,                                  //  Flags  
	NULL,                               //  Context  
	NULL,                               //  Operation callbacks  
	PtUnload,                           //  MiniFilterUnload  
	NULL,                               //  InstanceSetup  
	PtInstanceQueryTeardown,            //  InstanceQueryTeardown  
	NULL,                               //  InstanceTeardownStart  
	NULL,                               //  InstanceTeardownComplete  
	NULL,                               //  GenerateFileName  
	NULL,                               //  GenerateDestinationFileName  
	NULL                                //  NormalizeNameComponent  
};


#endif
#include "Header.h"


PFLT_FILTER gFilterHandle;
PFLT_PORT g_ServerPort;
PFLT_PORT g_ClientPort;


//同步事件物件
PRKEVENT g_pEventObject = NULL;
//控制代碼資訊
OBJECT_HANDLE_INFORMATION g_ObjectHandleInfo;

char g_szOutBuf[MAX_PATH] = { 0 };

/*
這裡要注意:1.資料地址的對齊.
2.文件建議使用:try/except處理.
3.如果是64位的驅動要考慮32位的EXE發來的請求.
*/
NTSTATUS MessageNotifyCallback(IN PVOID PortCookie, IN PVOID InputBuffer OPTIONAL, IN ULONG InputBufferLength, OUT PVOID OutputBuffer OPTIONAL, IN ULONG OutputBufferLength, OUT PULONG ReturnOutputBufferLength)
{
	NTSTATUS status = 0;

	PAGED_CODE();
	UNREFERENCED_PARAMETER(PortCookie);

	//返回使用者一些資訊.  
	RtlCopyMemory(OutputBuffer, g_szOutBuf, strlen(g_szOutBuf) + 1);
	return status;
}

VOID DisconnectNotifyCallback(_In_opt_ PVOID ConnectionCookie)
{
	PAGED_CODE();

	UNREFERENCED_PARAMETER(ConnectionCookie);

	FltCloseClientPort(gFilterHandle, &g_ClientPort);
}

NTSTATUS ConnectNotifyCallback(IN PFLT_PORT ClientPort, IN PVOID ServerPortCookie, IN PVOID ConnectionContext, IN ULONG SizeOfContext, OUT PVOID * ConnectionPortCookie)
{
	PAGED_CODE();

	UNREFERENCED_PARAMETER(ServerPortCookie);
	UNREFERENCED_PARAMETER(ConnectionContext);
	UNREFERENCED_PARAMETER(SizeOfContext);
	UNREFERENCED_PARAMETER(ConnectionPortCookie);

	g_ClientPort = ClientPort;
	return STATUS_SUCCESS;
}


NTSTATUS PtInstanceQueryTeardown(__in PCFLT_RELATED_OBJECTS FltObjects, __in FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags)
{
	return STATUS_SUCCESS;
}


NTSTATUS PtUnload(__in FLT_FILTER_UNLOAD_FLAGS Flags)
{

	FltCloseCommunicationPort(g_ServerPort);
	FltUnregisterFilter(gFilterHandle);
	return STATUS_SUCCESS;
}


//設定登錄檔鍵值    
NTSTATUS SetValueKey(PUNICODE_STRING pRegPath, PUNICODE_STRING pValueName, ULONG Type, wchar_t ValueData[MAX_PATH])
{


	//定義變數    
	size_t pcch = 0;
	OBJECT_ATTRIBUTES objectAttribues;
	HANDLE hRegister = NULL;
	NTSTATUS ntstatus;
	USHORT cbszSize = 0;

	//引數效驗    
	if (pRegPath == NULL || pValueName == 0 || ValueData == NULL)return FALSE;


	switch (Type)
	{
	case REG_SZ:
	{
		//獲取長度    
		RtlStringCchLengthW(ValueData, MAX_PATH, &pcch);
		if (pcch <= 0)return FALSE;
		cbszSize = (USHORT)(pcch * sizeof(wchar_t)) + sizeof(wchar_t);
	}
	break;
	case REG_DWORD:
	{
		cbszSize = sizeof(ULONG);
	}
	break;
	default:
		return STATUS_UNSUCCESSFUL;
	}


	//設定變數    
	InitializeObjectAttributes(&objectAttribues, pRegPath, OBJ_CASE_INSENSITIVE, NULL, NULL);

	//開啟登錄檔    
	ntstatus = ZwOpenKey(&hRegister, KEY_ALL_ACCESS, &objectAttribues);
	if (!NT_SUCCESS(ntstatus) || hRegister == NULL)return FALSE;


	//設定REG_SZ子健    
	ntstatus = ZwSetValueKey(hRegister, pValueName, 0, Type, ValueData, cbszSize);
	ZwClose(hRegister);
	return ntstatus;
}

//註冊MiniFilter  
NTSTATUS RegisterMiniFilter(PDRIVER_OBJECT DriverObject, PUNICODE_STRING pRegistryPath)
{


	UNICODE_STRING UnicodeDriverServerName;
	UNICODE_STRING UnicodeValue;
	UNICODE_STRING UnicodeSzText;
	UNICODE_STRING UnicodeSzServerNameInstances;
	ULONG ulValue;
	HANDLE hRegister;
	ULONG ulResult;
	NTSTATUS ntStatus;
	static wchar_t szInstances[MAX_PATH] = { 0 };
	static wchar_t szServerNameInstances[MAX_PATH] = { 0 };
	//初始化objectAttributes      
	OBJECT_ATTRIBUTES objectAttributes;
	wchar_t* pFind = NULL;
	ULONG  nAltitude = 399998;
	int i = 0;

	//引數效驗    
	if (DriverObject == NULL)return STATUS_UNSUCCESSFUL;


	if (pRegistryPath == NULL || pRegistryPath->Length <= 0)return STATUS_UNSUCCESSFUL;
	InitializeObjectAttributes(&objectAttributes, pRegistryPath, OBJ_CASE_INSENSITIVE, NULL, NULL);
	//建立或開啟登錄檔專案      
	ntStatus = ZwCreateKey(&hRegister, KEY_ALL_ACCESS, &objectAttributes, 0, NULL, (ULONG)REG_OPTION_NON_VOLATILE, &ulResult);
	if (hRegister == NULL || ntStatus != STATUS_SUCCESS) return STATUS_UNSUCCESSFUL;
	ZwClose(hRegister);

	//DependOnService    
	RtlInitUnicodeString(&UnicodeValue, L"DependOnService");
	SetValueKey(pRegistryPath, &UnicodeValue, REG_SZ, L"FltMgr");

	//Instances    
	RtlStringCbPrintfExW(szServerNameInstances, sizeof(szServerNameInstances), NULL, NULL, STRSAFE_FILL_BEHIND_NULL, L"%wZ\\Instances", pRegistryPath);
	RtlInitUnicodeString(&UnicodeSzServerNameInstances, szServerNameInstances);
	InitializeObjectAttributes(&objectAttributes, &UnicodeSzServerNameInstances, OBJ_CASE_INSENSITIVE, NULL, NULL);
	ntStatus = ZwCreateKey(&hRegister, KEY_ALL_ACCESS, &objectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, &ulResult);
	if (hRegister == NULL || ntStatus != STATUS_SUCCESS) return STATUS_UNSUCCESSFUL;
	ZwClose(hRegister);



	//獲取服務名    
	pFind = wcsrchr(pRegistryPath->Buffer, '\\');
	if (pFind)
		RtlInitUnicodeString(&UnicodeDriverServerName, pFind + sizeof(char));
	else
		return STATUS_UNSUCCESSFUL;

	//DefaultInstance    
	RtlInitUnicodeString(&UnicodeValue, L"DefaultInstance");
	RtlStringCbPrintfExW(szInstances, sizeof(szInstances), NULL, NULL, STRSAFE_FILL_BEHIND_NULL, L"%wZ Instance", &UnicodeDriverServerName);
	SetValueKey(&UnicodeSzServerNameInstances, &UnicodeValue, REG_SZ, szInstances);


	//ProtectFile Instance    
	RtlStringCbPrintfExW(szInstances, sizeof(szInstances), NULL, NULL, STRSAFE_FILL_BEHIND_NULL, L"%wZ\\%wZ Instance", &UnicodeSzServerNameInstances, &UnicodeDriverServerName);
	RtlInitUnicodeString(&UnicodeSzText, szInstances);
	InitializeObjectAttributes(&objectAttributes, &UnicodeSzText, OBJ_CASE_INSENSITIVE, NULL, NULL);
	ntStatus = ZwCreateKey(&hRegister, KEY_ALL_ACCESS, &objectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, &ulResult);
	if (hRegister == NULL || ntStatus != STATUS_SUCCESS) return STATUS_UNSUCCESSFUL;
	ZwClose(hRegister);

	//Altitude    
	RtlInitUnicodeString(&UnicodeValue, L"Altitude");
	SetValueKey(&UnicodeSzText, &UnicodeValue, REG_SZ, L"399999");


	//Flags    
	RtlInitUnicodeString(&UnicodeValue, L"Flags");
	ulValue = 0;
	SetValueKey(&UnicodeSzText, &UnicodeValue, REG_DWORD, (wchar_t*)&ulValue);


	return ntStatus;
}

//獲取程序名
PCHAR GetProcessName16ByProcessId(HANDLE ProcessId)
{
	//定義變數
	NTSTATUS status = STATUS_UNSUCCESSFUL;
	PEPROCESS ProcessObj = NULL;
	PUCHAR ProcessName = NULL;

	//程序ID和返回一個引用指標的過程EPROCESS結構
	status = PsLookupProcessByProcessId(ProcessId, &ProcessObj);
	if (NT_SUCCESS(status))
	{
		// ImageFileName    : [16]  "SogouExplorer.e"
		//使用這個函式,只能獲取程序名稱是16的長度,後面的被截取了。。。
		ProcessName = PsGetProcessImageFileName(ProcessObj);
		ObfDereferenceObject(ProcessObj);
	}

	return ProcessName;
}



VOID CreateProcessNotifyFunction(IN HANDLE  ParentId, IN HANDLE  ProcessId, IN BOOLEAN  Create)
{
	if (Create)
	{
		char* pName=GetProcessName16ByProcessId(ProcessId);
		if (pName)
		{
			RtlZeroMemory(g_szOutBuf, sizeof(g_szOutBuf));
			RtlCopyMemory(g_szOutBuf, pName, strlen(pName)+1);

			//設定事件為有訊號,通知應用層
			KeSetEvent(g_pEventObject, 0, FALSE);
		}

	}

	return;
}


VOID DriverUnload(DRIVER_OBJECT *DriverObject)
{
	PsSetCreateProcessNotifyRoutine(CreateProcessNotifyFunction, TRUE);
	UNICODE_STRING Win32Device;
	RtlInitUnicodeString(&Win32Device, L"\\DosDevices\\KernelHandle");
	IoDeleteSymbolicLink(&Win32Device);
	IoDeleteDevice(DriverObject->DeviceObject);
	return;
}

NTSTATUS KernelHandleCreate(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
	Irp->IoStatus.Status = STATUS_SUCCESS;
	Irp->IoStatus.Information = 0;
	IoCompleteRequest(Irp, IO_NO_INCREMENT);
	return STATUS_SUCCESS;
}

NTSTATUS KernelHandleClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
	Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
	Irp->IoStatus.Information = 0;
	IoCompleteRequest(Irp, IO_NO_INCREMENT);
	return Irp->IoStatus.Status;
}

NTSTATUS KernelHandleDefaultHandler(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
	NTSTATUS status = STATUS_SUCCESS;
	ULONG ulReturn = 0;
	PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
	ULONG ulCtrlCode = stack->Parameters.DeviceIoControl.IoControlCode;
	PVOID InputBuffer = (PVOID)Irp->AssociatedIrp.SystemBuffer;
	PVOID OutputBuffer = (PVOID)Irp->AssociatedIrp.SystemBuffer;
	ULONG ulInputBufferSize = stack->Parameters.DeviceIoControl.InputBufferLength;
	ULONG ulOutputBufferSize = stack->Parameters.DeviceIoControl.OutputBufferLength;

	switch (ulCtrlCode)
	{
	case IOCTL_START:
	{
		//設定同步事件
		if (InputBuffer == NULL || ulInputBufferSize < sizeof(HANDLE))
		{
			KdPrint(("Set Event Error~!\n"));
			break;
		}

		//取得控制代碼物件
		HANDLE hEvent = *(HANDLE*)InputBuffer;
		status = ObReferenceObjectByHandle(hEvent, GENERIC_ALL, NULL, KernelMode, (PVOID*)&g_pEventObject, &g_ObjectHandleInfo);
		PsSetCreateProcessNotifyRoutine(CreateProcessNotifyFunction, FALSE);
		break;
	}
	case IOCTL_STOP:
	{
	
		//移除程序建立通知函式
		PsSetCreateProcessNotifyRoutine(CreateProcessNotifyFunction, TRUE);
		//釋放物件引用
		if (g_pEventObject != NULL)
		{
			ObDereferenceObject(g_pEventObject);
			g_pEventObject = NULL;
		}

		break;
	}
	default:
		break;
	}


	Irp->IoStatus.Status = STATUS_SUCCESS;
	Irp->IoStatus.Information = ulOutputBufferSize;
	IoCompleteRequest(Irp, IO_NO_INCREMENT);
	return Irp->IoStatus.Status;
}

NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
{
	NTSTATUS status;
	PDEVICE_OBJECT DeviceObject = NULL;
	UNICODE_STRING DeviceName;
	UNICODE_STRING Win32Device;

	KdBreakPoint();
	DriverObject->DriverUnload = DriverUnload;
	RtlInitUnicodeString(&DeviceName, L"\\Device\\KernelHandle");
	RtlInitUnicodeString(&Win32Device, L"\\DosDevices\\KernelHandle");

	DriverObject->MajorFunction[IRP_MJ_CREATE] = KernelHandleCreate;
	DriverObject->MajorFunction[IRP_MJ_CLOSE] = KernelHandleClose;
	DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = KernelHandleDefaultHandler;



	status = IoCreateDevice(DriverObject,0,&DeviceName,FILE_DEVICE_UNKNOWN,0,FALSE,&DeviceObject);
	if (!NT_SUCCESS(status))
		return status;
	if (!DeviceObject)
		return STATUS_UNEXPECTED_IO_ERROR;
	DeviceObject->Flags |= DO_DIRECT_IO;
	DeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT;
	status = IoCreateSymbolicLink(&Win32Device, &DeviceName);
	DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;


	do
	{
		PSECURITY_DESCRIPTOR sd;
		OBJECT_ATTRIBUTES oa;
		UNICODE_STRING uniString;
		status = RegisterMiniFilter(DriverObject, RegistryPath);
		if (!NT_SUCCESS(status))break;

		status = FltRegisterFilter(DriverObject, &FilterRegistration, &gFilterHandle);
		if (!NT_SUCCESS(status))break;

		status = FltBuildDefaultSecurityDescriptor(&sd, FLT_PORT_ALL_ACCESS);
		if (!NT_SUCCESS(status))break;

		RtlInitUnicodeString(&uniString, L"\\CommunicationPort");
		InitializeObjectAttributes(&oa, &uniString, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, sd);
		status = FltCreateCommunicationPort(gFilterHandle, &g_ServerPort, &oa, NULL, ConnectNotifyCallback, DisconnectNotifyCallback, MessageNotifyCallback, 1);
		FltFreeSecurityDescriptor(sd);
		if (!NT_SUCCESS(status))break;

		status = FltStartFiltering(gFilterHandle);
		if (!NT_SUCCESS(status))break;

	} while (FALSE);


	if (!NT_SUCCESS(status))
	{
		if (NULL != g_ServerPort) {
			FltCloseCommunicationPort(g_ServerPort);
		}

		if (NULL != gFilterHandle) {
			FltUnregisterFilter(gFilterHandle);
		}
	}

	return STATUS_SUCCESS;
}



#include <windows.h>
#include <tchar.h>
#include <stdio.h>
//這兩個檔案在VS中沒有,在WDK中有.  
//如果要用VS編譯要拷貝相應的檔案到相應的目錄或者改變目錄的設定等.  
#include <fltuser.h>  
#pragma comment(lib, "fltLib.lib")  

HANDLE hDevice;
HANDLE g_hKernelEvent = NULL;
HANDLE g_hPort;

#define     NPMINI_PORT_NAME       L"\\CommunicationPort" 

//驅動控制程式碼
#define IOCTL_START CTL_CODE(FILE_DEVICE_UNKNOWN, 0x810,METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_STOP CTL_CODE(FILE_DEVICE_UNKNOWN, 0x811,METHOD_BUFFERED, FILE_ANY_ACCESS)



DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
	printf("執行緒開始執行\n");

	HRESULT hResult;


	while (WaitForSingleObject(g_hKernelEvent, INFINITE) == WAIT_OBJECT_0)
	{
		printf("收到狀態\n");

		wchar_t InBuffer[] = L"test";
		char OutBuffer[MAX_PATH] = { 0 };
		DWORD bytesReturned = 0;
		hResult = FilterSendMessage(g_hPort, InBuffer, lstrlen(InBuffer), OutBuffer, sizeof(OutBuffer), &bytesReturned);
		if (IS_ERROR(hResult))
		{
			printf("FilterSendMessage fail!\n");
		}
		else
		{
			printf("FilterSendMessage ok!\n");
		}

		printf("從核心發來的資訊是:%s\n", OutBuffer);

		//設定同步事件為無訊號,等待下一次通知
		ResetEvent(g_hKernelEvent);
	}

	printf("執行緒結束\n");
	return 0;
}





int main(void)
{

	//建立手動重置的事件
	g_hKernelEvent = CreateEvent(NULL, TRUE, FALSE, NULL);


	//開啟驅動的符號連結
	hDevice = CreateFile(L"\\\\.\\KernelHandle", GENERIC_READ | GENERIC_WRITE, 0,NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

	if (INVALID_HANDLE_VALUE == hDevice)
	{
		printf("CreateFile fail!\n");
		getchar();
		getchar();
		return FALSE;
	}
	DWORD dwRet;
	DeviceIoControl(hDevice, IOCTL_START, &g_hKernelEvent, sizeof(g_hKernelEvent), NULL, NULL, &dwRet, NULL);


	HRESULT hResult = S_OK;
	hResult = FilterConnectCommunicationPort(NPMINI_PORT_NAME, 0, NULL, 0, NULL, &g_hPort);
	if (IS_ERROR(hResult))
	{
		printf("FilterConnectCommunicationPort fail!\n");
		getchar();
		getchar();
		return hResult;
	}
	printf("FilterConnectCommunicationPort\n");

	HANDLE hThread =CreateThread(NULL, NULL, ThreadProc, NULL, NULL, NULL);
	CloseHandle(hThread);


	getchar();
	getchar();
	CloseHandle(g_hPort);
	DeviceIoControl(hDevice, IOCTL_STOP, NULL, 0, NULL, NULL, &dwRet, NULL);
	CloseHandle(hDevice);
	return 0;
}