Windows 2000/XP 預設啟用「信使服務」接收 UDP 埠 135 (實為 RPC 端點對應器,實際信使服務使用動態埠) 的 net send 訊息。本文分析信使服務 UDP 封包結構,實作純 UDP Socket 發送訊息,並探討使用 Raw Socket 偽裝來源 IP 的可行性。
完整封包 = IP Header (20B) + UDP Header (8B) + Messenger Payload。
Messenger Payload (第 29 字節起):
DWORD 發送時間 (Unix timestamp)。DWORD 訊息本體長度 (不含標頭)。
SOCKET s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
sockaddr_in to;
to.sin_family = AF_INET;
to.sin_port = htons(135); // 實際需查詢目標機器信使服務埠
to.sin_addr.s_addr = inet_addr("192.168.1.100");
// 手工構建 Messenger Payload (略)
char packet[1024] = { ... };
sendto(s, packet, len, 0, (sockaddr*)&to, sizeof(to));
closesocket(s);
限制:標準 Socket 無法偽裝來源 IP,接收端可見真實發送者 IP。若需匿名/偽裝,必須使用 Raw Socket (IP_HDRINCL)。
socket(AF_INET, SOCK_RAW, IPPROTO_RAW) (需管理員權限 / CAP_NET_RAW)。setsockopt(s, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)) 告知核心由應用層填寫 IP Header。sendto 發送 (目標 IP 僅供路由參考,實際來源 IP 取自 IP Header)。
#pragma pack(push, 1)
struct IPHeader {
BYTE ver_ihl; // 0x45
BYTE tos; // 0
WORD tot_len; // 總長度 (網路序)
WORD id; // 識別碼
WORD frag_off; // 0x4000 (Don't Fragment)
BYTE ttl; // 128
BYTE protocol; // IPPROTO_UDP (17)
WORD checksum; // IP Header checksum
DWORD src_addr; // 偽裝來源 IP
DWORD dst_addr; // 目標 IP
};
struct UDPHeader {
WORD src_port;
WORD dst_port;
WORD length;
WORD checksum; // 可設 0 (IPv4 選擇性)
};
#pragma pack(pop)