主要选了利用抓包工具对TCP工作过程进行分析和监控IP数据包两个题目,有时间有精力再说别的吧
Fiddler是位于客户端和服务器端的HTTP代理,也是目前最常用的http的抓包工具之一 。(一开始分析的时候没有注意该工具的定位,废了点时间)
Fiddler 下载地址 :https://www.telerik.com/download/fiddler
Fiddler2离线下载地址:https://pan.baidu.com/s/1bpnp3Ef 密码:5skw
这里需要注意,他是用于分析http/HTTPS的工具
如果是处理HTTP,HTTPS 还是用Fiddler, 其他协议比如TCP,UDP 就用wireshark.
软件下载路径:wireshark官网。按照系统版本选择下载,下载完成后,按照软件提示一路Next安装。
如果你是Win10系统,安装完成后,选择抓包但是不显示网卡,下载win10pcap兼容性安装包。下载路径:win10pcap兼容性安装包
wireshark是常用的网络抓包工具,这里尝试用它抓取TCP包并分析三次握手过程
看这个看这个!!https://www.cnblogs.com/xig112635/p/15236771.html
在Windows环境下,选择使用winpcap第三方的库文件
下载地址:https://www.winpcap.org/devel.htm,这里要注意一定要下载开发包
在配置过程中遇到了以下问题
在使用该库时由于Windows系统不兼容导致陷入很长时间的困境,依旧是上面的win10pcap兼容性安装包
未使用Packet.dll文件
解决:下载Packet.dll,将它拷贝到c:\windows\system32目录下即可(这里可以搜一下dll的配置),当然,如果要能让别人使用的话,最好还是要配置一下调用dll文件,比较简单的就是直接将它和exe文件放在一个目录下(vs的话就是debug目录了)
这里再放两个链接,是关于npcap的
Npcap基于WINPCAP,Winpcap基于libpcap,并做出了诸多改进。
下面是官网的介绍,看起来很牛的样子!!!
Npcap is the Nmap Project’s packet capture (and sending) library for
Microsoft Windows. It implements the open Pcap API using a custom
Windows kernel driver alongside our Windows build of the excellent
libpcap library.
这个是npcap的资源包 https://nmap.org/npcap/
这个是GitHub上的仓库 https://github.com/nmap/npcap
将开发包lib和include目录下内容分别拷贝至vs对应目录下,或者选择对该项目的vs目录(include路径和运行库路径增添修改)
如下图:
下面的代码都在vs2019下运行通过了,可以直接用
采用如下代码对环境进行测试
#include
#include
#include
// #include
// #include
#define WPCAP
#define HAVE_REMOTE
#include
#include"remote-ext.h"
//#pragma comment(lib,"wpcap.lib")
using namespace std;
int main()
{
pcap_if_t* alldevs;
pcap_if_t* d;
int i = 0;
char errbuf[PCAP_ERRBUF_SIZE];
/* 获取本地机器设备列表 */
if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL /* auth is not needed */, &alldevs, errbuf) == -1)
{
fprintf(stderr, "Error in pcap_findalldevs_ex: %s\n", errbuf);
exit(1);
}
/* 打印列表 */
for (d = alldevs; d != NULL; d = d->next)
{
printf("%d. %s", ++i, d->name);
if (d->description)
printf(" (%s)\n", d->description);
else
printf(" (No description available)\n");
}
if (i == 0)
{
printf("\nNo interfaces found! Make sure WinPcap is installed.\n");
return 1;
}
/* 不再需要设备列表了,释放它 */
pcap_freealldevs(alldevs);
return 0;
}
遇到问题: VS2019项目出现"const char *" 类型的实参与 “char *” 类型的形参不兼容
解决方案: 可以在VS2019中依次点击项目->属性->C/C+±>语言->符合模式,将原来的“是”改为“否”即可。
2.捕获数据包
下面是捕获所有数据包的示例程序:
#define WPCAP
#define HAVE_REMOTE
#include
#include"remote-ext.h"
//#pragma comment(lib,"wpcap.lib")
using namespace std;
int main()
{
pcap_if_t* allAdapters;//适配器列表
pcap_if_t* adapter;
pcap_t* adapterHandle;//适配器句柄
struct pcap_pkthdr* packetHeader;
const u_char* packetData;
char errorBuffer[PCAP_ERRBUF_SIZE];//错误信息缓冲区
if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL,
&allAdapters, errorBuffer) == -1)
{//检索机器连接的所有网络适配器
fprintf(stderr, "Error in pcap_findalldevs_ex function: %s\n", errorBuffer);
return -1;
}
if (allAdapters == NULL)
{//不存在任何适配器
printf("\nNo adapters found! Make sure WinPcap is installed.\n");
return 0;
}
int crtAdapter = 0;
for (adapter = allAdapters; adapter != NULL; adapter = adapter->next)
{//遍历输入适配器信息(名称和描述信息)
printf("\n%d.%s ", ++crtAdapter, adapter->name);
printf("-- %s\n", adapter->description);
}
printf("\n");
//选择要捕获数据包的适配器
int adapterNumber;
printf("Enter the adapter number between 1 and %d:", crtAdapter);
scanf_s("%d", &adapterNumber);
if (adapterNumber < 1 || adapterNumber > crtAdapter)
{
printf("\nAdapter number out of range.\n");
// 释放适配器列表
pcap_freealldevs(allAdapters);
return -1;
}
adapter = allAdapters;
for (crtAdapter = 0; crtAdapter < adapterNumber - 1; crtAdapter++)
adapter = adapter->next;
// 打开指定适配器
adapterHandle = pcap_open(adapter->name, // name of the adapter
65536, // portion of the packet to capture
// 65536 guarantees that the whole
// packet will be captured
PCAP_OPENFLAG_PROMISCUOUS, // promiscuous mode
1000, // read timeout - 1 millisecond
NULL, // authentication on the remote machine
errorBuffer // error buffer
);
if (adapterHandle == NULL)
{//指定适配器打开失败
fprintf(stderr, "\nUnable to open the adapter\n", adapter->name);
// 释放适配器列表
pcap_freealldevs(allAdapters);
return -1;
}
printf("\nCapture session started on adapter %s\n", adapter->name);
pcap_freealldevs(allAdapters);//释放适配器列表
// 开始捕获数据包
int retValue;
while ((retValue = pcap_next_ex(adapterHandle,
&packetHeader,
&packetData)) >= 0)
{
// timeout elapsed if we reach this point
if (retValue == 0)
continue;
//打印捕获数据包的信息
printf("length of packet: %d\n", packetHeader->len);
}
// if we get here, there was an error reading the packets
if (retValue == -1)
{
printf("Error reading the packets: %s\n", pcap_geterr(adapterHandle));
return -1;
}
pcap_close(adapterHandle);
return 0;
}
3.打印数据包的目的地址和源地址
下面尝试捕获udp数据报并对目标地址和源地址进行输出
可以在参考一下这两个链接查看过滤规则 复杂点的 简单点的
#include
#include
#include
// #include
// #include
#define WPCAP
#define HAVE_REMOTE
#include
#include"remote-ext.h"
#include
#pragma comment(lib,"wpcap.lib")
#pragma comment(lib,"packet.lib")
#pragma comment(lib,"ws2_32.lib")//ntohs头文件及链接库
//#pragma comment(lib,"wpcap.lib")
using namespace std;
/*4 bytes IP address */
typedef struct ip_address
{
u_char byte1;
u_char byte2;
u_char byte3;
u_char byte4;
}ip_address;
/* IPv4 header */
typedef struct ip_header
{
u_char ver_ihl; // Version (4 bits) + Internet header length (4 bits)
u_char tos; // Type of service
u_short tlen; // Total length
u_short identification; // Identification
u_short flags_fo; // Flags (3 bits) + Fragment offset (13 bits)
u_char ttl; // Time to live
u_char proto; // Protocol
u_short crc; // Header checksum
ip_address saddr; // Source address
ip_address daddr; // Destination address
u_int op_pad; // Option + Padding
}ip_header;
/* UDP header*/
typedef struct udp_header
{
u_short sport; // Source port
u_short dport; // Destination port
u_short len; // Datagram length
u_short crc; // Checksum
}udp_header;
/* prototype of the packet handler */
void packet_handler(u_char* param, const struct pcap_pkthdr* header, const u_char* pkt_data);
int main()
{
pcap_if_t* alldevs;
pcap_if_t* d;
pcap_t* adhandle;//数据包
int i = 0;
int inum;
u_int netmask;
char packet_filter[] = "ip and udp";
char errbuf[PCAP_ERRBUF_SIZE];
struct bpf_program fcode;
/* 获取本地机器设备列表 */
/*pcap_findalldevs_ex函数指定本机时指定参数"rpcap://" 或 预定义宏PCAP_SRC_IF_STRING
当指定远程机器时需要按照"rpcap://host:port"的格式,默认端口号为2002
远程机器有密码时需要指定用户名和密码。*/
if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL /* auth is not needed */, &alldevs, errbuf) == -1)
{
fprintf(stderr, "Error in pcap_findalldevs_ex: %s\n", errbuf);
exit(1);
}
/* 打印列表 */
for (d = alldevs; d != NULL; d = d->next)
{
printf("%d. %s", ++i, d->name);
if (d->description)
printf(" (%s)\n", d->description);
else
printf(" (No description available)\n");
}
if (i == 0)
{
printf("\nNo interfaces found! Make sure WinPcap is installed.\n");
return 1;
}
printf("Enter the interface number (1-%d):", i);
scanf_s("%d", &inum);
/* Check if the user specified a valid adapter */
if (inum < 1 || inum > i)
{
printf("\nAdapter number out of range.\n");
/* Free the device list */
pcap_freealldevs(alldevs);
return -1;
}
/* Jump to the selected adapter */
for (d = alldevs, i = 0; i < inum - 1; d = d->next, i++);
/* Open the adapter */
adhandle = pcap_open_live(d->name, // name of the device
65536, // portion of the packet to capture.
// 65536 grants that the whole packet will be captured on all the MACs.
PCAP_OPENFLAG_PROMISCUOUS, // promiscuous mode (nonzero means promiscuous)
1000, // read timeout
errbuf // error buffer
);
if (adhandle == NULL)
{
fprintf(stderr, "\nUnable to open the adapter. %s is not supported by WinPcap\n");
/* Free the device list */
pcap_freealldevs(alldevs);
return -1;
}
if (pcap_datalink(adhandle) != DLT_EN10MB)//判断链路层数据类型
{
fprintf(stderr, "\nThis program works only on Ethernet networks.\n");
/* Free the device list */
pcap_freealldevs(alldevs);
return -1;
}
if (d->addresses != NULL)
/* Retrieve the mask of the first address of the interface */
netmask = ((struct sockaddr_in*)(d->addresses->netmask))->sin_addr.S_un.S_addr;
else
/* If the interface is without addresses we suppose to be in a C class network */
netmask = 0xffffff;
//compile the filter
if (pcap_compile(adhandle, &fcode, packet_filter, 1, netmask) < 0)//把用户输入的过滤字符串编译进过滤信息的,这个过滤信息可以决定哪些包是用户可获取到的 。
{
fprintf(stderr, "\nUnable to compile the packet filter. Check the syntax.\n");
/* Free the device list */
pcap_freealldevs(alldevs);
return -1;
}
/* 不再需要设备列表了,释放它 */
pcap_freealldevs(alldevs);
/* start the capture */
pcap_loop(adhandle, 0, packet_handler, NULL);
//pcap_close(adhandle);
return 0;
}
void packet_handler(u_char* param, const pcap_pkthdr* header, const u_char* pkt_data)
{
printf("抓到数据了 ");
struct tm* ltime;
char timestr[16];
ip_header* ih;
udp_header* uh;
u_int ip_len;
u_short sport, dport;
time_t local_tv_sec;
/* convert the timestamp to readable format */
local_tv_sec = header->ts.tv_sec;
ltime = new struct tm;
time(&local_tv_sec);
localtime_s(ltime, &local_tv_sec);
//ltime=localtime(&local_tv_sec);//该函数在vs2010以后被弃用,改用增加了安全的localtime_s
strftime(timestr, sizeof timestr, "%H:%M:%S", ltime);
/* print timestamp and length of the packet */
printf("%s.%.6d len:%d \n", timestr, header->ts.tv_usec, header->len);
/* retireve the position of the ip header */
ih = (ip_header*)(pkt_data +
14); //length of ethernet header
/* retireve the position of the udp header */
ip_len = (ih->ver_ihl & 0xf) * 4;
uh = (udp_header*)((u_char*)ih + ip_len);
/* convert from network byte order to host byte order */
sport = ntohs(uh->sport);
dport = ntohs(uh->dport);
/* print ip addresses and udp ports */
printf("%d.%d.%d.%d.%d -> %d.%d.%d.%d.%d\n",
ih->saddr.byte1,
ih->saddr.byte2,
ih->saddr.byte3,
ih->saddr.byte4,
sport,
ih->daddr.byte1,
ih->daddr.byte2,
ih->daddr.byte3,
ih->daddr.byte4,
dport);
}