簡單分析用SPI實現防火牆 (轉)

amyz發表於2007-10-17
簡單分析用SPI實現防火牆 (轉)[@more@]

 簡單分析用SPI實現

 作者:snsins

如有轉載,請註明並保持文章的完整

2002.12.5

--------------------------------------------------------------------------------------------------------

 

本來上次寫了一個簡單的SPI防火牆(只做了IP過濾功能,包過濾功能沒有去做)後,已經放棄了對SPI的研究,但是最近有朋友問到SPI防火牆的實現,現在就再對SPI做一次詳細點的分析和總結。

先看看防火牆的一般實現方式

首先是的結構(OSI7層模型)
--------
|應用層|------exe程式,比如ie
--------
|表示層|-------ws2_32.dll
--------
|會話層|-------SPI
-------- 
|傳輸層|-------TDI(不能截獲ICMP等的資料)
-------- 
|層|-------NDIS(可以截獲所有的網路資料)
--------
|鏈路層|-------裝置
-------- 
|物理層|-------
--------
從上面我們可以很清楚地看到我們有多種方式實現防火牆,比如用HOOK 在表示層HOOK WINSOCKET的API,在會話層用提供的標準的SPI方式實現,SPI相對HOOK API方式要規範多了,而且功能也更強大,但是還是在user model裡,。在傳輸層可以寫驅動實現防火牆,雖然已經到了kernel model,但是和上面兩種方式一樣,過濾不了比如ICMP等協議的資料,因為ICMP等協議的資料並不經過傳輸層。這樣我們可以看到,在WINDOWS裡實現防火牆最標準最規範最強大的方式應該是在NDIS(也就是網路層實現),因為NDIS提供了一些規則,只要讓我們來一些寫好的函式來組織資料就可以了,功能不僅強大,而且相對下面鏈路層的裝置驅動要簡單,應該說在鏈路層也可以實現防火牆,但是覺得沒有必要,太複雜了。

現在回過頭來看看SPI的結構方式
--------------------
|  ws2_32.dll  |
--------------------
|  SPI  |
--------------------
|  SPI  |--------可以有很多層,就是所謂的分層服務提供者
--------------------
|  基礎服務提供者 |
--------------------

服務提供者有兩種,一種是分層服務提供者,一種是基礎服務提供者,上面這個圖不是很準確,我們這樣來理解,我們寫的分層服務提供者必須呼叫基礎服務提供者或者下面一層的分層提供者,然後把請求提交到他上面的一層(上面的一層可能是另外一個分層服務提供者,也可能是ws2_32.dll)。而我們寫的基礎服務提供者必須呼叫基礎服務提供者,然後把請求提交到ws2_32.dll。請注意,系統裡可能不僅僅了我們的基礎服務提供者,也安裝了別人寫的基礎服務提供者。在安裝多個分層服務提供者和多個基礎服務提供者的情況下,這兩者的組織方式是不同的
如下圖

-------------------------------------------------------------
| ws2_32.dll  |
-------------------------------------------------------------
  |  |  |
---------------------  |  |
|別人的分層服務提供者|  |  |
---------------------   |  |
  |  |  |
---------------------  |  |
|別人的分層服務提供者|  |  |
----------------------  |  |
  |  |  |
---------------------  |  |
|我們的分層服務提供者|  |  |
----------------------  |  |
  |  |  |
---------------------  ----------------------  ---------------
|別人的分層服務提供者|  |別人的基礎服務提供者| |我們的基礎服務提供者|
----------------------  ----------------------  ---------------------
  |  |  |
----------------------------------------------------------------
|  系統基礎服務提供者  |
————————————————————————————————

如果你連上面這個圖看了還是不懂我就沒辦法了。

從上面可以看出,這個SPI的組織思想就是分層。不過基礎服務提供者的層數相對分層服務提供者要少而已,理論上分層服務提供者可以有N層(不知道N是不是無限哦)

