利用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代理

int socksProxy(SOCKET s, const struct sockaddr *name, int namelen)
{int rc = 0;
// 这里应该先保存下socket的阻塞/非阻塞类型,在最后面跟据这里的值将它还原,但是不知道怎样获取此类型
// 修改socket为阻塞类型if (rc = WSAEventSelect(s, 0, NULL))//这一个可以不用执行
    {PutDbgStr(L"Error %d : WSAEventSelect Failure!", WSAGetLastError());}else{PutDbgStr(L"Message : WSAEventSelect successfully!");}unsigned long nonBlock = 0;if (rc = ioctlsocket(s, FIONBIO, &nonBlock))// 这个真正修改为阻塞类型
    {PutDbgStr(L"Error %d : Set Blocking Failure!", WSAGetLastError());}else{PutDbgStr(L"Message : Set Blocking successfully!");}
//连接代理服务器
    sockaddr_in serveraddr;memset(&serveraddr, 0, sizeof(serveraddr));serveraddr.sin_family = AF_INET;serveraddr.sin_addr.S_un.S_addr = inet_addr("76.120.160.122"); //代理服务器地址,从无忧代理网获取的,质量还行,不过只能用几天,发现连不上的话重新获取吧serveraddr.sin_port = htons(27977); // 端口号
    WSABUF DataBuf;char buffer[4];memset(buffer, 0, sizeof(buffer));DataBuf.len = 4;DataBuf.buf = buffer;int err = 0;if ((rc = NextProcTable.lpWSPConnect(s, (struct sockaddr *)&serveraddr, sizeof(struct sockaddr), &DataBuf, NULL, NULL, NULL, &err)) != 0){PutDbgStr(L"Error %d : attempting to connect to SOCKS server!", err);return rc;}else{PutDbgStr(L"Message : Connect to SOCKS server successfully!");}
//发送请求来协商版本和认证方法
//VER NMETHODS METHODS
//1 1 1 to 255char verstring[257];verstring[0] = 0x05; //VER (1 Byte)verstring[1] = 0x01; //NMETHODS (1 Byte)verstring[2] = 0x00; //METHODS (allow 1 - 255 bytes, current 1 byte)if ((rc = send(s, verstring, 3, 0)) < 0){PutDbgStr(L"Error %d : attempting to send SOCKS method negotiation!", WSAGetLastError());return rc;}else{PutDbgStr(L"Message : send SOCKS method negotiation successfully!");}
//接收代理服务器返回信息
//VER METHOD
//1 1/*当前定义的方法有:· X'00' 不需要认证· X'01' GSSAPI· X'02' 用户名/密码· X'03' -- X'7F' 由IANA分配· X'80' -- X'FE' 为私人方法所保留的· X'FF' 没有可以接受的方法*/if ((rc = recv(s, verstring, 257, 0)) < 0){PutDbgStr(L"Error %d : attempting to receive SOCKS method negotiation reply!", WSAGetLastError());return rc;}else{PutDbgStr(L"Message : receive SOCKS method negotiation reply successfully!");}if (rc < 2)//返回2字节
    {PutDbgStr(L"Error : Short reply from SOCKS server!");rc = ECONNREFUSED;return rc;}else{PutDbgStr(L"Message : reply from SOCKS server larger than 2");}
// 代理服务器选择方法
// 判断我们的方法是否可行if (verstring[1] == '/xff'){PutDbgStr(L"Error : SOCKS server refused authentication methods!");rc = ECONNREFUSED;return rc;}else if (verstring[1] == '/x02')// 方法2 : 用户名/密码
    {
//另外处理PutDbgStr(L"Error : SOCKS server need username/password!");}else if (verstring[1] == '/x00')// 方法0: 不需要认证
    {
//发送SOCKS请求
//VER CMD RSV ATYP DST.ADDR DST.PROT
//1 1 X'00' 1 Variable 2/* VER 协议版本: X'05'· CMD· CONNECT:X'01'· BIND:X'02'· UDP ASSOCIATE:X'03'· RSV 保留· ATYP 后面的地址类型· IPV4:X'01'· 域名:X'03'· IPV6:X'04''· DST.ADDR 目的地址· DST.PORT 以网络字节顺序出现的端口号SOCKS服务器会根据源地址和目的地址来分析请求,然后根据请求类型返回一个或多个应答。*/struct sockaddr_in sin;sin = *(const struct sockaddr_in *)name;char buf[10];buf[0] = '/x05'; // 版本 SOCKS5buf[1] = '/x01'; // 连接请求buf[2] = '/x00'; // 保留字段buf[3] = '/x01'; // IPV4memcpy(&buf[4], &sin.sin_addr.S_un.S_addr, 4);memcpy(&buf[8], &sin.sin_port, 2);
//发送if ((rc = send(s, buf, 10, 0)) < 0){PutDbgStr(L"Error %d : attempting to send SOCKS connect command!", WSAGetLastError());return rc;}else{PutDbgStr(L"Message : send SOCKS connect command successfully!");}
//应答
//VER REP RSV ATYP BND.ADDR BND.PORT
//1 1 X'00' 1 Variable 2/*VER 协议版本: X'05'· REP 应答字段:· X'00' 成功· X'01' 普通的SOCKS服务器请求失败· X'02' 现有的规则不允许的连接· X'03' 网络不可达· X'04' 主机不可达· X'05' 连接被拒· X'06' TTL超时· X'07' 不支持的命令· X'08' 不支持的地址类型· X'09' - X'FF' 未定义· RSV 保留· ATYP 后面的地址类型· IPV4:X'01'· 域名:X'03'· IPV6:X'04'· BND.ADDR 服务器绑定的地址· BND.PORT 以网络字节顺序表示的服务器绑定的段口标识为RSV的字段必须设为X'00'。*/if ((rc = recv(s, buf, 10, 0)) < 0) // 用了天翼的网络之后,这里就接收不到返回信息了,不解
        {PutDbgStr(L"Error %d : attempting to receive SOCKS connection reply!", WSAGetLastError());rc = ECONNREFUSED;return rc;}else{PutDbgStr(L"Message : receive SOCKS connection reply successfully!");}if (rc < 10){PutDbgStr(L"Message : Short reply from SOCKS server!");return rc;}else{PutDbgStr(L"Message : reply from SOCKS larger than 10!");}
//连接不成功if (buf[0] != '/x05'){PutDbgStr(L"Message : Socks V5 not supported!");return ECONNABORTED;}else{PutDbgStr(L"Message : Socks V5 is supported!");}if (buf[1] != '/x00'){PutDbgStr(L"Message : SOCKS connect failed!");switch ((int)buf[1]){case 1:PutDbgStr(L"General SOCKS server failure!");return ECONNABORTED;case 2:PutDbgStr(L"Connection denied by rule!");return ECONNABORTED;case 3:PutDbgStr(L"Network unreachable!");return ENETUNREACH;case 4:PutDbgStr(L"Host unreachable!");return EHOSTUNREACH;case 5:PutDbgStr(L"Connection refused!");return ECONNREFUSED;case 6:PutDbgStr(L"TTL Expired!");return ETIMEDOUT;case 7:PutDbgStr(L"Command not supported!");return ECONNABORTED;case 8:PutDbgStr(L"Address type not supported!");return ECONNABORTED;default:PutDbgStr(L"Unknown error!");return ECONNABORTED;}}else{PutDbgStr(L"Message : SOCKS connect Success!");}}else{PutDbgStr(L"Error : Method not supported!");}
//修改socket为非阻塞类型nonBlock = 1;if (rc = ioctlsocket(s, FIONBIO, &nonBlock)){PutDbgStr(L"Error %d : Set Non-Blocking Failure!", WSAGetLastError());return rc;}else{PutDbgStr(L"Message : Set Non-Blocking Successful!");}PutDbgStr(L"Message : Success!");return 0;
}
//WSPConnect
int WSPAPI WSPConnect(SOCKET s,const struct sockaddr *name,int namelen,LPWSABUF lpCallerData,LPWSABUF lpCalleeData,LPQOS lpSQOS,LPQOS lpGQOS,LPINT lpErrno)
{PutDbgStr(L"WSPConnect");struct sockaddr_in sin;sin=*(const struct sockaddr_in *)name;if (strcmp(inet_ntoa(sin.sin_addr), "127.0.0.1") == 0){return NextProcTable.lpWSPConnect(s, name, namelen, lpCallerData, lpCalleeData, lpSQOS, lpGQOS, lpErrno);}return socksProxy(s, name, namelen);
}
//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");struct sockaddr_in sin;sin=*(const struct sockaddr_in *)name;if (strcmp(inet_ntoa(sin.sin_addr), "127.0.0.1") == 0){return NextProcTable.lpWSPSendTo(s, lpBuffers, dwBufferCount, lpNumberOfBytesSent, dwFlags, lpTo, iTolen, lpOverlapped, lpCompletionRoutine, lpThreadId, lpErrno);}return socksProxy(s, lpTo, iTolen);
}

zetsin@gmail.com

2011-05-02 18:25:39

转自:http://blog.csdn.net/ze_tsin/article/details/6376831

利用SPI编写类似sockscap的代理工具相关推荐

  1. python数据预测_利用Python编写一个数据预测工具

    利用Python编写一个数据预测工具 发布时间:2020-11-07 17:12:20 来源:亿速云 阅读:96 这篇文章运用简单易懂的例子给大家介绍利用Python编写一个数据预测工具,内容非常详细 ...

  2. 内网渗透 | FRP代理工具详解

    FRP工具的使用 FRP官方文档:https://gofrp.org/docs 文章目录 **一.FRP工具的介绍** **1.为什么需要内网穿透** **2.FRP介绍** **3.为什么使用FRP ...

  3. 端口转发与代理工具 内网代理 内网反弹代理

    目录 一.LCX 二.nc 反弹 三.socks代理工具 四.frp 内网穿透利器 五.ngrok 内网穿透 理论上,任何接入互联网的计算机都是可访问的,但是如果目标主机处于内网,而我们又想和该目标主 ...

  4. 用ChatGPT处理word表格数据:直接采用ChatGPt和利用ChatGPT编写python脚本两种方法

    目录 摘要 0. 测试数据生成 1. 直接使用ChatGPT进行处理. 2 使用ChatGPT生成python脚本进行处理 3对比分析 4 结束语 摘要 为测试ChatGP在word文档表格的处理能力 ...

  5. 接口测试准备一、 网路基础 常用代理工具 charles使用 Android手机代理抓包

    移动互联网公司技术架构 接口测试的必要性 1.行业成熟方案 2.更早份发现问题 3.更快的质量反馈 接口测试不能替代UI测试 1.接口测试有很多优点,但是保证的好似后端的质量,不能解决移动端的额质量 ...

  6. python编写图形化界面的工具,python做出软件的界面

    python能写界面吗 作为Pyhon开发者,你迟早都会碰到图形用户界面(GUI)应用开发任务,这时候我们就需要一些界面库来帮助我们快速搭建界面,python的界面库很多,我认识的并不多,这里只列出几 ...

  7. 多级代理工具Stowaway

    多级代理工具Stowaway Stowaway是一个利用go语言编写.专为渗透测试工作者制作的多级代理工具 项目地址https://github.com/ph4ntonn/Stowaway 特性 管理 ...

  8. 爬虫实战(一)—利用requests、mongo、redis代理池爬取英雄联盟opgg实时英雄数据

    概述 可关注微信订阅号 loak 查看实际效果. 代码已托管github,地址为:https://github.com/luozhengszj/LOLGokSpider 包括了项目的所有代码. 此篇文 ...

  9. 5、内网渗透之端口转发与代理工具总结

    理论上,任何接入互联网的计算机都是可访问的,但是如果目标主机处于内网,而我们又想和该目标主机进行通信的话,就需要借助一些端口转发工具来达到我们的目的 注:文中提到的所有工具下载地址 https://g ...

  10. 代理工具Charles使用

    代理工具Charles使用 分类: MAC 2014-03-27 20:41 7810人阅读 评论(2) 收藏 举报 手机开发 一.跟踪HTTPS 1.下载官方的证书ssl.zip证书,解压成*.cr ...

最新文章

  1. P3321 [SDOI2015]序列统计(离散对数下NTT,乘法换加法)
  2. python 打印数组变量_使用Python将数组的元素导出到变量中(unpacking)
  3. 利用Bandwidth Splitter限制带宽
  4. 谷歌抽屉_Google(最终)会杀死导航抽屉吗?
  5. fopen php 乱码,如何解决php fgets读取文件乱码的问题
  6. LDR 、ADR介绍
  7. 网络通信协议八之UDP协议详解
  8. 中国医科大学计算机应用基础本科在线作业,中国医科大学《计算机应用基础(本科)》在线作业.docx...
  9. 5.9UDP客户端服务器-基于OK6410
  10. 最贵服务器多少钱_十次方分享:租服务器一般花费多少钱一年?
  11. Qt 获取控件位置坐标,屏幕坐标,相对父窗体坐标
  12. Android进阶之路 - keyStore、jks签名证书相互转换
  13. LeetCode——868. 二进制间距
  14. 程序员与代码之间的搞笑日常,笑的人肚子痛!
  15. Thymeleaf设置固定值属性
  16. win10环境编译支持xp的libcurl+openssl踩过的坑
  17. cgroup架构及控制文件介绍
  18. Java在Web端微信公众号授权登录
  19. 浪潮IPBS9505S短接线刷固件(附教程)
  20. 【Java】练习题库 单选题

热门文章

  1. About Face 3:交互设计精髓pdf
  2. Axure RP9授权码
  3. ZLMediaKit+wvp-GB28181-pro,搭建28181协议视频平台
  4. 【实用案例】R语言gdm函数实现地理探测器分析
  5. 在线 pdf转word
  6. 金蝶KIS商贸版开发销售出库单、销售订单带商品图片打印单据
  7. CSV 文件中的字段中的开头和结尾上,可能会存在空格或制表符,但是该如何处理呢?
  8. staruml怎么画协作图_er图怎么画?轻松绘制专业er图的软件
  9. cad化工设备绘图_化工设备CAD绘图技巧
  10. 计算机数值方法(1):引论