轉載:http://blog.csdn.net/heyabo/article/details/8721611
轉載:http://www.cnblogs.com/ljinshuan/archive/2012/03/15/2397743.html
一、建立通信端口
在DriverEntry函數里創建一個安全性敘述子。
函數FltBuildDefaultSecurityDescriptor是用來申請一個安全敘述子(簡單點就是給使用通信端口的用戶申請個權限,這里可以看到申請的權限是FLT_PORT_ALL_ACCESS,意思就是:用戶層的程序連接到設置了這個權限級別的通信端口后,可以獲得所有操作權限)。函數InitializeObejectAttributes就是用來給我們要創建的對象(名稱是:MINISPY_PORT_NAME)設置一些屬性值。
FltCreateCommunicationPort就是給這個端口定義所需要的三個函數,同時注冊這個端口(注冊了才能用)。這里注冊的三個函數分別是:
MiniConnect用戶層和內核層建立連接的時候會調用該函數
MiniDisconnect用戶層和內核層斷開連接的時候會調用該函數
MiniMessage用戶層和內核層進行通訊的時候會調用
當然,既然稱他們為回調函數,那他們就不是我們用戶層的程序去調用的,工作原理是這樣的,我們在用戶層通過兩個api:FilterConnectCommunicationPort和FilterSendMessage來發出請求,然后通訊端口會根據我們的請求自己去調用這三個函數完成具體的工作。其中前者對應NPMiniConnect,后者對應NPMiniMessage。
完成上面三個回調函數后,內核中的通訊代碼已經准備好了。
#define MINISPY_PORT_NAME L"\\MiniPort" //通信端口名字 PFLT_PORT gServerPort;//服務端口 PFLT_PORT gClientPort;//客戶端口 // Defines the commands between the utility and the filter typedef enum _MINI_COMMAND { ENUM_PASS = 0, ENUM_BLOCK } MINI_COMMAND; // Defines the command structure between the utility and the filter. typedef struct _COMMAND_MESSAGE { MINI_COMMAND Command; } COMMAND_MESSAGE, *PCOMMAND_MESSAGE;
NTSTATUS DriverEntry ( _In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath ) { NTSTATUS status; PSECURITY_DESCRIPTOR sd; OBJECT_ATTRIBUTES oa; UNICODE_STRING uniString; UNREFERENCED_PARAMETER( RegistryPath ); PT_DBG_PRINT( PTDBG_TRACE_ROUTINES, ("MiniFilter!DriverEntry: Entered\n") ); // // Register with FltMgr to tell it our callback routines // status = FltRegisterFilter( DriverObject, &FilterRegistration, &gFilterHandle ); FLT_ASSERT( NT_SUCCESS( status ) ); if (NT_SUCCESS( status )) { // // Start filtering i/o // status = FltStartFiltering( gFilterHandle ); if (!NT_SUCCESS( status )) { FltUnregisterFilter( gFilterHandle ); } } //產生一個安全性敘述子 status=FltBuildDefaultSecurityDescriptor(&sd,FLT_PORT_ALL_ACCESS); RtlInitUnicodeString( &uniString, MINISPY_PORT_NAME ); //初始化對象屬性 InitializeObjectAttributes( &oa, &uniString, OBJ_KERNEL_HANDLE|OBJ_CASE_INSENSITIVE, NULL, sd ); //內核建立通信端口 status = FltCreateCommunicationPort(gFilterHandle,&gServerPort,&oa,NULL,MiniConnect,MiniDisconnect,MiniMessage,1); FltFreeSecurityDescriptor( sd ); return status; }
//用戶態和內核態建立連接 NTSTATUS MiniConnect( __in PFLT_PORT ClientPort, __in PVOID ServerPortCookie, __in_bcount(SizeOfContext) PVOID ConnectionContext, __in ULONG SizeOfContext, __deref_out_opt PVOID *ConnectionCookie ) { DbgPrint("[mini-filter] NPMiniConnect"); PAGED_CODE(); UNREFERENCED_PARAMETER( ServerPortCookie ); UNREFERENCED_PARAMETER( ConnectionContext ); UNREFERENCED_PARAMETER( SizeOfContext); UNREFERENCED_PARAMETER( ConnectionCookie ); ASSERT( gClientPort == NULL ); gClientPort = ClientPort; return STATUS_SUCCESS; } //用戶態和內核斷開連接 VOID MiniDisconnect( __in_opt PVOID ConnectionCookie ) { PAGED_CODE(); UNREFERENCED_PARAMETER( ConnectionCookie ); DbgPrint("[mini-filter] NPMiniDisconnect"); // Close our handle FltCloseClientPort( gFilterHandle, &gClientPort ); } //用戶態和內核態傳送數據 NTSTATUS MiniMessage ( __in PVOID ConnectionCookie, __in_bcount_opt(InputBufferSize) PVOID InputBuffer, __in ULONG InputBufferSize, __out_bcount_part_opt(OutputBufferSize,*ReturnOutputBufferLength) PVOID OutputBuffer, __in ULONG OutputBufferSize, __out PULONG ReturnOutputBufferLength ) { MINI_COMMAND command; NTSTATUS status; PAGED_CODE(); UNREFERENCED_PARAMETER( ConnectionCookie ); UNREFERENCED_PARAMETER( OutputBufferSize ); UNREFERENCED_PARAMETER( OutputBuffer ); DbgPrint("[mini-filter] NPMiniMessage"); if ((InputBuffer != NULL) && (InputBufferSize >= (FIELD_OFFSET(COMMAND_MESSAGE,Command) + sizeof(MINI_COMMAND)))) { try { // Probe and capture input message: the message is raw user mode // buffer, so need to protect with exception handler command = ((PCOMMAND_MESSAGE) InputBuffer)->Command; } except( EXCEPTION_EXECUTE_HANDLER ) { return GetExceptionCode(); } switch (command) { //釋放規則 case ENUM_PASS: { DbgPrint("[mini-filter] ENUM_PASS"); gCommand = ENUM_PASS; status = STATUS_SUCCESS; break; } //阻擋規則 case ENUM_BLOCK: { DbgPrint("[mini-filter] ENUM_BLOCK"); gCommand = ENUM_BLOCK; status = STATUS_SUCCESS; break; } default: DbgPrint("[mini-filter] default"); status = STATUS_INVALID_PARAMETER; break; } } else { status = STATUS_INVALID_PARAMETER; } return status; }
二、應用層通過DLL使用通信端口
在用戶態編寫應用程序時,開發者可以編寫一個簡單的動態鏈接庫(DLL)來提供與內核中的MiniFilter內核驅動程序通信的功能。
動態庫
.h
#ifndef _MINIFILTER_H_ #define _MINIFILTER_H_ #include <windows.h> #include <stdio.h> #include <FltUser.h> #pragma comment(lib, "fltLib.lib") extern HANDLE g_hPort; #define MIN_PORT_NAME L"\\MiniPort" #ifdef MINI_EXPORTS #define MINI_API _declspec(dllexport) #else #define MINI_API _declspec(dllexport) #endif // NPMINI_EXPORTS extern "C" MINI_API int InitialCommuicationPort(void); extern "C" MINI_API int NPSendMessage(PVOID InputBuffer); typedef enum _MINI_COMMAND { ENUM_PASS = 0, ENUM_BLOCK }MIN_COMMAND; typedef struct _COMAND_MESSAGE { MIN_COMMAND Command; } COMMAND_MESSAGE,*PCOMMAND_MESSAGE; #endif
.cpp
#include "stdafx.h" #include "MiniFilter_dll.h" //初始化句柄 HANDLE g_hPort = INVALID_HANDLE_VALUE; int InitialCommuicationPort(void) { DWORD hResult = FilterConnectCommunicationPort(MIN_PORT_NAME,0,NULL,0,NULL,&g_hPort); printf("進入了通信端口初始化\n"); if (hResult != S_OK) { return hResult; printf("通信端口初始化不成功\n"); } printf("通信端口初始化成功\n"); return 0; } int NPSendMessage(PVOID InputBuffer) { DWORD bytesReturned = 0; DWORD hResult = 0; PCOMMAND_MESSAGE command_message = (PCOMMAND_MESSAGE)InputBuffer; printf("進入發送消息\n"); hResult = FilterSendMessage(g_hPort,command_message,sizeof(command_message),NULL,NULL,&bytesReturned); if (hResult != S_OK) { return hResult; } return 0; }

為了在任意目標機器上使用,此動態庫以靜態鏈接C/C++運行時庫
三、用戶程序調用
在此是顯示調用動態庫
.h
#include <windows.h> #include <vector> #include <string> using namespace std; HANDLE g_hPort = INVALID_HANDLE_VALUE; typedef enum _MINI_COMMAND { ENUM_PASS = 0, ENUM_BLOCK }MIN_COMMAND; typedef struct _COMAND_MESSAGE { MIN_COMMAND Command; }COMMAND_MESSAGE,*PCOMMAND_MESSAGE; class CApp { public: CApp(); virtual ~CApp(); int Init(); void Message(COMMAND_MESSAGE data); private: HINSTANCE m_hModule; bool LoadminifilterDll(); };
.cpp
#include "App.h" #include <iostream> using namespace std; typedef int (*pSendMessage)(PVOID pInBufffer); typedef int (*pInitiaCommunicationPort)(); CApp::CApp() { m_hModule = NULL; LoadminifilterDll(); } CApp::~CApp() { if (m_hModule) { FreeLibrary(m_hModule); } } bool CApp::LoadminifilterDll() { printf("進入了LoadminifilterDll,此函數是為了Minifilter_dll.dll中的NPSendMessage\n"); m_hModule = LoadLibrary(L"MiniFilter_dll.dll"); if (m_hModule != NULL) { pInitiaCommunicationPort pInit = (pInitiaCommunicationPort)GetProcAddress(m_hModule,"InitialCommuicationPort"); if (!pInit) { printf("調用了pInit ,但是失敗了\n"); return false; } pInit(); printf("調用了pInit ,並鏈接成功了\n"); return true; } printf("獲得MiniFilter_dll.dll的句柄失敗\n"); return false; } void CApp::Message(COMMAND_MESSAGE data) { if (m_hModule == NULL) { if (LoadminifilterDll() == false) { return ; } } printf("發送數據\n"); //根據符號名得到函數地址 pSendMessage send = (pSendMessage)GetProcAddress(m_hModule,"NPSendMessage"); send(&data); } void main() { CApp app; char input; while (true) { cout << "Enter 'a' for PASS MODE, 'b' for BLOCKMODE or 'q' to EXIT" << endl; cin >> input; if (input=='a' || input=='A') { COMMAND_MESSAGE data; data.Command =ENUM_PASS; printf("上一句是 data.Command = ENUM_PASS;\n"); app.Message(data); printf("==>NOTEPAD.EXE PASS MODE\n"); } else if (input=='b' || input=='B') { COMMAND_MESSAGE data; data.Command = ENUM_BLOCK; app.Message(data); printf("==>NOTEPAD.EXE BLOCK MODE\n"); } else if (input== 'q' || input=='Q') { printf("EXIT\n"); break; } else { printf("Wrong Parameter!!!\n"); } } system("pause"); }

DLL是以靜態鏈接運行時庫的,所以用戶程序也要以靜態鏈接運行時庫。
四、
驅動裝好后,以管理員權限在cmd下net start MiniFilter開啟服務
UseMiniFilter.exe 和 MiniFilter_dll.dll放在同一目錄下

以管理員權限打開UseMiniFilter.exe

輸入字符 b (阻止打開)

打開一個txt

通信成功了!!!!
