驅動開發:檔案微過濾驅動入門

2023-06-19 12:01:20

MiniFilter 微過濾驅動是相對於SFilter傳統過濾驅動而言的,傳統檔案過濾驅動相對來說較為複雜,且介面不清晰並不符合快速開發的需求,為了解決複雜的開發問題,微過濾驅動就此誕生,微過濾驅動在編寫時更簡單,多數IRP操作都由過濾管理器(FilterManager或Fltmgr)所接管,因為有了相容層,所以在開發中不需要考慮底層IRP如何派發,更無需要考慮相容性問題,使用者只需要編寫對應的回撥函數處理請求即可,這極大的提高了檔案過濾驅動的開發效率。

接下來將進入正題,講解微過濾驅動的API定義規範以及具體的使用流程,並最終實現一個簡單的過濾功能,首先你必須在VS上做如下設定,依次開啟設定選單,並增加驅動標頭檔案。

  • 設定屬性 > 聯結器 > 輸入> 附加依賴 > fltMgr.lib
  • 設定屬性 > C/C++ > 常規 > 設定 關閉所有警告 (警告視為錯誤關閉)

未過濾驅動的使用非常容易,在使用之前第一件事就是要向過濾管理器宣告我們的微過濾驅動的存在,我們以DriverEntry入口函數為例,首先在入口處需要使用FltRegisterFilter函數註冊一個過濾器元件,另外則需要通過FltStartFiltering開啟過濾功能,而當我們想要關閉時則需要呼叫FltUnregisterFilter登出過濾元件,首先來看一下入口處是如何初始化的;

NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
{
	NTSTATUS status;

	DbgPrint("Hello LyShark.com \n");

	// FltRegisterFilter 向過濾管理器註冊過濾器
	// 引數1:本驅動驅動物件
	// 引數2:微過濾驅動描述結構
	// 引數3:返回註冊成功的微過濾驅動控制程式碼
	status = FltRegisterFilter(DriverObject, &FilterRegistration, &gFilterHandle);
	if (NT_SUCCESS(status))
	{
		// 開啟過濾
		status = FltStartFiltering(gFilterHandle);
		DbgPrint("[過濾器] 開啟監控.. \n");

		if (!NT_SUCCESS(status))
		{
			// 如果啟動失敗,則取消註冊並退出
			FltUnregisterFilter(gFilterHandle);
			DbgPrint("[過濾器] 取消註冊.. \n");
		}
	}
	return status;
}

如上程式碼中我們最需要關注的是FltRegisterFilter函數的第二個引數FilterRegistration它用於宣告註冊資訊,這個結構內包含了過濾器的所有資訊,想要註冊成功則我們必須更具要求正確的填寫FLT_REGISTRATION微過濾器註冊結構,該結構體的微軟定義如下所示;

typedef struct _FLT_REGISTRATION {
  USHORT                                      Size;
  USHORT                                      Version;
  FLT_REGISTRATION_FLAGS                      Flags;
  const FLT_CONTEXT_REGISTRATION              *ContextRegistration;
  const FLT_OPERATION_REGISTRATION            *OperationRegistration;
  PFLT_FILTER_UNLOAD_CALLBACK                 FilterUnloadCallback;
  PFLT_INSTANCE_SETUP_CALLBACK                InstanceSetupCallback;
  PFLT_INSTANCE_QUERY_TEARDOWN_CALLBACK       InstanceQueryTeardownCallback;
  PFLT_INSTANCE_TEARDOWN_CALLBACK             InstanceTeardownStartCallback;
  PFLT_INSTANCE_TEARDOWN_CALLBACK             InstanceTeardownCompleteCallback;
  PFLT_GENERATE_FILE_NAME                     GenerateFileNameCallback;
  PFLT_NORMALIZE_NAME_COMPONENT               NormalizeNameComponentCallback;
  PFLT_NORMALIZE_CONTEXT_CLEANUP              NormalizeContextCleanupCallback;
  PFLT_TRANSACTION_NOTIFICATION_CALLBACK      TransactionNotificationCallback;
  PFLT_NORMALIZE_NAME_COMPONENT_EX            NormalizeNameComponentExCallback;
  PFLT_SECTION_CONFLICT_NOTIFICATION_CALLBACK SectionNotificationCallback;
} FLT_REGISTRATION, *PFLT_REGISTRATION;

