乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      基于NDIS中間層的驅(qū)動包截獲技術(shù)-【科技原創(chuàng)】電子科技大學(xué)

       tuohuang0303 2011-04-05
      基于NDIS中間層的驅(qū)動包截獲技術(shù)
      09-03-25 作者:   編輯:校方人員

      NDIS(Network Driver Interface Specification)是網(wǎng)絡(luò)驅(qū)動程序接口規(guī)范的簡稱。它橫跨傳輸層、網(wǎng)絡(luò)層和數(shù)據(jù)鏈路層,定義了網(wǎng)卡或網(wǎng)卡驅(qū)動程序與上層協(xié)議驅(qū)動程序之間的通信接口規(guī)范,屏蔽了底層物理硬件的不同使上層的協(xié)議驅(qū)動程序可以和底層任何型號的網(wǎng)卡通信。NDIS為網(wǎng)絡(luò)驅(qū)動程序創(chuàng)建了一個完整的開發(fā)環(huán)境,只需調(diào)用NDIS函數(shù),而不用考慮操作系統(tǒng)的內(nèi)核以及與其他驅(qū)動程序的接口問題,從而使得網(wǎng)絡(luò)驅(qū)動程序可以從與操作系統(tǒng)的復(fù)雜通訊中分離,極大地方便了網(wǎng)絡(luò)驅(qū)動程序的編寫。另外,利用NDIS的封裝特性,可以專注于一層驅(qū)動的設(shè)計,減少了設(shè)計的復(fù)雜性,同時易于擴展驅(qū)動程序棧。

      1  NDIS驅(qū)動模型簡介

      NDIS支持的網(wǎng)絡(luò)驅(qū)動程序類型:

      網(wǎng)卡驅(qū)動程序(NIC Drivers):網(wǎng)卡驅(qū)動程序是網(wǎng)卡與上層驅(qū)動程序通信的接口,它負責(zé)接收來自上層的數(shù)據(jù)包,或?qū)?shù)據(jù)包發(fā)送到上層相應(yīng)的驅(qū)動程序,同時它還完成處理中斷等工作。

      中間驅(qū)動程序(Intermediate Protocol Drivers)中間驅(qū)動程序位于網(wǎng)卡驅(qū)動程序和協(xié)議驅(qū)動程序之間,它向上提供小端口(Minport)函數(shù)集,向下提供協(xié)議(protocol)函數(shù)集,因此對于上層驅(qū)動程序而言,它是小端口驅(qū)動程序。對于底層的驅(qū)動程序,它是協(xié)議驅(qū)動程序。

      協(xié)議驅(qū)動程序(Upper Level Protocol Drivers):協(xié)議驅(qū)動程序執(zhí)行具體的網(wǎng)絡(luò)協(xié)議,如IPX/SPX、TCP/IP等。協(xié)議驅(qū)動程序為應(yīng)用層客戶程序提供服務(wù),接收來自網(wǎng)卡或中間驅(qū)動程序的信息。

      防火墻的開發(fā)一般采用的是中間驅(qū)動程序。通過NDIS中間層驅(qū)動,我們可以截獲來自網(wǎng)卡的所有原始數(shù)據(jù)包。圖1則是NDIS中間層驅(qū)動的工作過程圖:


      1  NDIS中間層驅(qū)動工作過程圖

      NDIS中間層驅(qū)動程序是工作在MINIPROTPROTOCOL接口之間的,驅(qū)動程序必須向下導(dǎo)出一個PROTOCOL接口,向上導(dǎo)出一個MINIPORT接口。將自己創(chuàng)建的驅(qū)動程序插入到網(wǎng)卡驅(qū)動程序與傳輸驅(qū)動程序之間。如此一來,當下層的網(wǎng)卡驅(qū)動程序接收到數(shù)據(jù)后會通過MINIPORT接口發(fā)送到導(dǎo)出的PROTOCOL接口上,NDIS中間層驅(qū)動程序便接收到了來自網(wǎng)卡的數(shù)據(jù)并調(diào)用準備好的回調(diào)函數(shù)處理數(shù)據(jù)包信息。接著NDIS中間層驅(qū)動在處理數(shù)據(jù)包完畢后再繼續(xù)把數(shù)據(jù)通過導(dǎo)出的MINIPROT接口向PROTOCOL接口發(fā)送,這樣就完成了一個截獲數(shù)據(jù)包的過程[1]

      2  NDIS中間層驅(qū)動的工作流程

      在開始學(xué)習(xí)NDIS中間層驅(qū)動之前,我們有必要了解下NDIS是怎樣工作的。當然這就包括了它的接收數(shù)據(jù)包的流程了。那么我們來看看NDIS接收數(shù)據(jù)包流程到底是怎樣的:

      1.低層的網(wǎng)卡驅(qū)動調(diào)用NdisMIndicateReceive或者NdisMEthIndicateReceive函數(shù)通知上一層已經(jīng)它們已經(jīng)收到數(shù)據(jù)。

      2.接著系統(tǒng)調(diào)用自定義的PtReceive或者PtReceivePacket函數(shù),到底系統(tǒng)會調(diào)用哪個函數(shù)跟機器的網(wǎng)卡有關(guān)。接著在函數(shù)中調(diào)用NdisGetReceivedPacket函數(shù)接受低層傳上來的數(shù)據(jù),如果我們得到了一個完整的packet包,我們就申請一個緩沖區(qū)存放下層傳上來的數(shù)據(jù),接著調(diào)用NdisMIndicateReceivePacket通知上層設(shè)備。如果此時MyPacketstatusNDIS_STATUS_RESOURCES,我們就在本函數(shù)中釋放我們分配的緩沖區(qū);否則我們在上層發(fā)送4的時候,在MPReturnPacket中釋放該緩沖區(qū)。

      3.如果在PtReceive或者PtReceivePacket函數(shù)中無法得到一個完整的packet,那么就調(diào)用NdisMEthIndicateReceive等函數(shù)通知系統(tǒng)。

      4.當上層設(shè)備得到了一個完整的數(shù)據(jù)并且處理完畢以后,它會調(diào)用NdisReturnPacket,然后NDIS會調(diào)用我們的MPReturnPacket。如果申請的緩沖區(qū)沒釋放,則在MPReturnPacket函數(shù)中釋放該緩沖區(qū)。然后同樣的向下層調(diào)用NdisReturnPacket。下層會釋放他們自己申請的緩沖區(qū)。

      5.如果3發(fā)生,那么系統(tǒng)會調(diào)用PtReceiveComplete函數(shù)。在PtReceiveComplete函數(shù)中我們應(yīng)該調(diào)用NdisMEthIndicateReceiveComplete,通知系統(tǒng)收到了完整的數(shù)據(jù)。

      6.當上層協(xié)議驅(qū)動得知底層已經(jīng)收到了完整的數(shù)據(jù)報文以后,可能會調(diào)用NdisTransferData,要求下層把剩余的數(shù)據(jù)傳上來。然后系統(tǒng)調(diào)用MPTransferData例程。在MPTransferData中,調(diào)用NdisTransferData。必須注意的是該函數(shù)的返回值:如果返回success,說明剩余的數(shù)據(jù)立刻就傳上來了。此時會立即返回。7步驟就不會調(diào)用;如果返回pending,表明底層在此阻塞,底層會在稍后的時候調(diào)用7。

      7.當?shù)讓?/span>miniport驅(qū)動做好了一個完整的packet,它會調(diào)用NdisTransferDataComplete。同樣的,系統(tǒng)會調(diào)用我們的PtTransferDataComplete函數(shù)。這樣,整個接收數(shù)據(jù)的流程就結(jié)束了[2]。


      2  NDIS中間層驅(qū)動工作流程圖

      通過流程圖可以知道在PtReceive或者PtReceivePacket中可以得到我們所希望的數(shù)據(jù),然后在以上2個函數(shù)中加入自己的處理代碼,就可以達到截獲數(shù)據(jù)并進行相應(yīng)處理的目的了。

      3  在驅(qū)動程序中導(dǎo)出接口

      我們首先必須在驅(qū)動程序中向系統(tǒng)注冊導(dǎo)出虛擬接口。這些工作將在DriverEntry函數(shù)中完成,代碼如下:

      DriverEntry(

                    IN   PDRIVER_OBJECT             DriverObject,

                    IN   PUNICODE_STRING          RegistryPath

                            )

      {

                    NDIS_STATUS                                        Status;

                    NDIS_PROTOCOL_CHARACTERISTICS  PChars;   //保存有關(guān)導(dǎo)出PROTOCOL接口的回調(diào)函數(shù)地址的結(jié)構(gòu)

                    NDIS_MINIPORT_CHARACTERISTICS   MChars;  //保存有關(guān)導(dǎo)出MINIPORT接口的回調(diào)函數(shù)地址的結(jié)構(gòu)

                    PNDIS_CONFIGURATION_PARAMETER Param;

                    NDIS_STRING                                        Name;

       

      NdisMInitializeWrapper(&NdisWrapperHandle, DriverObject, RegistryPath, NULL);  //初始化NdisWrapperHandle

         //設(shè)置其他的回調(diào)函數(shù)

      MChars.SendPacketsHandler = MPSendPackets;  //設(shè)置發(fā)送數(shù)據(jù)包的回調(diào)函數(shù)

      //NDIS注冊我們的MINIPORT接口

                    Status = NdisIMRegisterLayeredMiniport(NdisWrapperHandle,

                                                                                    &MChars,

                                                                                    sizeof(MChars),

                                                                                    &DriverHandle);

      PChars.ReceivePacketHandler = PtReceivePacket;  //設(shè)置接收數(shù)據(jù)包的回調(diào)函數(shù)

             //NDIS注冊MINIPORT接口

                    NdisRegisterProtocol(&Status,

                                                      &ProtHandle,

                                                      &PChars,

                                                      sizeof(NDIS_PROTOCOL_CHARACTERISTICS));

                    //通知NDIS生成所注冊的2個接口

                    NdisIMAssociateMiniport(DriverHandle, ProtHandle);

             }

      如此一來,驅(qū)動程序可以看成是工作在網(wǎng)卡層與協(xié)議層之間了,當?shù)讓泳W(wǎng)卡有數(shù)據(jù)到來時會先經(jīng)過驅(qū)動程序處理后再往上層設(shè)備發(fā)送的。那么我們就可以在自己的回調(diào)函數(shù)中處理來自網(wǎng)絡(luò)的數(shù)據(jù)了。

      4  回調(diào)函數(shù)的工作

      在向系統(tǒng)注冊的回調(diào)函數(shù)中,比較重要的就是PtReceivePtReceivePacket函數(shù)了。為了程序的通用性,2個回調(diào)函數(shù)的大致處理流程是一樣的。我們僅拿PtReceive函數(shù)來做例子。PtReceive函數(shù)的原型如下:

      NDIS_STATUS

      PtReceive(

             IN  NDIS_HANDLE  ProtocolBindingContext,

             IN  NDIS_HANDLE    MacReceiveContext,

             IN  PVOID   HeaderBuffer,            

             IN  UINT      HeaderBufferSize,                

             IN  PVOID   LookAheadBuffer,      

             IN  UINT      LookAheadBufferSize,         

             IN  UINT      PacketSize                                 

      )

      在該函數(shù)中,第三個參數(shù)的指向幀頭的起始緩沖區(qū),第五個參數(shù)指向數(shù)據(jù)體的起始緩沖區(qū),第七個參數(shù)的值為緩沖區(qū)大小。如果PacketSize大于LookAheadBufferSize,表明數(shù)據(jù)還未全部拷貝上來。如果這2個參數(shù)相等,那么說明數(shù)據(jù)全部在LookAheadBuffer變量指向的緩沖區(qū)內(nèi)。來看看下面的代碼:

      NDIS_STATUS

      PtReceive(

             IN  NDIS_HANDLE  ProtocolBindingContext,

             IN  NDIS_HANDLE    MacReceiveContext,

             IN  PVOID   HeaderBuffer,             //以太頭數(shù)據(jù)

             IN  UINT      HeaderBufferSize,                 //以太頭數(shù)據(jù)大小

             IN  PVOID   LookAheadBuffer,       //數(shù)據(jù)體部分

             IN  UINT      LookAheadBufferSize,          //LookAheadBuffer數(shù)據(jù)大小

             IN  UINT      PacketSize                                         //數(shù)據(jù)包大小

      )

      {

             PADAPT               pAdapt =(PADAPT)ProtocolBindingContext;

             PNDIS_PACKET   MyPacket, Packet;

             NDIS_STATUS             Status = NDIS_STATUS_SUCCESS , DataStatus ;

       

      if(!pAdapt->MiniportHandle)

             {

                    Status = NDIS_STATUS_FAILURE;

             }

             else do

             {

                    if(pAdapt->isSecondary)

                            ASSERT(0);

      //從下層驅(qū)動獲取數(shù)據(jù)包

                    Packet = NdisGetReceivedPacket(pAdapt->BindingHandle, MacReceiveContext); 

                    if(Packet != NULL)

                    {

                           //如果數(shù)據(jù)包不為空那么就為下層即將

                           //發(fā)送上來的數(shù)據(jù)包分配空間

                            NdisDprAllocatePacket(&Status

                                   , &MyPacket, pAdapt->RecvPacketPoolHandle);

                            if(Status == NDIS_STATUS_SUCCESS)

                            {

                                   //拷貝原下層數(shù)據(jù)包到我們分配的緩沖中

                                  MyPacket->Private.Head = Packet->Private.Head;

                                  MyPacket->Private.Tail = Packet->Private.Tail;

                                  NDIS_SET_ORIGINAL_PACKET(

      MyPacket, NDIS_GET_ORIGINAL_PACKET(Packet));

                                  NDIS_SET_PACKET_HEADER_SIZE(MyPacket, HeaderBufferSize);

                                  NdisGetPacketFlags(MyPacket) = NdisGetPacketFlags(Packet);

                                  NDIS_SET_PACKET_STATUS(MyPacket, DIS_STATUS_RESOURCES);

                                  ASSERT(NDIS_GET_PACKET_STATUS(MyPacket) == NDIS_STATUS_RESOURCES);

                                  //拷貝數(shù)據(jù)包完成

                                  //數(shù)據(jù)包分析處理函數(shù)

                                  PacketAnalysis(MyPacket);

             //處理代碼

             //通知NDIS已復(fù)制數(shù)據(jù)包到緩沖區(qū)中

      NdisMIndicateReceivePacket(pAdapt->MiniportHandle, &MyPacket, 1);

      //釋放數(shù)據(jù)包

                                  NdisDprFreePacket(MyPacket);

                                  break;

      PtReceive函數(shù)中我們要做的就是為從下層傳上來的數(shù)據(jù)分配緩沖區(qū),然后將收到的數(shù)據(jù)拷貝到分配的緩沖區(qū)中,接著調(diào)用NdisMIndicateReceivePacket函數(shù)將數(shù)據(jù)傳給上一層。PacketAnalysis函數(shù)就是包分析函數(shù),在該函數(shù)中我們就可以對傳來的數(shù)據(jù)進行處理,過濾和攔截了。

      5  數(shù)據(jù)包的分析與處理

      在以上代碼中,其實在MyPacket這個結(jié)構(gòu)中就儲存了所希望得到的數(shù)據(jù)包地址,但是如何得到數(shù)據(jù)呢?我們在得到數(shù)據(jù)的過程中需要了解NDIS_PACKETNDIS_BUFFER這兩個結(jié)構(gòu)。下面給出這兩個結(jié)構(gòu)的定義:

       


      // NDIS_PACKET
      結(jié)構(gòu)的定義  
      typedef struct _NDIS_PACKET  
      {  
      NDIS_PACKET_PRIVATE Private;  
      //
      這個其實是一個鏈表結(jié)構(gòu),Private.Head指向第一個鏈表,Private.Tail指向最后一個
        
      //
      以下有關(guān)于這個結(jié)構(gòu)的解釋
        
      union  
      {  
      struct // For Connection-less miniports   
      {  
      UCHAR MiniportReserved[2*sizeof(PVOID)];  
      UCHAR WrapperReserved[2*sizeof(PVOID)];  
      };  
      struct  
      {   
      // For de-serialized miniports. And by implication conn-oriented miniports.   
      // This is for the send-path only. Packets indicated will use WrapperReserved   
      // instead of WrapperReservedEx   
      UCHAR MiniportReservedEx[3*sizeof(PVOID)];  
      UCHAR WrapperReservedEx[sizeof(PVOID)];  

      struct  
      UCHAR MacReserved[4*sizeof(PVOID)];  
      ULONG_PTR Reserved[2]; // For compatibility with Win95   
      UCHAR ProtocolReserved[1];  
      } NDIS_PACKET, *PNDIS_PACKET, **PPNDIS_PACKET;  
      // NDIS_PACKET_PRIVATE
      的定義
        
      typedef struct _NDIS_PACKET_PRIVATE  
      {  
      UINT PhysicalCount; // number of physical pages in packet.   
      UINT TotalLength; // Total amount of data in the packet.   
      PNDIS_BUFFER Head; //
      鏈表指針,指向下一個
        
      PNDIS_BUFFER Tail; //
      鏈表指針,指向前面一個
        
      // if Head is NULL the chain is empty; Tail doesn\'t have to be NULL also   
      PNDIS_PACKET_POOL Pool; // so we know where to free it back to   
      UINT Count;  
      ULONG Flags;  
      BOOLEAN ValidCounts;  
      UCHAR NdisPacketFlags; // See fPACKET_xxx bits below   
      USHORT NdisPacketOobOffset;  
      } NDIS_PACKET_PRIVATE, * PNDIS_PACKET_PRIVATE;  
      //NDIS_BUFFER
      定義 其實就是一個內(nèi)存描述符

      typedef struct _NDIS_BUFFER {  
      struct _NDIS_BUFFER *Next; //
      指向下一個節(jié)點的指針

      PVOID VirtualAddress;      //
      指向報文首地址

      PNDIS_BUFFER_POOL Pool;  
      UINT Length;               //
      報文數(shù)據(jù)長度

      UINT Signature;  
      } NDIS_BUFFER, * PNDIS_BUFFER;  

      我們要的數(shù)據(jù)就儲存在NDIS_BUFFER這個結(jié)構(gòu)中的VirtualAddress成員里面,這個指針指向數(shù)據(jù)包的首地址。關(guān)系圖如圖3所示:


      3  結(jié)構(gòu)關(guān)系圖

      NDIS_PACKET是一個描述NDIS_BUFFER鏈表的結(jié)構(gòu),在NDIS_PACKET中的成員Private中有指向第一個NDIS_BUFFER的指針和指向最后一個NDIS_BUFFER的指針分別是Private.HeadPrivate.Tail[3][4]。而NDIS_BUFFER中就記錄了我們數(shù)據(jù)包的地址和下一個NDIS_BUFFER的地址。操作有很多種方法,但是由于這些結(jié)構(gòu)體本來對我們是不透明的,所以最安全的方法是用微軟提供的一系列函數(shù)來操作NDIS_PACKETNDIS_BUFFER。這些函數(shù)都可以在DDK中查得到。

      獲取數(shù)據(jù)包內(nèi)容的代碼如下:

      NDIS_STATUS status ;
         PNDIS_BUFFER NdisBuffer ;
         UINT TotalPacketLength = 0 , copysize = 0 , DataOffset = 0 , PhysicalBufferCount  ,  BufferCount   ;
         PUCHAR mybuffer = NULL ,tembuffer = NULL ;  
      //
      假設(shè)這個是在PtReceive等函數(shù)中得到的
      PACKET
      NdisQueryPacket(packet                     //
      先得到第一個NDISBUFFER的指針
         
              , &PhysicalBufferCount              
              , &BufferCount                           
              ,&NdisBuffer                               //NdisBuffer
      就是指向鏈表頭

              , &TotalPacketLength
              );
      其實也可以直接  NdisBuffer = packet->Private.Head ;就可以取得第一個BUFFER

          status = NdisAllocateMemory( &mybuffer, 2048, 0, HighestAcceptableMax );  //
      分配內(nèi)存塊

          if( status != NDIS_STATUS_SUCCESS )
              return NDIS_STATUS_FAILURE ;
          NdisZeroMemory( mybuffer, 2048 ) ;
          NdisQueryBufferSafe(  //
      取得NDIS_BUFFER描述符中數(shù)據(jù)的首地址和大小

                                      NdisBuffer,
                                      &tembuffer,
                                      &copysize,
                                      NormalPagePriority
              //
      將數(shù)據(jù)復(fù)制到內(nèi)存中

          NdisMoveMemory(mybuffer, tembuffer, copysize) ;
          DataOffset = copysize ;
          while(1)
          {
          
      也可以這樣操作而不用
      NdisGetNextBuffer
              if(NdisBuffer->Next == packet->Private.Tail )
                  break ;
              NdisBuffer = NdisBuffer->Next ;
              if(pmdl == NULL )
                 break ;
              //
      獲得下一個NDIS_BUFFER的的指針

          NdisGetNextBuffer(NdisBuffer , &NdisBuffer ) ;
              
      如果指針是NULL那么表示到鏈表尾了

          if( NdisBuffer == NULL )
              break ;
          NdisQueryBufferSafe(
                                      NdisBuffer,
                                      &tembuffer,
                                      &copysize,
                                      NormalPagePriority
                                      ) ;
          NdisMoveMemory( mybuffer + DataOffset , tembuffer, copysize) ;
          DataOffset += copysize  ;
      //
      我們要的數(shù)據(jù)就全部都在申請的內(nèi)存mybuffer中,數(shù)據(jù)大小為DataOffset

      我們想要的截獲數(shù)據(jù)包的功能就達到了,如果想要過濾數(shù)據(jù)包,那么就只需要對數(shù)據(jù)包的內(nèi)容進行判斷就可以了。但是需要注意的是mybuffer里面的數(shù)據(jù)為原始數(shù)據(jù)包的數(shù)據(jù),也就是包括了包頭等一系列信息,需要自己分析包頭信息來獲取希望的數(shù)據(jù)。

      6  結(jié)束語

      本文只通過簡單的一些示例代碼闡述了如何利用驅(qū)動來截獲數(shù)據(jù)包的方法。大部分防火墻就是通過該技術(shù)截獲網(wǎng)絡(luò)數(shù)據(jù)并判斷數(shù)據(jù)的合法性實現(xiàn)保護的。但是要寫出很具有通用性的代碼還需要更廣泛的知識作為基礎(chǔ)。在這里僅給大家拋磚引玉,至于關(guān)于NDIS中間驅(qū)動更詳細的信息讀者們可以去參考微軟提供的WDK文檔。

       

           

      [1] 朱耀輝《Windows防火墻與數(shù)據(jù)封包截獲技術(shù)》 北京.電子工業(yè)出版社

      [2] 《關(guān)于passthruSend/Receive的流程圖》(http://bbs./htm_data/10/0305/40727.html

      [3] NDIS_PACKET結(jié)構(gòu)討論[]》(http://feikoo./viewdiary.10774705.html

      [4] NDIS_PACKET結(jié)構(gòu)討論[]》(http://feikoo./viewdiary.10774711.html

        本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多