icmp篇 突破TCP-IP过滤/防火墙进入内网( 二 )


同时 , QQ客户端也在端口4000(假设为非内网主机上的第一个QQ)监听来自QQicmp(l)的数据报 。
我们可以看到 , 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数据然后以ICMP数据报的形式发送到QQicmp(g) , 在此需要自己构造ICMP echo Reply数据报,并将接收到的UDP数据报填充到ICMP报文的数据段 ,
sock[0][1]=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP); //创建ICMP协议的原始套接字 , 用来发送自定义数据报
bind(sock[0][1],(struct sockaddr *)&sin[0][2],addrlen); //并捆绑到指定地址 , 指定端口上icmphdr.type=0; //类型:echo reply
icmphdr.code=0; //代码
icmphdr.id=htons(65456); //序号
icmphdr.seq=htons(65456); //标志符 , 用以过滤数据报
icmphdr.checksum=0;if(istbcs==0) //填充ICMP数据报头部
{
memset(msgsend,0,sizeof(msgsend));
memcpy(msgsend,&icmphdr,sizeof(icmphdr));
istbcs =sizeof(icmphdr);
}
memcpy(msgsend istbcs,msgrecv,iret); //将接收到的UDP数据报的内容提取 , 准备以ICMP的形式发送iret=sendto(sock[0][1],msgsend,istbcs,0,(struct sockaddr *)&sin[0][3],addrlen); //发送到网关
同时 , 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 dwbufferlen[10];
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相关文件里就有 , 或安装SDKiret=recvfrom(sock[1][0],msgrecv,sizeof(msgrecv),0,(struct sockaddr *)&temps,&addrlen); //接收所有数据报
if(iret<=28) //文件过小
{
break;
}
if((icmphdr->type!=0) || (icmphdr->code!=0) || ((icmphdr->id)!=htons(65456)) || ((icmphdr->seq)!=htons(65456)))
//不符合接收条件
{
break;
}memcpy(msgsend istbcs,msgrecv,iret); //将接收到的ICMP数据报的内容提取 , 准备以UDP的形式发送
解包后 , 用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客户端我们创建了两个线程在两个方向(udp-->icmp,icmp-->udp)上接收并传送数据 , 如果某个线程出错 , 就重新创建该线程 ,
而未出错的线程则保持不变 ,
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发送数据的线程1while(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(l)的工作原理 , QQicmp(g)运行在网关上 , 虽然模式不同 , 但工作原理是一样的 , 只是数据报的流动方向有点差异 。

推荐阅读