pcap文件解析

本文介绍了如何直接读取和解析pcap文件,避免了将pcap包转换为txt格式的过程。通过理解pcap文件的结构体并在读取时注意字节顺序的转换,如使用ntohs()函数,可以正确解析TCP和UDP协议的数据包。作者分享了实践经验和代码示例,并展示了读取结果。此外,推荐了一个MFC教程链接。

看了很久终于搞清楚怎么解析pcap文件啦~以前的一个版本是我把pcap包保存成.txt,删除冗余项,然后再依照格式读入,输出相应格式。后来,我发现其他同学都是用.pcap格式直接读入的,然后我就不懂了,直接读入的pcap文件格式应该是什么样子的?根据实战经验,应该就是网上各种教程解析的那种格式,根据那种格式按字节读入就可以啦!下面上代码:

这个是pcap.h 里面定义了pcap文件的主要结构体。

#include<afx.h>
#include<stdio.h>
#include<direct.h>
#include<iostream>
#include<cstring>
using namespace std;
#include<stdlib.h>
#include<math.h>
#include <winsock2.h>
#pragma  comment(lib,"ws2_32.lib")
typedef long int32;
typedef unsigned long u_int32;
typedef unsigned short u_int16;
typedef unsigned char u_int8;
//pcap文件头结构
typedef struct pcap_file_header{
	u_int32 magic;//标识位
	u_int16 version_major;//主版本号
	u_int16 version_minor;//副版本号
	int32 thiszone;//区域时间
	u_int32 sigfigs;//精确时间戳
	u_int32 snaplen;//数据包最大长度
	u_int32 linktype;//链路层类型
}pcapFileHeader;
//packet数据包头文件
typedef struct pcap_packet_header{
	int32 sec;//秒计时时间戳
	int32 microsec;//微秒计时时间戳
	u_int32 caplen;//数据包长度,即所捕获的数据包保存在pcap文件中的实际长度
	u_int32 len;//数据包实际长度,即所捕获的数据包的真实长度
}pcapPacketHeader;
//捕获的以太网帧头
typedef struct ehternet_header{
	u_int8 dstMac[6];//目的Mac地址
	u_int8 srcMac[6];//源Mac地址
	u_int16 type;//帧类型
}ehternetHeader;
//IP数据报头
typedef struct ip_header{
	u_int8 ver_hlen;//版本+报头长度
	u_int8 typeOfService;//服务类型
	u_int16 totalLen;//总长度
	u_int16 id;//标识
	u_int16 flag_Segment;//标志+片偏移
	u_int8 ttl;//生存期
	u_int8 protocol;//协议类型
	u_int16 checksum;//校验和
	struct in_addr srcIP;//源IP地址
	struct in_addr dstIP;//目的IP地址
}ipHeader;
//TCP数据报头
typedef struct tcp_header{
	u_int16 srcPort;//源端口
	u_int16 dstPort;//目的端口
	u_int32 seqNO;//序列号
	u_int32 ackNO;//确认号
	u_int8 headerLen;//数据报头长度+保留
	u_int8 flags;//标识TCP不同的控制消息
	u_int16 window;//窗口大小
	u_int16 checkSum;//校验和
	u_int16 urgentPointer;//紧急指针
}tcpHeader;
//UDP数据报头
typedef struct udp_header{
	u_int16 srcPort;//源端口
	u_int16 dstPort;//目的端口
	u_int16 len;//UDP首部长度+UDP数据长度
	u_int16 checkSum;//UDP校验和
}udpHeader;
void readPacket(CString inputPath,CString outputPath);//读pcap文件
void writetcp(ipHeader *ipHead,tcpHeader *tcpHead,char *outputPath);//写入TCP
void writeudp(ipHeader *ipHead,udpHeader *udpHead,char *outputPath);//写入UDP
下面的是pcap.cpp文件,就是具体的实现函数了
#include "StdAfx.h"
#include"pcap.h"
FILE *fp=NULL;
FILE *output=NULL;
FILE *pcapfp=NULL;
void readPacket(CString inputPath,CString outputPath){
	int pkt_offset;
	pcapFileHeader *fileHeader;
	pcapPacketHeader *packetHeader;
	ehternetHeader *ehHeader;
	ipHeader *ipHead;
	tcpHeader *tcpHead;
	udpHeader *udpHead;
	fileHeader=(pcapFileHeader *)malloc(sizeof(pcapFileHeader));
	packetHeader=(pcapPacketHeader *)malloc(sizeof(pcapPacketHeader));
	ehHeader=(ehternetHeader *)malloc(sizeof(ehternetHeader));
	ipHead=(ipHeader *)malloc(sizeof(ipHeader));
	tcpHead=(tcpHeader *)malloc(sizeof(tcpHeader));
	udpHead=(udpHeader *)malloc(sizeof(udpHeader));
	inputPath.Replace(L"\\",L"\\\\");
	outputPath.Replace(L"\\",L"\\\\");
        //以下是将CString格式转化为char*  注意使用Unicode字符集和使用多字节字符集的转化方法不一样
       int n=inputPath.GetLength(); //按字符计算,str的长度
	int len=WideCharToMultiByte(CP_ACP,0,inputPath,n,NULL,0,NULL,NULL);//按Byte计算str长度
	char *s1 = new char[len+1];//按字节为单位
	WideCharToMultiByte(CP_ACP,0,inputPath,n,s1,len,NULL,NULL);//宽字节转换为多字节编码
	s1[len] = '\0';//不要忽略末尾结束标志
	n=outputPath.GetLength(); //按字符计算,str的长度
	len=WideCharToMultiByte(CP_ACP,0,outputPath,n,NULL,0,NULL,NULL);//按Byte计算str长度
	char *s2 = new char[len+1];//按字节为单位
	WideCharToMultiByte(CP_ACP,0,outputPath,n,s2,len,NULL,NULL);//宽字节转换为多字节编码
	s2[len] = '\0';//不要忽略末尾结束标志
	fp=fopen(s1,"rb");
	if(fp==NULL){
		printf("no pacp file");
	}
	pkt_offset=24;
	while(fseek(fp,pkt_offset,SEEK_SET)==0&&feof(fp)==0){
		if(fread(packetHeader,sizeof(pcapPacketHeader),1,fp)!=1){
			break;
		}
		pkt_offset+=16+packetHeader->caplen;
		if(fread(ehHeader,sizeof(ehternetHeader),1,fp)!=1){
			break;
		}
		else if(ntohs(ehHeader->type)!=0x0800){
			continue;
		}
		if(fread(ipHead,sizeof(ipHeader),1,fp)!=1){
			break;
		}
		if(ipHead->protocol==0x06){
			if(fread(tcpHead,sizeof(tcpHeader),1,fp)!=1){
				break;
			}
			writetcp(ipHead,tcpHead,s2);
		}
		if(ipHead->protocol==0x11){
			if(fread(udpHead,sizeof(udpHeader),1,fp)!=1){
				break;
			}
			writeudp(ipHead,udpHead,s2);
		}
	}
	fclose(fp);
}
void writetcp(ipHeader *ipHead,tcpHeader *tcpHead,char *outputPath){
	char *savePath=(char *)malloc(1024);
	u_int *fileheader=NULL;
	char path1[1024],path2[1024];
	strcpy(path1, inet_ntoa(ipHead->srcIP));
	strcpy(path2, inet_ntoa(ipHead->dstIP));
	sprintf(savePath,"%s\\\\TCP",outputPath);
	_mkdir(savePath);
	sprintf(savePath,"%s\\\\TCP\\\\tcp[%s][%d][%s][%d].txt",outputPath,path1,ntohs(tcpHead->srcPort),path2,ntohs(tcpHead->dstPort));
	output=fopen(savePath,"a+");
	fprintf(output,"[源端口]:%d\n[目的端口]:%d\n[序号]:%d\n[确认号]:%d\n[数据报头长度]:%d\n[控制消息]:%d\n[窗口大小]:%d\n[校验和]:%d\n[紧急指针]:%d\n\n\n\n\n",ntohs(tcpHead->srcPort),ntohs(tcpHead->dstPort),ntohs(tcpHead->seqNO),ntohs(tcpHead->ackNO),ntohs(tcpHead->headerLen),ntohs(tcpHead->flags),ntohs(tcpHead->window),ntohs(tcpHead->checkSum),ntohs(tcpHead->urgentPointer));
	fclose(output);
}
void writeudp(ipHeader *ipHead,udpHeader *udpHead,char *outputPath){
	char *savePath=(char *)malloc(1024);
	char path1[1024],path2[1024];
	strcpy(path1, inet_ntoa(ipHead->srcIP));
	strcpy(path2, inet_ntoa(ipHead->dstIP));
	sprintf(savePath,"%s\\\\UDP",outputPath);
	_mkdir(savePath);
	sprintf(savePath,"%s\\\\UDP\\\\udp[%s][%d][%s][%d].txt",outputPath,path1,ntohs(udpHead->srcPort),path2,ntohs(udpHead->dstPort));
	output=fopen(savePath,"a+");
	fprintf(output,"[源端口]:%d\n[目的端口]:%d\n[长度]:%d\n[校验和]:%d]\n\n\n\n\n",ntohs(udpHead->srcPort),ntohs(udpHead->dstPort),ntohs(udpHead->len),ntohs(udpHead->checkSum));
	fclose(output);
}
实现遇到的主要问题是把文件路径从CString格式转为char*,因为使用的是Unicode字符集,所以搜索的时候需要特别注明

还有就是第一次输出结果不正确,后来发现是因为没有把读入的数据转为主机字节顺序,用网络字节顺序计算,结果当然不对啦。要用ntohs()函数。

这个函数的输出是TCP和UDP两个文件夹,里面分别存放了TCP和UDP协议对应的包信息。

这是路径下的文件夹:

这是TCP文件打开的样子

这是打开.txt文件的样子:


UDP文件夹是一样的啦~


还有,推荐一个超赞的MFC教程:

http://blog.sina.com.cn/s/blog_671f486a0102voqr.html


在CTF竞赛中,解析PCAP(Packet Capture)文件是常见的任务之一,通常涉及网络流量分析、协议识别、数据提取等操作。以下是一些常用工具和方法,可以帮助从PCAP文件中提取有用信息。 ### 使用Wireshark进行深入分析 Wireshark 是一款功能强大的图形化网络协议分析工具,支持多种操作系统(如Windows、Linux、macOS)。它可以直观地展示每个数据包的详细结构,并提供过滤器语法用于快速定位目标信息。 - **基本操作**:打开PCAP文件后,可以使用显示过滤器(Display Filters)筛选特定协议的数据包,例如 `http` 或 `tcp.port == 80`。 - **导出对象**:对于HTTP流量,可以使用“File > Export Objects”功能导出传输的文件或图片,这在寻找隐藏的flag时非常有用[^1]。 - **追踪流**:右键点击某个TCP连接,选择“Follow > TCP Stream”,能够查看完整的会话内容,有助于发现嵌入在通信中的flag。 ### 使用Tcpdump进行命令行分析 Tcpdump 是一个轻量级的命令行工具,适用于Linux系统。它适合于自动化脚本编写以及远程服务器上的实时抓包。 - **基础命令**:`tcpdump -r file.pcap` 可以读取并显示PCAP文件中的所有数据包。 - **过滤规则**:通过添加表达式来限制输出,例如 `tcpdump -r file.pcap 'tcp port 80'` 将只显示端口为80的流量。 - **保存结果**:使用 `-w` 参数将过滤后的数据保存到新的PCAP文件中,便于后续处理。 ### 利用Zeek进行高级流量检测 Zeek(原名Bro)不仅是一个嗅探器,还具备深度检查能力,能生成详细的日志文件,包括连接统计、SSL握手细节等。 - **执行分析**:运行 `zeek -r file.pcap` 将对指定的PCAP文件进行分析,并生成多个日志文件。 - **日志解读**:重点关注conn.log(连接记录)、dns.log(DNS查询)以及ssl.log(SSL/TLS握手信息),这些可能包含异常行为或隐藏的数据[^1]。 ### 提取隐藏信息的小技巧 有时,CTF题目会利用非标准方式隐藏flag,比如在ICMP报文负载中编码消息或者在TLS加密通道内传递线索。 - **Hex Dump查看**:在Wireshark中启用十六进制视图(View > Show Packet in New > Hex Dump),直接观察原始字节流是否有可读字符串。 - **解密HTTPS流量**:如果提供了服务器私钥,则可以在Wireshark中配置该密钥以解密相关SSL/TLS流量。 - **脚本辅助**:编写Python脚本结合Scapy库解析PCAP文件,自动搜索特定模式或尝试恢复被分割发送的信息段。 ### 示例代码:使用Scapy解析PCAP文件 ```python from scapy.all import * # 读取PCAP文件 packets = rdpcap('example.pcap') # 遍历每个数据包 for packet in packets: if packet.haslayer(Raw): # 打印原始载荷 print(packet[Raw].load) ``` 此示例展示了如何用Scapy加载PCAP文件并打印出所有携带原始数据的有效载荷部分,这对于查找未经加密的敏感信息特别有效。 ---
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值