QQ客户端 〈 UDP 〉 QQicmp(l) 〈 ICMP 〉 QQicmp(g) 〈 UDP 〉Tencent服务器
-----〈----- -----〈----- -----〈-----
{
unsigned char h_lenver; //头部长度及版本
unsigned char tos; //服务类型
unsigned short total_len; //报文总长度
unsigned short ident; //信息包标志
unsigned short frag_and_flags; //标志及分段偏移量
unsigned char ttl; //生命周期
unsigned char proto; //协议类型
unsigned short checksum; //IP校验和
unsigned int sourceip; //源IP地址
unsigned int destip; //目的IP地址
}ipheader;
{
unsigned char type; //ICMP类型 0-〉回送应答 8-〉回送请求
unsigned char code; //代码
unsigned short checksum; //校验和
unsigned short seq; //序号
unsigned short id; //标识符
}icmpheader;
{
unsigned long cksum=0;
while(size〉0) //各位求和
{
cksum+=*buffer++;
size-=sizeof(unsigned short);
}
if(size)
cksum+=*(unsigned char *)buffer;
cksum=(cksum〉〉16)+(cksum & 0xffff);
cksum+=(cksum〉〉16);
return (unsigned short)(~cksum); //再求补
}
我们可以看到,QQicmp(l)的主要作用就是将接收到了来自QQ客户端的UPD数据报,sock[0][0]=socket(AF_INET,SOCK_DGRAM,0); //创建基于UDP协议的套接字bind(sock[0][0],(struct sockaddr *)&sin[0][1],addrlen); //绑定到指定地址,指定端口上iret=recvfrom(sock[0][0],msgrecv,sizeof(msgrecv),0,(struct sockaddr *)&tempr,&addrlen); //接收来自QQ客户端的UDP数据
sock[0][1]=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP); //创建ICMP协议的原始套接字,用来发送自定义数据报
bind(sock[0][1],(struct sockaddr *)&sin[0][2],addrlen); //并捆绑到指定地址,指定端口上
icmphdr.code=0; //代码
icmphdr.id=htons(65456); //序号
icmphdr.seq=htons(65456); //标志符,用以过滤数据报
icmphdr.checksum=0;
{
memset(msgsend,0,sizeof(msgsend));
memcpy(msgsend,&icmphdr,sizeof(icmphdr));
istbcs+=sizeof(icmphdr);
}
memcpy(msgsend+istbcs,msgrecv,iret); //将接收到的UDP数据报的内容提取,准备以ICMP的形式发送
同时,QQicmp(l)监听通过本机的IP数据报,筛选出来自QQicmp(g)及网关的数据报,
sock[1][0]=socket(AF_INET,SOCK_RAW,IPPROTO_IP); //创建原始套接字,接收所有的IP数据报
bind(sock[1][0],(struct sockaddr *)&sin[1][1],addrlen); //绑定到指定地址,端口
DWORD dwbufferinlen=1;
DWORD dwbytesreturned=0;
WSAIoctl(sock[1][0],SIO_RCVALL,&dwbufferinlen,sizeof(dwbufferinlen),&dwbufferlen,sizeof(dwbufferlen),&dwbytesreturned,NULL,NULL);
//设置为接收所有的数据报,需要mstcpip.h头文件,T-QQ相关文件里就有,或安装SDK
if(iret〈=28) //文件过小
{
break;
}
if((icmphdr-〉type!=0) || (icmphdr-〉code!=0) || ((icmphdr-〉id)!=htons(65456)) || ((icmphdr-〉seq)!=htons(65456))) //不符合接收条件
{
break;
}
解包后,用UDP数据报将接收到的来自网关的数据发送到QQ客户端,
idx=28; //ICMP数据报的前20字节是IP头部,接着的8字节是ICMP头部,
iret=sendto(sock[1][1],&msgsend[idx],ileft,0,(struct sockaddr *)&sin[1][3],addrlen); //发送到QQ客户端
hthreads[0]=CreateThread(NULL,0,u2i,(LPVOID)0,NULL,&hthreadid[0]); //创建udp接收数据,icmp发送数据的线程0
hthreads[1]=CreateThread(NULL,0,i2u,(LPVOID)1,NULL,&hthreadid[1]); //创建icmp接收数据,udp发送数据的线程1
{
dwret=WaitForMultipleObjects(2,hthreads,false,INFINITE); //等待某个线程的结束
if(dwret==WAIT_FAILED) //等待出错
{
cout〈〈“WaitForMultipleObjects Error: “〈 return -1;
}
log=dwret-WAIT_OBJECT_0;
if(log==0) //线程0结束
{
CloseHandle(hthreads[0]); //关闭线程handle
closesocket(sock[0][1]); //关闭套接字
hthreads[0]=CreateThread(NULL,0,u2i,(LPVOID)0,NULL,&hthreadid[0]); //重新创建线程0
}
else if(log==1) //线程1结束
{
CloseHandle(hthreads[1]);
closesocket(sock[1][0]);
hthreads[1]=CreateThread(NULL,0,i2u,(LPVOID)1,NULL,&hthreadid[1]);
}
QQicmp之源代码如下:
#include
#include
#include
#define maxsize 64*1024
{
unsigned char h_lenver;
unsigned char tos;
unsigned short total_len;
unsigned short ident;
unsigned short frag_and_flags;
unsigned char ttl;
unsigned char proto;
unsigned short checksum;
unsigned int sourceip;
unsigned int destip;
}ipheader;
{
unsigned char type;
unsigned char code;
unsigned short checksum;
unsigned short seq;
unsigned short id;
}icmpheader;
{
unsigned long cksum=0;
while(size〉0)
{
cksum+=*buffer++;
size-=sizeof(unsigned short);
}
if(size)
cksum+=*(unsigned char *)buffer;
cksum=(cksum〉〉16)+(cksum & 0xffff);
cksum+=(cksum〉〉16);
return (unsigned short)(~cksum);
}
{
cout〈〈“ ---------------------------------------------------\n“;
cout〈〈“ || || \n“;
cout〈〈“ || QQicmp (ICMP转发) || \n“;
cout〈〈“ || || \n“;
cout〈〈“ || Author:TOo2y SafeChina || \n“;
cout〈〈“ || || \n“;
cout〈〈“ ---------------------------------------------------“〈 }
{
cout〈〈“\nUsage:\r\n\tQQicmp -l[-g] ip port“〈 cout〈〈“\tQQicmp -h“〈 cout〈〈“Example:\r\n“;
cout〈〈“\tQQicmp -l 192.168.0.1 8000“〈 cout〈〈“\tQQicmp -g 61.144.238.156 11282“〈 cout〈〈“Attention:“〈 cout〈〈“\t选项 -l : 运行于本机上,ip填网关地址,port为本地监听客户端端口;“〈 cout〈〈“\t选项 -g : 运行于网关上,ip填腾讯服务器地址,port为自定义端口;“〈 cout〈〈“\t选项 -h : 查看相关帮助文件。“〈 }
SOCKET sock[2][2];
struct sockaddr_in sin[2][4],sag,sal,tempr,temps;
{
UNREFERENCED_PARAMETER(num);
char msgrecv[maxsize]={0},msgsend[maxsize]={0};
fd_set fdread,fdwrite;
int iret,ret,istbcs=0;
struct icmpheader icmphdr;
icmphdr.code=0;
icmphdr.id=htons(65456);
icmphdr.seq=htons(65456);
icmphdr.type=0;
icmphdr.checksum=checksum((unsigned short *)&icmphdr,sizeof(icmphdr));
{
cout〈〈“Socket sock[0][1] Error: “〈 return -1;
}
if(bind(sock[0][1],(struct sockaddr *)&sin[0][2],addrlen)==SOCKET_ERROR)
{
cout〈〈“Bind sock[0][1] Error: “〈 return -1;
}
{
FD_ZERO(&fdread);
FD_ZERO(&fdwrite);
FD_SET(sock[0][0],&fdread);
FD_SET(sock[0][1],&fdwrite);
{
cout〈〈“Select in thread 0 Error: “〈 break;
}
if(ret〉0)
{
if(FD_ISSET(sock[0][0],&fdread))
{
iret=recvfrom(sock[0][0],msgrecv,sizeof(msgrecv),0,(struct sockaddr *)&tempr,&addrlen);
if(iret==SOCKET_ERROR)
{
cout〈〈“\nRecvfrom sock[0][0] Error: “〈 break;
}
else if(iret==0)
{
cout〈〈“Iret==0“〈 break;
}
cout〈〈“\nThread 0 Recv “〈 if(istbcs==0)
{
memset(msgsend,0,sizeof(msgsend));
memcpy(msgsend,&icmphdr,sizeof(icmphdr));
istbcs+=sizeof(icmphdr);
}
memcpy(msgsend+istbcs,msgrecv,iret);
istbcs+=iret;
memset(msgrecv,0,sizeof(msgrecv));
}
else if(FD_ISSET(sock[0][1],&fdwrite))
{
{
{
cout〈〈“sin[0][3].sin_addr.s_addr==htonl(0)“〈 istbcs=0;
memset(msgsend,0,sizeof(msgsend));
break;
}
if(iret==SOCKET_ERROR)
{
cout〈〈“Sendto sock[0][1] Error: “〈 break;
}
cout〈〈“Thread 0 send “〈 istbcs-=iret;
}
memset(msgsend,0,sizeof(msgsend));
istbcs=0;
}
Sleep(20);
}
}
return 0;
}
DWORD WINAPI i2u(LPVOID num)
{
UNREFERENCED_PARAMETER(num);
fd_set fdread,fdwrite;
char msgrecv[maxsize]={0},msgsend[maxsize]={0};
int ret,iret,idx,istbcs=0,ileft;
DWORD dwbufferlen[10];
DWORD dwbufferinlen=1;
DWORD dwbytesreturned=0;
struct ipheader *iphdr;
struct icmpheader *icmphdr;
{
cout〈〈“Socket sock[1][0] Error: “〈 return -1;
}
if(bind(sock[1][0],(struct sockaddr *)&sin[1][1],addrlen)==SOCKET_ERROR)
{
cout〈〈“Bind sock[1][0] Error: “〈 return -1;
}
iphdr=(struct ipheader *)msgrecv;
icmphdr=(struct icmpheader *)(msgrecv+sizeof(struct ipheader));
{
FD_ZERO(&fdread);
FD_ZERO(&fdwrite);
FD_SET(sock[1][0],&fdread);
FD_SET(sock[1][1],&fdwrite);
{
cout〈〈“Select in thread 1 Error: “〈 break;
}
if(ret〉0)
{
if(FD_ISSET(sock[1][0],&fdread))
{
{
iret=recvfrom(sock[1][0],msgrecv,sizeof(msgrecv),0,(struct sockaddr *)&temps,&addrlen);
if(iret==SOCKET_ERROR)
{
cout〈〈“Recvfrom sock[1][0] Error: “〈 break;
}
{
break;
}
if((icmphdr-〉type!=0) || (icmphdr-〉code!=0) || ((icmphdr-〉id)!=htons(65456)) || ((icmphdr-〉seq)!=htons(65456)))
{
break;
}
if((sin[1][0].sin_addr.s_addr!=htonl(0)) && (sin[1][0].sin_addr.s_addr!=temps.sin_addr.s_addr))
break;
}
else if(sin[1][0].sin_addr.s_addr==htonl(0))
{
sin[1][0].sin_addr.s_addr=temps.sin_addr.s_addr;
sin[0][3].sin_addr.s_addr=temps.sin_addr.s_addr;
cout〈〈“sin[0][3] ==〉 “〈 }
memcpy(msgsend+istbcs,msgrecv,iret);
istbcs+=iret;
memset(msgrecv,0,sizeof(msgrecv));
}
}
else if(FD_ISSET(sock[1][1],&fdwrite))
{
ileft=istbcs-28;
idx=28;
while(ileft〉0)
{
iret=sendto(sock[1][1],&msgsend[idx],ileft,0,(struct sockaddr *)&sin[1][3],addrlen);
if(iret==SOCKET_ERROR)
{
cout〈〈“Sendto sock[1][1] Error: “〈 break;
}
cout〈〈“Thread 1 send “〈 ileft-=iret;
idx+=iret;
}
istbcs=0;
memset(msgsend,0,sizeof(msgsend));
}
Sleep(20);
}
}
return 0;
}
int main(int argc,char *argv[])
{
WSADATA wsa;
BOOL gl;
HANDLE hthreads[2];
DWORD hthreadid[2];
struct hostent *hp;
char cname[100];
int dwret,log;
start();
{
if(strcmp(argv[1],“-h“)==0)
{
ShellExecute(NULL,“open“,“help.txt“,NULL,NULL,SW_SHOWMAXIMIZED);
return 0;
}
else
{
usage();
return -1;
}
}
else if(argc!=4)
{
usage();
return -1;
}
if(!strcmp(argv[1],“-g“))
gl=true;
else if(!strcmp(argv[1],“-l“))
gl=false;
else
{
usage();
return -1;
}
{
cout〈〈“WSAStartup Error: “〈 return -1;
}
hp=gethostbyname(cname);
for(int ipnum=0;hp-〉h_addr_list[ipnum]!=NULL;ipnum++)
sag.sin_addr=*(in_addr *)hp-〉h_addr_list[ipnum];
sag.sin_family=AF_INET;
sag.sin_port=htons(65456);
if(ipnum〉1)
sal.sin_addr=*(in_addr *)hp-〉h_addr_list[ipnum-2];
{
sin[0][0].sin_addr.s_addr=inet_addr(argv[2]);
sin[0][0].sin_family=AF_INET;
sin[0][0].sin_port=htons(8000);
sin[0][1].sin_family=AF_INET;
sin[0][1].sin_port=htons(atoi(argv[3]));
sin[0][3].sin_family=AF_INET;
}
else
{
sin[0][0].sin_addr.s_addr=inet_addr(“127.0.0.1“);
sin[0][0].sin_family=AF_INET;
sin[0][0].sin_port=htons(4000);
sin[0][1].sin_family=AF_INET;
sin[0][1].sin_port=htons(atoi(argv[3]));
sin[0][3].sin_family=AF_INET;
}
sin[1][0]=sin[0][3];
sin[1][1]=sin[0][2];
sin[1][2]=sin[0][1];
sin[1][3]=sin[0][0];
{
cout〈〈“Socket sock[0][0] Error: “〈 return -1;
}
if(bind(sock[0][0],(struct sockaddr *)&sin[0][1],addrlen)==SOCKET_ERROR)
{
cout〈〈“Bind sock[0][0] Error: “〈 return -1;
}
sock[1][1]=sock[0][0];
hthreads[0]=CreateThread(NULL,0,u2i,(LPVOID)0,NULL,&hthreadid[0]);
hthreads[1]=CreateThread(NULL,0,i2u,(LPVOID)1,NULL,&hthreadid[1]);
while(1)
{
dwret=WaitForMultipleObjects(2,hthreads,false,INFINITE);
if(dwret==WAIT_FAILED)
{
cout〈〈“WaitForMultipleObjects Error: “〈 return -1;
}
log=dwret-WAIT_OBJECT_0;
if(log==0)
{
CloseHandle(hthreads[0]);
closesocket(sock[0][1]);
hthreads[0]=CreateThread(NULL,0,u2i,(LPVOID)0,NULL,&hthreadid[0]);
}
else if(log==1)
{
CloseHandle(hthreads[1]);
closesocket(sock[1][0]);
hthreads[1]=CreateThread(NULL,0,i2u,(LPVOID)1,NULL,&hthreadid[1]);
}
else
{
for(int no1=0;no1〈2;no1++)
{
CloseHandle(hthreads[no1]);
for(int no2=0;no2〈2;no2++)
closesocket(sock[no1][no2]);
}
}
}
WSACleanup();
return 0;
}