利用arp发现网络中的嗅探器

原创 2005年04月27日 17:13:00
 

1. Sniffer原理
所谓知己知彼方能百战不殆,要了解探测Sniffer的方法,就先得了解Sniffer的原理。首先,让我们来看一看局域网中是怎样传输数据的。当一个数据包的目的地是局域网内的某台计算机时,此数据包将以广播的形式被发送到网内每一台计算机上。而每台计算机的网卡将分析数据包中的目的Mac地址(即以太网地址),如果此地址为本计算机Mac地址或为广播地址(FF-FF-FF-FF-FF-FF),那么,数据包将被接收,而如果不是,网卡将直接将其丢弃。但是,这里有一个前提,就是接收端计算机的网卡是在正常模式下工作的。而如果网卡被设置为混杂模式,那么它就可以接收所有经过的数据包了(当然也包括目的地不是本机的数据包)。就是说,只要是发送到局域网内的数据包,都会被设置成混杂模式的网卡所接收!这也就是Sniffer的基本原理了。至于Sniffer的具体实现和一些细节,这里就不多讲了,大家有兴趣可以参考相关资料。

2. 以太网中传输的ARP数据报
知道了Sniffer的基本原理,现在,我们就要想想怎么才能将局域网中隐藏的Sniffer揪出来,这才是本篇文章的主题。这里,我们需要自己构造ARP数据包,所以,就先简单介绍一下ARP请求和应答数据报的结构:

typedef struct _et_header    //以太网头部
{
    unsigned char   eh_dst[6]; 
    unsigned char   eh_src[6];
    unsigned short  eh_type;
}ET_HEADER;

typedef struct _arp_header   //ARP头部
{
    unsigned short  arp_hdr;
    unsigned short  arp_pro;
    unsigned char   arp_hln;
    unsigned char   arp_pln;
    unsigned short  arp_opt;
    unsigned char   arp_sha[6];
    unsigned long   arp_spa;
    unsigned char   arp_tha[6];
    unsigned long   arp_tpa;
}ARP_HEADER;
  
以上就是网络中传输的ARP数据包的结构了。至于结构中每个字段所表示的具体含义以及如何初始化,超出了本文章的讨论范围,大家有兴趣可以参看《TCP-IP协议详解》一书。

3. 探测局域网中的Sniffer
终于进入主题了。既然Sniffer是一种静态的黑软,不会留下任何日志,那么我们就要主动的去探测它。鉴于Sniffer的原理是设置网卡为混杂模式,那么,我们就可以想办法探测网络中被设置为混杂模式的网卡,以此来判断是否存在Sniffer。
这里,让我们再来看看计算机接收数据包的规则。前面已经讲过,在正常模式下,首先由网卡判断数据包的目的Mac地址,如果为本机Mac地址或为广播地址,那么数据包将被接收进入系统核心,否则将被丢弃。而如果网卡被设置为混杂模式,那么所有的数据包都将直接进入系统核心。数据包到达系统核心后,系统还将进一步对数据包进行筛选:系统只会对目的Mac地址为本机Mac地址或广播地址的数据包做出响应――如果接收到的是ARP请求报文,那么系统将回馈一个ARP应答报文。但是,不同的是,系统核心和网卡对广播地址的判断有些不一样:以Windows系统为例,网卡会判断Mac地址的所有六位,而系统核心只判断Mac地址的前两位(Win98甚至只判断前一位),也就是说,对于系统核心而言,正确的广播地址FF-FF-FF-FF-FF-FF和错误的广播地址FF-FF-FF-FF-FF-FE是一样的,都被认为是广播地址,甚至FF-FF-00-00-00-00也会被系统核心认为是广播地址!
写到这里,聪明的读者大概已经知道该怎么做了。如果我们构造一个目的Mac地址为FF-FF-FF-FF-FF-FE的ARP请求报文,那么,对于在正常工作模式下的网卡,数据包将被丢弃,当然也就不会回馈任何报文;而对于在混杂模式下网卡,数据包将被接收进入系统核心。而系统核心会认为这个Mac地址是广播地址,因此就会回馈一个ARP应答报文。这样,我们就可以判断出这台机器上存在Sniffer了。

4. 主要源码分析
由以上分析可知,程序大概分为两个模块,一个是发送伪装广播地址的ARP请求报文,另一个是接收回馈的ARP应答报文并做出分析。我们就分别用两个线程来实现。主线程负责发送,监听线程负责接收。

首先是创建以太网头部和ARP头部的结构:


