hook connect异步的问题,写个简单的代理,hook connect,然后修改ip和端口,连接到socks5,但是 connect时候返回-1、

新之野望游戏工作室 软件调试-开发  2012-11-25 08:59:05
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include <WinSock2.h>
#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include "targetver.h"
#pragma comment(lib,"ws2_32.lib")

//本dll的handle 
HANDLE g_hInstance=NULL;
//修改API入口为 mov eax, 00400000;jmp eax是程序能跳转到自己的函数 
BYTE g_btNewBytes[8]={0xB8,0x0,0x0,0x40,0x0,0xFF,0xE0,0};
//保存原 API入口的 8 个字节
DWORD g_dwOldBytes[5][2] = {0x0,0x0,0x0,0x0};
//钩子句柄 
HHOOK g_hOldHook=NULL;
//API中 send函数的地址 
DWORD g_pSend=0;
DWORD g_pRecv=0;
DWORD g_pConnect=0;
DWORD g_pWSAConnect=0;
DWORD g_pSocket=0;
//事务,解决同步问题 
HANDLE g_hSendEvent=NULL;
//自己的函数地址,参数必须与 API 的 send 函数地址相同 

int _stdcall hook_connect(SOCKET s, struct sockaddr *name, int namelen);
int _stdcall hook_WSAConnect(SOCKET s,const struct sockaddr FAR * name, int namelen,\
LPWSABUF lpCallerData,LPWSABUF lpCalleeData,LPQOS lpSQOS,LPQOS lpGQOS);
int ConnectTcpToSocks5(char* UserName,char*PassWord,int GameServerPort,char *GameServerIP,SOCKET sClient);
int _stdcall hook_Socket(int af, int type,int p);
//要 Hook 的进程和主线程 ID 号 
DWORD g_dwProcessID=0;
DWORD g_dwThreadID=0;
//维护注入进程的socket

BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
g_hInstance = hModule;
g_hSendEvent = CreateEvent(0,0,1,0);

HMODULE hWsock=LoadLibrary("ws2_32.dll");

g_pConnect = (DWORD)GetProcAddress(hWsock,"connect");
//保存原始字节 
ReadProcessMemory(INVALID_HANDLE_VALUE,(void*)g_pConnect,\
(void*)g_dwOldBytes[2],sizeof(DWORD)*2,NULL);
*(DWORD*)(g_btNewBytes+1)=(DWORD)hook_connect;
//写入新地址
WriteProcessMemory(INVALID_HANDLE_VALUE,(void*)g_pConnect,\
(void*)g_btNewBytes,sizeof(DWORD)*2,NULL);

g_pWSAConnect = (DWORD)GetProcAddress(hWsock,"WSAConnect");
//保存原始字节 
ReadProcessMemory(INVALID_HANDLE_VALUE,(void*)g_pWSAConnect,\
(void*)g_dwOldBytes[3],sizeof(DWORD)*2,NULL);
*(DWORD*)(g_btNewBytes+1)=(DWORD)hook_WSAConnect;
//写入新地址
WriteProcessMemory(INVALID_HANDLE_VALUE,(void*)g_pWSAConnect,\
(void*)g_btNewBytes,sizeof(DWORD)*2,NULL);


}
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

