WinPcap编程(二)
0.
这一次具体讲抓包的两种方法。
(建议)清除ARP表,最好自己写个批处理命令。快一点。
1.0 抓包步骤
步骤很简单:先打开适配器列表 --> 选择适配器 --> 通过遍历链表的方式到达你选择的适配器位置 --> 打开设备 --> 开始抓包。
每一个步骤都是一个函数。了解步骤,后面就好办。
首先,了解一个数据类型pcap/pcap_t。它代表一个打开的设备,理解成它就是适配器就行(实际上是这个适配器的描述符)。这个结构体对用户来说是不透明的,它通过wpcap.dll提供的函数,维护了它的内容。
然后,跳转至你的设备在WinPcap编程(一)中存在,就不多说。
之后,打开设备的函数:
pcap_t* pcap_open ( const char * source, int snaplen, int flags, int read_timeout, struct pcap_rmtauth * auth, char * errbuf )
备注:
第一个参数:source是我们所要打开的设备。当我们获取所有的设备之后,这个source就是d->name。不能为NULL。
第二个参数:snaplen是我们抓取的数据包的大小,100就是抓取整个数据包的前100B,65536最大,把整个包都包括了。
第三个参数:flags设置为混杂模式(PCAP_OPENFLAG_PROMISCUOUS ),即不管数据包是否给我,我都去捕获。这样可以捕捉局域网内所有的包。
第四个参数: read_timeout设置超时时间,以毫秒计(1s=1000ms)。在适配器上进行读取数据操作的时候,不管网络上有没有包,都会在 read_timeout这个时间内响应。
设置为0意味着没有超时。没有数据包到达,读操作将永远不会返回。
设置成-1,无论有没有数据包到达,读操作都会立即返回。
第五个参数:auth远程机登录信息,若本地则为NULL;
第六个参数:errbuf 出错信息。
1.1抓包的两种方式:
1.1.1 回调函数的方法进行抓包
每次抓到包就用回调函数进行处理。处理完接着抓包(如果设置了num的话)。
抓包函数:
int pcap_loop ( pcap_t * p, int cnt, pcap_handler callback, u_char * user )
备注0:
第一个参数:P即是打开的设备。
第二个参数:cnt表示捕捉个数。
第三个参数:回调函数指针。对捕捉的数据包进行操作 。
第四个参数:用户信息,一般为NULL。
函数返回值:
返回值为0,捕捉了cnt次,正常返回。
返回值为-1,发生错误。
返回值为-2,使用pcap_breakloop()结束循环。
回调函数抓包还有一种方法, pcap_dispatch() 。
区别是: pcap_ dispatch() 当超时时间到了(timeout expires)就返回 (尽管不能保证) ,而 pcap_loop() 不会因此而返回,只有当 cnt 数据包被捕获。
所以,pcap_loop()会在一小段时间内,阻塞网络的利用。pcap_dispatch() 函数一般用于比较复杂的程序中。
1.1.2 不利用回调函数
回调函数比较好,但是有时候需要不用回调函数的方法,特别在多线程里面。
我用C# + WPF写的,用回调函数的话一直出现错误。仔细考虑,应该是托管与非托管的问题。看了SharpPcap的源码,貌似也没有好的解决方案。
【有好的方案的看见了希望能够提供一下,感谢。】
不利用回调函数抓包的话,方法比较简单,每次只能抓一个包,加个while()循环就OK了。
int pcap_next_ex (
pcap_t * p,
struct pcap_pkthdr ** pkt_header,
const u_char ** pkt_data
)
备注:
第一个参数:打开的设备。
第二个参数:WinPcap添加的一些信息。(时间戳,捕捉到包的长度,实际包的长度)。
第三个参数:实际数据包。
函数返回值:
返回值为1,正常返回;
返回值为0,超时后返回一个无效的包;
返回值为-1,发生错误;
返回值为-2,读到EOF。
源码:
#define WIN32
#include "pcap.h"
#include "winsock.h"
#include "time.h" /* 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;
int inum;
int i = ;
pcap_t *adhandle;
char errbuf[PCAP_ERRBUF_SIZE]; /* 获取本机设备列表 */
if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -)
{
fprintf(stderr, "Error in pcap_findalldevs: %s\n", errbuf);
exit();
} /* 打印列表 */
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 (i == )
{
printf("\nNo interfaces found! Make sure WinPcap is installed.\n");
return -;
} printf("Enter the interface number (1-%d):", i);
scanf_s("%d", &inum); if (inum < || inum > i)
{
printf("\nInterface number out of range.\n");
/* 释放设备列表 */
pcap_freealldevs(alldevs);
return -;
} /* 跳转到选中的适配器 */
for (d = alldevs, i = ; i< inum - ; d = d->next, i++); /* 打开设备 */
if ((adhandle = pcap_open(d->name, // 设备名
, // 65535保证能捕获到不同数据链路层上的每个数据包的全部内容
PCAP_OPENFLAG_PROMISCUOUS, // 混杂模式
, // 读取超时时间
NULL, // 远程机器验证
errbuf // 错误缓冲池
)) == NULL)
{
fprintf(stderr, "\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name);
/* 释放设备列表 */
pcap_freealldevs(alldevs);
return -;
} printf("\nlistening on %s...\n", d->description); /* 释放设备列表 */
pcap_freealldevs(alldevs); /* 开始捕获 */
pcap_loop(adhandle, , packet_handler, NULL); system("pause");
return ;
} /* 每次捕获到数据包时,libpcap都会自动调用这个回调函数 */
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)
{
struct tm ltime = {};
char timestr[];
time_t local_tv_sec; /* 将时间戳转换成可识别的格式 */
local_tv_sec = header->ts.tv_sec;
localtime_s(<ime, &local_tv_sec);
strftime(timestr, sizeof timestr, "%H:%M:%S", <ime); printf("%s,%.6d len:%d\n", timestr, header->ts.tv_usec, header->len);
}
回调函数
#define WIN32
#include "pcap.h" int main()
{
pcap_if_t *alldevs;
pcap_if_t *d;
int inum;
int i = ;
pcap_t *adhandle;
int res;
char errbuf[PCAP_ERRBUF_SIZE];
struct tm ltime;
char timestr[];
struct pcap_pkthdr *header;
const u_char *pkt_data;
time_t local_tv_sec; int j = ;//限制只抓10个包 /* 获取本机设备列表 */
if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -)
{
fprintf(stderr, "Error in pcap_findalldevs: %s\n", errbuf);
exit();
} /* 打印列表 */
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 (i == )
{
printf("\nNo interfaces found! Make sure WinPcap is installed.\n");
return -;
} printf("Enter the interface number (1-%d):", i);
scanf_s("%d", &inum); if (inum < || inum > i)
{
printf("\nInterface number out of range.\n");
/* 释放设备列表 */
pcap_freealldevs(alldevs);
return -;
} /* 跳转到已选中的适配器 */
for (d = alldevs, i = ; i< inum - ; d = d->next, i++); /* 打开设备 */
if ((adhandle = pcap_open(d->name, // 设备名
, // 要捕捉的数据包的部分
// 65535保证能捕获到不同数据链路层上的每个数据包的全部内容
PCAP_OPENFLAG_PROMISCUOUS, // 混杂模式
, // 读取超时时间
NULL, // 远程机器验证
errbuf // 错误缓冲池
)) == NULL)
{
fprintf(stderr, "\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name);
/* 释放设列表 */
pcap_freealldevs(alldevs);
return -;
} printf("\nlistening on %s...\n", d->description); /* 释放设备列表 */
pcap_freealldevs(alldevs); /* 获取数据包 */
while ((res = pcap_next_ex(adhandle, &header, &pkt_data)) >= &&j>){ if (res == )
/* 超时时间到 */
continue; /* 将时间戳转换成可识别的格式 */
local_tv_sec = header->ts.tv_sec;
localtime_s(<ime,&local_tv_sec);
strftime(timestr, sizeof timestr, "%H:%M:%S", <ime);
j--; printf("%s,%.6d len:%d\n", timestr, header->ts.tv_usec, header->len);
} if (res == -){
printf("Error reading the packets: %s\n", pcap_geterr(adhandle));
return -;
}
system("pause");
return ;
}
非回调函数
WinPcap编程(二)的更多相关文章
- Linux shell脚本编程(二)
Linux shell脚本编程(二) 练习:求100以内所有偶数之和; 使用至少三种方法实现; 示例1: #!/bin/bash # declare -i sum=0 #声明一个变量求和,初始值为0 ...
- 【原创】高性能网络编程(二):上一个10年,著名的C10K并发连接问题
1.前言 对于高性能即时通讯技术(或者说互联网编程)比较关注的开发者,对C10K问题(即单机1万个并发连接问题)应该都有所了解."C10K"概念最早由Dan Kegel发布于其个人 ...
- Java并发编程二三事
Java并发编程二三事 转自我的Github 近日重新翻了一下<Java Concurrency in Practice>故以此文记之. 我觉得Java的并发可以从下面三个点去理解: * ...
- WinPcap编程入门实践
转自:http://www.cnblogs.com/blacksword/archive/2012/03/19/2406098.html WinPcap可能对大多数人都很陌生,我在这里就先简单介绍一下 ...
- Python进阶之面向对象编程(二)
Python面向对象编程(二) .note-content {font-family: "Helvetica Neue",Arial,"Hiragino Sans GB& ...
- Linux网络编程(二)
Linux网络编程(二) 使用多进程实现服务器并发访问. 采用多进程的方式实现服务器的并发访问的经典范例. 程序实现功能: 1.客户端从标准输入读入一行文字,发送到服务器. 2.服务器接收到客户端发来 ...
- java GUI编程二
java基础学习总结--GUI编程(二) 一.事件监听 测试代码一: 1 package cn.javastudy.summary; 2 3 import java.awt.*; 4 import j ...
- Java Socket聊天室编程(二)之利用socket实现单聊聊天室
这篇文章主要介绍了Java Socket聊天室编程(二)之利用socket实现单聊聊天室的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下 在上篇文章Java Socket聊天室编程(一)之 ...
- s3c2440裸机-时钟编程(二、配置时钟寄存器)
s3c2440裸机编程-时钟编程(二.配置时钟寄存器) 1.2440时钟时序 下图是2440时钟配置时序: 1.上电后,nRESET复位信号拉低,此时cpu还无法取指令工作. 2.nRESET复位信号 ...
随机推荐
- 数学概念——I - 数论,线性方程
I - 数论,线性方程 Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u Submit ...
- [Java] JavaMail 简单案例
网易提供了免费的 SMTP / POP3服务,可用于编程测试,详情见 什么是POP3.SMTP和IMAP? 只需要拥有一个网易邮箱账号,并开启该账号的 SMTP / POP3 功能,便可以通过程序发送 ...
- 《Mathematical Olympiad——组合数学》——染色问题
恢复 继续关于<Mathematical Olympiad——组合数学>中问题的分析,这一篇文章将介绍有关染色的问题. 问题一: 将一些石头放入10行14列的矩形方格表内,允许在每个单元 ...
- Servlet的接口实现类
Sun公司提供了两个默认实现类 GenericServlet和HttpServlet HttpServlet指能够处理Http请求的Servlet,它在原有的Servlet基础上添加了与HTTp相关的 ...
- VC++ 动态检测串口的热插拔(一)通过注册表实现
在上一篇文章中讲述了如何通过循环遍历的方法获取可用串口,可是这样的方法过于暴力,难免会想有没有其他的办法那,嘿嘿,那是肯定会有的,不管什么问题,解决问题的方法永远都不止一种.下面讲述如何通过注册表来获 ...
- 隐式intent
使用隐式Intent,我们不仅可以启动自己程序内的活动,还可以启动其他程序的活动, 这里我们首先指定了Intent的action是Intent.ACTION_VIEW,这是一个Android系统内置的 ...
- jQuery EasyUI动态添加控件或者ajax加载页面后不能自动渲染问题的解决方法
博客分类: jquery-easyui jQueryAjax框架HTML 现象: AJAX返回的html无法做到自动渲染为EasyUI的样式.比如:class="easyui-layout ...
- 老鸟的Python新手教程
重要说明 这不是给编程新手准备的教程,假设您入行编程不久,或者还没有使用过1到2门编程语言,请移步!这是有一定编程经验的人准备的.最好是熟知Java或C,懂得命令行,Shell等.总之,这是面向老鸟的 ...
- 一个站点的诞生06-- ORM
站点上的数据,存在数据库里. 一般用Mysql,也实用sqlite,Postgre.操作数据库要会SQL语言,这个有点麻烦,经常须要查手冊. 此外.每家数据库在实现SQL语言的时候,经常会加料,添加一 ...
- PHP安全编程:主机文件目录浏览(转)
除了能在共享服务器上读取任意文件之外,攻击者还能建立一个可以浏览文件系统的脚本.由于你的大多数敏感文件不会保存在网站主目录下,此类脚本一般用于找到你的源文件的所在位置.请看下例: 01 <?ph ...