當然如上的這些欄位並非都要去填充,我們只需要填充自己所需要的部分即可,例如我們程式碼中只填充瞭如下這些必要的部分,其他部分可以省略掉,當使用如下結構體註冊時,只要範例發生了變化就會根據如下設定路由到不同的函數上面做處理。

// 過濾驅動資料結構
CONST FLT_REGISTRATION FilterRegistration =
{
	sizeof(FLT_REGISTRATION),         //  結構大小(預設)
	FLT_REGISTRATION_VERSION,           //  結構版本(預設)
	0,                                  //  過濾器標誌
	NULL,                               //  上下文
	Callbacks,                          //  註冊回撥函數集
	Unload,                             //  驅動解除安裝函數
	InstanceSetup,                      //  範例安裝回撥函數
	InstanceQueryTeardown,              //  範例銷燬回撥函數
	InstanceTeardownStart,              //  範例解除繫結時觸發
	InstanceTeardownComplete,           //  範例解綁完成時觸發
	NULL,                               //  GenerateFileName
	NULL,                               //  GenerateDestinationFileName
	NULL                                //  NormalizeNameComponent
};

如上結構中我們最需要注意的是Callbacks欄位,該欄位是操作回撥函數集註冊,我們對檔案的各種操作的回撥事件都會被寫入到此處,而此處我們只需要增加我們所需要的回撥事件即可,以IRP_MJ_CREATE為例,後面緊跟的是PreOperation事前回撥,以及PostOperation事後回撥,一般在要進行監控時通常在PreOperation()回撥中處理,如果時監視則一般在PostOperation()中處理。

// 回撥函數集
CONST FLT_OPERATION_REGISTRATION Callbacks[] =
{
	// 建立時觸發 PreOperation(之前回撥函數) / PostOperation(之後回撥函數)
	{ IRP_MJ_CREATE, 0, PreOperation, PostOperation },
	// 讀取時觸發
	{ IRP_MJ_READ, 0, PreOperation, PostOperation },
	// 寫入觸發
	{ IRP_MJ_WRITE, 0, PreOperation, PostOperation },
	// 設定時觸發
	{ IRP_MJ_SET_INFORMATION, 0, PreOperation, PostOperation },
	// 結束標誌
	{ IRP_MJ_OPERATION_END }
};

如下完整程式碼實現了監視當前系統下所有的檔案操作,如建立,讀取,寫入,修改,載入後則會監視系統下所有的檔案操作,當然如果是監控則需要在PreOperation事前回撥做文章,而如果僅僅只是監視則事前事後都是可以的。

// 署名權
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: [email protected]

#include <fltKernel.h>
#include <dontuse.h>
#include <suppress.h>

PFLT_FILTER gFilterHandle;

// ----------------------------------------------------------------------------------------
// 宣告部分
// ----------------------------------------------------------------------------------------
DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry(
	_In_ PDRIVER_OBJECT DriverObject,
	_In_ PUNICODE_STRING RegistryPath
	);

NTSTATUS
InstanceSetup(
_In_ PCFLT_RELATED_OBJECTS FltObjects,
_In_ FLT_INSTANCE_SETUP_FLAGS Flags,
_In_ DEVICE_TYPE VolumeDeviceType,
_In_ FLT_FILESYSTEM_TYPE VolumeFilesystemType
);

VOID
InstanceTeardownStart(
_In_ PCFLT_RELATED_OBJECTS FltObjects,
_In_ FLT_INSTANCE_TEARDOWN_FLAGS Flags
);

