利用libpcap抓取QQ号码信息

  最近想在QQ登录时把QQ号码信息记录下来,百度了很多都没有找到具体方式,最近用Wireshark分析报文+libpcap库嗅探实现了这个小功能。

通讯背景:

  QQ客户端在通讯时使用UDP协议,其中数据消息报文为UDP协议,控制报文为OICQ协议(UDP协议的一种封装),控制报文命令常见如下(括号内为改命令在OICQ报文中对应二进制编码的十进制表示):

"log out(1)",
"Heart Message(2)",
"Set status(13)",
"Receive message(23)",
"Request KEY(29)",                //登录时
"Get friend online(39)",
"Group name operation(60)",
"MEMO Operation(62)",
"Download group friend(88)",
"Get level(92)",
"Request login(98)",              //离线时
"Request extra information(101)",
"Signature operation(103)",
"Get status of friend(129)",
"Get friend‘s status of group(181)",

QQ客户端使用的端口为4000,服务器的端口为8000,当存在多个QQ客户端时,端口号从4000依次向上累加。

报文分析:

  在Windows下,由Wireshark抓包分析,QQ在登录与运行时,会向服务器发送UDP以及OICQ报文,这里假定一台机器上少于100个QQ号码登录,定义过滤器如下:

从oicq过滤中发现可以百分百命中含有QQ号码的报文,确定位置在以太网数据包的第49~52字节,以4字节的无符号整形数表示。但libpcap的过滤器仅支持到udp的过滤,于是按下面的filter来过滤测试:

发现,在udp数据包同样的位置也存放有明文的qq号码信息,于是确认了抓取条件(udp.srcport<4100 是为了避免某些不符合规则报文信息的干扰)。

调试代码:

  运行环境为Linux,需要安装libpcap,并且在链接时 -lpcap。

  头文件:

 1 #ifndef __SNIFFER_H__
 2 #define __SNIFFER_H__
 3
 4 #include <pcap.h>
 5 #include <stdio.h>
 6 #include <string.h>
 7 #include <stdlib.h>
 8 #include <ctype.h>
 9 #include <errno.h>
