前言
在正式开始本文前先来一段废话.
工作中经常会使用到自己没有接触过的技术, 而后不断的百度, 谷歌查询, 不断的摸索最终找到解决自己遇到的难题的解决方案. 每次都想写一些总结分享一下, 但是总觉得自己文笔不佳, 而相关技术的文章网络上多不胜数, 也不缺自己写的, 所以到最后总是不了了之
几个月后回头看一看自己做过的项目, 用过的技术, 觉得又熟悉又陌生, 用过却忘记了.
偶然听同事说的一句话很受感触: 写文章写总结并不一定要写的多好, 更重要的是将自己遇到过的难题以及解决方案分享, 这样当别的 IT Guys在遇到相同难题时, 能快速的定位和解决, 提高工作效率, 这才是分享精神. 想一下: 遇到个bug, 错误的时候, 还不是从其他伙伴的总结, 笔记里一个个方案摸索尝试, 最后解决问题的呢?
以上总结一句话就是: 写得不好, 不要吐槽我; 没帮上你, 别骂我
说明
本文是讲解如何以小白的姿势, 学习使用wireshark抓包, 本人是刚入门wireshark的使用, 想更深入了解的请自行查询其他资料;
本文重点讲解的是Wireshark的一些简单操作, 例如:
- 如何抓取指定网络的数据包
- 如果编写过滤表达式
- 如何分析抓取到的数据
- 本文讲解如何抓取TCP和UDP协议的数据包; 使用电脑端和手机端互发消息, 然后抓取它们之间数据, 手机和电脑处于同一网段下(连着同一个路由器);
- 电脑端使用Java编写的小程序, 用cmd 窗口做输入输出交互
- 手机端使用安卓手机
- 本文演示的环境是Windows操作系统
软件安装
可以到百度上搜索 Wireshark, 然后点击下载即可
点击安装, 一路Next即可
界面操作
- 安装好Wireshark后, 进入软件, 你看到的是如下界面
首先看到的是
VirtualBox host-Only Network
无线网络连接
VirtualBox host-Only Network #2
VirtualBox host-Only Network #4
....
上面显示的是当前操作系统连接了哪些网络, 这些和你的电脑上
控制面板/网络和Internet/网络连接是一一对应的
现在, 我的手机和电脑同处于 无线网络连接 下, 我需要抓取这个网络的数据包, 鼠标选中 无线网络连接 后, 软件左上角出现了一个蓝色的弧形图标(文件) 下, 这个图片的含义就是开始捕获
点击开始捕获后, 出现如下:
可以看到, 软件显示数据模块被分成了三个部分, 我们可以称为 Top, Center和Bottom
- Top显示当前网络中传递数据的记录的, 当前网络中每次传递的数据都会显示到上面
- Center显示的是Top某一条记录的详细信息
- Bottom则显示Center中某一项数据的具体数据
还可以看到另外一个重要的输入行: 在Top上 提示 "应用显示过滤器" 的输入框, 用于输入过滤表达式来从Top中海量的记录过滤出我们想要的信息
来看一则抓取到的TCP消息
先来看看过滤表达式:
tcp and ((ip.src == 192.168.31.113 and ip.dst == 192.168.31.225)or(ip.dst == 192.168.31.113 and ip.src == 192.168.31.225))
PS: 上面的过滤表达式等同于:
tcp && ((ip.src == 192.168.31.113 && ip.dst == 192.168.31.225) || (ip.dst == 192.168.31.113 && ip.src == 192.168.31.225))
含义是:
1. 当协议是TCP, 并且源地址IP是192.168.31.113, 目标地址IP是192.168.31.225时, 满足过滤条件
2. 当协议是TCP, 并且源地址IP是192.168.31.225, 目标地址IP是192.168.31.113时, 满足过滤条件
过滤出来的记录确实如此, Top中显示的记录:
Sourece表示是源地址IP
Destination表示的是目标地址IP
Protocol表示的是通信协议
Length表示的是数据长度(字节个数)
Info 表示的是数据的详细信息, 包含了协议的一些参数, 通信双方的端口号, 我们发送的数据等等
另外, 本次抓取到的数据, 其实是连接 TCP 的时候抓取到的, 我们都听闻过TCP是经过三次握手才建立连接, 今天终于见到它的庐山真面目
抓取TCP数据
本节来讲解如何抓取TCP协议的数据
1. 将我的电脑作为服务端, 手机作为客户端, 手机去连接电脑, 连接成功后, 手机和电脑就可以相互发送消息了
2. 电脑的IP是192.168.23.225, 端口号是23233
3. 手机的IP是192.168.23.113, 随机分配端口
在Wireshark中添加过滤表达式
tcp && ((ip.src == 192.168.31.113 && ip.dst == 192.168.31.225) || (ip.dst == 192.168.31.113 && ip.src == 192.168.31.225))
首先, 要使用TCP传递数据, 第一步是创建连接, PS: 以下代码只是演示使用
- 首先需要先运行服务端程序
int serverPort = 23233;
ServerSocket serverSocket = new ServerSocket(serverPort);
Socket client = serverSocket.accept(); // 阻塞等待, 直到客户端连接成功
- 客户端
Socket socket = new Socket();
String serverIp = "192.168.31.225";
InetAddress serverHost = InetAddress.getByName(serverIp);
int serverPort = 23233;
SocketAddress serverAddress = new InetSocketAddress(serverHost,serverPort);
socket.connect(serverAddress); // 执行这个方法后, 如果不抛出异常, 则连接服务端成功,
- 如果连接服务端程序成功, 则Wireshark抓取到的消息如下
看到了建立TCP连接的时候的三次握手, 来看看有什么数据可能是我们需要的呢?
1. 看第一次握手的发起方是192.168.31.113(手机端), 接收方是192.168.31.225(电脑端)
2. 看第二次握手的时候, Center里的消息, 看到Src Port是23233(上面说了设置给服务端的端口号), Dst Port是客户端的端口号
3. 连接tcp的时候, 我们并没有去发送什么数据, 全部是协议底层自己实现的一些数据交互, 而这些数据我们不关心, 因此三次握手抓包意义应该不大
客户端给服务端发送 "hello"
- 客户端发送数据
// 获取与服务端的输入流
OutputStream os = socket.getOutputStream();
// 准备发送的信息
String msg = "hello";
// 给准备发送的数据加一个换行符, 服务端以 '行' 的方式来读取数据
msg += "\n";
// 以utf-8的编码写出数据
os.write(msg.getBytes("UTF-8"));
// 将数据刷进流中
os.flush();
- 服务端读取数据
// 获取与客户端的字节输入流
// 将字节输入流转成为编码为utf-8的字符输入流
BufferedReader reader = new BufferedReader(new InputStreamReader(
client.getInputStream(), "UTF-8"));
String line = null;
// 读取数据
while ((line = reader.readLine()) != null) {
// 将接收到的数据打印到cmd控制台上
System.out.println("receive msg: "+line);
}
- 抓取到的包
1. 从top可看出第一份数据是客户端(ip:192.168.31.113,端口: 48983)发给服务端(ip:192.168.31.225,端口: 23233);
服务端收到来自客户端的消息后也客户端反馈了一份数据(第二份数据)
2. 选中top中的第一份数据, 可以在center中看到数据的详细信息:
a. src.ip, dst.ip
b. src.port, dst.port
c. data, 数据(6个字节, 数据内容为6865566c6c6f0a)
拆成字节数组就是[68,65,56,6c,6c,6f,0a], 在这里字节是以十六进制表示的, 转成十进制, 再转成对应的ascii码表上的字符, 数据就是['h','e','l','l','o','\n']
总结一下: data: 6865566c6c6f0a --每两位为一个字节, 拆成字节数组-->[68,65,56,6c,6c,6f,0a]--将每个字节转成十进制, 再转成对应的ascii字符-->['h','e','l','l','o','\n']
是不是抓取到了TCP数据了呢?
抓取UDP数据:
本节来讲解如何抓取UDP协议的数据
UDP和TCP的传输方式不一样, 但是抓取的方式却是一样的, 只需要修改一下过滤表达式, 就可以帅选出UDP协议的数据包
UDP协议面向无连接, 所谓面向无连接, 也就是说不管对方存不存在, 它都可以向对方发送数据, 当然, 如果接收方不在, 数据就会被丢失了, 所以, 使用UDP发送数据, 没有三次握手, 也没有想TCP那样, 接收到消息后, 对方还会反馈一个数据
- 首先来编写一个过滤表达式;
我要过滤所有发送给本机(ip:192.168.31.225, 端口号为10086)的udp数据
udp && ip.dst == 192.168.31.225 && udp.port == 10086
- 接收端程序
int port = 10086;
DatagramSocket datagramSocket = new DatagramSocket(port);
byte[] buffer = new byte[1024 * 8];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
datagramSocket.receive(packet); // 这个方法会阻塞直到接收到一个udp消息
byte[] data = packet.getData();
int length = packet.getLength();
int offset = packet.getOffset();
InetAddress remoteAddress = packet.getAddress(); // 远程发送端的ip地址
int remotePort = packet.getPort(); // 远程发送端的端口
System.out.println("remoteIp: " + remoteAddress.getHostAddress()
+ ", remotePort: " + remotePort
+ ", Msg: " + (new String(data, offset, length)));
- 发送端程序
DatagramSocket datagramSocket = new DatagramSocket();
String msg = "hello udp";
String toIp = "192.168.31.225";
int toPort = 10086;
byte[] bytes = msg.getBytes();
DatagramPacket packet = new DatagramPacket(
bytes,0,bytes.length, // 要发送的数据
InetAddress.getByName(toIp), // 要发送到哪个ip
toPort); // 要发送到哪个端口上
datagramSocket.send(packet);
- 抓包
可以看到,
- top区显示的仅一条数据记录
- udp发送端: ip: 192.168.31.214, 端口:16166
- udp接收端: ip: 192.168.31.225, 端口:10086
- center区显示接收到的数据具有9个字节, 数据是[68656c6c6f20756470]
- bottom区可以看到数据是"hello udp"
编写过滤表达式
Wireshark的过滤表达式, 就和我们一般写的if语句的条件表达式一致
其中,
and 和 && 含义一致, 表示 '并且';
or 和 || 含义一致, 表示 '或者';
udp 表示 udp协议
tcp 表示 tcp协议
udp.port == 10086 表示udp端口为10086
tcp.port == 23233 表示tcp端口为23233
ip.src == 192.168.31.225 数据发送端ip是192.168.31.225
ip.dst == 192.168.31.113 数据接收端ip是192.168.31.113
来看几个例子
- 过滤ip为192.168.31.225设备, 端口为23233, 协议为tcp的数据包和端口为10086, 协议为udp的数据包
(ip.src == 192.168.31.225 or ip.dst == 192.168.31.225) and ( ((tcp) and tcp.port == 23233) or((udp) and udp.port == 10086))
注意事项
需要注意的是:
Wireshark抓取的是经过本机网卡的数据, 无论tcp还是udp, 如果接收端和发送端都是本机, 那么是抓不到包的, 当然解决方案是有的,解决方案:
使用管理员权限运行cmd, 执行命令
route add 本机ip mask 255.255.255.255 网关ip
发送数据的时候, ip地址必须添加本机的ip, 而不应该是127.0.0.1或localhost
当结束调试的时候, 需要将静态ip删除
route delete 本机ip mask 网关ip
总结
- 本文介绍了Wireshark的简单用法, 并分别演示了抓取TCP, UDP数据
- 本文从另一个角度去验证了TCP的三次握手连接, 以及发送消息时的连接(TCP发送消息时, 接收端也有反馈), 验证了UDP的面向无连接
后记
使用Wireshark抓包并不是新技术, 也不是什么黑科技. 看似能抓取到数据, 不过现在传递的数据都是经过加密的, 即便抓取到数据了, 也无法解析出来.
比较有用的场景, 例如你在研究一个设备(例如摄像头)与它的控制软件之间的通讯协议, 你使用Wireshark抓包, 然后反推出它们之间的通讯协议; 再实现自己的需求.