當(dāng)前位置:首頁 > 嵌入式培訓(xùn) > 嵌入式學(xué)習(xí) > 講師博文 > libpcap使用
libpcap是一個(gè)網(wǎng)絡(luò)數(shù)據(jù)包捕獲函數(shù)庫,功能非常強(qiáng)大,Linux下著名的tcpdump就是以它為基礎(chǔ)的。今天我們利用它來完成一個(gè)我們自己的網(wǎng)絡(luò)嗅探器(sniffer)
首先先介紹一下本次實(shí)驗(yàn)的環(huán)境:
Ubuntu 11.04,IP:192.168.1.1,廣播地址:192.168.1.255,子網(wǎng)掩碼:255.255.255.0
可以使用下面的命令設(shè)置:
sudo ifconfig eth0 192.168.1.1 broadcast 192.168.1.255 netmask 255.255.255.0
1.安裝
在//www.tcpdump.org/下載libpcap(tcpdump的源碼也可以從這個(gè)網(wǎng)站下載)
解壓
./configure
make
sudo make install
2.使用
安裝好libpcap后,我們要使用它啦,先寫一個(gè)簡(jiǎn)單的程序,并介紹如何使用libpcap庫編譯它:
Makefile:
[plain] view plain copy
1. all: test.c
2. gcc -g -Wall -o test test.c -lpcap
3.
4. clean:
5. rm -rf *.o test
其后的程序的Makefile均類似,故不再重復(fù)
test1.c
[cpp] view plain copy
1. #include <pcap.h>
2. #include <stdio.h>
3.
4. int main()
5. {
6. char errBuf[PCAP_ERRBUF_SIZE], * device;
7.
8. device = pcap_lookupdev(errBuf);
9.
10. if(device)
11. {
12. printf("success: device: %s\n", device);
13. }
14. else
15. {
16. printf("error: %s\n", errBuf);
17. }
18.
19. return 0;
20. }
可以成功編譯,不過運(yùn)行的時(shí)候卻提示找不到libpcap.so.1,因?yàn)閘ibpcap.so.1默認(rèn)安裝到了/usr/local/lib下,我們做一個(gè)符號(hào)鏈接到/usr/lib/下即可:
運(yùn)行test的時(shí)候輸出"no suitable device found",原因是我們沒有以root權(quán)限運(yùn)行,root權(quán)限運(yùn)行后就正常了:
下面開始正式講解如何使用libpcap:
首先要使用libpcap,我們必須包含pcap.h頭文件,可以在/usr/local/include/pcap/pcap.h找到,其中包含了每個(gè)類型定義的詳細(xì)說明。
1.獲取網(wǎng)絡(luò)接口
首先我們需要獲取監(jiān)聽的網(wǎng)絡(luò)接口:
我們可以手動(dòng)指定或讓libpcap自動(dòng)選擇,先介紹如何讓libpcap自動(dòng)選擇:
char * pcap_lookupdev(char * errbuf)
上面這個(gè)函數(shù)返回第一個(gè)合適的網(wǎng)絡(luò)接口的字符串指針,如果出錯(cuò),則errbuf存放出錯(cuò)信息字符串,errbuf至少應(yīng)該是PCAP_ERRBUF_SIZE個(gè)字節(jié)長(zhǎng)度的。注意,很多l(xiāng)ibpcap函數(shù)都有這個(gè)參數(shù)。
pcap_lookupdev()一般可以在跨平臺(tái)的,且各個(gè)平臺(tái)上的網(wǎng)絡(luò)接口名稱都不相同的情況下使用。
如果我們手動(dòng)指定要監(jiān)聽的網(wǎng)絡(luò)接口,則這一步跳過,我們?cè)诘诙街袑⒁O(jiān)聽的網(wǎng)絡(luò)接口字符串硬編碼在pcap_open_live里。
2.釋放網(wǎng)絡(luò)接口
在操作為網(wǎng)絡(luò)接口后,我們應(yīng)該要釋放它:
void pcap_close(pcap_t * p)
該函數(shù)用于關(guān)閉pcap_open_live()獲取的pcap_t的網(wǎng)絡(luò)接口對(duì)象并釋放相關(guān)資源。
3.打開網(wǎng)絡(luò)接口
獲取網(wǎng)絡(luò)接口后,我們需要打開它:
pcap_t * pcap_open_live(const char * device, int snaplen, int promisc, int to_ms, char * errbuf)
上面這個(gè)函數(shù)會(huì)返回指定接口的pcap_t類型指針,后面的所有操作都要使用這個(gè)指針。
第一個(gè)參數(shù)是第一步獲取的網(wǎng)絡(luò)接口字符串,可以直接使用硬編碼。
第二個(gè)參數(shù)是對(duì)于每個(gè)數(shù)據(jù)包,從開頭要抓多少個(gè)字節(jié),我們可以設(shè)置這個(gè)值來只抓每個(gè)數(shù)據(jù)包的頭部,而不關(guān)心具體的內(nèi)容。典型的以太網(wǎng)幀長(zhǎng)度是1518字節(jié),但其他的某些協(xié)議的數(shù)據(jù)包會(huì)更長(zhǎng)一點(diǎn),但任何一個(gè)協(xié)議的一個(gè)數(shù)據(jù)包長(zhǎng)度都必然小于65535個(gè)字節(jié)。
第三個(gè)參數(shù)指定是否打開混雜模式(Promiscuous Mode),0表示非混雜模式,任何其他值表示混合模式。如果要打開混雜模式,那么網(wǎng)卡必須也要打開混雜模式,可以使用如下的命令打開eth0混雜模式:
ifconfig eth0 promisc
第四個(gè)參數(shù)指定需要等待的毫秒數(shù),超過這個(gè)數(shù)值后,第3步獲取數(shù)據(jù)包的這幾個(gè)函數(shù)就會(huì)立即返回。0表示一直等待直到有數(shù)據(jù)包到來。
第五個(gè)參數(shù)是存放出錯(cuò)信息的數(shù)組。
4.獲取數(shù)據(jù)包
打開網(wǎng)絡(luò)接口后就已經(jīng)開始監(jiān)聽了,那如何知道收到了數(shù)據(jù)包呢?有下面3種方法:
a)
u_char * pcap_next(pcap_t * p, struct pcap_pkthdr * h)
如果返回值為NULL,表示沒有抓到包
第一個(gè)參數(shù)是第2步返回的pcap_t類型的指針
第二個(gè)參數(shù)是保存收到的第一個(gè)數(shù)據(jù)包的pcap_pkthdr類型的指針
pcap_pkthdr類型的定義如下:
[cpp] view plain copy
1. struct pcap_pkthdr
2. {
3. struct timeval ts; /* time stamp */
4. bpf_u_int32 caplen; /* length of portion present */
5. bpf_u_int32 len; /* length this packet (off wire) */
6. };
注意這個(gè)函數(shù)只要收到一個(gè)數(shù)據(jù)包后就會(huì)立即返回
b)
int pcap_loop(pcap_t * p, int cnt, pcap_handler callback, u_char * user)
第一個(gè)參數(shù)是第2步返回的pcap_t類型的指針
第二個(gè)參數(shù)是需要抓的數(shù)據(jù)包的個(gè)數(shù),一旦抓到了cnt個(gè)數(shù)據(jù)包,pcap_loop立即返回。負(fù)數(shù)的cnt表示pcap_loop永遠(yuǎn)循環(huán)抓包,直到出現(xiàn)錯(cuò)誤。
第三個(gè)參數(shù)是一個(gè)回調(diào)函數(shù)指針,它必須是如下的形式:
void callback(u_char * userarg, const struct pcap_pkthdr * pkthdr, const u_char * packet)
第一個(gè)參數(shù)是pcap_loop的后一個(gè)參數(shù),當(dāng)收到足夠數(shù)量的包后pcap_loop會(huì)調(diào)用callback回調(diào)函數(shù),同時(shí)將pcap_loop()的user參數(shù)傳遞給它
第二個(gè)參數(shù)是收到的數(shù)據(jù)包的pcap_pkthdr類型的指針
第三個(gè)參數(shù)是收到的數(shù)據(jù)包數(shù)據(jù)
c)
int pcap_dispatch(pcap_t * p, int cnt, pcap_handler callback, u_char * user)
這個(gè)函數(shù)和pcap_loop()非常類似,只是在超過to_ms毫秒后就會(huì)返回(to_ms是pcap_open_live()的第4個(gè)參數(shù))
例子:
test2:
[cpp] view plain copy
1. #include <pcap.h>
2. #include <time.h>
3. #include <stdlib.h>
4. #include <stdio.h>
5.
6. int main()
7. {
8. char errBuf[PCAP_ERRBUF_SIZE], * devStr;
9.
10. /* get a device */
11. devStr = pcap_lookupdev(errBuf);
12.
13. if(devStr)
14. {
15. printf("success: device: %s\n", devStr);
16. }
17. else
18. {
19. printf("error: %s\n", errBuf);
20. exit(1);
21. }
22.
23. /* open a device, wait until a packet arrives */
24. pcap_t * device = pcap_open_live(devStr, 65535, 1, 0, errBuf);
25.
26. if(!device)
27. {
28. printf("error: pcap_open_live(): %s\n", errBuf);
29. exit(1);
30. }
31.
32. /* wait a packet to arrive */
33. struct pcap_pkthdr packet;
34. const u_char * pktStr = pcap_next(device, &packet);
35.
36. if(!pktStr)
37. {
38. printf("did not capture a packet!\n");
39. exit(1);
40. }
41.
42. printf("Packet length: %d\n", packet.len);
43. printf("Number of bytes: %d\n", packet.caplen);
44. printf("Recieved time: %s\n", ctime((const time_t *)&packet.ts.tv_sec));
45.
46. pcap_close(device);
47.
48. return 0;
49. }
打開兩個(gè)終端,先ping 192.168.1.10,由于我們的ip是192.168.1.1,因此我們可以收到廣播的數(shù)據(jù)包,另一個(gè)終端運(yùn)行test,就會(huì)抓到這個(gè)包。
下面的這個(gè)程序會(huì)把收到的數(shù)據(jù)包內(nèi)容全部打印出來,運(yùn)行方式和上一個(gè)程序一樣:
test3:
[cpp] view plain copy
1. #include <pcap.h>
2. #include <time.h>
3. #include <stdlib.h>
4. #include <stdio.h>
5.
6. void getPacket(u_char * arg, const struct pcap_pkthdr * pkthdr, const u_char * packet)
7. {
8. int * id = (int *)arg;
9.
10. printf("id: %d\n", ++(*id));
11. printf("Packet length: %d\n", pkthdr->len);
12. printf("Number of bytes: %d\n", pkthdr->caplen);
13. printf("Recieved time: %s", ctime((const time_t *)&pkthdr->ts.tv_sec));
14.
15. int i;
16. for(i=0; i<pkthdr->len; ++i)
17. {
18. printf(" %02x", packet[i]);
19. if( (i + 1) % 16 == 0 )
20. {
21. printf("\n");
22. }
23. }
24.
25. printf("\n\n");
26. }
27.
28. int main()
29. {
30. char errBuf[PCAP_ERRBUF_SIZE], * devStr;
31.
32. /* get a device */
33. devStr = pcap_lookupdev(errBuf);
34.
35. if(devStr)
36. {
37. printf("success: device: %s\n", devStr);
38. }
39. else
40. {
41. printf("error: %s\n", errBuf);
42. exit(1);
43. }
44.
45. /* open a device, wait until a packet arrives */
46. pcap_t * device = pcap_open_live(devStr, 65535, 1, 0, errBuf);
47.
48. if(!device)
49. {
50. printf("error: pcap_open_live(): %s\n", errBuf);
51. exit(1);
52. }
53.
54. /* wait loop forever */
55. int id = 0;
56. pcap_loop(device, -1, getPacket, (u_char*)&id);
57.
58. pcap_close(device);
59.
60. return 0;
61. }
如果我們沒有按Ctrl+c,test會(huì)一直抓到包,因?yàn)槲覀儗cap_loop()設(shè)置為永遠(yuǎn)循環(huán)
由于ping屬于icmp協(xié)議,并且發(fā)出icmp協(xié)議數(shù)據(jù)包之前必須先通過arp協(xié)議獲取目的主機(jī)的mac地址,因此我們抓到的包是arp協(xié)議的,而arp協(xié)議的數(shù)據(jù)包長(zhǎng)度正好是42字節(jié)(14字節(jié)的以太網(wǎng)幀頭+28字節(jié)的arp數(shù)據(jù))。具體內(nèi)容請(qǐng)參考相關(guān)網(wǎng)絡(luò)協(xié)議說明。
5.分析數(shù)據(jù)包
我們既然已經(jīng)抓到數(shù)據(jù)包了,那么我們要開始分析了,這部分留給讀者自己完成,具體內(nèi)容可以參考相關(guān)的網(wǎng)絡(luò)協(xié)議說明。在本文的后,我會(huì)示范性的寫一個(gè)分析arp協(xié)議的sniffer,僅供參考。要特別注意一點(diǎn),網(wǎng)絡(luò)上的數(shù)據(jù)是網(wǎng)絡(luò)字節(jié)順序的,因此分析前需要轉(zhuǎn)換為主機(jī)字節(jié)順序(ntohs()函數(shù))。
6.過濾數(shù)據(jù)包
我們抓到的數(shù)據(jù)包往往很多,如何過濾掉我們不感興趣的數(shù)據(jù)包呢?
幾乎所有的操作系統(tǒng)(BSD, AIX, Mac OS, Linux等)都會(huì)在內(nèi)核中提供過濾數(shù)據(jù)包的方法,主要都是基于BSD Packet Filter(BPF)結(jié)構(gòu)的。libpcap利用BPF來過濾數(shù)據(jù)包。
過濾數(shù)據(jù)包需要完成3件事:
a) 構(gòu)造一個(gè)過濾表達(dá)式
b) 編譯這個(gè)表達(dá)式
c) 應(yīng)用這個(gè)過濾器
a)
BPF使用一種類似于匯編語言的語法書寫過濾表達(dá)式,不過libpcap和tcpdump都把它封裝成更高級(jí)且更容易的語法了,具體可以man tcpdump,以下是一些例子:
src host 192.168.1.177
只接收源ip地址是192.168.1.177的數(shù)據(jù)包
dst port 80
只接收tcp/udp的目的端口是80的數(shù)據(jù)包
not tcp
只接收不使用tcp協(xié)議的數(shù)據(jù)包
tcp[13] == 0x02 and (dst port 22 or dst port 23)
只接收SYN標(biāo)志位置位且目標(biāo)端口是22或23的數(shù)據(jù)包(tcp首部開始的第13個(gè)字節(jié))
icmp[icmptype] == icmp-echoreply or icmp[icmptype] == icmp-echo
只接收icmp的ping請(qǐng)求和ping響應(yīng)的數(shù)據(jù)包
ehter dst 00:e0:09:c1:0e:82
只接收以太網(wǎng)mac地址是00:e0:09:c1:0e:82的數(shù)據(jù)包
ip[8] == 5
只接收ip的ttl=5的數(shù)據(jù)包(ip首部開始的第8個(gè)字節(jié))
b)
構(gòu)造完過濾表達(dá)式后,我們需要編譯它,使用如下函數(shù):
int pcap_compile(pcap_t * p, struct bpf_program * fp, char * str, int optimize, bpf_u_int32 netmask)
fp:這是一個(gè)傳出參數(shù),存放編譯后的bpf
str:過濾表達(dá)式
optimize:是否需要優(yōu)化過濾表達(dá)式
metmask:簡(jiǎn)單設(shè)置為0即可
c)
后我們需要應(yīng)用這個(gè)過濾表達(dá)式:
int pcap_setfilter(pcap_t * p, struct bpf_program * fp)
第二個(gè)參數(shù)fp就是前一步pcap_compile()的第二個(gè)參數(shù)
應(yīng)用完過濾表達(dá)式之后我們便可以使用pcap_loop()或pcap_next()等抓包函數(shù)來抓包了。
下面的程序演示了如何過濾數(shù)據(jù)包,我們只接收目的端口是80的數(shù)據(jù)包:
test4.c
[cpp] view plain copy
1. #include <pcap.h>
2. #include <time.h>
3. #include <stdlib.h>
4. #include <stdio.h>
5.
6. void getPacket(u_char * arg, const struct pcap_pkthdr * pkthdr, const u_char * packet)
7. {
8. int * id = (int *)arg;
9.
10. printf("id: %d\n", ++(*id));
11. printf("Packet length: %d\n", pkthdr->len);
12. printf("Number of bytes: %d\n", pkthdr->caplen);
13. printf("Recieved time: %s", ctime((const time_t *)&pkthdr->ts.tv_sec));
14.
15. int i;
16. for(i=0; i<pkthdr->len; ++i)
17. {
18. printf(" %02x", packet[i]);
19. if( (i + 1) % 16 == 0 )
20. {
21. printf("\n");
22. }
23. }
24.
25. printf("\n\n");
26. }
27.
28. int main()
29. {
30. char errBuf[PCAP_ERRBUF_SIZE], * devStr;
31.
32. /* get a device */
33. devStr = pcap_lookupdev(errBuf);
34.
35. if(devStr)
36. {
37. printf("success: device: %s\n", devStr);
38. }
39. else
40. {
41. printf("error: %s\n", errBuf);
42. exit(1);
43. }
44.
45. /* open a device, wait until a packet arrives */
46. pcap_t * device = pcap_open_live(devStr, 65535, 1, 0, errBuf);
47.
48. if(!device)
49. {
50. printf("error: pcap_open_live(): %s\n", errBuf);
51. exit(1);
52. }
53.
54. /* construct a filter */
55. struct bpf_program filter;
56. pcap_compile(device, &filter, "dst port 80", 1, 0);
57. pcap_setfilter(device, &filter);
58.
59. /* wait loop forever */
60. int id = 0;
61. pcap_loop(device, -1, getPacket, (u_char*)&id);
62.
63. pcap_close(device);
64.
65. return 0;
66. }
在下面的這一個(gè)例子中,客戶機(jī)通過tcp的9732端口連接服務(wù)器,發(fā)送字符'A',之后服務(wù)器將'A'+1即'B'返回給客戶機(jī),具體實(shí)現(xiàn)可以參考://blog.csdn.net/htttw/article/details/7519964
服務(wù)器的ip是192.168.56.101,客戶機(jī)的ip是192.168.56.1
服務(wù)器:
Makefile:
[plain] view plain copy
1. all: tcp_client.c tcp_server.c
2. gcc -g -Wall -o tcp_client tcp_client.c
3. gcc -g -Wall -o tcp_server tcp_server.c
4.
5. clean:
6. rm -rf *.o tcp_client tcp_server
tcp_server:
[cpp] view plain copy
1. #include <sys/types.h>
2. #include <sys/socket.h>
3. #include <netinet/in.h>
4. #include <arpa/inet.h>
5. #include <unistd.h>
6. #include <stdlib.h>
7. #include <stdio.h>
8.
9. #define PORT 9832
10. #define SERVER_IP "192.168.56.101"
11.
12. int main()
13. {
14. /* create a socket */
15. int server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
16.
17. struct sockaddr_in server_addr;
18. server_addr.sin_family = AF_INET;
19. server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
20. server_addr.sin_port = htons(PORT);
21.
22. /* bind with the local file */
23. bind(server_sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
24.
25. /* listen */
26. listen(server_sockfd, 5);
27.
28. char ch;
29. int client_sockfd;
30. struct sockaddr_in client_addr;
31. socklen_t len = sizeof(client_addr);
32. while(1)
33. {
34. printf("server waiting:\n");
35.
36. /* accept a connection */
37. client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_addr, &len);
38.
39. /* exchange data */
40. read(client_sockfd, &ch, 1);
41. printf("get char from client: %c\n", ch);
42. ++ch;
43. write(client_sockfd, &ch, 1);
44.
45. /* close the socket */
46. close(client_sockfd);
47. }
48.
49. return 0;
50. }
tcp_client:
[cpp] view plain copy
1. #include <sys/types.h>
2. #include <sys/socket.h>
3. #include <netinet/in.h>
4. #include <arpa/inet.h>
5. #include <unistd.h>
6. #include <stdlib.h>
7. #include <stdio.h>
8.
9. #define PORT 9832
10. #define SERVER_IP "192.168.56.101"
11.
12. int main()
13. {
14. /* create a socket */
15. int sockfd = socket(AF_INET, SOCK_STREAM, 0);
16.
17. struct sockaddr_in address;
18. address.sin_family = AF_INET;
19. address.sin_addr.s_addr = inet_addr(SERVER_IP);
20. address.sin_port = htons(PORT);
21.
22. /* connect to the server */
23. int result = connect(sockfd, (struct sockaddr *)&address, sizeof(address));
24. if(result == -1)
25. {
26. perror("connect failed: ");
27. exit(1);
28. }
29.
30. /* exchange data */
31. char ch = 'A';
32. write(sockfd, &ch, 1);
33. read(sockfd, &ch, 1);
34. printf("get char from server: %c\n", ch);
35.
36. /* close the socket */
37. close(sockfd);
38.
39. return 0;
40. }
運(yùn)行方法如下,首先在服務(wù)器上運(yùn)行tcp_server,然后運(yùn)行我們的監(jiān)聽器,然后在客戶機(jī)上運(yùn)行tcp_client,注意,我們可以先清空arp緩存,這樣就可以看到整個(gè)通信過程(包括一開始的arp廣播)
在客戶機(jī)上運(yùn)行下列命令來清空記錄服務(wù)器的arp緩存:
sudo arp -d 192.168.56.101
arp -a后發(fā)現(xiàn)已經(jīng)刪除了記錄服務(wù)器的arp緩存
抓包的結(jié)果如下所示,由于包太多了,無法全部截圖,因此我把所有內(nèi)容保存在下面的文本中了:
全部的包如下:
[plain] view plain copy
1. hutao@hutao-VirtualBox:~/test3$ sudo ./test
2. success: device: eth0
3. id: 1
4. Packet length: 60
5. Number of bytes: 60
6. Recieved time: Sat Apr 28 19:57:50 2012
7. ff ff ff ff ff ff 0a 00 27 00 00 00 08 06 00 01
8. 08 00 06 04 00 01 0a 00 27 00 00 00 c0 a8 38 01
9. 00 00 00 00 00 00 c0 a8 38 65 00 00 00 00 00 00
10. 00 00 00 00 00 00 00 00 00 00 00 00
11.
12. id: 2
13. Packet length: 42
14. Number of bytes: 42
15. Recieved time: Sat Apr 28 19:57:50 2012
16. 0a 00 27 00 00 00 08 00 27 9c ff b1 08 06 00 01
17. 08 00 06 04 00 02 08 00 27 9c ff b1 c0 a8 38 65
18. 0a 00 27 00 00 00 c0 a8 38 01
19.
20. id: 3
21. Packet length: 74
22. Number of bytes: 74
23. Recieved time: Sat Apr 28 19:57:50 2012
24. 08 00 27 9c ff b1 0a 00 27 00 00 00 08 00 45 00
25. 00 3c d4 af 40 00 40 06 74 55 c0 a8 38 01 c0 a8
26. 38 65 8e 20 26 68 79 e1 63 8c 00 00 00 00 a0 02
27. 39 08 d4 13 00 00 02 04 05 b4 04 02 08 0a 00 14
28. b7 23 00 00 00 00 01 03 03 06
29.
30. id: 4
31. Packet length: 74
32. Number of bytes: 74
33. Recieved time: Sat Apr 28 19:57:50 2012
34. 0a 00 27 00 00 00 08 00 27 9c ff b1 08 00 45 00
35. 00 3c 00 00 40 00 40 06 49 05 c0 a8 38 65 c0 a8
36. 38 01 26 68 8e 20 b6 c4 e6 e5 79 e1 63 8d a0 12
37. 38 90 f1 e5 00 00 02 04 05 b4 04 02 08 0a 00 57
38. a1 2c 00 14 b7 23 01 03 03 05
39.
40. id: 5
41. Packet length: 66
42. Number of bytes: 66
43. Recieved time: Sat Apr 28 19:57:50 2012
44. 08 00 27 9c ff b1 0a 00 27 00 00 00 08 00 45 00
45. 00 34 d4 b0 40 00 40 06 74 5c c0 a8 38 01 c0 a8
46. 38 65 8e 20 26 68 79 e1 63 8d b6 c4 e6 e6 80 10
47. 00 e5 fb c1 00 00 01 01 08 0a 00 14 b7 24 00 57
48. a1 2c
49.
50. id: 6
51. Packet length: 67
52. Number of bytes: 67
53. Recieved time: Sat Apr 28 19:57:50 2012
54. 08 00 27 9c ff b1 0a 00 27 00 00 00 08 00 45 00
55. 00 35 d4 b1 40 00 40 06 74 5a c0 a8 38 01 c0 a8
56. 38 65 8e 20 26 68 79 e1 63 8d b6 c4 e6 e6 80 18
57. 00 e5 ba b7 00 00 01 01 08 0a 00 14 b7 25 00 57
58. a1 2c 41
59.
60. id: 7
61. Packet length: 66
62. Number of bytes: 66
63. Recieved time: Sat Apr 28 19:57:50 2012
64. 0a 00 27 00 00 00 08 00 27 9c ff b1 08 00 45 00
65. 00 34 47 cb 40 00 40 06 01 42 c0 a8 38 65 c0 a8
66. 38 01 26 68 8e 20 b6 c4 e6 e6 79 e1 63 8e 80 10
67. 01 c5 f1 dd 00 00 01 01 08 0a 00 57 a1 2e 00 14
68. b7 25
69.
70. id: 8
71. Packet length: 67
72. Number of bytes: 67
73. Recieved time: Sat Apr 28 19:57:50 2012
74. 0a 00 27 00 00 00 08 00 27 9c ff b1 08 00 45 00
75. 00 35 47 cc 40 00 40 06 01 40 c0 a8 38 65 c0 a8
76. 38 01 26 68 8e 20 b6 c4 e6 e6 79 e1 63 8e 80 18
77. 01 c5 f1 de 00 00 01 01 08 0a 00 57 a1 2e 00 14
78. b7 25 42
79.
80. id: 9
81. Packet length: 66
82. Number of bytes: 66
83. Recieved time: Sat Apr 28 19:57:50 2012
84. 0a 00 27 00 00 00 08 00 27 9c ff b1 08 00 45 00
85. 00 34 47 cd 40 00 40 06 01 40 c0 a8 38 65 c0 a8
86.