typedef struct _et_header    //以太网头部
{
    unsigned char   eh_dst[6]; 
    unsigned char   eh_src[6];
    unsigned short  eh_type;
}ET_HEADER;

typedef struct _arp_header   //ARP头部
{
    unsigned short  arp_hdr;
    unsigned short  arp_pro;
    unsigned char   arp_hln;
    unsigned char   arp_pln;
    unsigned short  arp_opt;
    unsigned char   arp_sha[6];
    unsigned long   arp_spa;
    unsigned char   arp_tha[6];
    unsigned long   arp_tpa;
}ARP_HEADER;

然后是发送ARP请求报文的主线程,取得所有适配器的名字。其中,“adapter_name”表示一个用于存放适配器名字的缓冲区,而这些适配器名字将以UNICODE编码方式存入此缓冲区中。UNICODE编码方式就是用一个字的空间(两个字节)来存放一个字符。这样,每个字符间自然会出现一个'/0'。而两个适配器名字之间将会有一个字为'/0'作为间隔。adapter_length:这个缓冲区的大小:


if(PacketGetAdapterNames((char*)adapter_name, &adapter_length)==FALSE)
  {
     printf("PacketGetAdapterNames error:%d/n",GetLastError());
     return 0;
   }

打开适配器,此处我默认打开第一块适配器:


lpAdapter=(LPADAPTER)PacketOpenAdapter((LPTSTR)adapter_list[0]); 
  if (!lpAdapter||(lpAdapter->hFile==INVALID_HANDLE_VALUE))
  {
     printf("Unable to open the driver, Error Code : %lx/n", GetLastError());
     return 0;
  }

以太网头部和ARP头部结构赋值,StrToMac函数是笔者自定义的字符串转换为Mac地址的函数:


StrToMac("00E06E41508F",s_Mac);    //"00E06E41508F"是笔者测试程序所用的本地机的网卡地址,测试者应将其改为测试机网卡地址
memcpy(et_header.eh_src,s_Mac,6);
StrToMac("FFFFFFFFFFFE",d_Mac);  //目的物理地址设置为FFFFFFFFFFFE。   
memcpy(et_header.eh_dst,d_Mac,6);
et_header.eh_type=htons(0x0806);  //类型为0x0806表示这是ARP包
arp_header.arp_hdr=htons(0x0001);  //硬件地址类型以太网地址
arp_header.arp_pro=htons(0x0800);  //协议地址类型为IP协议
arp_header.arp_hln=6;              //硬件地址长度为6
arp_header.arp_pln=4;              //协议地址长度为4
arp_header.arp_opt=htons(0x0001);  //标识为ARP请求
arp_header.arp_spa=inet_addr("172.24.21.10");  //"172.24.21.10"是我测试程序所用的本地机的IP,测试者应将其改为测试机IP
memcpy(arp_header.arp_sha,et_header.eh_src,6);
arp_header.arp_tpa=inet_addr(argv[1]);
memcpy(arp_header.arp_tha,et_header.eh_dst,6);

发送数据包:


lpPacket=PacketAllocatePacket();     //给PACKET结构指针分配内存
PacketInitPacket(lpPacket,buffer,512);   //初始化PACKET结构指针
PacketSetNumWrites(lpAdapter,5);  //设置发送次数
PacketSendPacket(lpAdapter,lpPacket,TRUE);//发送ARP请求包

最后别忘了扫尾工作:


PacketFreePacket(lpPacket);   //释放PACKET结构指针
PacketCloseAdapter(lpAdapter);  //关闭适配器

最后是监听线程:
设置接收数据包的系列参数:


PacketSetHwFilter(lpAdapter, NDIS_PACKET_TYPE_DIRECTED);   //设置网卡为直接模式
PacketSetBuff(lpAdapter,1024);     //设置网卡接收数据包的缓冲区大小
PacketSetReadTimeout(lpAdapter,2);   //设置接收到一个包后的“休息”时间

接收数据包:

★PacketReceivePacket(lpAdapter, lpPacket, TRUE);   //接收数据包★

对数据包进行分析,以得出结论:


char *buf;
bpf_hdr *lpBpfhdr;
ET_HEADER *lpEthdr;
in_addr addr={0};
  buf=(char *)lpPacket->Buffer;
