利用SPI编写类似sockscap的代理工具
利用SPI編寫類似sockscap的代理工具
最近幫一個朋友實現sockscap的socks V5代理功能,sockscap貌似是通過API HOOK實現,一開始我便嘗試這種方式,遇到各種麻煩的問題,還是用SPI的LSP來試試吧。
SPI的出現其實就是微軟為了方便程序員對網絡API的各種HOOK,從而省去一些麻煩,然而相對的也會增加不少問題。對于SPI中的LSP這種分層的結構,可以很好的使用強盜手法將自己當作老大放在最上層,但是,如果有其他程序也使用同樣的手法,那么就會產生沖突了。
好吧進入正題。。。
一、LSP的安裝,先拋開socks代理不說
1、構造自己的LSP,并安裝之;
2、遍歷已有 服務提供者,找到剛安裝的LSP入口ID;
3、構造自己的協議鏈,并安裝之;
4、對所有協議鏈進行排序,并將我們的協議鏈放到最上面。
二、LSP的編寫
主要操作都在WSPStartup中,其他WSP函數就是對原函數的HOOK,詳情看下面代碼。
MSDN有完整LSP代碼的下載:
ftp://ftp.microsoft.com/bussys/WinSock/winsock2/layered.zip
同時,網上也有一些源代碼,與MSDN代碼相比,基本一樣,只是在LSP安裝的第一步有所不同,MSDN代碼是手工構造LSP,而網上許多代碼都是通過拷貝系統已有LSP進行對自己的LSP構造。
下面代碼來自網上:
INST_LSP.Cpp
#define UNICODE #define _UNICODE #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); } BOOL InstallProvider(WCHAR *pwszPathName) {WCHAR wszLSPName[] = L"ZetsinLSP";LPWSAPROTOCOL_INFOW pProtoInfo;int nProtocols;WSAPROTOCOL_INFOW OriginalProtocolInfo[3];DWORD dwOrigCatalogId[3];int nArrayCount = 0;DWORD dwLayeredCatalogId; // 我們分層協議的目錄ID號int nError;// 找到我們的下層協議,將信息放入數組中 // 枚舉所有服務程序提供者pProtoInfo = GetProvider(&nProtocols);BOOL bFindUdp = FALSE;BOOL bFindTcp = FALSE;BOOL bFindRaw = FALSE;for (int i=0; i<nProtocols; i++){if (pProtoInfo[i].iAddressFamily == AF_INET){if (!bFindUdp && pProtoInfo[i].iProtocol == IPPROTO_UDP){memcpy(&OriginalProtocolInfo[nArrayCount], &pProtoInfo[i], sizeof(WSAPROTOCOL_INFOW));OriginalProtocolInfo[nArrayCount].dwServiceFlags1 =OriginalProtocolInfo[nArrayCount].dwServiceFlags1 & (~XP1_IFS_HANDLES);dwOrigCatalogId[nArrayCount++] = pProtoInfo[i].dwCatalogEntryId;bFindUdp = TRUE;}if (!bFindTcp && pProtoInfo[i].iProtocol == IPPROTO_TCP){memcpy(&OriginalProtocolInfo[nArrayCount], &pProtoInfo[i], sizeof(WSAPROTOCOL_INFOW));OriginalProtocolInfo[nArrayCount].dwServiceFlags1 =OriginalProtocolInfo[nArrayCount].dwServiceFlags1 & (~XP1_IFS_HANDLES);dwOrigCatalogId[nArrayCount++] = pProtoInfo[i].dwCatalogEntryId;bFindTcp = TRUE;}if (!bFindRaw && pProtoInfo[i].iProtocol == IPPROTO_IP){memcpy(&OriginalProtocolInfo[nArrayCount], &pProtoInfo[i], sizeof(WSAPROTOCOL_INFOW));OriginalProtocolInfo[nArrayCount].dwServiceFlags1 =OriginalProtocolInfo[nArrayCount].dwServiceFlags1 & (~XP1_IFS_HANDLES);dwOrigCatalogId[nArrayCount++] = pProtoInfo[i].dwCatalogEntryId;bFindRaw = TRUE;}}} // 安裝我們的分層協議,獲取一個dwLayeredCatalogId // 隨便找一個下層協議的結構復制過來即可 WSAPROTOCOL_INFOW LayeredProtocolInfo;memcpy(&LayeredProtocolInfo, &OriginalProtocolInfo[0], sizeof(WSAPROTOCOL_INFOW)); // 修改協議名稱,類型,設置PFL_HIDDEN標志 wcscpy_s(LayeredProtocolInfo.szProtocol, wszLSPName);LayeredProtocolInfo.ProtocolChain.ChainLen = LAYERED_PROTOCOL; // 0;LayeredProtocolInfo.dwProviderFlags |= PFL_HIDDEN; // 安裝if (::WSCInstallProvider(&ProviderGuid,pwszPathName, &LayeredProtocolInfo, 1, &nError) == SOCKET_ERROR){printf("%d", nError);return FALSE;} // 重新枚舉協議,獲取分層協議的目錄ID號 FreeProvider(pProtoInfo);pProtoInfo = GetProvider(&nProtocols);for (int i=0; i<nProtocols; i++){if (memcmp(&pProtoInfo[i].ProviderId, &ProviderGuid, sizeof(ProviderGuid)) == 0){dwLayeredCatalogId = pProtoInfo[i].dwCatalogEntryId;break;}} // 安裝協議鏈 // 修改協議名稱,類型WCHAR wszChainName[WSAPROTOCOL_LEN + 1];for (int i=0; i<nArrayCount; i++){swprintf(wszChainName, L"%ws over %ws", wszLSPName, OriginalProtocolInfo[i].szProtocol);wcscpy_s(OriginalProtocolInfo[i].szProtocol, wszChainName);if (OriginalProtocolInfo[i].ProtocolChain.ChainLen == 1){OriginalProtocolInfo[i].ProtocolChain.ChainEntries[1] = dwOrigCatalogId[i];}else{for (int j = OriginalProtocolInfo[i].ProtocolChain.ChainLen; j>0; j--){OriginalProtocolInfo[i].ProtocolChain.ChainEntries[j]= OriginalProtocolInfo[i].ProtocolChain.ChainEntries[j-1];}}OriginalProtocolInfo[i].ProtocolChain.ChainLen ++;OriginalProtocolInfo[i].ProtocolChain.ChainEntries[0] = dwLayeredCatalogId;} // 獲取一個Guid,安裝之 GUID ProviderChainGuid;if (::UuidCreate(&ProviderChainGuid) == RPC_S_OK){if (::WSCInstallProvider(&ProviderChainGuid,pwszPathName, OriginalProtocolInfo, nArrayCount, &nError) == SOCKET_ERROR){return FALSE;}}elsereturn FALSE; // 重新排序Winsock目錄,將我們的協議鏈提前 // 重新枚舉安裝的協議 FreeProvider(pProtoInfo);pProtoInfo = GetProvider(&nProtocols);PDWORD dwIds = (PDWORD)malloc(sizeof(DWORD) * nProtocols);int nIndex = 0; // 添加我們的協議鏈for (int i=0; i<nProtocols; i++){if ((pProtoInfo[i].ProtocolChain.ChainLen > 1) &&(pProtoInfo[i].ProtocolChain.ChainEntries[0] == dwLayeredCatalogId))dwIds[nIndex++] = pProtoInfo[i].dwCatalogEntryId;} // 添加其它協議for (int i=0; i<nProtocols; i++){if ((pProtoInfo[i].ProtocolChain.ChainLen <= 1) ||(pProtoInfo[i].ProtocolChain.ChainEntries[0] != dwLayeredCatalogId))dwIds[nIndex++] = pProtoInfo[i].dwCatalogEntryId;} // 重新排序Winsock目錄if ((nError = ::WSCWriteProviderOrder(dwIds, nIndex)) != ERROR_SUCCESS){return FALSE;}FreeProvider(pProtoInfo);return TRUE; } BOOL RemoveProvider() {LPWSAPROTOCOL_INFOW pProtoInfo;int nProtocols;DWORD dwLayeredCatalogId; // 根據Guid取得分層協議的目錄ID號pProtoInfo = GetProvider(&nProtocols);int nError;int i;for (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);}else return FALSE;return TRUE; } void main(int argc, char *argv[]) {char *ptr; //if(argc==2) {ptr = argv[1];while (*ptr)*ptr++ = tolower(*ptr);int test;scanf("%d", &test);if (test == 1) //if(strcmp(argv[1], "-install")==0) {TCHAR szPathName[256];TCHAR* p;if (::GetFullPathName(L"LSP.dll", 256, szPathName, &p) != 0){if (InstallProvider(szPathName)){printf(" Install successully. /n");return;}}printf(" Install failed. /n");return;}else //else if(strcmp(argv[1],"-remove")==0) {if (RemoveProvider())printf(" Deinstall successully. /n");elseprintf(" Deinstall failed. /n");return;}}printf(" Usage: Instlsp [ -install │ -remove ] /n"); }LSP.Cpp
#define UNICODE #define _UNICODE #include <ws2spi.h> #include <errno.h> #include <fstream> #pragma comment(lib,"Ws2_32.lib") GUID filterguid = {0xd3c21122, 0x85e1, 0x48f3,{0x9a,0xb6,0x23,0xd9,0x0c,0x73,0x07,0xef}}; LPWSAPROTOCOL_INFOW ProtoInfo=NULL; WSPPROC_TABLE NextProcTable; DWORD ProtoInfoSize=0; int TotalProtos=0; // 輸出函數 int PutDbgStr(LPCTSTR lpFmt, ...) {TCHAR Msg[1024];int len=wvsprintf(Msg,lpFmt,va_list(1+&lpFmt));OutputDebugString(Msg);return len; } // 獲取各種值 BOOL GetLSP() {int errorcode;ProtoInfo=NULL;ProtoInfoSize=0;TotalProtos=0;if (WSCEnumProtocols(NULL,ProtoInfo,&ProtoInfoSize,&errorcode)==SOCKET_ERROR){if (errorcode!=WSAENOBUFS){PutDbgStr(L"First WSCEnumProtocols Error!");return FALSE;}}if ((ProtoInfo=(LPWSAPROTOCOL_INFOW)GlobalAlloc(GPTR,ProtoInfoSize))==NULL){PutDbgStr(L"GlobalAlloc Error!");return FALSE;}if ((TotalProtos=WSCEnumProtocols(NULL,ProtoInfo,&ProtoInfoSize,&errorcode))==SOCKET_ERROR){PutDbgStr(L"Second WSCEnumProtocols Error!");return FALSE;}return TRUE; } // 釋放內存 void FreeLSP() {GlobalFree(ProtoInfo); } // DLL入口函數 BOOL WINAPI DllMain(HINSTANCE hmodule,DWORD reason,LPVOID lpreserved) {TCHAR processname[MAX_PATH];if (reason==DLL_PROCESS_ATTACH){GetModuleFileName(NULL,processname,MAX_PATH);PutDbgStr(L"%s Loading IPFilter ...", processname);}return TRUE; } /********************************* 改寫WSP函數,只有WSPConnect被改寫成調用socksProxy函數,其它的直接調用下層WSP函數 ****************************************/ //WSPConnect int WSPAPI WSPConnect(SOCKET s,const struct sockaddr *name,int namelen,LPWSABUF lpCallerData,LPWSABUF lpCalleeData,LPQOS lpSQOS,LPQOS lpGQOS,LPINT lpErrno) {return NextProcTable.lpWSPConnect(s, name, namelen, lpCallerData, lpCalleeData, lpSQOS, lpGQOS, lpErrno); } } //WSPSocket SOCKET WINAPI WSPSocket(__in int af,__in int type,__in int protocol,__in LPWSAPROTOCOL_INFO lpProtocolInfo,__in GROUP g,DWORD dwFlags,__out LPINT lpErrno ) {PutDbgStr(L"WSPSocket");return NextProcTable.lpWSPSocket(af, type, protocol, lpProtocolInfo, g, dwFlags, lpErrno); } //WSPBind int WINAPI WSPBind(__in SOCKET s,__in const struct sockaddr *name,__in int namelen,__out LPINT lpErrno ) {PutDbgStr(L"WSPBind");return NextProcTable.lpWSPBind(s, name, namelen, lpErrno); } //WSPSend int WINAPI WSPSend(__in SOCKET s,__in LPWSABUF lpBuffers,__in DWORD dwBufferCount,__out LPDWORD lpNumberOfBytesSent,__in DWORD dwFlags,__in LPWSAOVERLAPPED lpOverlapped,__in LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,__in LPWSATHREADID lpThreadId,__out LPINT lpErrno ) {PutDbgStr(L"WSPSend");return NextProcTable.lpWSPSend(s, lpBuffers, dwBufferCount, lpNumberOfBytesSent, dwFlags, lpOverlapped, lpCompletionRoutine, lpThreadId, lpErrno); } //WSPSendTo int WINAPI WSPSendTo(__in SOCKET s,__in LPWSABUF lpBuffers,__in DWORD dwBufferCount,__out LPDWORD lpNumberOfBytesSent,__in DWORD dwFlags,__in const struct sockaddr *lpTo,__in int iTolen,__in LPWSAOVERLAPPED lpOverlapped,__in LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,__in LPWSATHREADID lpThreadId,__out LPINT lpErrno ) {PutDbgStr(L"WSPSendTo");return NextProcTable.lpWSPSendTo(s, lpBuffers, dwBufferCount, lpNumberOfBytesSent, dwFlags, lpTo, iTolen, lpOverlapped, lpCompletionRoutine, lpThreadId, lpErrno); } //WSPRecv int WINAPI WSPRecv(__in SOCKET s,__inout LPWSABUF lpBuffers,__in DWORD dwBufferCount,__out LPDWORD lpNumberOfBytesRecvd,__inout LPDWORD lpFlags,__in LPWSAOVERLAPPED lpOverlapped,__in LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,__in LPWSATHREADID lpThreadId,__out LPINT lpErrno ) {PutDbgStr(L"WSPRecv");return NextProcTable.lpWSPRecv(s, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd, lpFlags, lpOverlapped, lpCompletionRoutine, lpThreadId, lpErrno); } //WSPRecvFrom int WINAPI WSPRecvFrom(__in SOCKET s,__inout LPWSABUF lpBuffers,__in DWORD dwBufferCount,__out LPDWORD lpNumberOfBytesRecvd,__inout LPDWORD lpFlags,__out struct sockaddr *lpFrom,__inout LPINT lpFromlen,__in LPWSAOVERLAPPED lpOverlapped,__in LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,__in LPWSATHREADID lpThreadId,__inout LPINT lpErrno ) {PutDbgStr(L"WSPRecvFrom");return NextProcTable.lpWSPRecvFrom(s, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd, lpFlags, lpFrom, lpFromlen, lpOverlapped, lpCompletionRoutine, lpThreadId, lpErrno); } //WSPStartup int WSPAPI WSPStartup(WORD wversionrequested,LPWSPDATA lpwspdata,LPWSAPROTOCOL_INFOW lpProtoInfo,WSPUPCALLTABLE upcalltable,LPWSPPROC_TABLE lpproctable ) {PutDbgStr(L"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){PutDbgStr(L"ChainLen<=1");return FALSE;}GetLSP();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){PutDbgStr(L"WSCGetProviderPath Error!");return WSAEPROVIDERFAILEDINIT;}break;}}if (!ExpandEnvironmentStrings(filterpath,filterpath,MAX_PATH)){PutDbgStr(L"ExpandEnvironmentStrings Error!");return WSAEPROVIDERFAILEDINIT;}if ((hfilter=LoadLibrary(filterpath))==NULL){PutDbgStr(L"LoadLibrary Error!");return WSAEPROVIDERFAILEDINIT;}if ((wspstartupfunc=(LPWSPSTARTUP)GetProcAddress(hfilter,"WSPStartup"))==NULL){PutDbgStr(L"GetProcessAddress Error!");return WSAEPROVIDERFAILEDINIT;}if ((errorcode=wspstartupfunc(wversionrequested,lpwspdata,lpProtoInfo,upcalltable,lpproctable))!=ERROR_SUCCESS){PutDbgStr(L"wspstartupfunc Error!");return errorcode;}NextProcTable=*lpproctable;// 保存原來的入口函數表 //改寫函數lpproctable->lpWSPSendTo = WSPSendTo;lpproctable->lpWSPSend = WSPSend;lpproctable->lpWSPBind = WSPBind;lpproctable->lpWSPConnect = WSPConnect;lpproctable->lpWSPRecv = WSPRecv;lpproctable->lpWSPRecvFrom = WSPRecvFrom;lpproctable->lpWSPSocket = WSPSocket;FreeLSP();return 0; }
關于SOCKS V5代理,下回修改文章再貼上。
zetsin@gmail.com
2011-04-30 20:57:02
要說SOCKS V5代理,其實非常簡單,細讀一遍RFC1928文檔就OK了,文檔地址如下:
http://www.ietf.org/rfc/rfc1928.txt
如果需要遠程解析域名,則將上述文檔中第四點的 ATYP 置為 /X03
最后將前面所寫的LSP與SOCKS V5代理結合,TCP的話只要攔截WSPCONNECT函數,UDP因為不是面向連接的所以只要攔截WSPSENDTO即可,具體代碼如下:
// 連接socks5代理
zetsin@gmail.com
2011-05-02 18:25:39
轉自:http://blog.csdn.net/ze_tsin/article/details/6376831
總結
以上是生活随笔為你收集整理的利用SPI编写类似sockscap的代理工具的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 校园网更改计算机的mac,Mac怎么连接
- 下一篇: 利用VB2005制作颜色渐变的进度条