您的位置:首页 > 其它

Winpcap数据包的抓取及还原

2013-01-26 23:12 211 查看
winpcap技术手册,除了安装文件里doc文件下有个帮助,这里在给一个:http://www.ferrisxu.com/WinPcap/html/index.html

这里我们用pcap_next_ex 函数抓取到数据包后,我们就要开始提取其中的关键信息了,这里我保存在了pkt_data里,之后又传到了处理函数中

代码如下,我也已经写的很清楚了。其中MAC地址是在数据链路层获取的,其他的诸如端口号,IP等都是通过分析IP包和TCP包获取。

唯一需要注意的就是在定义结构体的时候要注意字节的大小,不然获取的信息就是错误的了。

#include <stdio.h>
#include <iostream>
#define HAVE_REMOTE
#include "pcap.h"
#include "remote-ext.h"

#pragma comment(lib, "Ws2_32.lib")
#pragma comment(lib, "wpcap.lib")

using namespace std;

FILE* fp;

// 以太网协议格式的定义
typedef struct ether_header {
u_char ether_dhost[6];		// 目标地址
u_char ether_shost[6];		// 源地址
u_short ether_type;			// 以太网类型
}ether_header;

// 用户保存4字节的IP地址
typedef struct ip_address {
u_char byte1;
u_char byte2;
u_char byte3;
u_char byte4;
}ip_address;

// 用于保存IPV4的首部
typedef struct ip_header {
#ifdef WORDS_BIGENDIAN
u_char ip_version : 4, header_length : 4;
#else
u_char header_length : 4, ip_version : 4;
#endif

u_char ver_ihl;		// 版本以及首部长度,各4位
u_char tos;			// 服务质量
u_short tlen;		// 总长度
u_short identification;		// 身份识别
u_short offset;			// 分组偏移
u_char ttl;			// 生命周期
u_char proto;		// 协议类型
u_short checksum;		// 包头测验码
ip_address saddr;	// 源IP地址
ip_address daddr;	// 目的IP地址
u_int op_pad;		//可选 填充字段
}ip_header;

// 保存TCP首部
typedef struct tcp_header {
u_short sport;
u_short dport;
u_int sequence;		// 序列码
u_int ack;					// 回复码

#ifdef WORDS_BIGENDIAN
u_char offset : 4, reserved : 4;		// 偏移 预留
#else
u_char reserved : 4, offset : 4;		// 预留 偏移
#endif

u_char flags;				// 标志
u_short windows;			// 窗口大小
u_short checksum;			// 校验和
u_short urgent_pointer;		// 紧急指针
}tcp_header;

typedef struct udp_header {
u_int32_t sport;			// 源端口
u_int32_t dport;			// 目标端口
u_int8_t zero;				// 保留位
u_int8_t proto;				// 协议标识
u_int16_t datalen;			// UDP数据长度
}udp_header;

typedef struct icmp_header {
u_int8_t type;				// ICMP类型
u_int8_t code;				// 代码
u_int16_t checksum;			// 校验和
u_int16_t identification;	// 标识
u_int16_t sequence;			// 序列号
u_int32_t init_time;		// 发起时间戳
u_int16_t recv_time;		// 接受时间戳
u_int16_t send_time;		// 传输时间戳
}icmp_header;

typedef struct arp_header {
u_int16_t arp_hardware_type;
u_int16_t arp_protocol_type;
u_int8_t arp_hardware_length;
u_int8_t arp_protocol_length;
u_int16_t arp_operation_code;
u_int8_t arp_source_ethernet_address[6];
u_int8_t arp_source_ip_address[4];
u_int8_t arp_destination_ethernet_address[6];
u_int8_t arp_destination_ip_address[4];
}arp_header;

void tcp_protocol_packet_handle(
u_char *argument,
const struct pcap_pkthdr *packet_header,
const u_char *packet_content
) {
struct tcp_header *tcp_protocol;
u_short sport;
u_short dport;
int header_length;
u_short windows;
u_short urgent_pointer;
u_int sequence;
u_int acknowledgement;
u_short checksum;
u_char flags;

printf("===========TCP Protocol===========\n");

tcp_protocol = (struct tcp_header*)(packet_content + 14 + 20);
sport = ntohs(tcp_protocol->sport);
dport = ntohs(tcp_protocol->dport);
header_length = tcp_protocol->offset * 4;
sequence = ntohl(tcp_protocol->sequence);
acknowledgement = ntohl(tcp_protocol->ack);
windows = ntohs(tcp_protocol->windows);
urgent_pointer = ntohs(tcp_protocol->urgent_pointer);
flags = tcp_protocol->flags;
checksum = ntohs(tcp_protocol->checksum);

fprintf(fp, "%d0%d%d%c%d", header_length, sport, dport, flags, windows);

switch(dport) {
default:
break;
}

if(flags & 0x08) printf("PSH");
if(flags & 0x10) printf("ACK");
if(flags & 0x02) printf("SYN");
if(flags & 0x20) printf("URG");
if(flags & 0x01) printf("FIN");
if(flags & 0x04) printf("RST");
printf("\n");
}