VOID
InstanceTeardownComplete(
_In_ PCFLT_RELATED_OBJECTS FltObjects,
_In_ FLT_INSTANCE_TEARDOWN_FLAGS Flags
);

NTSTATUS
Unload(
_In_ FLT_FILTER_UNLOAD_FLAGS Flags
);

NTSTATUS
InstanceQueryTeardown(
_In_ PCFLT_RELATED_OBJECTS FltObjects,
_In_ FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags
);

FLT_PREOP_CALLBACK_STATUS
PreOperation(
_Inout_ PFLT_CALLBACK_DATA Data,
_In_ PCFLT_RELATED_OBJECTS FltObjects,
_Flt_CompletionContext_Outptr_ PVOID *CompletionContext
);
FLT_POSTOP_CALLBACK_STATUS
PostOperation(
_Inout_ PFLT_CALLBACK_DATA Data,
_In_ PCFLT_RELATED_OBJECTS FltObjects,
_In_opt_ PVOID CompletionContext,
_In_ FLT_POST_OPERATION_FLAGS Flags
);

// ----------------------------------------------------------------------------------------
// 回撥函數
// ----------------------------------------------------------------------------------------

// 當範例被安裝時觸發
NTSTATUS InstanceSetup(_In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ FLT_INSTANCE_SETUP_FLAGS Flags, _In_ DEVICE_TYPE VolumeDeviceType, _In_ FLT_FILESYSTEM_TYPE VolumeFilesystemType)
{
	DbgPrint("[LyShark] 安裝 MiniFilter \n");
	return STATUS_SUCCESS;
}

// 當範例被銷燬時觸發
NTSTATUS InstanceQueryTeardown(_In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags)
{
	DbgPrint("[LyShark] 銷燬 MiniFilter \n");
	return STATUS_SUCCESS;
}

// 範例解除繫結時觸發
VOID InstanceTeardownStart(_In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ FLT_INSTANCE_TEARDOWN_FLAGS Flags)
{
	DbgPrint("[LyShark] 解綁 MiniFilter \n");
	return STATUS_SUCCESS;
}

// 範例解綁完成時觸發
VOID InstanceTeardownComplete(_In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ FLT_INSTANCE_TEARDOWN_FLAGS Flags)
{
	DbgPrint("[LyShark] 解綁完成 MiniFilter \n");
	return STATUS_SUCCESS;
}

// 驅動關閉時解除安裝監控
NTSTATUS Unload(_In_ FLT_FILTER_UNLOAD_FLAGS Flags)
{
	DbgPrint("[LyShark] 解除安裝 MiniFilter \n");
	FltUnregisterFilter(gFilterHandle);
	return STATUS_SUCCESS;
}

// 回撥函數集
CONST FLT_OPERATION_REGISTRATION Callbacks[] =
{
	// 建立時觸發 PreOperation(之前回撥函數) / PostOperation(之後回撥函數)
	{ IRP_MJ_CREATE, 0, PreOperation, PostOperation },
	// 讀取時觸發
	{ IRP_MJ_READ, 0, PreOperation, PostOperation },
	// 寫入觸發
	{ IRP_MJ_WRITE, 0, PreOperation, PostOperation },
	// 設定時觸發
	{ IRP_MJ_SET_INFORMATION, 0, PreOperation, PostOperation },
	// 結束標誌
	{ IRP_MJ_OPERATION_END }
};

// 過濾驅動資料結構
CONST FLT_REGISTRATION FilterRegistration =
{
	sizeof(FLT_REGISTRATION),           //  結構大小(預設)
	FLT_REGISTRATION_VERSION,           //  結構版本(預設)
	0,                                  //  過濾器標誌
	NULL,                               //  上下文
	Callbacks,                          //  註冊回撥函數集
	Unload,                             //  驅動解除安裝函數
	InstanceSetup,                      //  範例安裝回撥函數
	InstanceQueryTeardown,              //  範例銷燬回撥函數
	InstanceTeardownStart,              //  範例解除繫結時觸發
	InstanceTeardownComplete,           //  範例解綁完成時觸發
	NULL,                               //  GenerateFileName
	NULL,                               //  GenerateDestinationFileName
	NULL                                //  NormalizeNameComponent
};