lpBpfhdr=(bpf_hdr *)buf;
lpEthdr=(ET_HEADER *)(buf+lpBpfhdr->bh_hdrlen);
if(lpEthdr->eh_type==htons(0x0806))     //判断是否为ARP包
  {
    ARP_HEADER *lpArphdr=(ARP_HEADER*)(buf+lpBpfhdr->bh_hdrlen+sizeof(ET_HEADER));
char source_ip[20]={0},dest_ip[20]={0};
addr.S_un.S_addr=lpArphdr->arp_spa;
memcpy(source_ip,inet_ntoa(addr),strlen(inet_ntoa(addr)));
memset(&addr,0,sizeof(in_addr));
addr.S_un.S_addr=lpArphdr->arp_tpa;
memcpy(dest_ip,inet_ntoa(addr),strlen(inet_ntoa(addr)));
if(!strcmp(source_ip,ip) && !strcmp(dest_ip,"172.24.21.10"))   //判断接收到的包的源IP与目的IP是否正确(字符串变量ip是从主线程传递过来的被探测机的ip)
  {
    if(lpArphdr->arp_opt==htons(0x0002))     //判断是否为ARP应答
      {
   printf("There is a Sniffer!/n");
      }
   }
}

5. 结尾
真的是所谓一物降一物,Sniffer虽然厉害,但我们终究找到了破解它的办法了。由于这个原理,软件Anti-sniff应运而生。当然,我写的这个程序比起Anti-sniff来可以说是小巫见大巫,但是,万变不离其综,它们的基本原理都是一样的。

基于ARP的网络嗅探器

  • 2015年04月05日 13:47
  • 546KB
  • 下载

IP探测实现 ARP与设备发现

前几天遇到个需求,要探测局域网内 PC机的 IP,有可能跨网段,但是在同一个交换机;于是果断从网上下载了一个DEMO,可以填写探测的IP地址范围,扫描出范围内的主机IP; 抓包看了下,发现一堆icmp...
  • LIFEXX
  • LIFEXX
  • 2016年10月23日 21:32
  • 1662

linux网络嗅探器

这是前段时间学习libpcap写的一个小软件。   吐槽: Linux编程,本人是从大三上学期开始学习。 相对来说,比较喜欢Socket编程这块。期间也写过dos、通讯等小程序。...
  • wzs298
  • wzs298
  • 2013年08月03日 13:29
  • 3542

网络嗅探器(Sniffer)的原理与实现(1)

一.背景 为了使不同体系结构的计算机网络都能进行互联,国际标准化组织ISO于1997年成立了专门的结构研究这个问题。不久他们就提出了一个试图使各种计算机在世界范围内都能互联的成网的标准框架,即著名的...
  • bobopeng
  • bobopeng
  • 2014年02月19日 20:29
  • 2644

winPcap+MFC实现网络嗅探器

winPcap+MFC实现网络嗅探器
  • yjw19901214
  • yjw19901214
  • 2015年12月15日 20:54
  • 1697

VC++编程实现网络嗅探器

引言  从事网络安全的技术人员和相当一部分准黑客(指那些使用现成的黑客软件进行攻击而不是根据需要去自己编写代码的人)都一定不会对网络嗅探器(sniffer)感到陌生,网络嗅探器无论是在网络安全还是在黑...
  • junnan321
  • junnan321
  • 2007年08月10日 15:30
  • 1958

简单网络嗅探器

从事网络安全的技术人员和相当一部分准黑客(指那些使用现成的黑客软件进行攻击而不是根据需要去自己编写代码的人)都一定不会对网络嗅探器(sniffer)感到陌生,网络嗅探器无论是在网络安全还是在黑客攻击方...
  • gdut5276
  • gdut5276
  • 2017年05月31日 09:14
  • 744

arp嗅探(windows)

arp嗅探口令教程(windows环境)
  • Luosec
  • Luosec
  • 2017年04月10日 11:14
  • 1158

网络嗅探器(MFC实现)

大家也许用过网络嗅探器吧,确实网络嗅探器用在了很多方面。网络嗅探器是通过把网卡设置为混杂模式来捕获网络数据包的,简单介绍网络嗅探器的实现:   1 定义IP协议结构 typedef struct...
  • qiurisuixiang
  • qiurisuixiang
  • 2011年09月22日 22:18
  • 4296

一个简易网络嗅探器的实现

引言  目前,已经有不少的Sniff工具软件,如Windows环境下,最富盛名的工具是Netxray和Sniffer pro,用它们在 Windows环境下抓包来分析,非常方便。在UNIX环境下如Sn...
  • crabinhit
  • crabinhit
  • 2005年03月29日 17:01
  • 1077
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:利用arp发现网络中的嗅探器
举报原因:
原因补充:

(最多只允许输入30个字)