当前位置:   article > 正文

WinPcap权威指南(二)_delphi pacp

delphi pacp

        上一节我们简单介绍了WinPcap的一些基础知识,同时也枚举到所有网卡的设备名称,现在我们就可以操作网卡了。WinPcap有一个结构叫TADAPTER,你可以把它想象为一个句柄,我们平时操作文件,一般是先打开/创建一个文件,如果成功,则返回一个句柄,然后读文件就可以使用ReadFile,写文件可以使用WriteFile,操作完毕后,CloseHandle关闭这个句柄,WinPcap下的操作也是类似的:

1、打开一个网卡,返回句柄:function PacketOpenAdapter(AdapterName: PAnsiChar): LPADAPTER;

        其中AdapterName就是上一节获取的网卡设备名称,打开成功则返回该网卡的句柄,失败返回nil。一般地说,打开句柄后,还可以做一些初始化工作。例如:调用PacketSetHwFilter将网卡设置为混杂模式(只有网卡处于混杂模式,才可以获取不是发送给本机的数据);调用PacketSetBuff设置缓冲区大小;调用PacketSetReadTimeout设置接收超时。具体请参考演示代码。

2、从网卡获取数据:function PacketReceivePacket(AdapterObject: LPADAPTER; pPacket: LPPACKET; Sync: Byte): Byte;

        AdapterObject: 就是网卡的句柄,pPacket则对应一个TPACKET结构的指针。一般是先通过函数PacketAllocatePacket来分配一个pPacket,再调用PacketInitPacket将自己的接收缓冲区和它关联,使用完毕后调用PacketFreePacket释放掉。对应的WinPcap内部实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
function PacketAllocatePacket(): LPPACKET;
var
   pPacket: LPPACKET;
begin
   pPacket := GlobalAllocPtr(GMEM_MOVEABLE or GMEM_ZEROINIT, sizeof(TPACKET));
   if (pPacket = nil ) then
   begin
     //TRACE_PRINT("PacketAllocatePacket: GlobalAlloc Failed");
   end ;
 
   Result := pPacket;
end ;
 
procedure PacketInitPacket( var pPacket: LPPACKET; Buffer: Pointer ; Length: UINT);
begin
   //TRACE_ENTER("PacketInitPacket");
 
   pPacket^.Buffer := Buffer; //关联用户缓冲区
   pPacket^.Length := Length; //用户缓冲区大小
   pPacket^.ulBytesReceived := 0 ;
   pPacket^.bIoComplete := 0 ;
 
   //TRACE_EXIT("PacketInitPacket");
end ;
 
procedure PacketFreePacket( var pPacket: LPPACKET);
begin
   //TRACE_ENTER("PacketFreePacket");
   GlobalFreePtr(pPacket);
   //TRACE_EXIT("PacketFreePacket");
end ;

3、通过网卡发送数据:function PacketSendPacket(AdapterObject: LPADAPTER; pPacket: LPPACKET; Sync: Byte): Byte;

4、关闭网卡句柄:procedure PacketCloseAdapter(lpAdapter: LPADAPTER);

        我们的程序使用了两个线程来处理数据,其中TRecvPackThread用于从网卡获取数据,然后添加到全局的g_List;而TAnalysePacketsThread则从g_List里面取出数据来处理。为了界面更友好,再添加一个TTimer来获取WinPcap的内部状态。

        现在我们获取了数据,但这个数据就是一个指针,里面是什么东西呢?其实跟我们的《张曼玉与指针》里面说的,数据就是一切,你说它是什么,它就是什么。实际上,我们捕获的都是以太网帧数据,帧头结构如下:

1
2
3
4
5
6
7
8
type
   _ETHERNET_HDR = packed record
     DestMac: array [ 0..5 ] of Byte ; //目的MAC地址
     SourceMac: array [ 0..5 ] of Byte ; //源MAC地址
     EthernetType: Word ; //帧类型
   end ;
   TEthernetHeader = _ETHERNET_HDR;
   LPEthernetHeader = ^_ETHERNET_HDR;

        实际上,不管上层是什么协议,到了底层,都会封装为以太帧,然后发送出去。例如,TCP协议,是基于IP协议的,那么到了底层,实质上会封装为:以太帧头+IP头+TCP头+实际数据(如果存在)。所以我们在这里根据EthernetType判断是什么类型的帧,再作进一步解释:

1
2
3
4
5
6
7
8
9
10
11
12
pEthernetHeader := LPEthernetHeader(pBuffer);
case ntohs(pEthernetHeader^.EthernetType) of //判断以太帧类型
   ETHERTYPE_ARP: ProcessARPPacket(LPARPPacket(pBuffer));
   ETHERTYPE_IP: //IP帧
     begin
       pIPHeader := LPIPHeader(pBuffer + sizeof(TEthernetHeader)); //判断是TCP、UDP还是ICMP等
       case pIPHeader^.Protocol of
         IPPROTO_TCP: ProcessTCPPacket(LPTCPPacket(pBuffer));
         IPPROTO_UDP: ProcessUDPPacket(LPUDPPacket(pBuffer));
       end ;
     end ;
end ;

winpcap2

附件下载:
本节代码

        本节仅简单的解释了ARP和UDP协议,下一节再结合发包深入网络的连接过程。例如:ARP的欺骗、路由器的实质、数据的修改等。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/162490
推荐阅读
相关标签
  

闽ICP备14008679号