LSP自己是DLL,能夠將它安裝到winsock目錄,以便建立套接字的應用程序沒必要知道此LSP的任何信息就能調用它。編程
運行原理:windows
套接字建立函數會在winsock目錄中尋找合適的協議數組
調用此協議,的提供者導出的函數 完成各類功能。ide
編寫目的:函數
讓用戶調用自定義的服務提供者,有自定義的服務提供者調用下層提供者。這樣便截獲全部的winsock調用了。工具
服務提供者自己是DLL,導出一些與winsock API相對應的SPI函數。winsock庫加載服務提供者時,便依靠這些函數來實現winsockAPI。ui
LSP也是如此,它向上導出全部的SPI函數供 Ws2_32.dll調用,在內部經過調用基礎提供者實現這些SPI。編碼
安裝LSP:spa
實現LSP以前,要先將分層提供者安裝到winsock目錄,安裝包括一個WSAPPROTOCOL_INFOW結構,定義了分層提供者的特性和LSP填寫鏈的方式。(也叫作協議入口)命令行
協議鏈:
協議鏈描述了 分層提供者 加入winsock的目錄的順序。
typedef struct _WSAPROTOCOLCHAIN{ int ChainLen; DWORD ChainEntries[Max_PROTOCOL_CHAN]; }WSAPROTOCOLCHAIN,*LPWSAPROTOCOLCHAIN;
ChainLen爲0:分層協議 爲1 基礎協議 大於1 協議鏈
當ChainLen爲0或者1時,ChainEntries數組無心義
大於1時,各個服務提供者的目錄ID就包含在數組中。
實現LSP的DLL要麼被另外一個LSP加載,要麼直接被WS2_32.DLL加載。取決於它的位置。
若是LSP沒有在協議鏈的頂端,就會被鏈中位於它上層的LSP加載,不然的話,將被WS2_32.DLL加載。
安裝LSP時,必須在winsock目錄中安裝兩種協議:一個分層協議,一個協議鏈。
安裝分層協議視爲了獲取winsock庫分配的目錄ID號,一邊在協議鏈中標識本身的位置。
協議鏈纔是winsock目錄中LSP的真正入口,連中包含了本身分層協議的目錄ID號和下層提供者的目錄ID號。
在安裝時,要先安裝一個分層協議,用系統分配給此分層協議的目錄ID和下層提供者的目錄ID構建一個 ChainEntries數組,進而構建一個WSAPROTOCOL_INFOW結構,而後再安裝這個協議鏈。
安裝函數:
提供LSP GUID DLL WSAPROTOCOL_INFOW結構即可。
int WSCInstallProvider( const LPGUID lpProviderId, const LPWSTR lpszProviderDllPath, const LPWSAPROTOCOL_INFOW lpProtocolInfoList, DWORD dwNumberOfEntries, LPINT lpErrno );
每個安裝提供者須要一個GUID來標識它的入口,GUID能夠經過命令行工具UUIDGEN或者在編程使用UuidCreate函數來生成。
LSP的WSAPROTOCOL_INFOW結構一般從它要分層的下層提供者拷貝
1 szProtocol域要修改,以包含新提供者的名稱
2 若是包含XP1_IFS_HANDLES標識,要從dwServiceFlags1域移除。
從新目錄排序 WSCWriteProviderOrder
新安裝的LSP會默認安裝到winsock目錄的結尾,這樣系統調用的時候,仍是會調用原先調用的LSP,所以只有進行從新的排序才能讓系統調用到新安裝的LSP。
總結:
1 安裝分層協議入口,以便獲取系統分配的目錄ID號。
2 安裝一個或者多個協議鏈,安裝的數量取決於要分層的下層協議的數量。
3 在結尾進行目錄排序。
示例代碼:
//////////////////////////////////////////////////////// // InstDemo.cpp #include <Ws2spi.h> #include <Sporder.h> // 定義了WSCWriteProviderOrder函數 #include <windows.h> #include <stdio.h> #pragma comment(lib, "Ws2_32.lib") #pragma comment(lib, "Rpcrt4.lib") // 實現了UuidCreate函數 // 要安裝的LSP的硬編碼,在移除的時候還要使用它 GUID ProviderGuid = {0xd3c21122, 0x85e1, 0x48f3, {0x9a,0xb6,0x23,0xd9,0x0c,0x73,0x07,0xef}}; LPWSAPROTOCOL_INFOW GetProvider(LPINT lpnTotalProtocols) { DWORD dwSize = 0; int nError; LPWSAPROTOCOL_INFOW pProtoInfo = NULL; // 取得須要的長度 if(::WSCEnumProtocols(NULL, pProtoInfo, &dwSize, &nError) == SOCKET_ERROR) { if(nError != WSAENOBUFS) return NULL; } pProtoInfo = (LPWSAPROTOCOL_INFOW)::GlobalAlloc(GPTR, dwSize); *lpnTotalProtocols = ::WSCEnumProtocols(NULL, pProtoInfo, &dwSize, &nError); return pProtoInfo; } void FreeProvider(LPWSAPROTOCOL_INFOW pProtoInfo) { ::GlobalFree(pProtoInfo); } // 將LSP安裝到UDP協議提供者之上 int InstallProvider(WCHAR *wszDllPath) { WCHAR wszLSPName[] = L"TinyLSP"; // 咱們的LSP的名稱 int nError = NO_ERROR; LPWSAPROTOCOL_INFOW pProtoInfo; int nProtocols; WSAPROTOCOL_INFOW UDPLayeredInfo, UDPChainInfo; // 咱們要安裝的UDP分層協議和協議鏈 DWORD dwUdpOrigCatalogId, dwLayeredCatalogId; // 在Winsock目錄中找到原來的UDP協議服務提供者,咱們的LSP要安裝在它之上 // 枚舉全部服務程序提供者 pProtoInfo = GetProvider(&nProtocols); for(int i=0; i<nProtocols; i++) { if(pProtoInfo[i].iAddressFamily == AF_INET && pProtoInfo[i].iProtocol == IPPROTO_UDP) { memcpy(&UDPChainInfo, &pProtoInfo[i], sizeof(UDPLayeredInfo)); // UDPChainInfo.dwServiceFlags1 = UDPChainInfo.dwServiceFlags1 & ~XP1_IFS_HANDLES; // 保存原來的入口ID dwUdpOrigCatalogId = pProtoInfo[i].dwCatalogEntryId; break; } } // 首先安裝分層協議,獲取一個Winsock庫安排的目錄ID號,即dwLayeredCatalogId // 直接使用下層協議的WSAPROTOCOL_INFOW結構便可 memcpy(&UDPLayeredInfo, &UDPChainInfo, sizeof(UDPLayeredInfo)); // 修改協議名稱,類型,設置PFL_HIDDEN標誌 wcscpy(UDPLayeredInfo.szProtocol, wszLSPName); UDPLayeredInfo.ProtocolChain.ChainLen = LAYERED_PROTOCOL; // LAYERED_PROTOCOL即0 UDPLayeredInfo.dwProviderFlags |= PFL_HIDDEN; // 安裝 if(::WSCInstallProvider(&ProviderGuid, wszDllPath, &UDPLayeredInfo, 1, &nError) == SOCKET_ERROR) return nError; // 從新枚舉協議,獲取分層協議的目錄ID號 FreeProvider(pProtoInfo); pProtoInfo = GetProvider(&nProtocols); for(i=0; i<nProtocols; i++) { if(memcmp(&pProtoInfo[i].ProviderId, &ProviderGuid, sizeof(ProviderGuid)) == 0) { dwLayeredCatalogId = pProtoInfo[i].dwCatalogEntryId; break; } } // 安裝協議鏈 // 修改協議名稱,類型 WCHAR wszChainName[WSAPROTOCOL_LEN + 1]; swprintf(wszChainName, L"%ws over %ws", wszLSPName, UDPChainInfo.szProtocol); wcscpy(UDPChainInfo.szProtocol, wszChainName); if(UDPChainInfo.ProtocolChain.ChainLen == 1) { UDPChainInfo.ProtocolChain.ChainEntries[1] = dwUdpOrigCatalogId; } else { for(i=UDPChainInfo.ProtocolChain.ChainLen; i>0 ; i--) { UDPChainInfo.ProtocolChain.ChainEntries[i] = UDPChainInfo.ProtocolChain.ChainEntries[i-1]; } } UDPChainInfo.ProtocolChain.ChainLen ++; // 將咱們的分層協議置於此協議鏈的頂層 UDPChainInfo.ProtocolChain.ChainEntries[0] = dwLayeredCatalogId; // 獲取一個Guid,安裝之 GUID ProviderChainGuid; if(::UuidCreate(&ProviderChainGuid) == RPC_S_OK) { if(::WSCInstallProvider(&ProviderChainGuid, wszDllPath, &UDPChainInfo, 1, &nError) == SOCKET_ERROR) return nError; } else return GetLastError(); // 從新排序Winsock目錄,將咱們的協議鏈提早 // 從新枚舉安裝的協議 FreeProvider(pProtoInfo); pProtoInfo = GetProvider(&nProtocols); DWORD dwIds[20]; int nIndex = 0; // 添加咱們的協議鏈 for(i=0; i<nProtocols; i++) { if((pProtoInfo[i].ProtocolChain.ChainLen > 1) && (pProtoInfo[i].ProtocolChain.ChainEntries[0] == dwLayeredCatalogId)) dwIds[nIndex++] = pProtoInfo[i].dwCatalogEntryId; } // 添加其它協議 for(i=0; i<nProtocols; i++) { if((pProtoInfo[i].ProtocolChain.ChainLen <= 1) || (pProtoInfo[i].ProtocolChain.ChainEntries[0] != dwLayeredCatalogId)) dwIds[nIndex++] = pProtoInfo[i].dwCatalogEntryId; } // 從新排序Winsock目錄 nError = ::WSCWriteProviderOrder(dwIds, nIndex); FreeProvider(pProtoInfo); return nError; } void RemoveProvider() { LPWSAPROTOCOL_INFOW pProtoInfo; int nProtocols; DWORD dwLayeredCatalogId; // 根據Guid取得分層協議的目錄ID號 pProtoInfo = GetProvider(&nProtocols); int nError; for(int i=0; i<nProtocols; i++) { if(memcmp(&ProviderGuid, &pProtoInfo[i].ProviderId, sizeof(ProviderGuid)) == 0) { dwLayeredCatalogId = pProtoInfo[i].dwCatalogEntryId; break; } } if(i < nProtocols) { // 移除協議鏈 for(i=0; i<nProtocols; i++) { if((pProtoInfo[i].ProtocolChain.ChainLen > 1) && (pProtoInfo[i].ProtocolChain.ChainEntries[0] == dwLayeredCatalogId)) { ::WSCDeinstallProvider(&pProtoInfo[i].ProviderId, &nError); } } // 移除分層協議 ::WSCDeinstallProvider(&ProviderGuid, &nError); } } //////////////////////////////////////////////////// int binstall = 0; void main() { if(binstall) { if(InstallProvider(L"lsp.dll") == ERROR_SUCCESS) { printf(" Install successully \n"); } else { printf(" Install failed \n"); } } else RemoveProvider(); }