Java网络抓包: 使用wintun创建网络适配器实现数据捕获

646 阅读1分钟

在Windows系统上,使用Java JNA调用wintun.dll创建网络适配器,并通过pcap4解析网络数据包。

wintun官网:www.wintun.net/ 下载wintun的dll

使用idea创建一个maven项目,maven需要的依赖。(jna调用wintun.dll,pcap4j用于解析数据包。)

<dependency>
    <groupId>net.java.dev.jna</groupId>
    <artifactId>jna</artifactId>
    <version>5.10.0</version> 
</dependency>

<dependency>
    <groupId>org.pcap4j</groupId>
    <artifactId>pcap4j-core</artifactId>
    <version>1.8.2</version>
</dependency>

<dependency>
    <groupId>org.pcap4j</groupId>
    <artifactId>pcap4j-packetfactory-static</artifactId>
    <version>1.8.2</version>
</dependency>

创建WintunLibrary类,通过jna调用wintun.dll

public interface WintunLibrary extends Library {
    WintunLibrary INSTANCE = (WintunLibrary) Native.load("wintun", WintunLibrary.class);

    Pointer WintunCreateAdapter(WString name, WString tunnelType, Pointer requestedGUID);

    Pointer WintunStartSession(Pointer sessionHandle, int capacity);

    Pointer WintunReceivePacket(Pointer sessionHandle, IntByReference packetSize);

    void WintunSendPacket(Pointer sessionHandle, Pointer packet);

    void WintunReleaseReceivePacket(Pointer sessionHandle, Pointer packet);

    Pointer WintunGetReadWaitEvent(Pointer sessionHandle);

    void WintunGetAdapterLuid(Pointer sessionHandle, Pointer luid);

    Pointer WintunAllocateSendPacket(Pointer sessionHandle, int packetSize);

    void WintunCloseAdapter(Pointer sessionHandle);
}

main方法(需要管理员启动idea,主线程关闭会销毁网络适配器)

public static void main(String[] args) {
    String name = "Test";
    String tunnelType = "Wintun";
    //创建网络适配器
    Pointer adapterHandle = WintunLibrary.INSTANCE.WintunCreateAdapter(new WString(name), new WString(tunnelType), null);

    if (adapterHandle == null) {
        //可能没用管理员启动
        throw new RuntimeException("网络适配器创建失败!");
    }

    //启动适配器
    Pointer sessionHandle = WintunLibrary.INSTANCE.WintunStartSession(adapterHandle, 0x400000);

    while (true){

        //读取适配器数据包
        IntByReference incomingPacketSize = new IntByReference();
        Pointer incomingPacket = WintunLibrary.INSTANCE.WintunReceivePacket(sessionHandle, incomingPacketSize);

        if (incomingPacket != null) {
            try {
                int packetSize = incomingPacketSize.getValue();
                byte[] packetBytes = incomingPacket.getByteArray(0, packetSize);

                //解析数据包
                IpPacket packet1 = (IpPacket) IpSelector.newPacket(packetBytes, 0, packetBytes.length);
                System.out.println(packet1);


            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                WintunLibrary.INSTANCE.WintunReleaseReceivePacket(sessionHandle, incomingPacket);
            }
        } else {

            int lastError = Native.getLastError();
            if (lastError == 0x103) {
                //没数据等待数据
                Pointer readWaitEvent = WintunLibrary.INSTANCE.WintunGetReadWaitEvent(sessionHandle);
            } else {
                WintunLibrary.INSTANCE.WintunCloseAdapter(sessionHandle);
                throw new RuntimeException("数据包读取失败,错误码:"+lastError);
            }
        }

    }

}

网络适配器可以在 ->控制面板->网络和 Internet->更改适配器设置->查看

QQ截图20240124013343.png

查看实际抓包数据可以通过 Wireshark 软件查看,对比一下java的抓包

QQ截图20240124014345.png