以下我是抓取的QQ客户端向服务器发送的UDP包
00000000 02 11 5B 00 C6 38 A9 23 D8 07 B9 04 9A BA 69 A6 ..[..8.# ......i.
00000010 F4 AF 1E 60 BD B0 AE 56 DC FE F9 03 ...`...V ....
00000000 02 11 5B 00 C6 38 A9 D0 82 3C AD 82 7F FA 54 A9 ..[..8.. .<.. .T.
00000010 58 12 86 0B D4 89 50 51 12 69 C9 48 34 94 24 BB X.....PQ .i.H4.$.
00000020 24 15 A6 B1 79 2C FC 03
在中国协议分析网上看到了相关的解释
02 开始是payload
11 5B 是qq版本号
00 C6就是心跳信息命令代码,(这个数据是会变化的)
38 A9 是令牌号(也会变化,好像是每次加1,有待考证)
23 D8 07 B9是QQ号
由上面的包格式我们不难得到局域网中其它用户的QQ号,将网卡设为混合模式,监听所有的数据,对UDP包进行分析,若端口在4000-4007之间,我们认定为QQ数据包.可按上面格式分析出QQ号码.C++代码如下:
#include
#include "stdio.h"
#pragma comment(lib,"WS2_32")
#define SIO_RCVALL 0x98000001
//IP 头 20字节
typedef struct _IPHeader
{
UCHAR iphVerLen; //版本号和头长度
UCHAR ipTOS; //服务类型
USHORT ipLength; //封包总长度,即整个IP报的长度
USHORT ipID; //封包标识,惟一标识发送的第一个数据报
USHORT ipFlags; //标志
UCHAR ipTTL; //生存时间
UCHAR ipProtocol; //协议,TCP UDP ICMP等
USHORT ipChecksum; //校验和
ULONG ipSource; //源IP地址
ULONG ipDestination; //目的IP地址
}IPHeader,*PIPHeader;
//TCP 头结构 20字节
typedef struct _TCPHeader
{
USHORT sourcePort; //16bits 源端口号
USHORT destinationPort; //16bits 目的端口号
ULONG sequenceNumber; //32bits 序列号
ULONG acknowledgeNumber; //32bits 确认号
UCHAR dataoffset; //4bits 首部长度
UCHAR flags; //6bits 标志位
USHORT windows; //16bits 窗口大小
USHORT checksum; //16bits 校验和
USHORT urgentPointer; //16bits 紧急数据偏移量
}TCPHeader,*PTCPHeader;
//UDP 包头
typedef struct _UDPHeader
{
USHORT sourcePort;
USHORT destinationPort;
USHORT len;
USHORT checksum;
}UDPHeader,*PUDPHeader;
//加载网络库
void InitWinSock()
{
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
printf("Windows sockets 2.2 startup failed!");
}
}
//将网络顺序转换成本机顺序
int ToLocal(int net)
{
byte bb[4];
int local;
bb[0]=(byte)(net&0xff);
bb[1]=(byte)((net>>8)&0xff);
bb[2]=(byte)((net>>16)&0xff);
bb[3]=(byte)((net>>24)&0xff);
local=(int)((bb[0]<<24)|(bb[1]<<16)|(bb[2]<<8)|(bb[3]));
return local;
}
void DecodeUDPPacket(char* pData,in_addr source,in_addr dest)
{
//得到源地址和目的地址
UDPHeader *pUDPHdr=(UDPHeader *)pData;
char szSourceIp[32],szDestIp[32];
strcpy(szSourceIp,::inet_ntoa(source));
strcpy(szDestIp,::inet_ntoa(dest));
//从4000开始为QQ使用端口,具体到多少,不知道,先定到7吧
switch(::ntohs(pUDPHdr->sourcePort))
{
case 4000:
case 4001:
case 4002:
case 4003:
case 4004:
case 4005:
case 4006:
case 4007:
int qq[1];
memcpy(qq,pData+4*sizeof(USHORT)+7,4);//具体数据见我另一篇文章,偏移量7处为QQ密码
printf("源地址:%s 端口:%d QQ:%d 服务器:%s/n",szSourceIp,ntohs(pUDPHdr->sourcePort),ToLocal(qq[0]),szDestIp);
break;
default:break;
}
}
void DecodeIPPacket(char *pData)
{
IPHeader *pIPHdr=(IPHeader *)pData;
in_addr source,dest;
source.S_un.S_addr=pIPHdr->ipSource;
dest.S_un.S_addr=pIPHdr->ipDestination;
int nHeaderLen=(pIPHdr->iphVerLen&0xf)*sizeof(ULONG);
switch(pIPHdr->ipProtocol)
{
case IPPROTO_TCP:
break;
case IPPROTO_UDP:
DecodeUDPPacket(pData+nHeaderLen,source,dest);
break;
default:break;
}
}
void main()
{
InitWinSock();
SOCKET sRaw=socket(AF_INET,SOCK_RAW,IPPROTO_IP);
//获取本机IP
char szHostName[56];
SOCKADDR_IN addr_in;
struct hostent *pHost;
gethostname(szHostName,56);
if((pHost=gethostbyname((char *)szHostName))==NULL)
return;
//在调用ioctl之前,绑定
addr_in.sin_family=AF_INET;
addr_in.sin_port=htons(0);
memcpy(&addr_in.sin_addr.S_un.S_addr,pHost->h_addr_list[0],pHost->h_length);
printf("开始监听局域网中的QQ...../n");
if(bind(sRaw,(PSOCKADDR)&addr_in,sizeof(addr_in))==SOCKET_ERROR)
{
printf("Bind error!/n");
return;
}
//设置SIO_RCVAL控制代码,以便接收所有IP包
DWORD dwValue=1;
if(ioctlsocket(sRaw,SIO_RCVALL,&dwValue)!=0)
return;
//开始收封包
char buf[1024];
int nRet;
while(true)
{
nRet=recv(sRaw,buf,1024,0);
if(nRet>0)
{
DecodeIPPacket(buf);
}
}
closesocket(sRaw);
}
为原创,若转载请注明出处.