水平有限,简单记录下实现过程:
首先准备一个开源项目SSCAP https://sourceforge.net/p/sscap/code/ci/master/tree/ (c++ mfc sscap源码)。
SSCap是一个本地代理服务器,SSCap是一个Windows下C++版的Shadowsocks客户端. 相比其它的客户端更稳定更快速,不会出现其它版本中常现的接收数据错误。
通过SSCap可以启动本地代理服务器。你可以让IE或其他需要软件通过SOCKS5访问的软件先连接到 SSCAP,SSCAP再将请求加密后再连接到服务器。服务器可以将请求转发到国外游戏服务器,实现网络游戏加速。
SSCAP界面:
SSCap是开源的。本文将SScap的功能整合起来。实现对魔兽世界怀旧服LH网络加速的功能。
原理很简单:
1、先整合sscap的功能,将本地服务器启动起来。
// 加载ss服务器列表CSSConfigInfo *pCfg = GetConfigInfo();CSSNodeInfo* pNode = new CSSNodeInfo(0);pNode->id = 0;pNode->server = "140.0.0.00";pNode->server_port = 65501;pNode->password = "1234"; pNode->method = "aes-256-cfb";pNode->enable = true;pNode->Upload_traffic = 7450.00;pNode->Download_traffic = 21477.00;pNode->ConnectedTimes = 12;pNode->lastStatus = -1;pCfg->ssNodeInfo.clear();pCfg->ssNodeInfo.push_back(pNode);pCfg->localSocksUser = "local_user";pCfg->localSocksPass = "local_pass";pCfg->localPort = 1080;pCfg->isPrivoxyRunned = RunPrivoxy( );RestartLocalSocketService(FALSE);
那么本地服务器就启动好了。127.0.0.1:1080 登陆账号:local_user 登陆密码:local_pass
2、启动魔兽世界6.0。注入DLL,拦截ws2_32.dll的connect方法。
DetourRestoreAfterWith();//恢复原来的状态DetourTransactionBegin();//拦截开始DetourUpdateThread(GetCurrentThread());//刷新当前线程 //以下为hook connect内容g_trueConnect = (_gconnect)DetourFindFunction("Ws2_32.dll", "connect");g_trueWSAConnect = (_gWSAConnect)DetourFindFunction("Ws2_32.dll", "WSAConnect");DetourAttach(&(PVOID&)g_trueConnect,hook_connect);DetourAttach(&(PVOID&)g_trueWSAConnect,hook_WSAConnect);if( DetourTransactionCommit() == NO_ERROR )//拦截生效{WriteLog(_T("hook success"));}elseWriteLog(_T("hook faild"));
int _stdcall hook_connect(SOCKET s, struct sockaddr *name, int namelen)
{CString strDbgInfo;strDbgInfo.Format(_T("Socket in hook connect:%d"),s);//修改目的IP为VIPSOCKADDR_IN* addr =(SOCKADDR_IN*)name;//如果IP是指定要修改端口的IP,就改掉端口char * ipaddr=NULL;ipaddr = inet_ntoa(addr->sin_addr);//原游戏连接信息TCHAR temp[255];memset(temp,0,255); char* proxyserver = "127.0.0.1";int proxyport = 1081;char* proxyuser = "local_user";char* proxypwd = "local_pass";int iRet = ConnecToProxyServer(s,proxyserver,proxyport,proxyuser,proxypwd,3,ipaddr,ntohs(addr->sin_port));if (iRet>=0){WriteLog(_T("in connecta: connect socks5 success 1!"));}else{memset(temp,0,255);wsprintf(temp,_T("Err connect ss5:%d"),iRet);WriteLog(temp);}return iRet;
}
//代理服务器登录
//char* g_proxyserver = "140.1xx.1x.1xx";
//int g_proxyport = 65500;
//char* g_proxyuser = "";
//char* g_proxypwd = "";
//int g_proxyid = 3; //2 - sock4代理 3 - sock5代理
//char server_name[100]= {0}; //真正的服务器地址
//int server_port=8000; //真正的服务器端口
int ConnecToProxyServer(SOCKET m_hSocketpop,char* g_proxyserver,int g_proxyport,char* g_proxyuser,char* g_proxypwd,int g_proxyid,char* server_name,int server_port,int connectType)
{//原游戏连接信息SOCKADDR_IN ToAddr;memset(&ToAddr, 0, sizeof(ToAddr));ToAddr.sin_family &#61; AF_INET; ToAddr.sin_addr.s_addr &#61; inet_addr(g_proxyserver);//这是我的SOCKS服务器ToAddr.sin_port &#61; htons(g_proxyport); int retCt &#61; -1;if (connectType &#61;&#61; 1)retCt &#61; g_trueWSAConnect(m_hSocketpop,(SOCKADDR*)&ToAddr,sizeof(ToAddr),NULL,NULL,NULL ,NULL);elseretCt &#61; g_trueConnect(m_hSocketpop,(SOCKADDR*)&ToAddr,sizeof(ToAddr));if( SOCKET_ERROR &#61;&#61; retCt ){int iErr &#61; WSAGetLastError(); if (iErr&#61;&#61;WSAEWOULDBLOCK){fd_set fdWrite;timeval tv;FD_ZERO(&fdWrite);//初始化fd_setFD_SET(m_hSocketpop,&fdWrite);tv.tv_sec &#61; 30;tv.tv_usec &#61; 0;int nRet &#61; select(0,NULL,&fdWrite,NULL,&tv);if (nRet<&#61;0){closesocket(m_hSocketpop);return -111;}}else{closesocket(m_hSocketpop);return -112;}}char buf[100] &#61; {0};if(g_proxyid &#61;&#61; 3) //sock5 代理方式{// 让PROXY选择认证方法buf[0] &#61; 0x05;buf[1] &#61; 0x02; //确认2种认证方式 无需认证和需要认证buf[2] &#61; 0x00; // 无需认证buf[3] &#61; 0x02; // 需要认证WriteLog(_T("Send a request asking if authentication is required"));if(send(m_hSocketpop,(const far char*)buf,4,0) &#61;&#61; SOCKET_ERROR){closesocket(m_hSocketpop);return -12;}//查询是否有返回fd_set fdread;timeval tv;FD_ZERO(&fdread);//初始化fd_setFD_SET(m_hSocketpop,&fdread);tv.tv_sec &#61; 30;tv.tv_usec &#61; 0;int nRet;nRet &#61; select(0,&fdread,NULL,NULL,&tv);if (nRet<&#61;0){return -122;}//接收返回if(recv(m_hSocketpop,buf,10,0) &#61;&#61; SOCKET_ERROR){closesocket(m_hSocketpop);return -13;}if(buf[1] &#61;&#61; 0x02){//需要认证WriteLog(_T("need auth"));char userStr[128] &#61; {0};userStr[0]&#61;0x01;userStr[1]&#61;strlen(g_proxyuser);strcpy(userStr&#43;2,g_proxyuser);userStr[2&#43; strlen(g_proxyuser)]&#61; strlen(g_proxypwd);strcpy(userStr&#43;3&#43; strlen(g_proxyuser),g_proxypwd);int result&#61;send(m_hSocketpop,userStr,strlen(userStr), 0);if(result &#61;&#61; SOCKET_ERROR){closesocket(m_hSocketpop);return -1;}Sleep(100);char validateChar[2] &#61; {1};result&#61;recv(m_hSocketpop,validateChar,2, 0);if(result &#61;&#61; SOCKET_ERROR){closesocket(m_hSocketpop);return -1;}if(validateChar[1]!&#61;&#39;\x00&#39;){//认证失败closesocket(m_hSocketpop);return -1;}}// 向PROXY服务器发送CONNECT 请求&#xff0c;WriteLog(_T("Send connect request to PROXY server!"));memset(buf, 0, 100);buf[0] &#61; 0x05;buf[1] &#61; 0x01; // connection request.buf[2] &#61; 0x00; // reserved!buf[3] &#61; 0x01; // address type:Ip V4 ;*((ULONG*)(buf&#43;4))&#61;inet_addr(server_name);*((USHORT*)(buf&#43;8))&#61;htons(server_port);if(send(m_hSocketpop,(const far char*)buf,10,0) &#61;&#61; SOCKET_ERROR){closesocket(m_hSocketpop);return -14;}//Sleep(100); FD_ZERO(&fdread);//初始化fd_setFD_SET(m_hSocketpop,&fdread);tv.tv_sec &#61; 30;tv.tv_usec &#61; 0;nRet &#61; select(0,&fdread,NULL,NULL,&tv);if (nRet<&#61;0){return -141;}// 接收PROXY服务器返回的REPLYmemset(buf, 1, 100);if(recv(m_hSocketpop,buf, 20,0) &#61;&#61; SOCKET_ERROR){closesocket(m_hSocketpop);return -15;}if(buf[1] !&#61; 0) // 只有当第二个字节为0时&#xff0c;才表示成功。{// printf("Cannot connect to the remote server!\n");closesocket(m_hSocketpop);return -16;}// theApp.m_ClientSocket.Attach(m_hSocketpop);}if(g_proxyid &#61;&#61; 2) //sock4 代理方式{int result;memset(buf, 0, 100);buf[0] &#61; 0x04;buf[1] &#61; 0x01; // connection request.*((USHORT*)(buf&#43;2))&#61;htons(server_port);*((ULONG*)(buf&#43;4))&#61;inet_addr(server_name);buf[8] &#61; 0x00;result &#61; send(m_hSocketpop, (const far char*)buf, 9, 0);if(result &#61;&#61; SOCKET_ERROR){closesocket(m_hSocketpop);return -1;}Sleep(100);char EchoStr[10];memset(EchoStr,0,10);result&#61;recv(m_hSocketpop,EchoStr,8, 0);if(result &#61;&#61; SOCKET_ERROR){closesocket(m_hSocketpop);return -1;}if(EchoStr[1] !&#61; 90){closesocket(m_hSocketpop);return -1;}// theApp.m_ClientSocket.Attach(m_hSocketpop);}return 0;
}
游戏会建立与本地服务器的连接&#xff0c;本地服务器会将游戏请求通过sock5发送到服务器上。实现游戏加速。
服务端架设参考&#xff1a;
用shadowsocks-libev架设服务器端&#xff1a;
https://blog.csdn.net/wwzuizz/article/details/78194159