分享

Java TCP 抓包简单示例

 根的情义 2018-03-15

由于目前网上没有一篇能真正方便读者操作的此类文章,本文对此通过示例做个简单介绍。

缘起

有一天本来在看头条,然后看到一则游戏的广告,看画面可能是我喜欢的建造类型(纪元1404,卡特尔一类)的游戏,就下载玩了。由于同时间我在看《网络是怎样连接的》,所以就在想如何通过抓包获取游戏中的地图数据。

这里写图片描述

这里写图片描述

这里写图片描述

前两张图是游戏截图,暴露了个人坐标,和三体中暴露地球坐标一样危险。

第3张图是最近刚看过的一本书,是一本很详细介绍网络连接的书,但不是TCP抓包方面的书。

抓包过程中发现地图数据很难分析,但是世界对话却很简单,因此就开始分析对话,分析出来后,就想着怎么写个程序来获取这些数据呢,网上搜了一些例子,都是比较早的,而且64位支持的不是很好,所以就有了本文。

准备工作

由于我很早之前安装 Wireshark 的时候安装过 winpcap,所以没有注意这个软件的兼容性,下载地址如下:

https://www./

Windows 必须安装的一个软件,其他工具都是基于 winpcap 的。

现在网上能查到和 Java 抓包相关的基本都是 jPcap,由于找不到版本配套的下载文件和64位的 dll,我找到了另一个工具 jnetpcap

下载地址:https://github.com/ruedigergad/clj-net-pcap/blob/master/jnetpcap/jnetpcap-src-1.4.r1425-1.zip

打开页面点击下载,这个链接不能直接通过迅雷等软件下载。

对应网盘地址:http://pan.baidu.com/s/1o7GvB5o 密码:5g1y

下载解压后,将 jnetpcap.dll 和 jnetpcap-pcap100.dll 放到 Java 的 bin 和 jre/bin 两个目录下。

额外准备

希望这个游戏能坚持到你看这篇文章的时候。

如果你想按照我这里的过程,针对这个游戏进行抓包测试,可以额外装一些软件进行,如果仅仅是如何使用 Java 抓包,不需要这些。

通过安卓抓包软件简单获取服务器IP等信息,如下图:

这里写图片描述

简单抓包数据分析:

这里写图片描述

分解代码

以下内容和游戏无关,就是基本的用法。

获取网卡

通过下面代码获取当前机器的网卡信息。