int _stdcall hook_connect(SOCKET s, struct sockaddr *name, int namelen)
{
//int Ret;
WaitForSingleObject(g_hSendEvent,INFINITE);
//恢复 API 头 8 个字节 
WriteProcessMemory(INVALID_HANDLE_VALUE,(void*)g_pConnect,\
(void*)g_dwOldBytes[2],sizeof(DWORD)*2,NULL);
//分析sock数据
SOCKADDR_IN* addr =(SOCKADDR_IN*)name;
DWORD GameServerPort;
char GameServerIP[128];
GameServerPort = ntohs(addr->sin_port);
strcpy(GameServerIP,inet_ntoa(addr->sin_addr));
SOCKADDR_IN AddrSock;
AddrSock.sin_addr.S_un.S_addr=inet_addr("192.168.1.103");
AddrSock.sin_port = htons(1080);
AddrSock.sin_family = AF_INET;
int errorx = GetLastError();
unsigned long ul = 0;
int ret = ioctlsocket (s, FIONBIO, (unsigned long*)&ul);

int i = connect(s,(SOCKADDR*)&AddrSock,namelen);
if(i)
{
errorx = GetLastError();
char yy[25];
sprintf(yy,"%d",errorx);
::MessageBoxA(0,yy,0,0);
}
*(DWORD*)(g_btNewBytes+1)=(DWORD)hook_connect;
//继续hook
WriteProcessMemory(INVALID_HANDLE_VALUE,(void*)g_pConnect,\
(void*)g_btNewBytes,sizeof(DWORD)*2,NULL);
ul = 1;
ret = ioctlsocket (s, FIONBIO, (unsigned long*)&ul);
ConnectTcpToSocks5(0,0,GameServerPort,GameServerIP,s);


SetEvent(g_hSendEvent);
return true;
}
int _stdcall hook_WSAConnect(SOCKET s,const struct sockaddr FAR * name, int namelen,\
LPWSABUF lpCallerData,LPWSABUF lpCalleeData,LPQOS lpSQOS,LPQOS lpGQOS)
{

int Ret;
WaitForSingleObject(g_hSendEvent,INFINITE);
//恢复API入口
//分析sock数据
SOCKADDR_IN* addr =(SOCKADDR_IN*)name;
char text[255]={0};
sprintf(text,"IP:%s\nPort:%d",inet_ntoa(addr->sin_addr),ntohs(addr->sin_port));
//::MessageBox(0,text,"有连接建立,IP和端口如下",0);

WriteProcessMemory(INVALID_HANDLE_VALUE,(void*)g_pWSAConnect,\
(void*)g_dwOldBytes[3],sizeof(DWORD)*2,NULL);
Ret = WSAConnect(s,name,namelen,lpCallerData,lpCalleeData,lpSQOS,lpGQOS);
//继续hook
*(DWORD*)(g_btNewBytes+1)=(DWORD)hook_WSAConnect;
WriteProcessMemory(INVALID_HANDLE_VALUE,(void*)g_pWSAConnect,\
(void*)g_btNewBytes,sizeof(DWORD)*2,NULL);
SetEvent(g_hSendEvent);
return Ret;

}
static LRESULT WINAPI HookProc(int nCode,WPARAM wParam,LPARAM lParam)
{
return CallNextHookEx(g_hOldHook,nCode,wParam,lParam);
}
extern "C"_declspec(dllexport)BOOL StartHook(HWND hWnd)
{
//通过传入的窗口句柄获取线程句柄 
g_dwThreadID=GetWindowThreadProcessId(hWnd,&g_dwProcessID);
//WH_CALLWNDPROC类型的 Hook 
g_hOldHook=SetWindowsHookEx(WH_CALLWNDPROC,HookProc,(HINSTANCE)g_hInstance,g_dwThreadID);
if(g_hOldHook==NULL)
return FALSE;
return TRUE;
}
extern "C"_declspec(dllexport)void StopHook(void)
{
if(g_hOldHook != NULL)
{
WaitForSingleObject(g_hSendEvent,INFINITE);
HANDLE hProcess = NULL;
hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,g_dwProcessID);
DWORD dwOldProc;
DWORD dwNewProc;
//改变页面属性为读写 
VirtualProtectEx(hProcess,(void*)g_pSend,8,PAGE_READWRITE,&dwOldProc);
//回复函数入口地址
WriteProcessMemory(hProcess,(void*)g_pSend,(void*)g_dwOldBytes[0],sizeof(DWORD)*2,NULL);
WriteProcessMemory(hProcess,(void*)g_pRecv,(void*)g_dwOldBytes[1],sizeof(DWORD)*2,NULL);
WriteProcessMemory(hProcess,(void*)g_pConnect,(void*)g_dwOldBytes[2],sizeof(DWORD)*2,NULL);
WriteProcessMemory(hProcess,(void*)g_pWSAConnect,(void*)g_dwOldBytes[3],sizeof(DWORD)*2,NULL);
//恢复页面文件的属性
VirtualProtectEx(hProcess,(void*)g_pSend,8,dwOldProc,&dwNewProc);
CloseHandle(g_hSendEvent);

int i = UnhookWindowsHookEx(g_hOldHook);
if(!i)
::MessageBox(NULL,"卸载模块失败,我感觉你可以重启了","",NULL);
}
}
//使用TCP连接sock5服务器
int ConnectTcpToSocks5(char* UserName,char*PassWord,int GameServerPort,char *GameServerIP,SOCKET sClient)
{
unsigned long ul = 0;
ioctlsocket (sClient, FIONBIO, (unsigned long*)&ul);

//::MessageBoxA(0,"进入链接代理",0,0);

//向服务器发送请求,用于确定连接方式
char buffer[1024];
int bufferlen=1023;
int ret;
sock5req1 *m_proxyreq1;

/*struct sock5req1
{
char Ver; //版本
char nMethods; //方式数目
char Methods[255]; //请求连接方式
};*/
m_proxyreq1=(sock5req1 *)buffer;
m_proxyreq1->Ver=SOCKS_VER;
m_proxyreq1->nMethods=2;
m_proxyreq1->Methods[0]=METHOD_AUTH_NO;
m_proxyreq1->Methods[1]=METHOD_AUTH;
//send请求
ret=send(sClient,buffer,4,0);
if(ret==SOCKET_ERROR)
{
int errorx = GetLastError();
char yy[25];
sprintf(yy,"%d",errorx);
::MessageBoxA(0,yy,0,0);
closesocket(sClient);
return 0;
}
//send后接收服务器返回
ret=recv(sClient,buffer,bufferlen,0);
if(ret==SOCKET_ERROR)
{
int errorx = GetLastError();
char yy[25];
sprintf(yy,"%d",errorx);
::MessageBoxA(0,yy,0,0);
closesocket(sClient);
return 0;
}

sock5ans1 *m_proxyans1;
m_proxyans1=(sock5ans1 *)buffer;
/*struct sock5ans1
{
char Ver; //版本
char Method; //允许的连接方式
};
*/
if(m_proxyans1->Ver==SOCKS_VER && m_proxyans1->Method==METHOD_AUTH_NO && m_proxyans1->Method==METHOD_AUTH)
{
//closesocket(sClient);
}
//返回0x02请求,需要进行密码账户验证
if(m_proxyans1->Method==METHOD_AUTH)
{
char AuthName[255] = "jiahui";
char AuthPasswd[255]= "123123";

socks5authreq *m_authreq;
int iNameLen=strlen(AuthName);
int iPasswd=strlen(AuthPasswd);
m_authreq=(socks5authreq *)buffer;

m_authreq->Ver=SOCKS_AUTH_VER;
m_authreq->other[0]=iNameLen;
strcpy(m_authreq->other+1,AuthName);
m_authreq->other[iNameLen+1]=iPasswd;
strcpy(m_authreq->other+iNameLen+2,AuthPasswd);

//把账户密码发送到服务器进行验证
ret=send(sClient,buffer,3+iNameLen+iPasswd,0);
if(ret==SOCKET_ERROR)
{
int errorx = GetLastError();
char yy[25];
sprintf(yy,"%d",errorx);
::MessageBoxA(0,yy,0,0);
closesocket(sClient);
return 0;
}
//接收申请的返回
ret=recv(sClient,buffer,bufferlen,0);
if(ret==SOCKET_ERROR)
{
int errorx = GetLastError();
char yy[25];
sprintf(yy,"%d",errorx);
::MessageBoxA(0,yy,0,0);
closesocket(sClient);
return 0;
}

socks5authans *m_authans;
m_authans=(socks5authans *)buffer;

if(m_authans->Ver!=SOCKS_AUTH_VER && m_authans->Status!=SOCKS_AUTH_OK)
{

int errorx = GetLastError();
char yy[25];
sprintf(yy,"%d",errorx);
::MessageBoxA(0,yy,0,0);
closesocket(sClient);
return 0;
}
}

//char *DestAddr=m_DestAddr.GetBuffer(0);
//将目的IP和端口发给服务器
sock5req2 *m_proxyreq2;
unsigned short pt = htons(GameServerPort);
//in_addr goal=GetIpByHost(DestAddr);
in_addr goal;
goal.S_un.S_addr = inet_addr(GameServerIP);
int len;

m_proxyreq2 = (sock5req2 *)buffer;
m_proxyreq2->Ver=SOCKS_VER;
m_proxyreq2->Cmd=CMD_CONNECT;
m_proxyreq2->Rsv=FIELD_RSV;

if(goal.s_addr!=INADDR_NONE)
{
m_proxyreq2->Atyp=ATYP_IPV4;
CopyMemory(&m_proxyreq2->other[0],&goal,4);
CopyMemory(&m_proxyreq2->other[4],&pt,2);
len=10;
}
/*else
{
m_proxyreq2->Atyp=ATYP_DOMAINNAME;
len=m_DestAddr.GetLength();
m_proxyreq2->other[0]=len;
CopyMemory(&m_proxyreq2->other[1],DestAddr,len);
CopyMemory(&m_proxyreq2->other[1]+len,&pt,2);
len+=7;
}*/
//发送目标IP和端口
ret=send(sClient,buffer,len,0);
if(ret==SOCKET_ERROR)
{
int errorx = GetLastError();
char yy[25];
sprintf(yy,"%d",errorx);
::MessageBoxA(0,yy,0,0);
closesocket(sClient);
return 0;
}
//接收申请后的返回
ret=recv(sClient,buffer,bufferlen,0);
if(ret==SOCKET_ERROR)
{
int errorx = GetLastError();
char yy[25];
sprintf(yy,"%d",errorx);
::MessageBoxA(0,yy,0,0);
closesocket(sClient);
return 0;
}

sock5ans2 *m_proxyans2;
m_proxyans2 = (sock5ans2 *)buffer;

if(m_proxyans2->Rep!=REP_SUCCESS)
{
int errorx = GetLastError();
char yy[25];
sprintf(yy,"%d",errorx);
::MessageBoxA(0,yy,0,0);
closesocket(sClient);
return 0;
}
ul = 1;
ioctlsocket (sClient, FIONBIO, (unsigned long*)&ul);
//::MessageBoxA(0,"到此代理已经建立",0,0);
return true;
}
...全文
1487 点赞 收藏 11
写回复
11 条回复
新之野望游戏工作室 2012年11月25日
引用 8 楼 hurryboylqs 的回复:
我发段代码,你用这个函数在勾住的connect函数里调用就可以了: C/C++ code? 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747……
太阳哥,你的代码我还试,我自己的连接成功了。 我用我的代理打开11平台,可以登录,进房间,但是在启动游戏的时候提示超时。 什么原因? 还有我试试你的代码
回复 点赞
hurryboylqs 2012年11月25日
我发段代码,你用这个函数在勾住的connect函数里调用就可以了:

