由于目前网上没有一篇能真正方便读者操作的此类文章,本文对此通过示例做个简单介绍。 缘起有一天本来在看头条,然后看到一则游戏的广告,看画面可能是我喜欢的建造类型(纪元1404,卡特尔一类)的游戏,就下载玩了。由于同时间我在看《网络是怎样连接的》,所以就在想如何通过抓包获取游戏中的地图数据。
抓包过程中发现地图数据很难分析,但是世界对话却很简单,因此就开始分析对话,分析出来后,就想着怎么写个程序来获取这些数据呢,网上搜了一些例子,都是比较早的,而且64位支持的不是很好,所以就有了本文。 准备工作由于我很早之前安装 Wireshark 的时候安装过 winpcap,所以没有注意这个软件的兼容性,下载地址如下:
现在网上能查到和 Java 抓包相关的基本都是 jPcap,由于找不到版本配套的下载文件和64位的 dll,我找到了另一个工具 jnetpcap。 下载地址:https://github.com/ruedigergad/clj-net-pcap/blob/master/jnetpcap/jnetpcap-src-1.4.r1425-1.zip
下载解压后,将 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;
}
输出网卡的信息。 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());
}
在我电脑上输出的信息如下。 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]
选择一个要监控的网卡PcapIf device = alldevs.get(2);
可以根据更多信息来匹配一个网卡,这里简单选择的第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;
}
创建一个数据包处理器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
);
}
};
循环监听 10 个//可以修改 10 为 Integer.MAX_VALUE 来长期监听
pcap.loop(10, printSummaryHandler, 'jNetPcap rocks!');
//监听结束后关闭
pcap.close();
上述过程的完整代码见文末。 解析数据前面提到的游戏,我个人对其中的世界聊天部分进行了分析,还提供了基于 Spring Boot 和 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();
}
}
|
|