// ----------------------------------------------------------------------------------------
// 功能函數
// ----------------------------------------------------------------------------------------

// 預操作回撥函數(在執行過濾操作之前先執行此處)
FLT_PREOP_CALLBACK_STATUS PreOperation(_Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _Flt_CompletionContext_Outptr_ PVOID *CompletionContext)
{
	NTSTATUS status;

	// 獲取檔案路徑
	UCHAR MajorFunction = Data->Iopb->MajorFunction;
	PFLT_FILE_NAME_INFORMATION lpNameInfo = NULL;

	// 得到檔名相關資訊
	status = FltGetFileNameInformation(Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &lpNameInfo);
	if (NT_SUCCESS(status))
	{
		status = FltParseFileNameInformation(lpNameInfo);
		if (NT_SUCCESS(status))
		{
			// 建立
			if (IRP_MJ_CREATE == MajorFunction)
			{
				DbgPrint("[建立檔案時] %wZ", &lpNameInfo->Name);

				// 拒絕建立
				// STATUS_INSUFFICIENT_RESOURCES                 提示不是有效的資源
				// STATUS_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY  靜默拒絕
				// STATUS_ACCESS_DENIED                          提示存取拒絕
				// return STATUS_ACCESS_DENIED;
				// return FLT_PREOP_COMPLETE;
			}
			// 讀取
			else if (IRP_MJ_READ == MajorFunction)
			{
				DbgPrint("[讀取檔案時] %wZ", &lpNameInfo->Name);
				// return FLT_PREOP_COMPLETE;
			}
			// 檔案寫入
			else if (IRP_MJ_WRITE == MajorFunction)
			{
				DbgPrint("[寫入檔案時] %wZ", &lpNameInfo->Name);
				// return FLT_PREOP_COMPLETE;
			}
			// 修改檔案資訊
			else if (IRP_MJ_SET_INFORMATION == MajorFunction)
			{
				DbgPrint("[修改檔案] %wZ", &lpNameInfo->Name);
				// return FLT_PREOP_COMPLETE;
			}
		}
	}
	return FLT_PREOP_SUCCESS_WITH_CALLBACK;
}

// 後操作回撥函數 (在執行過濾之後執行此處)
FLT_POSTOP_CALLBACK_STATUS PostOperation(_Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _In_opt_ PVOID CompletionContext, _In_ FLT_POST_OPERATION_FLAGS Flags)
{
	return FLT_POSTOP_FINISHED_PROCESSING;
}

// ----------------------------------------------------------------------------------------
// 入口函數
// ----------------------------------------------------------------------------------------
NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
{
	NTSTATUS status;

	DbgPrint("Hello LyShark.com \n");

	// FltRegisterFilter 向過濾管理器註冊過濾器
	// 引數1:本驅動驅動物件
	// 引數2:微過濾驅動描述結構
	// 引數3:返回註冊成功的微過濾驅動控制程式碼
	status = FltRegisterFilter(DriverObject, &FilterRegistration, &gFilterHandle);
	if (NT_SUCCESS(status))
	{
		// 開啟過濾
		status = FltStartFiltering(gFilterHandle);
		DbgPrint("[過濾器] 開啟監控.. \n");

		if (!NT_SUCCESS(status))
		{
			// 如果啟動失敗,則取消註冊並退出
			FltUnregisterFilter(gFilterHandle);
			DbgPrint("[過濾器] 取消註冊.. \n");
		}
	}
	return status;
}

過濾驅動的安裝方式有多種,可以通過函數註冊或者使用INF檔案像系統註冊驅動,首先以INF為例安裝,通過修改INF中的ServiceName以及DriverName並將其改為WinDDK,將檔案儲存為install.inf滑鼠右鍵選擇安裝即可。