那麼這些層和層之間是如何組織的呢?透過一個函式來把他們連線起來,這個函式就是
WSPStartup
下面是他的原型
int WSPStartup (
    wVersionRequested, 
  LPWSPDATAW  lpWSPData, 
  LPWSAPROTOCOL_INFOW  lpProtocolInfo, 
  WSPUPCALLTABLE  UpcallTable, 
  LPWSPPROC_TABLE  lpProcTable 
);

這裡比較重要的是第三個引數lpProtocolInfo和最後一個引數lpProcTable,lpProtocolInfo留到後面再講,這和服務者的安裝有關

現在我們看看ws2_32.dll裡的API的,ws2_32裡的API被應用程式呼叫後大部分都最終對映成了SPI裡的30個函式,這30個函式都是用WSP開頭的。注意,SPI裡的30個函式是不能被應用程式直接呼叫的,而是應該由ws2_32.dll來呼叫。而LPWSPPROC_TABLE是一個表,裡面儲存了這30個函式的指標。我們透過呼叫下一層服務提供者的WSPStarup來得到下一層服務提供者的30個函式指標,同時我們也要EXPORT(SPI是一個DLL)這個函式,以便我們上一層的服務提供者來呼叫得到這30個函式指標。

例如
int WSPStartup (
  WORD  wVersionRequested, 
  LPWSPDATAW  lpWSPData, 
  LPWSAPROTOCOL_INFOW  lpProtocolInfo, 
  WSPUPCALLTABLE  UpcallTable, 
  LPWSPPROC_TABLE  lpProcTable 
)
{
  LPWSPSTARUP WSPStroc=GetProcAddress(LbHandle,"WSPStartup");//得到下一層服務提供者的WSPStatrup函式指標,記得要先LoadLibrary下一層服務提供者的DLL
 
  WSPStarProc(wVersionRequested,lpWSPData,lpProtocolInfo,UpcallTable,lpProcTable )
 
//記得要保留下一層原來的函式指標,有過HOOK API的朋友應該知道,就像要儲存你HOOK 的API原來的地址一樣


  WSPPROC_TABLE SystemProc=*lpProcTable;


//然後就可以設定自己的處理函式了,和HOOK API也差不多,比如
  lpProcTable->lpWSPSend=WSPSend;

  return 1;

然後我們實現自己的WSPSend

int WSPSend (
  SOCKET  s, 
  LPWSABUF  lpBuffers, 
  DWORD  dwBufferCount, 
  LPDWORD  lpNumberOfBytesSent, 
  DWORD  dwFlags, 
  LPWSAOVERLAPPED  lpOverlapped, 
  LPWSAOVERLAPPED_COMPLETION_ROUTINE  lpCompletionRoutine, 
  LPWSATHREADID  lpThreadId, 
  LPINT  lpErrno 
)
{
  /*++
在這裡我們用getsockname等函式和第一個引數可以得到這個套接字的埠和IP這些東西,還有buffer這些東西都可以在這裡處理,實現IP過濾包過濾都可以實現,然後再呼叫下一層服務提供者的相應函式並返回
--*/
  return SystemProc.lpWSPSend(s,lpBuffers,dwBufferCount,lpNumberOfBytesSent,dwFlags,lpOverlapped,lpCompletionRoutine,lpThreaId,lpErrno);
 
}

當然,在具體的實現中沒這麼簡單,對於WINSOCKET 中的複雜的I/O模型和重疊請求中,還要寫回撥函式等,現在就不討論這些問題,有興趣的自己查詢資料

還有,用這個也可以實現sniffer功能,分析出比如POP3以及等明文傳輸的網路協議中你感興趣的東西

資料都在LPWSABUF  lpBuffers,這個引數裡


下面給出這個結構
該知道怎麼解析包了吧?
typedef struct __WSABUF {
  u_long  len;
  char FAR  *buf;
} WSABUF, FAR * LPWSABUF;

-----------------
待續.....


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752019/viewspace-977175/,如需轉載,請註明出處,否則將追究法律責任。

相關文章