一、個人防火牆技術概述
隨著網絡安全問題日益嚴重,廣大用戶對網絡安全產品也越來越關注。防火牆作為一種網絡安全工具,早已受到大家的青睐。在PC機上使用的個人防火牆,很大程度上成為廣大網民的安全保護者。Windows下的個人防火牆都是基於對數據報的攔截技術之上。當然在具體的實現方式上它們卻有很大的不同。總的來說可分為用戶級和內核級數據報攔截兩類。其中內核級主要是TDI過濾驅動程序,NDIS中間層過濾驅動程序,NDIS過濾鉤子驅動程序等,它們都是利用網絡驅動來實現的;而用戶級的過濾包括SPI接口,Windows2000包過濾接口等。本文主要講述基於SPI的包過濾實現,它是Winsock 2的一個新特性。
二、Winsock 2 SPI介紹
Winsock 2 是一個接口,而不是協議,所以它可以用於發現和使用任意數量的底層傳輸協議所提供的通信能力。起初的Winsock是圍繞著TCP/IP協議運行的,但是在Winsock 2中卻增加了對更多傳輸協議的支持。Winsock 2不僅提供了一個供應用程序訪問網絡服務的Windows socket應用程序編程接口(API),還包含了由傳輸服務提供者和名字解析服務提供者實現的Winsock服務提供者接口(SPI)和ws2_32.dll。本文僅討論傳輸服務提供者及其應用,暫不對名字解析服務提供者進行分析。
Winsock 2的傳輸服務提供者是以動態鏈接庫的形式(DLL)存在的,它是通過WSPStartup函數為上層函數提供接口,而其他的傳輸服務提供者函數則是通過分配表的方式來訪問WS2_32.DLL。傳輸服務提供者的動態鏈接庫只有在應用程序需要時才由Ws2_32.dll來裝入內存中的,在不需要時則會被自動卸載。以下是winsock 2在傳輸服務提供者上的WOSA(Windows開放服務結構):
----------------------------
│Windows socket 2 應用程序│
----------------------------Windows socket 2 API
│ WS2_32.DLL │
----------------------------Windows socket 2 傳輸SPI
│ 傳輸服務提供者(DLL) │
----------------------------
Windows socket SPI在服務提供者中使用了以下的函數前綴命名方式:WSP(Windows socket服務提供者),WPU(Windows socket提供者向上調用),WSC(Windows socket配置)。每一個傳輸服務提供者都有它自己所支持的傳輸協議,它是使用WSAPROTCOL_INFOW結構來實現的。傳輸服務提供者把所有的相關信息都存放在這個結構中,而應用程序就是通過這個結構的內容來將自己和相應的傳輸服務提供者相關聯。
Windows socket SPI提供三種協議:分層協議,基礎協議和協議鏈。分層協議是在基礎協議的上層,依靠底層基礎協議實現更高級的通信服務。基礎協議是能夠獨立,安全地和遠程端點實現數據通信的協議,它是相對與分層協議而言的。協議鏈是將一系列的基礎協議和分層協議按特點的順序連接在一起的鏈狀結構,請參見下圖:
API------------------------
│ WS2_32.DLL │
SPI------------------------
│ 分層協議 │
SPI-------------
│ 分層協議 │
SPI------------------------
│ 基礎協議 │
------------------------
Ws2_32.dll數據傳輸部分的主要功能是在服務提供者和應用程序之間提供流量管理的功能。每個應用程序通過Ws2_32.dll和相應的服務提供者進行嚴格的數據交換。Ws2_32.dll根據應用程序在創建套接字時所提供的參數來選擇特定的服務提供者,然後把應用程序的實現過程轉發由所選創建套接字的服務提供者來管理。也就是說,Ws2_32.dll只是一個中間過程,而應用程序只是一個接口,數據通信的實現卻是有服務提供者來完成的。我們說過,Ws2_32.dll是通過創建套接字的API函數WSASocket或socket的參數來確定使用哪一個服務提供者。而WSASocket/socket的參數中包括了地址族,套接字類型和協議類型,這三個因素共同決定了創建套接字的服務提供者。Ws2_32.dll在服務提供者中尋找第一個和前面三因素相匹配的WSAPROTOCOL_INFOW結構,然後就調用這個WSAPROTOCOL_INFOW結構相應的WSPStartup函數,(所有的數據傳輸服務提供者以DLL的形式,它們對外的接口就只有WSPStartup,其他的服務提供者函數都是通過WSPStartup來調用的),進而調用如WSPSocket的函數來創建套接字,WSPConnect的函數來建立連接等等。除了流量管理功能外,Ws2_32.dll還提供了其他的服務,比如協議枚舉,基於線程的阻塞鉤子管理和在Ws2_32.dll和服務提供者之間進行版本協商。
傳輸服務提供者實現的功能包括建立連接,傳輸數據,實現流控制和差錯控制等函數。其實Ws2_32.dll並不知道服務提供者的請求等活動是如何實現了,Ws2_32.dll在應用程序和服務提供者之間實現了媒介的功能。傳輸服務提供者可分為兩類:套接字描述符是可安裝的文件系統(IFS)句柄的提供者;剩下的是非IFS的提供者。在我們的程序中選用了非IFS提供者。可見,服務提供者實現了底層的與網絡相關的協議。Ws2_32.dll提供了介質級別的流量管理,應用程序則提供了有關如何實現網絡相關的操作,它實現了用戶所希望的功能。
在傳輸服務提供者的實現過程中,安裝順序是非常重要的。我們不僅要正確的安裝服務提供者,而且還必須在Windows socket中注冊,將相關的系統信息保存在數據庫中,這樣Ws2_32.dll才能夠方便的獲得下層服務提供者的相關信息。在Ws2_32.dll中提供了用來安裝服務提供者的函數WSCInstallProvider,它需要服務提供者的有關數據,比如DLL的名稱和路徑。同時Ws2_32.dll還提供了卸載服務提供者的函數WSCDeinstallProvider,在不需要時通過它將特定的服務提供者從系統中刪除。為什麼說傳輸服務者的安裝順序很重要呢?在服務提供者配置函數中的WSCEnumProtocols是用來枚舉系統中所有已安裝的服務提供者,它按照服務提供者的安裝順序相應的列出他們。在前面我們也提到過,Ws2_32.dll在服務提供者中按安裝順序搜尋和WSASocket/socket提供的三個參數相匹配的服務提供者,所以安裝順序在一定程度上是決定了服務提供者是否被正確調用的關鍵。Windows socket 2還提供了一個動態鏈接庫Sporder.dll,它提供了對已安裝的所有服務提供者順序的重新排列(此DLL系統沒有自帶,common目錄中已提供)。在附錄中的T-Sporder.exe是一個查詢當前已安裝所有數據傳輸服務提供者屬性的工具。
服務提供者系統中區分基礎協議,分層協議和協議鏈是通過結構WSAPROTOCOL_INFOW中的Protocolchain結構的ChainLen值來實現的。分層協議的ChainLen值為0,基礎協議的值為1,而協議鏈的值是大於1。在數據傳輸服務提供者的實現方式中分層協議和基礎協議幾乎是相同的,它們的不同之處在安裝上。Windows中,現有的系統服務提供者(系統自帶)幾乎已提供了所有基本的服務,因此我們所寫的服務提供者程序,都可以對數據報進行適當“修飾”後調用系統服務提供者來完成絕大部分剩下的功能,無論是基礎服務提供者還是分層服務提供者都可以使用這種技術,免去不必要的勞動。基礎服務提供者的實現過程主要是替換當前系統服務提供者的安裝路徑為自己的服務提供者的安裝路徑即可,當然我們必須保存所以系統服務者的相關數據,在我們卸載自己的服務提供者還原系統服務提供者時要用到這些信息,如系統服務者DLL的名稱和路徑。而協議鏈就不同了,首先我們必須安裝好所有的基礎協議和分層協議後,再構造協議鏈的WSAPROTOCOL_INFOW結構鏈,組成協議鏈的每個協議都會在協議鏈的ProtocolChain.ChainEntries數組中被定義,協議鏈數組中的第一個協議應該是第一個分層服務提供者。當然在安裝分層協議及協議鏈時我們不會改變系統服務提供者,最多只是改變系統服務提供者的安裝順序罷了。在此,我們以分層服務提供者為例來說明數據傳輸服務提供者的安裝過程。
Ws2_32.dll是使用標准的動態鏈接庫來加載服務提供者接口的DLL到系統中去的,並調用WSPStartup來初始化。WSPStartup是Windows Socket 2應用程序調用SPI程序的初始化函數,也就是入口函數。WSPStartup的參數LPWSAPROTOCOL_INFOW指針提供應用程序所期望的協議信息,然後通過這個結構指針我們可以獲得所保存的系統服務提供者的DLL名稱和路徑,加載系統服務提供者後查找到系統SPI程序的WSPStartup函數的指針,通過這個指針我們就可以將自己服務提供者的WSPStartup函數和系統SPI程序的WSPStartup函數相關聯,進而調用系統的各個服務提供者函數。在數據傳輸服務提供者的實現中,我們需要兩個程序,一個是可執行文件用來安裝傳輸服務提供者;另一個就是DLL形式的數據傳輸服務提供者。下面我們就對安裝程序(instif.exe)和實現程序(ipfilter.dll)所使用的主要函數進行簡要分析。
三、相關程序代碼分析
1.instif.exe
可執行程序instif.exe的主要功能是安裝我們自己的分層傳輸服務提供者,並重新排列所有傳輸服務提供者的順序,使我們的服務提供者位於協議鏈的頂端,這樣相應類型的應用程序就會首先進入我們的傳輸服務提供者接口。本程序只有一個參數,就是安裝(-install)或卸載(-remove)。作為演示,本程序只安裝了IP分層協議及與UDP相關的協議鏈。(在ipfilter.dll中,我們只過濾目標端口為8000的UDP數據報)
自定義函數:
BOOL getfilter(); //獲得所有已經安裝的傳輸服務提供者
void freefilter(); //釋放存儲空間
void installfilter(); //安裝分層協議,協議鏈及排序
void removefilter(); //卸載分層協議和協議鏈
代碼分析:
protoinfo=(LPWSAPROTOCOL_INFOW)GlobalAlloc(GPTR,protoinfosize);
//分配WSAPROTOCOL_INFOW結構的存儲空間
totalprotos=WSCEnumProtocols(NULL,protoinfo,&protoinfosize,&errorcode);
//獲得系統中已安裝的所有服務提供者
GetCurrentDirectory(MAX_PATH,filter_path);
//得到當前的路徑
_tcscpy(filter_name,_T("\\ipfilter.dll"));
//構造服務提供者文件ipfilter.dll的路徑全名
WSCInstallProvider(&filterguid,filter_path,&iplayerinfo,1,&errorcode);
//安裝自定義的IP分層協議
iplayercataid=protoinfo[i].dwCatalogEntryId;
//獲得已安裝自定義IP分層協議的由Ws2_32.dll分配的唯一標志
udpchaininfo.ProtocolChain.ChainEntries[0]=iplayercataid;
//將自定義的IP分層協議作為自定義UDP協議鏈的根分層服務提供者安裝在協議鏈的頂端
WSCInstallProvider(&filterchainguid,filter_path,chainarray,provcnt,&errorcode);
//安裝協議鏈
WSCWriteProviderOrder(cataentries,totalprotos);
//更新所有服務提供者的安裝順序,把自定義的服務提供者排在所有協議的最前列
WSCDeinstallProvider(&filterguid,&errorcode);
//卸載IP分層協議
WSCDeinstallProvider(&filterchainguid,&errorcode);
//卸載協議鏈
2.ipfilter.dll
傳輸服務提供者都是以動態鏈接庫的形式存在的,在應用程序需要時由Ws2_32.dll加載,在用完之後就被卸載。本文的ipfilter.dll提供了對發送的UDP數據報進行過濾的功能。也就是自定義WSPSendTo函數,在調用系統服務提供者之前進行過濾,判斷是否繼續向下調用,而其他的函數都是直接調用下層的系統服務提供者由它們直接處理。傳輸服務提供者只有一個入口函數就是WSPStartup,它是Windows Socket 應用程序調用SPI的初始化函數,其他SPI函數的調用都是通過WSPStartup的參數WSPUPCALLTABLE來實現的。
自定義函數:
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);
//SPI函數WSPSendTo和Windows Socket 2的API函數WSASendTo相對應
int WSPAPI WSPStartup(WORD wversionrequested,LPWSPDATA lpwspdata,LPWSAPROTOCOL_INFOW lpprotoinfo,
WSPUPCALLTABLE upcalltable,LPWSPPROC_TABLE lpproctable);
//SPI函數WSPStartup和Windows Socket 2的API函數WSAStartup相對應,WSPStartup是唯一的入口函數,剩下的30個SPI函數則是通過參數upcalltable來實現的,它們只能在內部調用,不向外提供入口
代碼分析:
GetModuleFileName(NULL,processname,MAX_PATH);
//獲得調用本服務提供者動態鏈接庫的可執行文件的全名
OutputDebugString(_T("WSPSendTo Tencent Filtered"));
//輸出調試信息
nextproctable.lpWSPSendTo(s,lpbuffer,dwbuffercount,lpnumberofbytessent,dwflags,lpto,
itolen,lpoverlapped,lpcompletionroutine,lpthreadid,lperrno);
//如果數據報滿足發送條件,調用下層系統服務提供者發送數據
layerid=protoinfo[i].dwCatalogEntryId;
//獲得已安裝自定義IP分層協議的由Ws2_32.dll分配的唯一標志
nextlayerid=lpprotoinfo->ProtocolChain.ChainEntries[i+1];
//獲得下一層傳輸服務提供者的標志信息
WSCGetProviderPath(&protoinfo[i].ProviderId,filterpath,&filterpathlen,&errorcode);
//獲得下一層傳輸服務提供者的安裝路徑
ExpandEnvironmentStrings(filterpath,filterpath,MAX_PATH);
//擴展環境變量
hfilter=LoadLibrary(filterpath));
//裝載下一層傳輸服務提供者
wspstartupfunc=(LPWSPSTARTUP)GetProcAddress(hfilter,"WSPStartup"));
//獲得下一層傳輸服務提供者的入口函數WSPStartup,以便調用
wspstartupfunc(wversionrequested,lpwspdata,lpprotoinfo,upcalltable,lpproctable);
//調用下一層傳輸服務提供者的WSPStartup函數,實現鉤子功能
nextproctable=*lpproctable;
//保存下一層服務提供者的30個服務函數指針
lpproctable->lpWSPSendTo=WSPSendTo;
//調用自定義函數WSPSendTo
由於以動態鏈接庫形式的服務提供者要向外提供一個入口函數,因此還須一個配置文件ipfilter.def:
EXPORTS WSPStartup
//向外提供入口函數WSPStartup
3.T-Sporder.exe
T-Sporder.exe是一個輔助工具,用來查看當前系統中所有已經安裝的傳輸服務提供者的屬性。
totalprotocols=WSCEnumProtocols(NULL,protoinfo,&protoinfosize,&errorcode);
//獲得系統中的所有傳輸服務提供者,然後根據參數輸出它們的各項屬性。
四、小結與後記
本文向大家介紹了Windows Socket 2的一個新特性,那就是服務提供者接口SPI(Service Provider Interface)。它不僅包括我們主要講解的傳輸服務提供者接口,還包括名字空間服務提供者接口。當然,基於SPI的包過濾安全措施並不是特別的好,因為很多建立在TDI上面的數據傳輸並不會受到SPI的影響,所以當前流行的防火牆大都是建立在NDIS之上的。
傳輸服務提供者是以DLL的形式存在於系統之中的,在基於IP協議的網絡程序運行時,如果參數相匹配就會加載我們的傳輸服務提供者程序。而且在Windows下有很多系統網絡服務,它們都是在系統啟動時自動加載的,這就為我們隱藏木馬的進程提供了有利的條件。也就是說在傳輸服務提供者程序裡嵌入木馬程序,很多基於IP協議的網絡系統程序在開機時運行,這樣我們嵌入的木馬程序就會在系統啟動時自動加載,在系統關閉時才會卸載。它的特點是只要安裝一次後每每系統啟動就會加載我們的傳輸服務提供者(裡面包含木馬程序),而不必像遠程注入線程那樣在系統每次啟動時執行安裝程序,並且它可同時被多個系統網絡程序加載。
已編譯好的可執行文件(過濾QQ數據報),您可以在我們的網站(http://fz5fz.yeah.net)下載。
五、附錄之源程序
1.instif.exe
#define UNICODE
#define _UNICODE
#include <stdio.h>
#include <tchar.h>
#include <string.h>
#include <ws2spi.h>
#include <sporder.h>
GUID filterguid={0x4d1e91fd,0x116a,0x44aa,{0x8f,0xd4,0x1d,0x2c,0xf2,0x7b,0xd9,0xa9}};
GUID filterchainguid={0xd3c21121,0x85e1,0x48f3,{0x9a,0xb6,0x23,0xd9,0x0c,0x73,0x07,0xef}};
BOOL getfilter();
void freefilter();
void installfilter();
void removefilter();
void start();
void usage();
int totalprotos=0;
DWORD protoinfosize=0;
LPWSAPROTOCOL_INFOW protoinfo=NULL;
int main(int argc,char *argv[])
{
start();
if(argc==2)
{
if(strcmp(argv[1],"-install")==0)
{
installfilter();
return 0;
}
else if(strcmp(argv[1],"-remove")==0)
{
removefilter();
return 0;
}
}
usage();
return 0;
}
BOOL getfilter()
{
int errorcode;
protoinfo=NULL;
totalprotos=0;
protoinfosize=0;
if(WSCEnumProtocols(NULL,protoinfo,&protoinfosize,&errorcode)==SOCKET_ERROR)
{
if(errorcode!=WSAENOBUFS)
{
_tprintf(_T("First WSCEnumProtocols Error: %d\n"),errorcode);
return FALSE;
}
}
if((protoinfo=(LPWSAPROTOCOL_INFOW)GlobalAlloc(GPTR,protoinfosize))==NULL)
{
_tprintf(_T("GlobalAlloc in getfilter Error: %d\n"),GetLastError());
return FALSE;
}
if((totalprotos=WSCEnumProtocols(NULL,protoinfo,&protoinfosize,&errorcode))==SOCKET_ERROR)
{
_tprintf(_T("Second WSCEnumProtocols Error: %d\n"),GetLastError());
return FALSE;
}
_tprintf(_T("Found %d protocols!\n"),totalprotos);
return TRUE;
}
void freefilter()
{
GlobalFree(protoinfo);
}
void installfilter()
{
int i;
int provcnt;
int cataindex;
int errorcode;
BOOL rawip=FALSE;
BOOL udpip=FALSE;
DWORD iplayercataid=0,udporigcataid=0;
TCHAR filter_path[MAX_PATH];
TCHAR filter_name[MAX_PATH];
TCHAR chainname[WSAPROTOCOL_LEN+1];
LPDWORD cataentries;
WSAPROTOCOL_INFOW iplayerinfo,udpchaininfo,chainarray[1];
getfilter();
for(i=0;i<totalprotos;i++)
{
if(!rawip
&& protoinfo[i].iAddressFamily==AF_INET
&& protoinfo[i].iProtocol==IPPROTO_IP)
{
rawip=TRUE;
memcpy(&iplayerinfo,&protoinfo[i],sizeof(WSAPROTOCOL_INFOW));
iplayerinfo.dwServiceFlags1=protoinfo[i].dwServiceFlags1 & (~XP1_IFS_HANDLES);
}
if(!udpip
&& protoinfo[i].iAddressFamily==AF_INET
&& protoinfo[i].iProtocol==IPPROTO_UDP)
{
udpip=TRUE;
udporigcataid=protoinfo[i].dwCatalogEntryId;
memcpy(&udpchaininfo,&protoinfo[i],sizeof(WSAPROTOCOL_INFOW));
udpchaininfo.dwServiceFlags1=protoinfo[i].dwServiceFlags1 & (~XP1_IFS_HANDLES);
}
}
_tcscpy(iplayerinfo.szProtocol,_T("T-IpFilter"));
iplayerinfo.ProtocolChain.ChainLen=LAYERED_PROTOCOL;
if(GetCurrentDirectory(MAX_PATH,filter_path)==0)
{
_tprintf(_T("GetCurrentDirectory Error: %d\n"),GetLastError());
return ;
}
_tcscpy(filter_name,_T("\\ipfilter.dll"));
_tcscat(filter_path,filter_name);
if(WSCInstallProvider(&filterguid,filter_path,&iplayerinfo,1,&errorcode)==SOCKET_ERROR)
{
_tprintf(_T("WSCInstallProvider Error: %d\n"),errorcode);
return ;
}
freefilter();
getfilter();
for(i=0;i<totalprotos;i++)
{
if(memcmp(&protoinfo[i].ProviderId,&filterguid,sizeof(GUID))==0)
{
iplayercataid=protoinfo[i].dwCatalogEntryId;
break;
}
}
provcnt=0;
if(udpip)
{
_tcscpy(chainname,_T("T-UdpFilter"));
_tcscpy(udpchaininfo.szProtocol,chainname);
if(udpchaininfo.ProtocolChain.ChainLen==BASE_PROTOCOL)
{
udpchaininfo.ProtocolChain.ChainEntries[1]=udporigcataid;
}
elsE
{
for(i=udpchaininfo.ProtocolChain.ChainLen;i>0;i--)
{
udpchaininfo.ProtocolChain.ChainEntries[i+1]=udpchaininfo.ProtocolChain.ChainEntries[i];
}
}
udpchaininfo.ProtocolChain.ChainLen++;
udpchaininfo.ProtocolChain.ChainEntries[0]=iplayercataid;
memcpy(&chainarray[provcnt++],&udpchaininfo,sizeof(WSAPROTOCOL_INFOW));
}
if(WSCInstallProvider(&filterchainguid,filter_path,chainarray,provcnt,&errorcode)==SOCKET_ERROR)
{
_tprintf(_T("WSCInstallProvider for chain Error: %d\n"),errorcode);
return ;
}
freefilter();
getfilter();
if((cataentries=(LPDWORD)GlobalAlloc(GPTR,totalprotos*sizeof(WSAPROTOCOL_INFOW)))==NULL)
{
_tprintf(_T("GlobalAlloc int installfilter Error: %d\n"),errorcode);
return ;
}
cataindex=0;
for(i=0;i<totalprotos;i++)
{
if(memcmp(&protoinfo[i].ProviderId,&filterguid,sizeof(GUID))==0
|| memcmp(&protoinfo[i].ProviderId,&filterchainguid,sizeof(GUID))==0)
{
cataentries[cataindex++]=protoinfo[i].dwCatalogEntryId;
}
}
for(i=0;i<totalprotos;i++)
{
if(memcmp(&protoinfo[i].ProviderId,&filterguid,sizeof(GUID))!=0
&& memcmp(&protoinfo[i].ProviderId,&filterchainguid,sizeof(GUID))!=0)
{
cataentries[cataindex++]=protoinfo[i].dwCatalogEntryId;
}
}
if((errorcode==WSCWriteProviderOrder(cataentries,totalprotos))!=ERROR_SUCCESS)
{
_tprintf(_T("WSCWriteProviderOrder Error: %d\n"),GetLastError());
return ;
}
freefilter();
_tprintf(_T("\nInstall IP Filter Successfully"));
return ;
}
void removefilter()
{
int errorcode;
BOOL signal=TRUE;
if(WSCDeinstallProvider(&filterguid,&errorcode)==SOCKET_ERROR)
{
_tprintf(_T("WSCDeinstall filterguid Error: %d\n"),errorcode);
signal=FALSE;
}
if(WSCDeinstallProvider(&filterchainguid,&errorcode)==SOCKET_ERROR)
{
_tprintf(_T("WSCDeinstall filterchainguid Error: %d\n"),errorcode);
signal=FALSE;
}
if(signal)
{
_tprintf(_T("Deinstall IP Filter Successfully"));
}
return ;
}
void start()
{
_tprintf(_T("Install IP Filter, by TOo2y\n"));
_tprintf(_T("E-Mail: [email protected]\n"));
_tprintf(_T("HomePage: www.safechina.net\n"));
_tprintf(_T("Date: 10-29-2002\n\n"));
return ;
}
void usage()
{
_tprintf(_T("Usage: instif [ -install │ -remove ]\n"));
return ;
}
2.ipfilter.dll
#define UNICODE
#define _UNICODE
#include <ws2spi.h>
#include <tchar.h>
GUID filterguid={0x4d1e91fd,0x116a,0x44aa,{0x8f,0xd4,0x1d,0x2c,0xf2,0x7b,0xd9,0xa9}};
LPWSAPROTOCOL_INFOW protoinfo=NULL;
WSPPROC_TABLE nextproctable;
DWORD protoinfosize=0;
int totalprotos=0;
BOOL getfilter()
{
int errorcode;
protoinfo=NULL;
protoinfosize=0;
totalprotos=0;
if(WSCEnumProtocols(NULL,protoinfo,&protoinfosize,&errorcode)==SOCKET_ERROR)
{
if(errorcode!=WSAENOBUFS)
{
OutputDebugString(_T("First WSCEnumProtocols Error!"));
return FALSE;
}
}
if((protoinfo=(LPWSAPROTOCOL_INFOW)GlobalAlloc(GPTR,protoinfosize))==NULL)
{
OutputDebugString(_T("GlobalAlloc Error!"));
return FALSE;
}
if((totalprotos=WSCEnumProtocols(NULL,protoinfo,&protoinfosize,&errorcode))==SOCKET_ERROR)
{
OutputDebugString(_T("Second WSCEnumProtocols Error!"));
return FALSE;
}
return TRUE;
}
void freefilter()
{
GlobalFree(protoinfo);
}
BOOL WINAPI DllMain(HINSTANCE hmodule,
DWORD reason,
LPVOID lpreserved)
{
TCHAR processname[MAX_PATH];
TCHAR showmessage[MAX_PATH+25];
if(reason==DLL_PROCESS_ATTACH)
{
GetModuleFileName(NULL,processname,MAX_PATH);
_tcscpy(showmessage,processname);
_tcscat(showmessage,_T(" Loading IPFilter ..."));
OutputDebugString(showmessage);
}
return TRUE;
}
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;
sin=*(const struct sockaddr_in *)lpto;
if(sin.sin_port==htons(8000))
{
OutputDebugString(_T("WSPSendTo Tencent Filtered"));
return 0;
}
elsE
{
return nextproctable.lpWSPSendTo(s,lpbuffer,dwbuffercount,
lpnumberofbytessent,dwflags,lpto,itolen,
lpoverlapped,lpcompletionroutine,lpthreadid,lperrno);
}
}
int WSPAPI WSPStartup(
WORDwversionrequested,
LPWSPDATA lpwspdata,
LPWSAPROTOCOL_INFOWlpprotoinfo,
WSPUPCALLTABLEupcalltable,
LPWSPPROC_TABLElpproctablE
)
{
OutputDebugString(_T("IPFilter WSPStartup ..."));
int i;
int errorcode;
int filterpathlen;
DWORD layerid=0;
DWORD nextlayerid=0;
TCHAR *filterpath;
HINSTANCE hfilter;
LPWSPSTARTUP wspstartupfunc=NULL;
if(lpprotoinfo->ProtocolChain.ChainLen<=1)
{
OutputDebugString(_T("ChainLen<=1"));
return FALSE;
}
getfilter();
for(i=0;i<totalprotos;i++)
{
if(memcmp(&protoinfo[i].ProviderId,&filterguid,sizeof(GUID))==0)
{
layerid=protoinfo[i].dwCatalogEntryId;
break;
}
}
for(i=0;i<lpprotoinfo->ProtocolChain.ChainLen;i++)
{
if(lpprotoinfo->ProtocolChain.ChainEntries[i]==layerid)
{
nextlayerid=lpprotoinfo->ProtocolChain.ChainEntries[i+1];
break;
}
}
filterpathlen=MAX_PATH;
filterpath=(TCHAR*)GlobalAlloc(GPTR,filterpathlen);
for(i=0;i<totalprotos;i++)
{
if(nextlayerid==protoinfo[i].dwCatalogEntryId)
{
if(WSCGetProviderPath(&protoinfo[i].ProviderId,filterpath,&filterpathlen,&errorcode)==SOCKET_ERROR)
{
OutputDebugString(_T("WSCGetProviderPath Error!"));
return WSAEPROVIDERFAILEDINIT;
}
break;
}
}
if(!ExpandEnvironmentStrings(filterpath,filterpath,MAX_PATH))
{
OutputDebugString(_T("ExpandEnvironmentStrings Error!"));
return WSAEPROVIDERFAILEDINIT;
}
if((hfilter=LoadLibrary(filterpath))==NULL)
{
OutputDebugString(_T("LoadLibrary Error!"));
return WSAEPROVIDERFAILEDINIT;
}
if((wspstartupfunc=(LPWSPSTARTUP)GetProcAddress(hfilter,"WSPStartup"))==NULL)
{
OutputDebugString(_T("GetProcessAddress Error!"));
return WSAEPROVIDERFAILEDINIT;
}
if((errorcode=wspstartupfunc(wversionrequested,lpwspdata,lpprotoinfo,upcalltable,lpproctable))!=ERROR_SUCCESS)
{
OutputDebugString(_T("wspstartupfunc Error!"));
return errorcode;
}
nextproctable=*lpproctable;
lpproctable->lpWSPSendTo=WSPSendTo;
freefilter();
return 0;
}
本文配套源碼