
详谈调用 winpcap 驱动写 arp 多功能工具
创建时间:2002-09-14
文章属性:原创
文章来源:中华安全网
文章提交:TOo2y (too2y_at_safechina.net)
详谈调用 winpcap 驱动写 arp 多功能工具
Author: TOo2y[原创]
E-mail: [email protected]
Homepage: www.safechina.net
Date: 11-9-2002
一 winpcap 驱动简介
二 Packet.dll 相关数据结构及函数
三 T-ARP 功能及原理介绍
四 T-ARP 主要代码分析
五 T-ARP 源代码
一)winpcap 驱动简介
winpcap(windows packet capture)是 windows 平台下一个免费,公共的网络访问系统。开发
winpcap 这个项目的目的在于为 win32 应用程序提供访问网络底层的能力。它提供了以下的各项功能:
1> 捕获原始数据报,包括在共享网络上各主机发送/接收的以及相互之间交换的数据报;
2> 在数据报发往应用程序之前,按照自定义的规则将某些特殊的数据报过滤掉;
3> 在网络上发送原始的数据报;
4> 收集网络通信过程中的统计信息。
winpcap 的主要功能在于独立于主机协议(如 TCP-IP)而发送和接收原始数据报。也就是说,
winpcap 不能阻塞,过滤或控制其他应用程序数据报的发收,它仅仅只是监听共享网络上传送的数据报。
因此,它不能用于 QoS 调度程序或个人防火墙。
目前,winpcap 开发的主要对象是 windows NT/2000/XP,这主要是因为在使用 winpcap 的用户中
只有一小部分是仅使用 windows 95/98/Me,并且 M$也已经放弃了对 win9x 的开发。因此本文相关的程序
T-ARP 也是面向 NT/2000/XP 用户的。其实 winpcap 中的面向 9x 系统的概念和 NT 系统的非常相似,只是在
某些实现上有点差异,比如说 9x 只支持 ANSI 编码,而 NT 系统则提倡使用 Unicode 编码。
本文讨论的是 packet.dll 所提供的各种函数,因为它们完全可以实现本文所希望的各项要求。但
是如果你有其他特别的或更高级的要求,winpcap 也提供了另一个动态连接库 wpcap.dll。虽然 wpcap.dll
依靠于 packet.dll,但是它却提供了一种更简单,直接,有力的方法来更好的利用编程环境。比如捕获一
个数据报,创建一个数据报过滤装置或将监听到的数据报转存到某个文件等,wpcap.dll 都会为你提供更
加安全的实现方法。

二)Packet.dll 相关数据结构及函数
本文的目的之一在于介绍如何利用 winpcap 驱动写 ARP 工具,因此有必要介绍一些相关的数据结
构和函数,要不然看着一行行代码和函数,也许会有些不知所云。
首先介绍一些相关的数据结构:
1. typedef struct _ADAPTER ADAPTER //描述一个网络适配器;
2. typedef struct _PACKET PACKET //描述一组网络数据报的结构;
3. typedef struct NetType NetType //描述网络类型的数据结构;
4. typedef struct npf_if_addr npf_if_addr //描述一个网络适配器的 ip 地址;
5. struct bpf_hdr //数据报头部;
6. struct bpf_stat //当前捕获数据报的统计信息。
下面,将介绍 T-ARP 用到的各个函数,他们都是在 packet.dll 中定义的:
1> LPPACKET PacketAllocatePacket(void)
如果运行成功,返回一个_PACKET 结构的指针,否则返回 NULL。成功返回的结果将会传
送到 PacketReceivePacket()函数,接收来自驱动的网络数据报。
2> VOID PacketCloseAdapter(LPADAPTER lpAdapter)
关闭参数中提供的网络适配器,释放相关的 ADAPTER 结构。
3> VOID PacketFreePacket(LPPACKET lpPacket)
释放参数提供的_PACKET 结构。
4> BOOLEAN PacketGetAdapterNames(LPSTR pStr,PULONG BufferSize)
返回可以得到的网络适配器列表及描述。
5> BOOLEAN PacketGetNetInfoEx(LPTSTR AdapterNames,npf_ip_addr *buff, PLONG NEntries)
返回某个网络适配器的全面地址信息。
其中 npf_ip_addr 结构包含:IPAddress,SubnetMask,Broadcast
IPAddress: ip 地址
SubnetMask: 子网掩码
Broadcast: 广播地址
6> BOOLEAN PacketGetNetType(LPADAPTER AdapterObject, NetType *type)
返回某个网络适配器的 MAC 类型。
NetType 结构里包含了 LinkSpeed(速度)和 LinkType(类型)。其中 LinkType 包含以下
几种情况:
NdisMedium802_3: Ethernet(802.3)
NdisMediumWan: WAN
NdisMedium802_5: Token Ring(802.5)
NdisMediumFddi: FDDI
NdisMediumAtm: ATM
NdisMediumArcnet878_2: ARCNET(878.2)

