ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

ARP欺骗代码实战:C++与WinPcap伪造ARP报文全解析

ARP欺骗代码实战:C++与WinPcap伪造ARP报文全解析 简介这是一份面向网络协议学习者和安全初学者的ARP欺骗研究代码包基于C实现涵盖从ARP地址解析、报文构造到欺骗攻击逻辑的完整过程。包体共10个文件以cpp源码、h头文件和lib链接库为主另含Visual Studio工程配置及辅助文件总大小仅23KB便于快速查看与二次编译调试。已有177人学习资源虽小但结构典型涉及Packet32抓包、WS2_32网络编程等关键接口适合配合抓包工具观察ARP请求/应答与中间人攻击流程。通过阅读源码可理解伪造ARP报文触发地址映射篡改的原理并据此思考网关绑定、动态ARP检测等防护手段有助于打通网络协议、Windows网络编程与网络安全三方面知识。1. ARP欺骗代码包它到底能让你学会什么如果你翻过网络协议的书一定见过ARP那一章只有几十行文字IP要换MAC广播问一下被问的人回一下。这种描述配上抓包图看着明白可真到自己动手写才发现一个问题什么函数能把一个ARP包发出去怎么让应答包里的“我是192.168.1.1”骗得过对端这份arp.rar里的arp欺骗代码就是回答这些问题的——它用C把WinPcap发包、抓包、伪造ARP应答全串起来了。压缩包里是VC6工程直接能编译适合两类人一是刚读完TCP/IP协议栈、想亲手构造一个ARP报文的初学者二是要做局域网安全实验但不想从零写抓包循环的从业者。它的价值不在“能攻陷什么”而在把ARP协议从文字变成可运行的代码。2. 拆包看结构从文件清单反推代码的技术栈与编译方式2.1 arp.cpp与Packet32.hWinPcap抓包库的核心用法拿到压缩包先别急着双击arp.dsw。先看文件名单里面藏着这个项目的技术选型arp.cpp是唯一源码文件说明整个ARP欺骗逻辑集中在一个文件里没有分模块。它include了Packet32.h这个头文件来自WinPcap开发者包是驱动级抓包接口的入口。注意它不是pcap.h而是Packet32.h——这意味着代码很可能不是用libpcap的跨平台API而是直接用了WinPcap的底层PacketSendPacket、PacketReceivePacket之类函数。这样做的好处是更贴近NDIS驱动缺点是只能在Windows下编译运行。为什么不用WSAIoctl那套因为ARP欺骗需要发送一个“不受系统协议栈影响”的原始帧。WinSock2虽然能发原始套接字但Windows从XP SP2开始限制RAW Socket收发而且系统会干扰ARP包的处理。WinPcap的Packet32接口直接旁路协议栈从NDIS驱动层面收发光以太网帧这才是ARP欺骗能成立的关键。arp.cpp里大概率有一段初始化网卡、读取MAC地址的代码用的就是PacketOpenAdapter然后配合pcap_sendpacket的底层版本PacketSendPacket发包。2.2 项目文件与链接库Visual C 6.0时代的编译模型看文件后缀就能判断这是Visual C 6.0工程arp.dsw是工作区文件arp.dsp是项目文件arp.ncb是类浏览信息缓存arp.opt是工程选项缓存arp.plg是构建日志。这些文件告诉你作者当时用的是VC6WinPcap 3.x/4.x时代的环境。编译时工程依赖两个库WS2_32.LIB和Packet.lib。前者是Windows Socket 2库提供socket、inet_addr、htons这类函数后者是WinPcap的Packet接口静态库对应Packet32.h。在现代编译器里打开这个工程最直接的坑是VC6的预编译头设置。老工程默认把stdafx.h作为预编译头但源文件清单里没看到stdafx.h说明作者可能关闭了预编译选项或者直接在source文件里手动声明了Windows头文件。编译报错C1010未找到预编译头时请在工程设置里把Yc改成Yu或者直接设置“不使用预编译头”。另外项目默认字符集是ANSI如果代码里有中文注释在中文版系统上打开会有乱码但不影响编译。2.3 代码包的运行边界它为什么只做ARP欺骗而不做TCP转发很多人拿到ARP欺骗代码第一句就问能劫持HTTP吗能抓微信密码吗看文件清单就知道这个项目没有实现数据转发。它只做两件事持续发送伪造的ARP应答告诉目标主机“网关的MAC是我”同时告诉网关“目标主机的MAC是我”。至于流经目标主机的TCP数据包代码没有做IP转发也没有开启Windows的IPEnableRouter注册表项。也就是说受害者在欺骗期间会断网而不是被中间人悄无声息地转发流量。这不是作者的疏忽而是学习型代码的合理边界专注演示ARP状态表的篡改过程把复杂的数据转发、会话重建留给读者自己扩展。真要做中间人至少还需要启用系统路由功能、用libnet或自己构造IP包转交数据还要处理TTL减1、TCP序列号透传。所以如果目标是想读懂ARP欺骗的报文交互这个包很合适如果是想做一个攻击工具它只是起点。运行它你会看到效果受害者ping不通外网但能ping通攻击机因为网关和受害者之间的双向MAC映射都被改成攻击机的MAC了。3. 核心代码还原WinPcap下ARP请求与应答的构造流程3.1 构造ARP报文用结构体做内存映射ARP帧头固定42字节14字节以太网头28字节ARP数据。常见实现是定义两个结构体然后把它们fwrite到缓冲区。注意以太网头要先写目标MAC再写源MAC最后是0x0806类型。下面这段代码是典型写法你在这个包里看到的arp.cpp应该就是类似结构。// 以太网帧头 typedef struct _ETH_HDR { BYTE dst_mac[6]; // 目的MAC伪造应答时填受害者MAC BYTE src_mac[6]; // 源MAC填攻击机网卡MAC WORD ether_type; // 0x0806 ARP } ETH_HDR; // ARP报文体按RFC 826 typedef struct _ARP_HDR { WORD hw_type; // 1 Ethernet WORD proto_type; // 0x0800 IP BYTE hw_len; // 6 BYTE proto_len; // 4 WORD opcode; // 1请求 2应答 BYTE sender_mac[6]; // 发送方MAC BYTE sender_ip[4]; // 发送方IP BYTE target_mac[6]; // 目标MAC BYTE target_ip[4]; // 目标IP } ARP_HDR;逻辑说明把固定的协议字段写进结构体直接用memcpy把值填入偏移位置比逐字节拼接更不容易错。发送时ETH_HDR里的ether_type必须转网络字节序ARP_HDR里所有WORD字段也要用htons。否则抓包软件里看到的类型是0x0800IP而不是0x0806ARPopcode从2变成0x0200欺骗直接失效。参数说明hw_type填1proto_type填0x0800这两个值都是固定协议号。hw_len和proto_len是地址长度6和4。opcode是灵魂请求填1应答填2。做欺骗时你主动发的全是应答opcode2而且不受收到请求的限制——这也是ARP无状态协议的缺陷任何人都能主动向受害者发应答受害者无条件相信。sender_mac、sender_ip就是你要伪造的“身份”。注意sender_mac填的是攻击机网卡真实MAC不是伪造IP对应的真机MAC因为二层帧的源MAC必须能被交换机学习否则网关直接丢弃。3.2 收发循环pcap_sendpacket与pcap_next_ex怎么配合构造完包体之后主循环一般是这样定时发两个应答一个给受害者告诉它“网关IP是我的MAC”一个给网关告诉它“受害者IP是我的MAC”。循环间隔通常设1到2秒目的是对抗ARP缓存老化。下面是基于Packet32接口的伪代码也是这个项目最可能用的模式。// 打开网卡0为第一个适配器 LPADAPTER adapter PacketOpenAdapter(\\Device\\NPF_{网卡GUID}); if (!adapter) { printf(Open adapter failed\n); return -1; } // 构造一个60字节的buffer前面填ETH_HDR后面填ARP_HDR char sendbuf[60]; ETH_HDR eth; ARP_HDR arp; memcpy(eth.dst_mac, victim_mac, 6); // 欺骗受害者时目的MAC填受害者 memcpy(eth.src_mac, attacker_mac, 6); eth.ether_type htons(0x0806); // ... 填充arp结构opcode htons(2) // 打到发到网卡的netmon_buffer memcpy(sendbuf, eth, 14); memcpy(sendbuf 14, arp, 28); // 补够60字节最小以太网帧长 for (int i 42; i 60; i) sendbuf[i] 0; // 持续发送 while (1) { PacketSendPacket(adapter, (PPACKET)sendbuf, 60, TRUE); Sleep(1000); // 1秒一次抗老化 }逻辑说明PacketSendPacket的第一个参数是网卡句柄第二个参数要的是一个PACKET结构而不是裸buffer。这里为了简化示意为直接传buffer真实代码会先把sendbuf拷贝到PACKET的Data成员里然后设置Length字段。Sleep(1000)不能去掉也不能太长——ARP缓存表默认老化时间在Windows上是45秒但在收到新应答时会立即更新1秒一次是为了保证受害者表项始终指向你网络恢复时又能迅速还原。参数说明接收部分用PacketReceivePacket或pcap_next_ex都可能。如果是学习用更推荐pcap因为PACKET结构更靠近libpcap将来移植到Linux只改接口名。注意循环里最好加一个检测如果受害者发来的流量里已经有ARP请求你可以实时回复一个伪造应答这样更逼真。但这个包大概率是死循环发不做请求响应——这正是它实现简单的体现。3.3 关键参数网卡索引、IP/MAC映射、伪造源地址的填写真正跑起来会卡住的第一个参数是网卡名字。PacketOpenAdapter需要的是设备路径形如\Device\NPF_{7E1A0D2B-...}而不是“本地连接”。获取方式有两种用PacketFindAllAdapters遍历或者用WinPcap自带的wpcap.dll里的pcap_findalldevs_ex。代码里如果写死了网卡名你就要去适配器管理里查GUID然后手动替换。更常见的做法是代码里遍历让用户选序号。第二个参数是ARP缓存表里的MAC地址。攻击机不一定知道受害者的真实MAC所以代码里至少要有两个分支一个是用一个ARP请求去探测目标发广播请求“谁是这个IP”从回包提取MAC另一个是直接从网络抓包流量里学。很多ARP欺骗代码会硬编码受害者MAC这在静态环境演示没问题但换个实验环境就翻车。建议拿到包后先把网卡混合模式打开抓到受害者发来的数据帧自动记录source MAC这样就不用手动填了。第三个参数是IP地址长度。ARP_HDR里sender_ip是BYTE[4]如果用char*保存“192.168.1.1”一定要先inet_addr转成u_long再memcpy。很多人在这里直接strcpy导致IP字节序错乱欺骗时受害者收到的“网关IP”变成1.1.168.192协议栈直接丢弃。这个坑在抓包软件里看ARP包内容时特别明显。4. 避坑与常见问题旧项目在Win10/新WinPcap下复活很多人把arp.rar下载下来编译时报错一片第一个念头是“代码太老”。实际多数是自己环境没配对。这里列几个最常踩的坑按现象→原因→解决写。4.1 问题一头文件找不到编译报错fatal error C1083现象打开arp.dsp直接编译提示无法打开Packet32.h或DEVIOCTL.H。原因VC6默认在工程目录和系统Include目录里找头文件但WinPcap开发者包的头文件装在WinPcap\Include目录工程没有添加这个路径。解决把Packet32.h和DEVIOCTL.H复制到源码同目录或者在VC菜单Tools→Options→Directories里把Include和Lib路径加上。DEVIOCTL.H其实是NDIS驱动访问IOCTL的头文件WinPcap头文件依赖它单独复制就行。顺带检查一下Packet32.h里的#include windows.h老版本可能写的是windows.h在VC里没问题但VC2005以后要改成Windows.h才不会因为大小写混淆。4.2 问题二lib文件链接顺序和命名约束现象编译过了链接报错LNK2001 unresolved external symbol __imp__PacketSendPacket16或者WS2_32.LIB里的socket函数未解析。原因Packet.lib和WS2_32.LIB没有添加到工程依赖或者添加了但顺序不对。VC6里链接顺序会影响解析Packet.lib依赖WS2_32。解决在Project Settings→Link→Object/library modules里写“Packet.lib WS2_32.LIB”注意先Packet后WS2_32。如果你用的是WinPcap 4.1.2Packet.lib在WpdPack\Lib\x86目录下要选x86版本别选x64——VC6本来就是32位编译器选了x64的lib直接报找不到符号。4.3 问题三抓不到自己的包pcap_next_ex一直超时现象运行代码后发送循环在发包但注释掉的抓包代码收不到任何ARP包抓包循环里timeout一直触发。原因网卡没开混合模式promiscuous mode。Packet32接口在打开网卡后需要调用PacketSetHwFilter设置NDIS_PACKET_TYPE_PROMISCUOUS而不是仅调pcap_next_ex。大多数人的抓包循环里写了pcap_setfilter过滤只收ARP但忘了底层需要混合模式。解决在OpenAdapter后加一行PacketSetHwFilter(adapter, NDIS_PACKET_TYPE_PROMISCUOUS)。如果是Win10还需要检查“允许应用程序绕过系统网络栈”的WinPcap服务是否启动命令是net start npf_ndis或者npcap的服务。4.4 问题四欺骗不生效受害者ARP表里的网关MAC一直不变现象代码在跑受害者ARP表里网关MAC还是真实网关ping外网正常。稍等会儿又变成了攻击机MAC然后一会儿又变回去。原因这个代码只发了单向欺骗——只改了受害者的表没改网关的ARP表。网关发现自己到受害者的包发不出去会重新发ARP请求学习到受害者真实MAC并覆盖。解决这个代码包里如果只有一条发包循环那就是作者自己打错方向了。应在同一循环里发送两条应答一条发给受害者VICTIM_IP→ATTACKER_MAC一条发给网关GATEWAY_IP→ATTACKER_MAC。如果你拿到的版本里没有这条需要自己在发包循环里加第二个sendbuf。这个坑很容易忽略但一旦出现用抓包软件一看“双向流量不对称”就明白了。4.5 问题五VC6编译通过但运行时提示0xc000007b或找不到入口点现象VC6下编译、链接全过生成exe双击运行弹“应用程序无法正常启动0xc000007b”或者提示“找不到wpcap.dll”。原因WinPcap库分为Packet.dll和wpcap.dll运行时从System32或程序目录加载。VC6默认用动态加载Packet.lib如果系统装了Npcap而不是WinPcap会出现接口不兼容。Npcap的npf服务是Npcap Loopback Adapter跟老代码的设备路径不符。解决切换到Npcap的WinPcap兼容模式——在Npcap安装时勾选“Install Npcap in WinPcap API-compatible Mode”或者把Packet.lib改为静态链接。更省事的方法是卸载Npcap装回WinPcap 4.1.3。如果你是Win10/11推荐用Wireshark自带Npcap然后在代码里调用pcap_lookupdev动态获取网卡名别写死\Device\NPF_因为新版本GUID变了。5. 进阶从欺骗代码到诊断工具——验证与防护思路拿到这份代码别急着拿它去折腾同事的电脑。先把它当学习样本用三步验证你是否真的理解了它。第一步用Wireshark抓包看发送循环里的ARP报文——只看opcode2的包观察sender_mac是不是你的网卡MACsender_ip是不是你伪造的网关IP。如果你能看到受害者发来的ARP请求说明你的网卡混合模式正常。第二步在受害者机器上打开cmd输入arp -a看网关IP对应的MAC是不是你机器物理地址。第三步做双向欺骗后再从受害者机器ping外网观察是否全丢包——丢包正常不丢包说明你的欺骗被网关的反向ARP请求修复了。接下来想做点正事这里有三个改进方向。第一个是把Sleep(1000)改成动态适应ARP老化你可以周期性发送ARP请求去探测频率从2秒降到500毫秒再提到2秒观察受害者ARP缓存更新情况直到找出稳定欺骗的最小频率。第二个是增加被动学习在发包循环里监听收到的ARP包实时提取受害者IP和MAC的映射这样不需要硬编码受害者MAC。第三个是做防护练习在同一台机器上写一段ARP攻击检测代码——连续N秒收到两个不同IP对应两个不同MAC的ARP应答就报警“网关被欺骗”。这段代码和攻击代码用的是同一组Packet32函数能把破坏性学习变成防御性学习。使用这份代码还有一条底线不要在别人的网络里做测试尤其是公司网、学校网ARP欺骗即便只发几秒也会打断整个子网所有主机的TCP连接网关日志和网管告警都查得到。我自己的习惯是在虚拟机里搭两台Ubuntu一个Windows宿主用Bridge专门开一个隔离网段来跑这套代码。第一次跑通时看到受害者虚拟机里的arp -a变成自己的MAC那种感觉确实挺震撼但也让我意识到ARP协议在设计上完全没有认证机制——从那以后我每调一次网络排障都会先在交换机上看ARP表是否突变也算是被这份代码改变了看网络的方式。这份资源适合你下载后把arp.cpp打开逐行对着RFC 826注释着读比任何教材都直观。希望帮到你。本文还有配套的精品资源点击获取
返回列表