簡單分析用SPI實現防火牆
來源:互聯網
上載者:User
本來上次寫了一個簡單的SPI防火牆程式(只做了IP過濾功能,包過濾功能沒有去做)後,已經放棄了對SPI的研究,但是最近有朋友問到SPI防火牆的實現,現在就再對SPI做一次詳細點的分析和總結。先看看防火牆的一般實現方式首先是TCP/IP的結構(OSI7層模型)
——–
|應用程式層|——exe程式,比如ie
——–
|展示層|——-ws2_32.dll
——–
|會話層|——-SPI
——–
|傳輸層|——-TDI(不能截獲ICMP等協議的資料)
——–
|網路層|——-NDIS(可以截獲所有的網路資料)
——–
|鏈路層|——-裝置驅動
——–
|物理層|——-網卡
——–
從上面我們可以很清楚地看到我們有多種方式實現防火牆,比如用HOOK API在展示層HOOK WINSOCKET的API函數,在會話層用WINDOWS提供的標準的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 (
WORD 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 WSPStarProc=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;
} 然後我們實現自己的WSPSendint 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以及TELNET等明文傳輸的網路通訊協定中你感興趣的東西資料都在LPWSABUF lpBuffers,這個參數裡下面給出這個結構
該知道怎麼解析包了吧?
typedef struct __WSABUF {
u_long len;
char FAR *buf;
} WSABUF, FAR * LPWSABUF;—————–