[Version]
Signature   = "$Windows NT$"     
Class       = "ActivityMonitor"  ;指明瞭驅動的分組,必須指定.
ClassGuid   = {b86dff51-a31e-4bac-b3cf-e8cfe75c9fc2}  ;GUID 每個分組都有固定的GUID
Provider    = %Msft% ;變數值 從STRING節中可以看到驅動提供者的名稱 
DriverVer   = 06/16/2007,1.0.0.1 ;版本號
CatalogFile = passthrough.cat    ;inf對應的cat 檔案 可以不需要

[DestinationDirs]
DefaultDestDir          = 12    ;告訴我們驅動拷貝到哪裡 13代表拷貝到%windir%
MiniFilter.DriverFiles  = 12            ;%windir%\system32\drivers

[DefaultInstall]
OptionDesc          = %ServiceDescription%
CopyFiles           = MiniFilter.DriverFiles

[DefaultInstall.Services]
AddService          = %ServiceName%,,MiniFilter.Service

[DefaultUninstall]
DelFiles   = MiniFilter.DriverFiles

[DefaultUninstall.Services]
DelService = %ServiceName%,0x200      ;Ensure service is stopped before deleting

[MiniFilter.Service]                 ;服務的一些資訊
DisplayName      = %ServiceName%
Description      = %ServiceDescription%
ServiceBinary    = %12%\%DriverName%.sys        ;%windir%\system32\drivers\
Dependencies     = "FltMgr"                     ;服務的依賴
ServiceType      = 2                            ;SERVICE_FILE_SYSTEM_DRIVER
StartType        = 3                            ;SERVICE_DEMAND_START
ErrorControl     = 1                            ;SERVICE_ERROR_NORMAL
LoadOrderGroup   = "FSFilter Activity Monitor"  ;檔案過濾分組
AddReg           = MiniFilter.AddRegistry       ;檔案過濾登入檔需要新增的高度值等資訊

[MiniFilter.AddRegistry]
HKR,,"DebugFlags",0x00010001 ,0x0
HKR,"Instances","DefaultInstance",0x00000000,%DefaultInstance%
HKR,"Instances\"%Instance1.Name%,"Altitude",0x00000000,%Instance1.Altitude%
HKR,"Instances\"%Instance1.Name%,"Flags",0x00010001,%Instance1.Flags%

[MiniFilter.DriverFiles]
%DriverName%.sys

[SourceDisksFiles]
passthrough.sys = 1,,

[SourceDisksNames]
1 = %DiskId1%,,,

[Strings]
Msft                    = "Microsoft Corporation"
ServiceDescription      = "WinDDK Mini-Filter Driver"
ServiceName             = "WinDDK"
DriverName              = "WinDDK"
DiskId1                 = "WinDDK Device Installation Disk"

DefaultInstance         = "WinDDK Instance"
Instance1.Name          = "WinDDK Instance"
Instance1.Altitude      = "370030"
Instance1.Flags         = 0x0              ; Allow all attachments

第二種安裝方式則是通過字寫驅動載入工具實現,本人更推薦使用此方式安裝,此種方式的原理同樣是向登入檔中寫出子健,但同時具備有啟動與關閉驅動的功能,比INF安裝更靈活易於使用,完整程式碼如下所示;

// 署名權
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: [email protected]

#include <Windows.h>
#include <iostream>
#include <winsvc.h>
#include <winioctl.h>