10 #include <sys/types.h>
11 #include <sys/socket.h>
12 #include <netinet/in.h>
13 #include <arpa/inet.h>
14 #include <time.h>
15
16 /* 以太网帧头部 */
17 #define ETHER_ADDR_LEN 6
18
19 struct sniff_ethernet{
20     u_char ether_dhost[ETHER_ADDR_LEN]; /* 目的主机的地址 */
21     u_char ether_shost[ETHER_ADDR_LEN]; /* 源主机的地址 */
22     u_short ether_type;
23 };
24
25 /* IP数据包的头部 */
26 struct sniff_ip{
27     #if BYTE_ORDER == LITTLE_ENDIAN
28     u_int ip_hl:4,                         /* 头部长度 */
29     ip_v:4;                             /* 版本号 */
30     #if BYTE_ORDER == BIG_ENDIAN
31     u_int ip_v:4,                         /* 版本号 */
32     ip_hl:4;                             /* 头部长度 */
33     #endif
34     #endif /* not _IP_VHL */
35     u_char ip_tos;                         /* 服务的类型 */
36     u_short ip_len;                     /* 总长度 */
37     u_short ip_id;                         /* 包标志号 */
38     u_short ip_off;                     /* 碎片偏移 */
39     #define IP_RF 0x8000                 /* 保留的碎片标志 */
40     #define IP_DF 0x4000                 /* dont fragment flag */
41     #define IP_MF 0x2000                 /* 多碎片标志*/
42     #define IP_OFFMASK 0x1fff             /* 分段位 */
43     u_char ip_ttl;                         /* 数据包的生存时间 */
44     u_char ip_p;                         /* 所使用的协议 */
45     u_short ip_sum;                     /* 校验和 */
46     struct in_addr ip_src,ip_dst;         /* 源地址、目的地址*/
47 };
48
49 /* TCP 数据包的头部 */
50 typedef u_int tcp_seq;
51
52 struct sniff_tcp{
53     u_short th_sport;                     /* 源端口 */
54     u_short th_dport;                     /* 目的端口 */
55     tcp_seq th_seq;                     /* 包序号 */
56     tcp_seq th_ack;                     /* 确认序号 */
57     #if BYTE_ORDER == LITTLE_ENDIAN
58     u_int th_x2:4,                         /* 还没有用到 */
59     th_off:4;                             /* 数据偏移 */
60     #endif
61     #if BYTE_ORDER == BIG_ENDIAN
62     u_int th_off:4,                     /* 数据偏移*/
63     th_x2:4;                             /* 还没有用到 */
64     #endif
65     u_char th_flags;
66     #define TH_FIN 0x01
67     #define TH_SYN 0x02
68     #define TH_RST 0x04
69     #define TH_PUSH 0x08
70     #define TH_ACK 0x10
71     #define TH_URG 0x20
72     #define TH_ECE 0x40
73     #define TH_CWR 0x80
74     #define TH_FLAGS (TH_FINTH_SYNTH_RSTTH_ACKTH_URGTH_ECETH_CWR)
75     u_short th_win;                        /* TCP滑动窗口 */
76     u_short th_sum;                     /* 头部校验和 */
77     u_short th_urp;                     /* 紧急服务位 */
78 };
79
80
81 #endif /* __SNIFFER_H__ */

  源码:

 1 #include "sniffer.h"
 2
 3 void getPacket(u_char *arg, const struct pcap_pkthdr *pkthdr, const u_char *packet)
 4 {
 5     static int id = 0;
 6     const struct sniff_ethernet *ethernet;             /* 以太网帧头部*/
 7     const struct sniff_ip *ip;                         /* IP包头部 */
 8     const struct sniff_tcp *tcp;                     /* TCP包头部 */
 9     const char *payload;                             /* 数据包的有效载荷*/
10
11     int size_ethernet = sizeof(struct sniff_ethernet);
12     int size_ip = sizeof(struct sniff_ip);
13     int size_tcp = sizeof(struct sniff_tcp);
14
15     ethernet = (struct sniff_ethernet*)(packet);
16     ip = (struct sniff_ip*)(packet + size_ethernet);
17     tcp = (struct sniff_tcp*)(packet + size_ethernet + size_ip);
18     payload = (u_char *)(packet + size_ethernet + size_ip + size_tcp);
19
20     int sport = ntohs(tcp->th_sport);
21     int dport = ntohs(tcp->th_dport);
22
23     //for QQ
24     if (dport != 8000 || sport > 4100)
25     {
26         return ;
27     }
28     printf("packet: %d\n", ++id);
29     printf("%s:%d -> ", inet_ntoa(ip->ip_src), sport);
30     printf("%s:%d \n", inet_ntoa(ip->ip_dst), dport);
31     printf("QQ:%d\n", packet[49]*16*16*16*16*16*16 +
32                       packet[50]*16*16*16*16 +
33                       packet[51]*16*16 +
34                       packet[52]);
35
36     /*for test
37     int i;
38     for(i=0; i<pkthdr->len; ++i)
39     {
40         printf(" %02x", packet[i]);
41         if ((i + 1) % 16 == 0 )
42         {
43             printf("\n");
44         }
45         if ((i + 1) % 8 == 0 )
46         {
47             printf(" ");
48         }
49     }*/
50
51     printf("\n");
52 }
53
54 int main(int argc, char **argv)
55 {
56     pcap_t *devic = NULL;
57     char *devStr = NULL;
58     char errBuf[PCAP_ERRBUF_SIZE] = "";
59     char *filter_rule = "dst port 8000";
60     struct bpf_program filter;
61
62     devStr = pcap_lookupdev(errBuf);
63     if (!devStr)
64     {
65         printf("Error: %s\n", errBuf);
66         return -1;
67     }
68     printf("Success: %s\n", devStr);
69
70     devic = pcap_open_live(devStr, 65535, 1, 0, errBuf);
71     if (!devic)
72     {
73         printf("Error: %s\n", errBuf);
74         return -1;
75     }
76
77     pcap_compile(devic, &filter, filter_rule, 1, 0);
78     pcap_setfilter(devic, &filter);
79
80     pcap_loop(devic, -1, getPacket, NULL);
81
82     pcap_close(devic);
83
84     return 0;
85 }
86     

测试结果:

  

备注:

  在测试时发现,极少的情况OICQ协议里,含有"MEMO Operation(62)"的数据包中,会概率性出现非该测试QQ的另一个号码,原因未知... 当时忘了记录,最近实验了几次又一直没出现,没有图片了。

时间: 2024-08-28 21:14:22

利用libpcap抓取QQ号码信息的相关文章

利用 selenium 抓取 淘宝信息

