程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> 利用libpcap抓取QQ號碼信息,libpcap抓取qq號碼

利用libpcap抓取QQ號碼信息,libpcap抓取qq號碼

編輯:關於C語言

利用libpcap抓取QQ號碼信息,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的另一個號碼,原因未知... 當時忘了記錄,最近實驗了幾次又一直沒出現,沒有圖片了。

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved