抓包分析YY音频

YY的音频数据传输是P2P协议,音频的编码为AAC,下面抓去的音频编码的信息和频谱信息。

音频编码为AAC,采样为44K,码率24kb/s。音频编码在24kb/s码率能达到15K的音质。值得大家学习啊。

 

1.准备工具

procexp.exe      分析YY的进程信息

Procmon.exe      分析YY的网络数据包

wireshark.exe    分析网络包的内容

 

2.分析YY的进程信息

  使用procexp分析YY的大致信息,比如进程号,网络连接等

 

 

 

3.分析YY的网络传输信息

使用procmon分析YY的网络数据,根据上面的得到的进程ID设置过滤,只接受YY的UDP数据包

 

过滤后得到数据包如下:


从上面的数据可以看到端口为8456的UDP接受数据最多,可以看出这个端口接受的就是P2P音频数据。

 

4.使用wireshark抓取P2P音频数据包

设置wireshark的过滤器,只抓去端口为8456的UDP数据包

 

抓去的数据如下:

 

查看UDP数据流,这里面存的就是YY的音频数据。从下面的数据看不出来具体的音频编码。

不急,我们多看几个数据包就会发现,他们都有固定的数据头,紧接着都刚好是0xff|0xf1(这个刚好是aac ADTS的同步头)。所以我们可以按照这个思路分析下去。

 

 

5. 使用代码分析pcap抓去的数据包

详细分析参考代码:

 

    1. #include <stdio.h>  
    2. #include <stdlib.h>  
    3. #include <WinSock2.h>  
    4. #include <assert.h>  
    5.   
    6. ///  
    7. typedef unsigned int  bpf_u_int32;  
    8. typedef unsigned char u_char;  
    9. typedef unsigned short  u_short;  
    10. typedef unsigned int u_int;  
    11. typedef int bpf_int32;  
    12.   
    13. /* 
    14. Pcap文件分析如下: 
    15. +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ 
    16. |Pcap Header    |Packet Header  |Packet Body    |Packet Header  |Packet Body    |        
    17. +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ 
    18.  
    19. */  
    20. /* 
    21. Pcap文件头 
    22. +-------+-------+-------+-------+ 
    23. |       Magic 4B                | 
    24. +-------+-------+-------+-------+ 
    25. |   Major 2B    |  Minor 2B     | 
    26. +-------+-------+-------+-------+ 
    27. |       ThisZone 4B             | 
    28. +-------+-------+-------+-------+ 
    29. |       SigFigs 4B              | 
    30. +-------+-------+-------+-------+ 
    31. |       SnapLen 4B              | 
    32. +-------+-------+-------+-------+ 
    33. |       LinkType 4B             | 
    34. +-------+-------+-------+-------+ 
    35.  
    36. Pcap文件头24B各字段说明: 
    37. Magic:4B:0x1A 2B 3C 4D:用来标示文件的开始 
    38. Major:2B,0x02 00:当前文件主要的版本号      
    39. Minor:2B,0x04 00当前文件次要的版本号 
    40. ThisZone:4B当地的标准时间;全零 
    41. SigFigs:4B时间戳的精度;全零 
    42. SnapLen:4B最大的存储长度     
    43. LinkType:4B链路类型 
    44. 常用类型: 
    45. 0            BSD loopback devices, except for later OpenBSD 
    46. 1            Ethernet, and Linux loopback devices 
    47. 6            802.5 Token Ring 
    48. 7            ARCnet 
    49. 8            SLIP 
    50. 9            PPP 
    51. */  
    52. typedef struct pcap_file_header {  
    53.     bpf_u_int32 magic;  
    54.     u_short version_major;  
    55.     u_short version_minor;  
    56.     bpf_int32 thiszone;      
    57.     bpf_u_int32 sigfigs;     
    58.     bpf_u_int32 snaplen;     
    59.     bpf_u_int32 linktype;    
    60. }pcap_file_header;  
    61.   
    62. /* 
    63. Packet 包头和Packet数据组成 
    64. +-------+-------+ 
    65. |Packet Header  | 
    66. +-------+-------+ 
    67. |Packet Body    | 
    68. +-------+-------+ 
    69.  
    70. Paket 包头 
    71. +-------+-------+-------+-------+ 
    72. |       Timestamp 4B            | 
    73. +-------+-------+-------+-------+ 
    74. |       Timestamp 4B            | 
    75. +-------+-------+-------+-------+ 
    76. |       Caplen 4B               | 
    77. +-------+-------+-------+-------+ 
    78. |       Len 4B                  | 
    79. +-------+-------+-------+-------+ 
    80.  
    81. 字段说明: 
    82. Timestamp:时间戳高位,精确到seconds      
    83. Timestamp:时间戳低位,精确到microseconds 
    84. Caplen:当前数据区的长度,即抓取到的数据帧长度,由此可以得到下一个数据帧的位置。 
    85. Len:离线数据长度:网络中实际数据帧的长度,一般不大于caplen,多数情况下和Caplen数值相等。 
    86. Packet 数据:即 Packet(通常就是链路层的数据帧)具体内容,长度就是Caplen,这个长度的后面,就是当前PCAP文件中存放的下一个Packet数据包,也就 是说:PCAP文件里面并没有规定捕获的Packet数据包之间有什么间隔字符串,下一组数据在文件中的起始位置。我们需要靠第一个Packet包确定。 
    87. */  
    88. typedef struct  timestamp{  
    89.     bpf_u_int32 timestamp_s;  
    90.     bpf_u_int32 timestamp_ms;  
    91. }timestamp;  
    92.   
    93. typedef struct pcap_header{  
    94.     timestamp ts;  
    95.     bpf_u_int32 capture_len;  
    96.     bpf_u_int32 len;  
    97.   
    98. }pcap_header;  
    99.   
    100. //help funtion  
    101. void  printPcapHeader(pcap_file_header * ph)      
    102. {  
    103.     printf("=====================\n"  
    104.        "magic:0x%0x\n"  
    105.        "version_major:%u\n"  
    106.        "version_minor:%u\n"  
    107.        "thiszone:%d\n"  
    108.        "sigfigs:%u\n"  
    109.        "snaplen:%u\n"  
    110.        "linktype:%u\n"  
    111.        "=====================\n",  
    112.        ph->magic,  
    113.        ph->version_major,  
    114.        ph->version_minor,  
    115.        ph->thiszone,  
    116.        ph->sigfigs,  
    117.        ph->snaplen,  
    118.        ph->linktype);  
    119. }  
    120.   
    121. void printPacketHeader(pcap_header * ph)  
    122. {  
    123.     printf("=====================\n"  
    124.         "ts.timestamp_s:%u\n"  
    125.         "ts.timestamp_ms:%u\n"  
    126.         "capture_len:%u\n"  
    127.         "len:%d\n"  
    128.         "=====================\n",  
    129.         ph->ts.timestamp_s,  
    130.         ph->ts.timestamp_ms,  
    131.         ph->capture_len,  
    132.         ph->len);  
    133. }  
    134. //////////////////////////////////////////////////////////////////////////  
    135. /* 
    136.     UDP包分析 
    137. */  
    138. /* 4字节的IP地址 */  
    139. typedef struct ip_address{  
    140.     u_char byte1;  
    141.     u_char byte2;  
    142.     u_char byte3;  
    143.     u_char byte4;  
    144. }ip_address;  
    145.   
    146. /* IPv4头 */  
    147. typedef struct ip_header{  
    148.     u_char  ver_ihl;        // 版本 (4 bits) + 首部长度 (4 bits)  /// 首部长度  
    149.     u_char  tos;            // 服务类型(Type of service)   
    150.     u_short tlen;           // 总长(Total length)   
    151.     u_short identification; // 标识(Identification)  
    152.     u_short flags_fo;       // 标志位(Flags) (3 bits) + 段偏移量(Fragment offset) (13 bits)  
    153.     u_char  ttl;            // 存活时间(Time to live)  
    154.     u_char  proto;          // 协议(Protocol)  
    155.     u_short crc;            // 首部校验和(Header checksum)  
    156.     ip_address  saddr;      // 源地址(Source address)  
    157.     ip_address  daddr;      // 目的地址(Destination address)  
    158.     u_int   op_pad;         // 选项与填充(Option + Padding)  
    159. }ip_header;  
    160.   
    161. /* UDP头 */  
    162. typedef struct udp_header{  
    163.     u_short sport;          // 源端口(Source port)  
    164.     u_short dport;          // 目的端口(Destination port)  
    165.     u_short len;            // UDP数据包长度(Datagram length)   /// UDP总长度  
    166.     u_short crc;            // 校验和(Checksum)  
    167. }udp_header;  
    168.   
    169. u_char pkt_data[65536];  
    170.   
    171. int main()  
    172. {  
    173.     FILE * fp = fopen("yy.p2p.packet_long.pcap""rb");  
    174.     if (!fp)  
    175.     {  
    176.         fprintf(stderr, "open file error\n");  
    177.         return -1;  
    178.     }  
    179.     FILE * aacfp = fopen("yy.p2p.packet_long.pcap.aac""wb");  
    180.     if (!fp)  
    181.     {  
    182.         fprintf(stderr, "open file error\n");  
    183.         return -1;  
    184.     }  
    185.   
    186.     //1. Read pcap file header  
    187.     pcap_file_header pfh;  
    188.     fread(&pfh, 1, sizeof(pfh), fp);  
    189.     printPcapHeader(&pfh);  
    190.       
    191.   
    192.     //2. Read pcap packet  
    193.     while (!feof(fp))  
    194.     {  
    195.         pcap_header ph;  
    196.         if (fread(&ph, 1, sizeof(ph), fp) != sizeof(ph))  
    197.             break;  
    198.         printPacketHeader(&ph);  
    199.           
    200.         if (fread(pkt_data, 1, ph.capture_len, fp) != ph.capture_len)  
    201.             break;  
    202.   
    203.         //3. 分析消息包内容  
    204.         //fseek(fp, ph.capture_len, 1);  
    205.         // 获取IP数据包头的位置  
    206.         ip_header *ih = (ip_header *)(pkt_data + 14); // 14以太网头部长度  
    207.               
    208.         // 只处理UDP包  
    209.         if (ih->proto != 0x11)  
    210.             continue;  
    211.   
    212.         // 获取UDP首部的位置  
    213.         u_int ip_len = (ih->ver_ihl & 0x0f) * 4;  
    214.         udp_header * uh = (udp_header *)((u_char *)ih + ip_len);  
    215.       
    216.         //   
    217.         u_short sport = ntohs(uh->sport);    
    218.         u_short dport = ntohs(uh->dport);  
    219.         u_short udplen = ntohs(uh->len);  
    220.   
    221.         if(sport != 8455) // yy源端口为8455  
    222.             continue;   
    223.         /* 打印IP地址和UDP端口 */  
    224.         printf("%d.%d.%d.%d.%d -> %d.%d.%d.%d.%d\n",  
    225.             ih->saddr.byte1,  
    226.             ih->saddr.byte2,  
    227.             ih->saddr.byte3,  
    228.             ih->saddr.byte4,  
    229.             sport,  
    230.             ih->daddr.byte1,  
    231.             ih->daddr.byte2,  
    232.             ih->daddr.byte3,  
    233.             ih->daddr.byte4,  
    234.             dport);  
    235.   
    236.         //  
    237.         u_char * udp_data = (u_char *)uh + 8;  
    238.         //u_char * aac_data = udp_data + 34;  
    239.         //u_short  aac_len = udplen - 8 - 34;  
    240.   
    241.         u_char * aac_data = pkt_data + 14 + ip_len + 8 + 34;  
    242.         int  aac_len = ph.capture_len - (14 + ip_len + 8 + 34);  
    243.         //assert(aac_len > 0);   
    244.         if (aac_len <= 0) continue;   /// 只有 yy头,没有aac数据  
    245.         assert(aac_len < ph.capture_len);  
    246.   
    247.         printf("aac len = %d pkt_len = %d\n", aac_len, ph.capture_len);  
    248.         assert(aac_data[0] == 0xff && aac_data[1] == 0xf1);  
    249.               
    250.         fwrite(aac_data, 1, aac_len, aacfp);  
    251.   
    252.     }  
    253.   
    254.     fclose(fp);  
    255.     fclose(aacfp);  
    256.     return 0;  
    257. }  
posted @ 2014-06-14 01:01  腐烂的翅膀  阅读(1895)  评论(0编辑  收藏  举报