7> BOOLEAN PacketGetStats(LPADAPTER AdapterObject,struct bpf_stat *s)
返回几个关于当前捕获报告的统计信息。
其中 bpf_stat 结构包含:bs_recv, bs_drop,ps_ifdrop,bs_capt
bs_recv: 从网络适配器开始捕获数据报开始所接收到的所有数据报的数目,包括丢
失的数据报;
bs_drop: 丢失的数据报数目。在驱动缓冲区已经满时,就会发生数据报丢失的情况。
8> PCHAR PacketGetVersion()
返回关于 dll 的版本信息。
9> VOID PacketInitPacket(LPPACKET lpPacket, PVOID Buffer, UINT Length)
初始化一个_PACKET 结构。
10> LPADAPTER PacketOpetAdapter(LPTSTR AdapterName)
打开一个网络适配器。
11> BOOLEAN PacketReceivePacket(LPADAPTER AdapterObject,LPPACKET lpPacket,BOOLEAN Sync)
从 NPF 驱动程序读取网络数据报及统计信息。
数据报编码结构: |bpf_hdr|data|Padding|bpf_hdr|data|Padding|
12> BOOLEAN PacketSendPacket(LPADAPTER AdapterObject,LPPACKET lpPacket, BOOLEAN Sync)
发送一个或多个数据报的副本。
13> BOOLEAN PacketSetBuff(LPADAPTER AdapterObject,int dim)
设置捕获数据报的内核级缓冲区大小。
14> BOOLEAN PacketSetHwFilter(LPADAPTER AdapterObject,ULONG Filter)
为接收到的数据报设置硬件过滤规则。
以下为一些典型的过滤规则:
NDIS_PACKET_TYPE_PROMISCUOUS: 设置为混杂模式,接收所有流过的数据报;
NDIS_PACKET_TYPE_DIRECTED: 只有目的地为本地主机网络适配器的数据报才会被接
收;
NDIS_PACKET_TYPE_BROADCAST: 只有广播数据报才会被接收;
NDIS_PACKET_TYPE_MULTICAST: 只有与本地主机网络适配器相对应的多播数据报才
会被接收;
NDIS_PACKET_TYPE_ALL_MULTICAST: 所有多播数据报均被接收;
NDIS_PACKET_TYPE_ALL_LOCAL: 所有本地数据报均被接收。
15> BOOLEAN PacketSetNumWrites(LPADAPTER AdapterObject,int nwrites)
设置调用 PacketSendPacket()函数发送一个数据报副本所重复的次数。
16> BOOLEAN PacketSetReadTimeout(LPADAPTER AdapterObject,int timeout)
设置在接收到一个数据报后“休息”的时间。

以上就是 T-ARP 所调用的各个函数,它包含了 packet.dll 里的大部分函数。如果你想更深层的了
解 winpcap,请访问相关网站,主页地址: http://winpcap.polito.it
三)T-ARP 功能及原理介绍
准备工作:
1. 安装 winpcap 驱动,目前最新的版本为 winpcap_3.0_alpha, 稳定版本为 winpcap_2.3;
2. 使用 ARP 欺骗功能前,必须启动 ip 路由功能,修改(添加)注册表选项:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\IPEnableRo
uter = 0x1
选项:
-m 主机扫描,获得局域网内指定 ip 段中存活主机的 ip 地址和 mac 地址;
-a 反嗅探扫描,获得局域网内指定 ip 段中嗅探主机的 ip 地址和 mac 地址;
-s ARP 欺骗,欺骗局域网内指定的两台主机,使其相互发送接收的数据报均通过本地主
机;
网络嗅探,如果你选择欺骗的两台主机均是本地主机,那么将会监听到所有流过本
地主机的数据报;
IP 冲突,如果你选择欺骗的两台主机是同一台非本地主机,那么就会发起 ip 冲突
攻击;
-r 重置被欺骗主机,使被欺骗的两台主机恢复正常的工作状态。
原理及实现过程:
无论什么选项,第一件事就是获得本地主机的 mac 地址及相关网络设置。我们以一个特殊的 ip
地址(112.112.112.112)向本地主机发送一个 ARP Request(ARP 请求)数据报,当本地主机接收到后,就会
发送一个 ARP Reply(ARP 应答)数据报来回应请求,这样我们就可以获得本地主机的 mac 地址了。至于相关
的网络设置可以通过 PacketGetNetInfoEx()和 PacketGetNetType()获得。
-m 以本地主机的名义(本地主机的 ip 和 mac)向指定 ip 网段内的所有主机发送广播
(ff:ff:ff:ff:ff:ff)ARP Request 数据报,存活的主机就会发送 ARP Reply 数据报,这样就可以获得当前
存活主机的列表。因为在很多网关上都对 ARP Request 做了限制--非内网 ip 发送的 ARP Request 数据报不
会得到网关的回应,如果你用内网的其他某台主机的 ip 来发送 ARP Request 数据报,如果填写的 mac 地址
和相应的 ip 不合,就会出现 ip 冲突。所以最好还是用自己的 ip 和 mac 地址来发送请求。
-a 以本地主机的名义(本地主机的 ip 和 mac)向指定 ip 网段内的所有主机发送 31 位伪
广播地址(ff:ff:ff:ff:ff:fe)的 ARP Request 数据报,只有正在嗅探的主机才会发送 ARP Reply 数据报,
这样就可以获得当前存活主机的列表。嗅探中的 win2000 系统还会对 16 位伪广播地址(ff:ff:00:00:00:00)
做出回应;而嗅探中的 win95/98/me 不仅会回应 16 位伪广播地址,而且也会回应 8 位伪广播地址
(ff:00:00:00:00:00),而*NIX 系统对各种广播地址所做出的反应却有些不同。在此我们选择 31 位伪广播
地址,是因为绝大多数的系统在嗅探时都会对它做出回应。而正常状况下的各种系统,都不会对 31 位伪广
播地址做出回应。
-s (ARP 欺骗 spoof) 需要强调的是在某些局域网(如以太网)内,数据报的发送与接收是基于
硬件地址的,这是我们实现欺骗的基础。首先获得指定的两台主机(假设为 A 和 B)的 mac 地址,然后向 A
发送 ARP Reply 数据报,其中的源 ip 地址为 B 的 ip 地址,但是源 mac 地址却是本地主机的 mac 地址,这