void udp_protocol_packet_handle(
u_char *argument,
const struct pcap_pkthdr *packet_header,
const u_char *packet_content
) {
struct udp_header* udp_protocol;
u_short sport;
u_short dport;
u_short datalen;

udp_protocol = (struct udp_header*)(packet_content + 14 + 20);
sport = ntohs(udp_protocol->sport);
dport = ntohs(udp_protocol->dport);
datalen = ntohs(udp_protocol->datalen);

fprintf(fp, "0%d%d%d",datalen, sport, dport);
}

void arp_protocol_packet_handle(
u_char *argument,
const struct pcap_pkthdr *packet_header,
const u_char *packet_content
) {
struct arp_header *arp_protocol;
u_short protocol_type;
u_short hardware_type;
u_short operation_code;
u_char hardware_length;
u_char protocol_length;

struct tm* ltime;
char timestr[16];
time_t local_tv_sec;
local_tv_sec = packet_header->ts.tv_sec;
ltime = localtime(&local_tv_sec);
strftime(timestr, sizeof(timestr), "%H:%M:%S", ltime);

printf("--------   ARP协议    --------\n");
arp_protocol = (struct arp_header*)(packet_content + 14);
hardware_type = ntohs(arp_protocol->arp_hardware_type);
protocol_type = ntohs(arp_protocol->arp_protocol_type);
operation_code = ntohs(arp_protocol->arp_operation_code);
hardware_length = arp_protocol->arp_hardware_length;
protocol_length = arp_protocol->arp_protocol_length;

fprintf(fp, "%d%s", protocol_length, timestr);

switch (operation_code)
{
case 1:
printf("ARP请求协议\n");
break;
case 2:
printf("ARP应答协议\n");
break;
case 3:
printf("RARP请求协议\n");
break;
case 4:
printf("RARP应答协议\n");
break;
default:
break;
}
}

void icmp_protocol_packet_handle(
u_char *argument,
const struct pcap_pkthdr *packet_header,
const u_char *packet_content
) {
struct icmp_header *icmp_protocol;
u_short type;
u_short datalen;
u_int init_time;
u_int recv_time;
u_int send_time;

icmp_protocol = (struct icmp_header*)(packet_content + 14 + 20);
datalen = sizeof(icmp_protocol);
type = icmp_protocol->type;
init_time = icmp_protocol->init_time;
recv_time = icmp_protocol->recv_time;
send_time = icmp_protocol->send_time;

fprintf(fp, "%d%c%d%d%d", datalen, type, init_time, recv_time, send_time);

//	printf("===========ICMP Protocol==========\n");

switch(icmp_protocol->type) {
case 8:
// 回显请求报文
break;
case 0:
// 回显应答报文
break;
default:
break;
}
}

void ip_protocol_packet_handle(
u_char *argument,
const struct pcap_pkthdr *packet_header,
const u_char *packet_content
) {
struct ip_header *ip_protocol;
u_int header_length;
u_char tos;
u_short checksum;

ip_address saddr;
ip_address daddr;
u_char ttl;
u_short tlen;
u_short identification;
u_short offset;

printf("===========IP Protocol===========\n");

ip_protocol = (struct ip_header*)(packet_content + 14);
header_length = ip_protocol->header_length * 4;
checksum = ntohs(ip_protocol->checksum);
tos = ip_protocol->tos;
offset = ntohs(ip_protocol->offset);

saddr = ip_protocol->saddr;
daddr = ip_protocol->daddr;
ttl = ip_protocol->ttl;
identification = ip_protocol->identification;
tlen = ip_protocol->tlen;
offset = ip_protocol->offset;

fprintf(fp, "%d%d%c%d%d%d", saddr, daddr, ttl, identification, tlen, offset);

switch(ip_protocol->proto) {
case 6:
tcp_protocol_packet_handle(argument, packet_header, packet_content);
break;
case 17:
udp_protocol_packet_handle(argument, packet_header, packet_content);
break;
case 1:
icmp_protocol_packet_handle(argument, packet_header, packet_content);
break;
default:
break;
}
}