// 安裝MiniFinter
BOOL InstallDriver(const char* lpszDriverName, const char* lpszDriverPath, const char* lpszAltitude)
{
	char szTempStr[MAX_PATH];
	HKEY hKey;
	DWORD dwData;
	char szDriverImagePath[MAX_PATH];

	if (NULL == lpszDriverName || NULL == lpszDriverPath)
	{
		return FALSE;
	}

	// 得到完整的驅動路徑
	GetFullPathName(lpszDriverPath, MAX_PATH, szDriverImagePath, NULL);

	SC_HANDLE hServiceMgr = NULL; // SCM管理器的控制程式碼
	SC_HANDLE hService = NULL;    // NT驅動程式的服務控制程式碼

	// 開啟服務控制管理器
	hServiceMgr = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
	if (hServiceMgr == NULL)
	{
		// OpenSCManager失敗
		CloseServiceHandle(hServiceMgr);
		return FALSE;
	}

	// OpenSCManager成功  

	// 建立驅動所對應的服務
	hService = CreateService(hServiceMgr,
		lpszDriverName,             // 驅動程式的在登入檔中的名字
		lpszDriverName,             // 登入檔驅動程式的DisplayName 值
		SERVICE_ALL_ACCESS,         // 載入驅動程式的存取許可權
		SERVICE_FILE_SYSTEM_DRIVER, // 表示載入的服務是檔案系統驅動程式
		SERVICE_DEMAND_START,       // 登入檔驅動程式的Start 值
		SERVICE_ERROR_IGNORE,       // 登入檔驅動程式的ErrorControl 值
		szDriverImagePath,          // 登入檔驅動程式的ImagePath 值
		"FSFilter Activity Monitor",// 登入檔驅動程式的Group 值
		NULL,
		"FltMgr",                   // 登入檔驅動程式的DependOnService 值
		NULL,
		NULL);

	if (hService == NULL)
	{
		if (GetLastError() == ERROR_SERVICE_EXISTS)
		{
			// 服務建立失敗,是由於服務已經創立過
			CloseServiceHandle(hService);       // 服務控制程式碼
			CloseServiceHandle(hServiceMgr);    // SCM控制程式碼
			return TRUE;
		}
		else
		{
			CloseServiceHandle(hService);       // 服務控制程式碼
			CloseServiceHandle(hServiceMgr);    // SCM控制程式碼
			return FALSE;
		}
	}
	CloseServiceHandle(hService);       // 服務控制程式碼
	CloseServiceHandle(hServiceMgr);    // SCM控制程式碼

	//-------------------------------------------------------------------------------------------------------
	// SYSTEM\\CurrentControlSet\\Services\\DriverName\\Instances 子鍵下的鍵值項 
	//-------------------------------------------------------------------------------------------------------
	strcpy(szTempStr, "SYSTEM\\CurrentControlSet\\Services\\");
	strcat(szTempStr, lpszDriverName);
	strcat(szTempStr, "\\Instances");
	if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, szTempStr, 0, "", TRUE, KEY_ALL_ACCESS, NULL, &hKey, (LPDWORD)&dwData) != ERROR_SUCCESS)
	{
		return FALSE;
	}
	// 登入檔驅動程式的DefaultInstance 值 
	strcpy(szTempStr, lpszDriverName);
	strcat(szTempStr, " Instance");
	if (RegSetValueEx(hKey, "DefaultInstance", 0, REG_SZ, (CONST BYTE*)szTempStr, (DWORD)strlen(szTempStr)) != ERROR_SUCCESS)
	{
		return FALSE;
	}
	// 重新整理登入檔
	RegFlushKey(hKey);
	RegCloseKey(hKey);

	//-------------------------------------------------------------------------------------------------------
	// SYSTEM\\CurrentControlSet\\Services\\DriverName\\Instances\\DriverName Instance 子鍵下的鍵值項 
	//-------------------------------------------------------------------------------------------------------
	strcpy(szTempStr, "SYSTEM\\CurrentControlSet\\Services\\");
	strcat(szTempStr, lpszDriverName);
	strcat(szTempStr, "\\Instances\\");
	strcat(szTempStr, lpszDriverName);
	strcat(szTempStr, " Instance");
	if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, szTempStr, 0, "", TRUE, KEY_ALL_ACCESS, NULL, &hKey, (LPDWORD)&dwData) != ERROR_SUCCESS)
	{
		return FALSE;
	}
	// 登入檔驅動程式的Altitude 值
	strcpy(szTempStr, lpszAltitude);
	if (RegSetValueEx(hKey, "Altitude", 0, REG_SZ, (CONST BYTE*)szTempStr, (DWORD)strlen(szTempStr)) != ERROR_SUCCESS)
	{
		return FALSE;
	}
	// 登入檔驅動程式的Flags 值
	dwData = 0x0;
	if (RegSetValueEx(hKey, "Flags", 0, REG_DWORD, (CONST BYTE*)&dwData, sizeof(DWORD)) != ERROR_SUCCESS)
	{
		return FALSE;
	}
	// 重新整理登入檔
	RegFlushKey(hKey);
	RegCloseKey(hKey);
	return TRUE;
}