样主机 A 就会认为主机 B 的 mac 地址是本地主机的 mac 地址,所以主机 A 发送到主机 B 的数据报都发送到
本地主机了。同理向主机 B 发送 ARP Reply 数据报,通知它主机 A 的 mac 地址为本地主机的 mac 地址。这
样主机 A 和主机 B 就会把目的主机的 mac 地址理解为本地主机的 mac 地址,于是他们之间相互发送的数据
报都首先到达了本地主机,而先前我们已经将本地主机设置了 ip 路由功能,系统会自动将数据报转发到真
正的目的主机。其间,你就可以监听它们通信的各种数据报了。
-s (网络嗅探 sniff) 如果指定的两个目的主机均为本地主机,那么就只是将网络适配器设置
为混杂模式,这样就可以监听到流过本地主机网络适配器的各种数据。
-s (ip 冲突 shock) 如果你选择欺骗的两台主机是同一台非本地主机(假如是主机 C),那么
就会不断地向主机 C 发送 ARP Reply 数据报,报文中的源 ip 地址就是主机 C 的 ip 地址,但是源 mac 地址
却是本地主机的 mac 地址,因此主机 C 就会发现有另一台主机同时拥有和自己相同的 ip,这就是 ip 冲突
攻击。如果是非 xp 系统,都会跳出一个 ip 冲突的提示窗口,而 xp 系统也会有类似的警告。但是请注意,
在主机 C 的系统事件查看器中,会留下本地主机的 mac 地址与之冲突的恶心记录,所以你最好不要滥用这
个功能。
-r 在实现了 ARP 欺骗的情况下,向主机 A 和 B 发送 ARP Reply 数据报,通知主机 A(B)注
意主机 B(A)的 mac 地址为主机 B(A)自己的 mac 地址,这样主机 A 和 B 就会更新他们的 ARP 缓存,实现正常
的数据通信。
四)T-ARP 主要代码分析
1> 自定义函数:
int getmine() //发送 ARP Request 数据报,请求获得本地主机的 mac 地址;
void getdata(LPPACKET lp,int op) //分类处理接收到的数据报;
DWORD WINAPI sniff(LPVOID no) //将网络适配器设置为混杂模式,接收所有流过的
数据报;
DWORD WINAPI sendMASR(LPVOID no) //发送 ARP Request 数据报,请求获得指定 ip 的 mac
地址;
DWORD WINAPI sendSR(LPVOID no) //发送 ARP Reply 进行 ARP 欺骗,或是更新主机的 ARP
缓存。
2> 主要代码分析
printf("\nLibarary Version: %s",PacketGetVersion()); //输出 dll 的版本信息;
PacketGetAdapterNames((char *)adaptername,&adapterlength) //获得本地主机的网络
适配器列表和描述;
lpadapter=PacketOpenAdapter(adapterlist[open-1]); //打开指定的网络适配器;
PacketGetNetType(lpadapter,&ntype) //获得网络适配器的 MAC 类型;
PacketGetNetInfoEx(adapterlist[open-1],&ipbuff,&npflen) //获得指定网络适配器
的相关信息;