void ethernet_protocol_packet_handle (
u_char *argument,
const struct pcap_pkthdr *packet_header,
const u_char *packet_content
) {
u_short ethernet_type;		// 以太网类型
struct ether_header *ethernet_protocol;		// 以太网协议变量
u_char *mac_string;			// 以太网地址

ethernet_protocol = (struct ether_header*)packet_content;		// 获取以太网数据内容
printf("Ethernet type is : \n");
ethernet_type = ntohs(ethernet_protocol->ether_type);	// 获取以太网类型
printf("	%04x\n", ethernet_type);

switch(ethernet_type) {
case 0x0800:
printf("The network layer is IP protocol\n");
break;
case 0x0806:
printf("The network layer is ARP protocol\n");
break;
default:
break;
}

// 获取以太网源地址
//	printf("MAC Source Address is : \n");
mac_string = ethernet_protocol->ether_shost;

fprintf(fp, "%02x:%02x:%02x:%02x:%02x:%02x",
*mac_string,
*(mac_string + 1),
*(mac_string + 2),
*(mac_string + 3),
*(mac_string + 4),
*(mac_string + 5)
);

// 获取以太网目的地址
//	printf("MAC Target Address is : \n");
mac_string = ethernet_protocol->ether_dhost;
fprintf(fp, "%02x:%02x:%02x:%02x:%02x:%02x",
*mac_string,
*(mac_string + 1),
*(mac_string + 2),
*(mac_string + 3),
*(mac_string + 4),
*(mac_string + 5)
);

fprintf(fp, "%d", sizeof(packet_content));

switch(ethernet_type) {
case 0x0800:
ip_protocol_packet_handle(argument, packet_header, packet_content);
break;
default:
break;
}
}

int main() {
pcap_if_t *alldevs;
pcap_if_t *d;
pcap_t *adhandle;
char errbuf[PCAP_ERRBUF_SIZE];
int inum;
int i = 0;
u_int netmask;
char packet_filter[] = "ip and tcp";
struct bpf_program fcode;
int res;
struct pcap_pkthdr *header;
struct tm *ltime;
const u_char *pkt_data;
time_t local_tv_sec;
char timestr[16];
ip_header *ih;

// 获得设备列表 pcap_findalldevs_ex()

if(pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1) {
fprintf(stderr, "Error in pcap_findalldevs: %s\n", errbuf);
exit(1);
}

for(d = alldevs; d; d = d->next) {
printf("%d. %s", ++i, d->name);
if(d->description) {
printf("(%s)\n", d->description);
}
else {
printf("No description available\n");
}
}

if(0 == i) {
printf("\nNo interface found!Make sure WinPcap is installed\n");
return -1;
}

printf("Enter the interface number(1-%d):", i);
scanf_s("%d", &inum);
if(inum < 1 || inum > i) {
printf("\nInterface number out of range.\n");
pcap_freealldevs(alldevs);
return -1;
}

for(d = alldevs, i = 0; i < inum-1; d=d->next, i++);
// 跳转到该设备,打开适配器

// 设备名,要捕捉的数据包的部分(65536保证能捕获到不同数据链路层上的每个数据包的全部内容),混杂模式,读取超时时间,错误缓冲池
if((adhandle = pcap_open_live(d->name, 65536, 1, 1000, errbuf)) == NULL) {
fprintf(stderr, "\nUnable to open the adapter.%s is not supported by WinPcap\n", errbuf);
pcap_freealldevs(alldevs);
return -1;
}
// 检查数据链路层(只考虑了以太网)
if(pcap_datalink(adhandle) != DLT_EN10MB) {
fprintf(stderr, "\nThis program works only on Ethernet networks.\n");
pcap_freealldevs(alldevs);
return -1;
}

if(d->addresses != NULL) {
// 获得接口的第一个地址的掩码
netmask = ((struct sockaddr_in*)(d->addresses->netmask))->sin_addr.S_un.S_addr;
}
else {
netmask = 0xffffff;
}
/*
// 编译过滤器
if(pcap_compile(adhandle, &fcode, packet_filter, 1, netmask) < 0) {
fprintf(stderr, "\nUnable to compile the packet filter.Check the syntax\n");
pcap_freealldevs(alldevs);
return -1;
}

// 设置过滤器

if(pcap_setfilter(adhandle, &fcode) < 0) {
fprintf(stderr, "\nError setting the filter.\n");
pcap_freealldevs(alldevs);
return -1;
}
printf("\nlistenting on %s...\n", d->description);
*/
fp = freopen("in.txt", "w", stdin);

while((res = pcap_next_ex(adhandle, &header, &pkt_data)) >= 0) {

// 请求超时
if(0 == res) {
continue;
}

// 分析数据包
ethernet_protocol_packet_handle(NULL, header, pkt_data);

// 将时间戳转换成可识别的格式
local_tv_sec = header->ts.tv_sec;
ltime = localtime(&local_tv_sec);
strftime(timestr, sizeof(timestr), "%H:%M:%S", ltime);
ih = (ip_header *)(pkt_data + 14); //以太网头部长度

// 输出时间和IP信息
printf("%s.%.6d len:%d ", timestr, header->ts.tv_usec, header->len);

printf("%d.%d.%d.%d -> %d.%d.%d.%d\n",
ih->saddr.byte1,
ih->saddr.byte2,
ih->saddr.byte3,
ih->saddr.byte4,
ih->daddr.byte1,
ih->daddr.byte2,
ih->daddr.byte3,
ih->daddr.byte4);
}

if(-1 == res) {
printf("Error reading the packet:%s\n", pcap_geterr(adhandle));
return -1;
}
pcap_freealldevs(alldevs);

fclose(fp);
fclose(stdin);

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: