01 概述
基于tshark, cpp开发类wireshark软件 nbEasyTshark
Wireshark主要特点:
- 支持三千多种协议深度解析
- 实时捕获和离线分析
- 强大的过滤功能 (Display Filter、Capture Filter)
- 支持流分析(FollowStream)
- 支持多种操作系统(Windows、Linux、macOS)
- tshark命令练习
- 使用
tshark -D枚举你的网络接口。 - 选择合适的网卡接口并抓取1000个数据包(提示:使用
-c 1000参数限制抓包数量),然后保存为capture.pcap。 - 解析
capture.pcap并筛选出所有TCP协议的数据包。 - 统计
capture.pcap中各个协议的数据包数量。
- 使用
02 开发环境搭建
真的很久很久没开发windows端应用了。这次使用VisualStudio 2022为IDE开发,习惯了JB家的IDE和高颜值vscode,用这个old school的界面看着有点难受喵~
挂一个项目地址:https://github.com/yangnanbei/nb_easy_tshark
首先我们要读取tshark的内容。tshark工具可以在命令行下分析数据包,我们整点包先。
tshark -h一堆东西输出,toooo verbose,我直接不看,问一手AI先。
tshark -D
找网口:

那么显然 \Device\NPF_{FFCB4D95-E737-4DCA-B016-522C9BA641B5} 这就是我们要找的网口了
tshark制定网口留存1000个数据包:
tshark -i ‘\Device\NPF_{FFCB4D95-E737-4DCA-B016-522C9BA641B5}’ -c 1000 -w capture.pcap
注意反斜杠有需要转义,我们可以直接用单引号括起来先。
ok,拿到了对应的包。
Length Name
263324 capture.pcap
VisualStudio cmd编码问题
将tshark的输出通过popen传入Visual Studio,测试时发现了个问题。
那就是cmd的默认编码是gbk的,需要改成utf8才能愉快玩耍~
见以下攻略:
C++/8/VS2022更改为UTF-8的n种方法 – 归海言诺 – 博客园
但是博主的攻略有个问题是:
HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor
在右侧窗格中,右键单击空白区域,选择“新建”>“DWORD值(32位)”。
将新创建的DWORD值命名为“Autorun”,然后双击它以编辑其值数据。
在“数值数据”框中,输入“chcp 65001”,然后点击“确定”
这里“新建”>“DWORD值(32位)”是不对的,类型得是字符串类型。
但是后续发现设置autorun会导致cmd/powershell启动报错
最后采用在main函数开头设置utf8属性
setlocale(LC_ALL, "zh_CN.UTF-8");
03 以json格式获取数据包信息
我们通过tshark获取信息之后要将其存储下来,
信息结构体:
相关命令:
tshark -r .\10pkts.pcap -T fields -e frame.number -e frame.time -e ip.src -e ip.dst -e _ws.col.Protocol -e _ws.col.Info
解析离线包的相关数据:
typedef struct Packet_ {
int frame_number;
std::string time;
std::string src_ip;
std::string dst_ip;
int src_port;
int dst_port;
std::string protocol;
std::string info;
} Packet;使用rapidjson库以json格式输出,解析成功:

04 pcap文件格式
我们已经可以读取离线pcap的一些元组信息。现在我们需要获取数据包的原始十六进制数据

那么将packet的数据保存在结构体中,在需要的时候去读吧。
packet文件格式

可以看到 pcap文件结构中,以一个24字节的Pcap Header开头,而后的每个包都以Packet Header+Packet Data的形式存在。
Pcap Header
全局文件头,共24B位于文件的起始位置,每个文件只有一个。包含如下字段
magic number(4B): 用于标识文件格式- 可以从此区分大端(0xa1b2c3d4)和小端(0x4dc3b2a1)
- 现在电脑大部分是小端模式
- 可以从此区分大端(0xa1b2c3d4)和小端(0x4dc3b2a1)
version(2B + 2B):pcap文件版本号,如2.4- major(2B): 主要版本
- minor(2B): 次要版本
this zone(4B): 时区偏移,通常为0sigfigs(4B): 时间戳精度,通常为0snaplen(4B): 捕获的数据表最大长度network(4B): 链路层类型,如以太网
Packet Header
每个数据表的metadata,共16B,包含如下字段:
timestamp second(4B): 时间戳, 秒级timestamp microseconds(4B):时间戳,微妙级capture length(4B): 实际捕获的数据包长度。即抓取到的数据帧长度,由此可以得到下一个数据帧的位置。original length(4B): 数据包原始长度。离线数据长度,网路中实际数据帧的长度,一般不大于 Caplen,多数情况下和 Caplen值一样
数据表数据以16进制的形式存储。我们可以将其读取后以16进制形式打印出来
/* read pcap data */
std::vector<unsigned char> data(packetHeader.caplen);
file.read(reinterpret_cast<char*>(data.data()), packetHeader.caplen);
按照之前所说,我们现在要记录报文的偏移和长度,把它保存起来,那就需要
- 修改一下packet的结构体。
- tshark在分析的时候,将报文的长度输出出来:
frame.cap_len. 这样我们就能获取报文长度,来计算偏移并记录了。
在解析的时候记录每个包的offset+caplen,而后在最后读取文件时输出即可。
解析函数:
bool readPacketHex(const std::string& packet_file, uint32_t file_offset,
uint32_t length, std::vector<unsigned char>& buffer)
{
buffer.resize(length);
FILE* file = fopen(packet_file.c_str(), "rb");
if (!file) {
std::cerr << "Failed to open file: " << packet_file << std::endl;
buffer.clear();
return false;
}
if (fseek(file, file_offset, SEEK_SET) != 0) {
std::cerr << "Failed to seek to offset: " << file_offset << std::endl;
fclose(file);
buffer.clear();
return false;
}
size_t bytesRead = fread(buffer.data(), 1, length, file);
fclose(file);
if (bytesRead != length) {
std::cerr << "Failed to read data from file. Expected: " << length << ", got: " << bytesRead << std::endl;
buffer.resize(bytesRead);
return false;
}
return true;
}此时我们的相关定义如下:
struct PcapHeader {
uint32_t magic_number;
uint16_t version_major;
uint16_t version_minor;
int32_t thiszone;
uint32_t sigfigs;
uint32_t snaplen;
uint32_t network;
};
struct PacketHeader {
uint32_t ts_sec;
uint32_t ts_usec;
uint32_t caplen;
uint32_t len;
};
struct Packet {
int frame_number;
std::string time;
uint32_t cap_len;
std::string src_ip;
uint16_t src_port;
std::string dst_ip;
uint16_t dst_port;
std::string protocol;
std::string info;
uint32_t file_offset;
};测试:
试一试我们解析出的hex数据和wireshark中做比较:
我们解析的:

wireshark中:
是能对应上的~