StringBuilder errbuf = new StringBuilder(); int r = Pcap.findAllDevs(alldevs, errbuf); if (r == Pcap.NOT_OK || alldevs.isEmpty()) { System.err.printf('Can't read list of devices, error is %s', errbuf .toString()); return; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

输出网卡的信息。

System.out.println('Network devices found:'); int i = 0; for (PcapIf device : alldevs) { System.out.printf('#%d: %s [%s]\n', i , device.getName(), device .getDescription()); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在我电脑上输出的信息如下。

Network devices found: #0: \Device\NPF_{22788384-70D1-47E6-A182-DEAE1D091D2C} [VMware Virtual Ethernet Adapter] #1: \Device\NPF_{144877C1-CBA4-4E7A-B408-E482BFA7F59D} [VMware Virtual Ethernet Adapter] #2: \Device\NPF_{93282E0F-D399-4904-95D5-062F4325FD48} [Microsoft] #3: \Device\NPF_{055061E0-011E-488C-BF6C-D48252BCDEAB} [Microsoft] #4: \Device\NPF_{6246A8BA-F000-4355-B3E0-5CAAF7229813} [VMware Virtual Ethernet Adapter] #5: \Device\NPF_{E4AB7839-5786-427B-BB2A-E8C40C529494} [Realtek PCIe GBE Family Controller]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

名字相同的网卡很难区分,还可以通过 device 获取网卡的 IP 信息来轻松识别网卡。

选择一个要监控的网卡

PcapIf device = alldevs.get(2);
  • 1

可以根据更多信息来匹配一个网卡,这里简单选择的第3个网卡。

打开设备

int snaplen = 64 * 1024; int flags = Pcap.MODE_PROMISCUOUS; int timeout = 10 * 1000; Pcap pcap = Pcap.openLive(device.getName(), snaplen, flags, timeout, errbuf); if (pcap == null) { System.err.printf('Error while opening device for capture: ' errbuf.toString()); return; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

创建一个数据包处理器

PcapHandler<String> printSummaryHandler = new PcapHandler<String>() { public void nextPacket(String user, long seconds, int useconds, int caplen, int len, ByteBuffer buffer) { Date timestamp = new Date(seconds * 1000 useconds/1000); // In millis System.out.printf('Received packet at %s caplen=%-4d len=%-4d %s\n', timestamp.toString(), // timestamp to 1 ms accuracy caplen, // Length actually captured len, // Original length of the packet user // User supplied object ); } };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

循环监听 10 个

//可以修改 10 为 Integer.MAX_VALUE 来长期监听 pcap.loop(10, printSummaryHandler, 'jNetPcap rocks!'); //监听结束后关闭 pcap.close();
  • 1
  • 2
  • 3
  • 4

上述过程的完整代码见文末。

解析数据

前面提到的游戏,我个人对其中的世界聊天部分进行了分析,还提供了基于 Spring Boot 和 websocket 的小程序,可以启动后通过网页查看。

启动方法:

  1. 按照前面的要求配置好基础环境
  2. 安卓模拟器安装游戏,在12区创建一个账号(可以修改下面源码配置文件中的服务器IP)
  3. 登陆游戏后,下载下面的源码,修改代码中选择网卡的地方,改成自己连接网络的那个网卡
  4. 启动 TalkApplication 后访问 localhost:9090 即可

源码下载:

链接:http://pan.baidu.com/s/1min9JCk 密码:6sfd

已知问题:websocket 中没有维持心跳包,因此过段时间后会自动断开。

效果图:

这里写图片描述

这里写图片描述

完整示例代码

import org.jnetpcap.Pcap; import org.jnetpcap.PcapHandler; import org.jnetpcap.PcapIf; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Date; import java.util.List; public class ClassicPcapExample { public static void main(String[] args) { List<PcapIf> alldevs = new ArrayList<PcapIf>(); // Will be filled with NICs StringBuilder errbuf = new StringBuilder(); // For any error msgs /******************************************** * First get a list of devices on this system ********************************************/ int r = Pcap.findAllDevs(alldevs, errbuf); if (r == Pcap.NOT_OK || alldevs.isEmpty()) { System.err.printf('Can't read list of devices, error is %s', errbuf .toString()); return; } System.out.println('Network devices found:'); int i = 0; for (PcapIf device : alldevs) { System.out.printf('#%d: %s [%s]\n', i , device.getName(), device .getDescription()); } PcapIf device = alldevs.get(2); // We know we have atleast 1 device System.out.printf('\nChoosing '%s' on your behalf:\n', device .getDescription()); /*************************************** * Second we open up the selected device ***************************************/ int snaplen = 64 * 1024; // Capture all packets, no trucation int flags = Pcap.MODE_PROMISCUOUS; // capture all packets int timeout = 10 * 1000; // 10 seconds in millis Pcap pcap = Pcap .openLive(device.getName(), snaplen, flags, timeout, errbuf); if (pcap == null) { System.err.printf('Error while opening device for capture: ' errbuf.toString()); return; } /********************************************************************** * Third we create a packet hander which will be dispatched to from the * libpcap loop. **********************************************************************/ PcapHandler<String> printSummaryHandler = new PcapHandler<String>() { public void nextPacket(String user, long seconds, int useconds, int caplen, int len, ByteBuffer buffer) { Date timestamp = new Date(seconds * 1000 useconds/1000); // In millis System.out.printf('Received packet at %s caplen=%-4d len=%-4d %s\n', timestamp.toString(), // timestamp to 1 ms accuracy caplen, // Length actually captured len, // Original length of the packet user // User supplied object ); } }; /************************************************************ * Fourth we enter the loop and tell it to capture 10 packets ************************************************************/ pcap.loop(10, printSummaryHandler, 'jNetPcap rocks!'); /* * Last thing to do is close the pcap handle */ pcap.close(); } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多