int connect_proxy(SOCKET sock, const char *lpszDestHost, int nDestPort, const char * lpszProxyAddress, const int nProxyPort, BOOL bNeedAuth, const char * lpszUserName, const char * lpszPassword)
{
	//connect to proxy
	char szBuffer[1024 + 1] = {""};
	int nLen = 0;

	SOCKADDR_IN saProxy;
	saProxy.sin_family = AF_INET;
	saProxy.sin_port = htons(nProxyPort);
	saProxy.sin_addr.s_addr= inet_addr(lpszProxyAddress);
	if (saProxy.sin_addr.S_un.S_addr == INADDR_NONE)
	{
		LPHOSTENT lphost;
		lphost = gethostbyname(lpszProxyAddress);
		if (lphost != NULL)
			saProxy.sin_addr.S_un.S_addr = ((LPIN_ADDR)lphost->h_addr)->s_addr;
		else
		{
			return -1;
		}
	} 

    int nRet = -1;
	if(connectT(sock, (sockaddr*)&saProxy, sizeof(sockaddr))==SOCKET_ERROR)
	{
		if (WSAGetLastError()==WSAEWOULDBLOCK)
		{
			fd_set      fdWrite;
			timeval     tv;
			FD_ZERO(&fdWrite);//初始化fd_set
			FD_SET(sock,&fdWrite);
			tv.tv_sec = 30;
			tv.tv_usec = 0;
			nRet = select(0,NULL,&fdWrite,NULL,&tv);
			if (nRet<=0)
			{
				return -1;
			}
		}
		else
		  return -1;
	}


		//auth
		nLen = 0;
		if(bNeedAuth)
		{
			szBuffer[0] = 5;
			szBuffer[1] = 2;
			szBuffer[2] = 0;
			szBuffer[3] = 2;
			nLen = 4;
			send(sock, szBuffer, nLen, 0);
			nLen = 2;
			fd_set      fdread;
			timeval     tv;
			FD_ZERO(&fdread);//初始化fd_set
			FD_SET(sock,&fdread);
			tv.tv_sec = 30;
			tv.tv_usec = 0;
			nRet = select(0,&fdread,NULL,NULL,&tv);
			if (nRet<=0)
			{
				return -1;
			}
			recv(sock, szBuffer, nLen, 0);
			if(szBuffer[0] == 5)
			{
				//need auth
				if(szBuffer[1] == 2)
				{
					szBuffer[0] = 1;
					nLen = strlen(lpszUserName);
					szBuffer[1] = nLen;
					strcpy(szBuffer+2, lpszUserName);
					nLen += 2;
					szBuffer[nLen] = strlen(lpszPassword);
					strcpy(szBuffer+nLen+1, lpszPassword);
					nLen = nLen + 1 + strlen(lpszPassword);
					send(sock, szBuffer, nLen, 0);
					nLen = 2;
					fd_set      fdread;
					timeval     tv;
					FD_ZERO(&fdread);//初始化fd_set
					FD_SET(sock,&fdread);
					tv.tv_sec = 30;
					tv.tv_usec = 0;
					nRet = select(0,&fdread,NULL,NULL,&tv);
					if (nRet<=0)
					{
						return -1;
					}
					recv(sock, szBuffer, nLen, 0);
					if(szBuffer[1] != 0)
					{
						return -1;
					}
				}
				else
				{
					if(szBuffer[1] != 0)
					{
						return -1;
					}
				}
			}
			else
				return -1;

		}
		else
		{
			szBuffer[0] = 5;
			szBuffer[1] = 1;
			szBuffer[2] = 0;
			nLen = 3;
			send(sock, szBuffer, nLen, 0);
			nLen = 2;
			fd_set      fdread;
			timeval     tv;
			FD_ZERO(&fdread);//初始化fd_set
			FD_SET(sock,&fdread);
			tv.tv_sec = 30;
			tv.tv_usec = 0;
			nRet = select(0,&fdread,NULL,NULL,&tv);
			if (nRet<=0)
			{
				return -1;
			}
			recv(sock, szBuffer, nLen, 0);
			if(szBuffer[0] != 5 || szBuffer[1] != 0)
			{
				return -1;
			}
		}
		//translate DestAddr
		szBuffer[0] = 5;
		szBuffer[1] = 1;
		szBuffer[2] = 0;
		szBuffer[3] = 3;//DOMAIN
		szBuffer[4] = strlen(lpszDestHost);//domain len
		strcpy(szBuffer+5, lpszDestHost);
		unsigned short uPort = htons(nDestPort);
		memcpy(szBuffer+5+strlen(lpszDestHost), &uPort, 2);
		nLen = 5 + strlen(lpszDestHost) + 2;
		send(sock, szBuffer, nLen, 0);
		nLen = 10;
		fd_set      fdread;
		timeval     tv;
		FD_ZERO(&fdread);//初始化fd_set
		FD_SET(sock,&fdread);
		tv.tv_sec = 30;
		tv.tv_usec = 0;
		nRet = select(0,&fdread,NULL,NULL,&tv);
		if (nRet<=0)
		{
			return -1;
		}
		recv(sock, szBuffer, nLen, 0);
		if(szBuffer[0] != 5 || szBuffer[1] != 0)
		{
			return -1;
		}

		return 0;
}
回复 点赞
新之野望游戏工作室 2012年11月25日
引用 5 楼 hurryboylqs 的回复:
一样的啊,send完就立即select探测是否有数据返回,有就recv接收
select 返回-1是错误,返回0超时,我在else里边写连接?!
回复 点赞
新之野望游戏工作室 2012年11月25日
引用 5 楼 hurryboylqs 的回复:
一样的啊,send完就立即select探测是否有数据返回,有就recv接收
就是说,连接socks5的时候也按照 你给我的connect的格式,用select实现异步?是吗 大哥?
回复 点赞
hurryboylqs 2012年11月25日
一样的啊,send完就立即select探测是否有数据返回,有就recv接收
回复 点赞
新之野望游戏工作室 2012年11月25日
引用 2 楼 hurryboylqs 的回复:
在Hook_Connect的时候,连接你的socket5服务器这么实现: C/C++ code? 123456789101112131415161718192021 if(connect(sock, (sockaddr*)&saProxy, sizeof(sockaddr))==SOCKET_ERROR) { if (WSAGetLastError()……
因为 连接socks5服务器 还有很多步骤,要send/recv 很多次,这些也可能报10035错误呢。这些怎么弄
回复 点赞
新之野望游戏工作室 2012年11月25日
引用 2 楼 hurryboylqs 的回复:
在Hook_Connect的时候,连接你的socket5服务器这么实现: C/C++ code? 123456789101112131415161718192021 if(connect(sock, (sockaddr*)&saProxy, sizeof(sockaddr))==SOCKET_ERROR) { if (WSAGetLastError()……
具体连接socks5 放到 哪里
回复 点赞
hurryboylqs 2012年11月25日
在Hook_Connect的时候,连接你的socket5服务器这么实现:


	if(connect(sock, (sockaddr*)&saProxy, sizeof(sockaddr))==SOCKET_ERROR)
	{
		if (WSAGetLastError()==WSAEWOULDBLOCK)
		{
			fd_set      fdWrite;
			timeval     tv;
			FD_ZERO(&fdWrite);//初始化fd_set
			FD_SET(sock,&fdWrite);
			tv.tv_sec = 30;
			tv.tv_usec = 0;
			nRet = select(0,NULL,&fdWrite,NULL,&tv);
			if (nRet<=0)
			{
				return -1;
			}
		}
		else
		  return -1;
	}
回复 点赞
新之野望游戏工作室 2012年11月25日
代码在公司,这是 家里没优化的,大神帮忙看看,怎么才能在connect里边 处理好这个异步。 我直接修改了。貌似不行
回复 点赞
新之野望游戏工作室 2012年11月25日
大哥,用你的代码也是 启动游戏的时候提示超时。 是不是 是游戏的问题
回复 点赞
新之野望游戏工作室 2012年11月25日
ConnnectT()是什么函数。
回复 点赞
发动态
发帖子
网络编程
创建于2007-09-28

7880

社区成员

6.4w+

社区内容

VC/MFC 网络编程
社区公告
暂无公告