import lxml from bs4 import BeautifulSoup import time from selenium import webdriver import re driver = webdriver.PhantomJS() driver.set_window_size(1600,20000) driver.get("https://item.taobao.com/item.htm?spm=2013.1.0.0.bLyAul&id=17676925595&quo

利用RCurl抓取电影团购信息

1 抓取的网址是360团购 http://tuan.360.cn/bei_jing/c_0.html?kw=电影&pageno=1#tuanFilter 2 利用firefox的FireBug插件分析其源代码,如下所示: "//*/h3[@class='desc']" 匹配电影院名称 "//*/span [@class='discount']" 匹配原价 "//*/span [@class='price']" 匹配优惠价 "//

WireShark抓取QQ邮箱

WireShark抓取QQ邮箱 实验环境:MacOS + WireShark 1.QQ邮箱是网址是基于HTTPS协议的 HTTPS(Hypertext Transfer Protocol over Secure Socket Layer)能够加密信息,由HTTP+TLS/SSL组成,在原本的HTTP协议上增加了一层加密信息模块,服务端和客户端的信息传输都要经过TLS进行加密,所以传输的数据都是加密后的数据. 2.TLS/SSL 简介 握手过程: 1.初始化阶段.客户端创建随机数,发送Client

通过Scrapy抓取QQ空间

毕业设计题目就是用Scrapy抓取QQ空间的数据,最近毕业设计弄完了,来总结以下: 首先是模拟登录的问题: 由于Tencent对模拟登录比较讨厌,各个防备,而本人能力有限,所以做的最简单的,手动登录后,获得Cookie信息,然后携带访问. 其次是数据接口: 通过对QQ空间的网页分析,数据主要是通过Json的形式返回.选择了两个数据接口进行数据抓取 每个QQ的详细信息接口: "http://user.qzone.qq.com/p/base.s8/cgi-bin/user/cgi_userinfo_

Python爬虫实战---抓取图书馆借阅信息

原创作品,引用请表明出处:Python爬虫实战---抓取图书馆借阅信息 前段时间在图书馆借了很多书,借得多了就容易忘记每本书的应还日期,老是担心自己会违约,影响日后借书,而自己又懒得总是登录到学校图书馆借阅系统查看,于是就打算写一个爬虫来抓取自己的借阅信息,把每本书的应还日期给爬下来,并写入txt文件,这样每次忘了就可以打开该txt文件查看,每次借阅信息改变了,只要再重新运行一遍该程序,原txt文件就会被新文件覆盖,里面的内容得到更新. 用到的技术: Python版本是 2.7 ,同时用到了ur

对比使用Charles和Fiddler两个工具及利用Charles抓取https数据(App)

原文:https://www.cnblogs.com/qingqing-919/p/8444816.html 对比使用Charles和Fiddler两个工具及利用Charles抓取https数据(App) 实验目的:对比使用Charles和Fiddler两个工具 实验对象:车易通App,易销通App 实验结果: 1.     接口数据呈现方式对比: (1) Charles树状结构呈现于屏幕,清晰易区分 (2)Fiddler默认按时间倒叙呈现所有接口数据,不易区分 个人觉得图形界面上Charles

c#实现从其他网站抓取imei码信息,手工输入验证码

阅读全文:http://www.yzswyl.cn/blread-1603.html 功能:从其他网站手工输入验证码并抓取手机IMEI信息 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.For

手把手教你使用Python抓取QQ音乐数据!

[一.项目目标] 通过手把手教你使用Python抓取QQ音乐数据(第一弹)我们实现了获取 QQ 音乐指定歌手单曲排行指定页数的歌曲的歌名.专辑名.播放链接. 通过手把手教你使用Python抓取QQ音乐数据(第二弹)我们实现了获取 QQ 音乐指定歌曲的歌词和指定歌曲首页热评. 通过手把手教你使用Python抓取QQ音乐数据(第三弹)我们实现了获取更多评论并生成词云图. 此次我们将将三个项目封装在一起,通过菜单控制爬取不同数据. [二.需要的库] 主要涉及的库有:requests.openpyxl.

利用Fiddler抓取websocket包

一.利用fiddler抓取websockt包 打开Fiddler,点开菜单栏的Rules,选择Customize Rules... 这时会打开CustomRules.js文件,在class Handlers中加入以下代码 static function OnWebSocketMessage(oMsg: WebSocketMessage) { // Log Message to the LOG tab FiddlerApplication.Log.LogString(oMsg.ToString()