// 啟動驅動
BOOL StartDriver(const char* lpszDriverName)
{
	SC_HANDLE schManager;
	SC_HANDLE schService;
	SERVICE_STATUS svcStatus;

	if (NULL == lpszDriverName)
	{
		return FALSE;
	}

	schManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
	if (NULL == schManager)
	{
		CloseServiceHandle(schManager);
		return FALSE;
	}
	schService = OpenService(schManager, lpszDriverName, SERVICE_ALL_ACCESS);
	if (NULL == schService)
	{
		CloseServiceHandle(schService);
		CloseServiceHandle(schManager);
		return FALSE;
	}

	if (!StartService(schService, 0, NULL))
	{
		CloseServiceHandle(schService);
		CloseServiceHandle(schManager);
		if (GetLastError() == ERROR_SERVICE_ALREADY_RUNNING)
		{
			// 服務已經開啟
			return TRUE;
		}
		return FALSE;
	}

	CloseServiceHandle(schService);
	CloseServiceHandle(schManager);

	return TRUE;
}

// 關閉驅動
BOOL StopDriver(const char* lpszDriverName)
{
	SC_HANDLE schManager;
	SC_HANDLE schService;
	SERVICE_STATUS svcStatus;
	bool bStopped = false;

	schManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
	if (NULL == schManager)
	{
		return FALSE;
	}
	schService = OpenService(schManager, lpszDriverName, SERVICE_ALL_ACCESS);
	if (NULL == schService)
	{
		CloseServiceHandle(schManager);
		return FALSE;
	}
	if (!ControlService(schService, SERVICE_CONTROL_STOP, &svcStatus) && (svcStatus.dwCurrentState != SERVICE_STOPPED))
	{
		CloseServiceHandle(schService);
		CloseServiceHandle(schManager);
		return FALSE;
	}

	CloseServiceHandle(schService);
	CloseServiceHandle(schManager);

	return TRUE;
}

// 刪除驅動
BOOL DeleteDriver(const char* lpszDriverName)
{
	SC_HANDLE schManager;
	SC_HANDLE schService;
	SERVICE_STATUS svcStatus;

	schManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
	if (NULL == schManager)
	{
		return FALSE;
	}
	schService = OpenService(schManager, lpszDriverName, SERVICE_ALL_ACCESS);
	if (NULL == schService)
	{
		CloseServiceHandle(schManager);
		return FALSE;
	}
	ControlService(schService, SERVICE_CONTROL_STOP, &svcStatus);
	if (!DeleteService(schService))
	{
		CloseServiceHandle(schService);
		CloseServiceHandle(schManager);
		return FALSE;
	}
	CloseServiceHandle(schService);
	CloseServiceHandle(schManager);

	return TRUE;
}

int main(int argc, char* argv[])
{
	InstallDriver("minifilter", ".\\WinDDK.sys", "225864");

	while (1)
	{
		char str[20] = "\0";
		printf("請輸入命令: ");
		gets(str);

		if (strcmp(str, "start") == 0)
		{
			printf("[*] 啟動驅動 \n");
			StartDriver("minifilter");
		}
		if (strcmp(str, "stop") == 0)
		{
			printf("[-] 關閉驅動 \n");
			StopDriver("minifilter");
		}
	}
	return 0;
}

