QQ心跳包格式分析 监听局域网QQ号代码

以下我是抓取的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);

}

为原创,若转载请注明出处.

你可能感兴趣的:(QQ心跳包格式分析 监听局域网QQ号代码)