.NET框架中的驅動程序應用技術

 

.NET框架中的驅動程序應用技術

——用.NET和NDIS Hook Driver開發單機版網絡防火牆的關鍵技術分析

N-Byte網絡守望者是一款由我們團隊開發的單機版網絡安全工具,簡言之,就是一個用.NET開發的個人版防火牆。在N-Byte網絡守望者1.0版的開發中,我們使用了NDIS Hook Driver技術來實現網絡封包過濾功能,這使我們的N-Byte網絡守望者能夠在網絡層過濾網絡封包,從而實現強大的功能。

由於我們軟件的主程序是用C#寫的,C#中沒有提供具有類似DeviceIoControl函數功能的驅動設備控制函數,而NDIS Hook Driver技術下的驅動程序是用DDK下的C語言寫的,爲了能夠實現主程序對驅動程序的控制和相互通信,我們採用了以下設計方案:

在以上方案中,我們需要一個負責主程序與NDIS Hook Driver驅動程序通信與控制的模塊DriverDll.dll,並用C#編寫的一個封裝驅動程序中封包信息的模塊,可以發送這個驅動程序信息到主程序,主程序可識別並操作模塊中的數據類型。<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

.NET應用程序使用驅動程序的問題上,我們面臨着兩個問題:

1.       怎樣實現.NET應用程序控制驅動程序的功能?

2.       怎樣從驅動程序向.NET應用程序傳遞非託管的數據類型?

 

以下是我們就這些問題的詳細解決方法:

 

怎樣實現.NET應用程序控制驅動程序的功能?

 

我們使用託管C++編寫的DriverDll.dll來實現對驅動程序的直接控制,而主程序通過調用其中的方法來實現對驅動程序的間接控制。比如我們在NByte.h文件中定義了START_IP_HOOK常數用來作爲傳給驅動程序用來開啓驅動程序封包過濾功能的參數,下面我們在託管C++模塊中定義了IoCtrl託管類並定義了下面的向緩衝區寫入參數的方法:

 

//向緩衝區寫入數據。

DWORD WriteIo(DWORD code,PVOID buffer,DWORD count)

{

      if(hDriverHandle == NULL)

           return ERROR_DRIVER_HANDLE;

      DWORD bytesReturned;

      BOOL returnCode = DeviceIoControl(hDriverHandle,

                                                   code,

                                                   buffer,

                                                   count,

                                                   NULL,

                                                   0,

                                                   &bytesReturned, 

                                                    NULL);

 

      if(!returnCode)

           return ERROR_IO_CTRL;

      return SUCCESS;

}

 

當然直接使用這個方法不太方便,所以定義一個公有函數,用來提供給主程序調用:

 

//開始進行封包過濾

bool StartIpHook()

{

      return (WriteIo(START_IP_HOOK, NULL, 0)==SUCCESS);

}

 

這樣,只要在主程序中聲明IoCtrl的對象ic,就可以通過ic.StartIpHook()就可以實現對驅動程序過濾功能的開啓,用同樣的方法也可以實現對驅動程序進行其它操作,比如添加、修改封包過濾規則等。

 

怎樣從驅動程序向.NET應用程序傳遞非託管的數據類型?

 

爲了能夠輸出安全日誌,我們必須讓主程序獲得驅動程序中的封包信息。使用信號量機制可以很方便的實現驅動程序和非託管代碼間的信息傳遞,那麼對託管代碼呢?這需要向.NET應用程序傳遞非託管的數據類型ACCESS_INFO。在NByte.h中,我們是這樣定義這個ACCESS_INFO結構的:

 

typedef struct _ACCESS_INFO

{

      USHORT protocol; 

      ULONG  sourceIp;

      ULONG  destinationIp;

      USHORT sourcePort;

      USHORT destinationPort;

}ACCESS_INFO;

 

顯然,直接傳遞非託管數據類型是不可以的,我們需要轉換一下。首先,我們在IoCtrl類中定義了幾個要傳遞的封包信息參數:

 

public __gc class IoCtrl

{

public:

      USHORT protocol;             //網際協議類型

      ULONG  sourceIp;           //IP地址

      ULONG  destinationIp;      //目的IP地址    

      USHORT sourcePort;          //源端口

      USHORT destinationPort;   //目的端口

………………

}

 

然後,在GetAccessInfo()函數中來給這些參數賦值:

 

void GetAccessInfo()

{

      ACCESS_INFO ai;

      bool result=(ReadIo(GET_INFO,&ai,sizeof(ai))==SUCCESS);

      this->protocol=ai.protocol;

      this->sourceIp=ai.sourceIp;

      this->destinationIp=ai.destinationIp;

      this->sourcePort=ai.sourcePort;

      this->destinationPort=ai.destinationPort;

}

 

既然在IoCtrl類中獲得了這些信息,但是需要把它們封裝成主程序容易處理的數據類型,這樣,我用C#實現了InfoEvent類用來封裝這些信息:

 

//本類封裝了數據包的詳細信息,可以通過事件實現對它的模塊間傳遞。

public class InfoEvent:EventArgs

{

      string sInfo;                           //用來存放輸出信息的私有成員

      public int pLength;                //CommonFunction.sPort數組的長度

      public ushort protocol;            //網絡通信協議類型

      public uint sourceIp;               //數據包的源IP

      public uint destinationIp;        //數據包的目的IP

      public ushort sourcePort;         //數據包的源端口

      public ushort destinationPort;  //數據包的目的端口

………………………………

}

 

下面在用託管C++實現的InfoProvider驅動程序信息提供者類中把個InfoEvent類的對象傳遞給主程序,需要使用一個委託生成一個事件:

 

//聲明委託事件,用來向主程序傳遞數據。

__delegate void DriverInfo(Object* sender, InfoEvent* e);

//聲明響應事件函數。

__event DriverInfo* OnDriverInfo;

 

然後在InfoProvider驅動程序信息提供者類中定義一個方法,在主程序中以線程的方式運行這個方法,在這個方法中使用了事件函數OnDriverInfo

 

//用來獲得驅動程序信息的進程,在主程序中將開啓該進程。

void GetInfoThreadProc()

{

      this->hEvent=OpenEvent(SYNCHRONIZE,FALSE,"NBEvent");

      if(!ic->GetDriverHandle())

      {

           return;

      }

      while(true)

      {

           f(!hEvent)

                 ExitThread(0);

           WaitForSingleObject(this->hEvent,INFINITE);

           nPackets++;

           ic->GetAccessInfo();

           ic->ResetEvent();

           //定義一個主程序可以識別的對象,通過OnDriverInfo傳給主程序。

           InfoEvent*ie=new InfoEvent(ic->protocol,ic->sourceIp,ic->destinationIp,ic->sourcePort,ic->destinationPort);

           OnDriverInfo(this,ie);

      }

      ic->CloseDriverHandle();

      return;

}

 

在主程序中,我會開啓這個進程並定義了OnDriverInfo的處理函數DealWithInfo

 

pInfo=new InfoProvider();

//開啓與驅動交換信息的進程

FilterThread=new Thread(new ThreadStart(pInfo.GetInfoThreadProc));

FilterThread.IsBackground=true;

FilterThread.Start();

pInfo.OnDriverInfo+=new InfoProvider.DriverInfo(DealWithInfo);

 

這樣主程序就可以在DealWithInfo函數中加入對InfoEvent對象的處理了。可見,通過中間模塊IoCtrl的轉換,便實現了.NET主程序對驅動程序中非託管數據類型的獲取和處理。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章