至此分別編譯驅動程式,以及應用層下的安裝程式,並將兩者放入到同一目錄下,執行使用者端程式lyshark.exe並輸入start啟動驅動,輸入stop則是關閉,啟動後會看到如下資訊;

這裡簡單介紹一下如何摘除微過濾驅動回撥函數,其實摘除回撥的方法有多種,常用的第一種通過向過濾驅動中寫出一個返回命令讓其不被執行從而實現繞過,另一種是找到回撥函數並替換為我們自己的回撥,而在自己的回撥中什麼也不做,這裡以第二種方法為例,實現替換的程式碼可以寫成如下案例;

#include <fltKernel.h>

// 設定預設回撥
NTSTATUS DriverDefaultHandle(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
	NTSTATUS status = STATUS_SUCCESS;
	pIrp->IoStatus.Status = status;
	pIrp->IoStatus.Information = 0;
	IoCompleteRequest(pIrp, IO_NO_INCREMENT);

	return status;
}

// ------------------------------------------------------------------------
// 訊息轉向函數
// ------------------------------------------------------------------------

// 自定義回撥 訊息處理前
FLT_PREOP_CALLBACK_STATUS MyMiniFilterPreOperation(_Inout_ PFLT_CALLBACK_DATA Data,_In_ PCFLT_RELATED_OBJECTS FltObjects,_Flt_CompletionContext_Outptr_ PVOID *CompletionContext)
{
	UNREFERENCED_PARAMETER(FltObjects);
	UNREFERENCED_PARAMETER(CompletionContext);

	return FLT_PREOP_SUCCESS_WITH_CALLBACK;
}

// 自定義回撥 訊息處理後
FLT_POSTOP_CALLBACK_STATUS MyMiniFilterPostOperation(_Inout_ PFLT_CALLBACK_DATA Data,_In_ PCFLT_RELATED_OBJECTS FltObjects,_In_opt_ PVOID CompletionContext,_In_ FLT_POST_OPERATION_FLAGS Flags)
{
	UNREFERENCED_PARAMETER(Data);
	UNREFERENCED_PARAMETER(FltObjects);
	UNREFERENCED_PARAMETER(CompletionContext);
	UNREFERENCED_PARAMETER(Flags);

	return FLT_POSTOP_FINISHED_PROCESSING;
}

// 替換回撥函數
NTSTATUS RemoveCallback(PFLT_FILTER pFilter)
{
	LONG lOperationsOffset = 0;
	PFLT_OPERATION_REGISTRATION pFltOperationRegistration = NULL;

	// 遍歷過濾器Filter
	pFltOperationRegistration = (PFLT_OPERATION_REGISTRATION)(*(PVOID *)((PUCHAR)pFilter + lOperationsOffset));
	__try
	{
		while (IRP_MJ_OPERATION_END != pFltOperationRegistration->MajorFunction)
		{
			if (IRP_MJ_MAXIMUM_FUNCTION > pFltOperationRegistration->MajorFunction)
			{
				// 替換回撥函數
				pFltOperationRegistration->PreOperation = MyMiniFilterPreOperation;
				pFltOperationRegistration->PostOperation = MyMiniFilterPostOperation;
			}

			pFltOperationRegistration = (PFLT_OPERATION_REGISTRATION)((PUCHAR)pFltOperationRegistration + sizeof(FLT_OPERATION_REGISTRATION));
		}
	}
	__except (EXCEPTION_EXECUTE_HANDLER)
	{
		return STATUS_SUCCESS;
	}

	return STATUS_SUCCESS;
}

VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
	return STATUS_SUCCESS;
}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath)
{
	NTSTATUS status = STATUS_SUCCESS;

	pDriverObject->DriverUnload = DriverUnload;

	for (ULONG i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
	{
		pDriverObject->MajorFunction[i] = DriverDefaultHandle;
	}

	return status;
}