隨著網路安全威脅日益嚴峻,個人防火牆已成為電腦用戶的必備防護工具。Windows 平台上的防火牆核心技術均建立在封包攔截機制之上,實作層級主要分為「核心層級」(TDI/NDIS 驅動程式)與「使用者層級」(SPI/封包過濾介面)。本文深入探討基於 Winsock 2 SPI(Service Provider Interface)的封包過濾實作原理與程式碼分析。
Winsock 2 並非單一協定,而是支援多種傳輸協定的開放架構。其分層模型如下:
┌─────────────────────────┐ ← Windows Socket 2 應用程式 (API) ├─────────────────────────┤ ← WS2_32.DLL (流量管理、協定枚舉、版本協商) ├─────────────────────────┤ ← Windows Socket 2 SPI │ 分層協定 (Layered) │ 依賴基礎協定提供進階服務 ├─────────────────────────┤ ← Windows Socket 2 SPI │ 基礎協定 (Base) │ 獨立實現資料傳輸 (TCP/IP 等) └─────────────────────────┘
關鍵結構 WSAPROTOCOL_INFOW 中的 ProtocolChain.ChainLen 決定協定類型:
ChainLen = 0:分層協定ChainLen = 1:基礎協定ChainLen > 1:協定鏈自訂 SPI 必須透過 WSCInstallProvider 註冊至系統目錄,並以 WSCWriteProviderOrder 調整優先順序,確保自訂分層協定位於協定鏈最上層,優先攔截封包。安裝程式 instif.exe 核心流程:
WSCEnumProtocols 列舉現有提供者T-IpFilter),ChainLen = LAYERED_PROTOCOLChainEntries[0])動態連結庫 ipfilter.dll 僅匯出 WSPStartup 入口點,透過攔截 WSPSendTo 實現 UDP 封包過濾:
int WSPAPI WSPSendTo(SOCKET s, LPWSABUF lpBuffer, DWORD dwBufferCount,
LPDWORD lpNumberOfBytesSent, DWORD dwFlags,
const struct sockaddr FAR *lpTo, int iToLen,
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
LPWSATHREADID lpThreadId, LPINT lpErrno)
{
struct sockaddr_in sin = *(const struct sockaddr_in *)lpTo;
// 過濾目標埠 8000 的 UDP 封包 (示範用)
if (sin.sin_port == htons(8000)) {
OutputDebugString(_T("WSPSendTo Tencent Filtered"));
return 0; // 丟棄封包
}
// 其餘封包轉交下層提供者處理
return nextProcTable.lpWSPSendTo(s, lpBuffer, dwBufferCount, ...);
}
WSPStartup 初始化時會載入下層系統提供者 (如 mswsock.dll),取得其函數指標表並置換 lpWSPSendTo 達到 Hook 效果。
文章指出 SPI 過濾存在固有局限:
附錄提供完整原始碼 (instif.exe、ipfilter.dll、T-Sporder.exe),展示從提供者安裝、協定鏈構建到封包攔截的完整工程實作,是研究 Windows 網路程式設計與安全機制的優良參考資料。