邪恶八进制信息安全团队技术讨论组's Archiver

EvilOctal 2005-7-25 17:42

[转载]手把手教你玩转ARP包 第三部分

文章作者:PiggyXP

  目录:
二。发送数据包的编程实现
  1.  填充数据包
  2.  发送数据包
三。一些附加步骤及说明
  1.  如果在VC中使用winpcap
  2.  获得网卡信息列表
  3.  获得系统ARP信息列表

      ................紧接上文................

1.      填充数据包

下面我举个填充包头的例子,我首先定义个了一个转换字符的函数,如下

/****************************************************************************
*  Name & Params::
*         formatStrToMAC
*         (
*            const LPSTR lpHWAddrStr : 用户输入的MAC地址字符串
*            unsigned char *HWAddr :  返回的MAC地址字符串(赋给数据包结构体)
*         )
*  Purpose:
*         将用户输入的MAC地址字符转成数据包结构体需要的格式
****************************************************************************/
void formatStrToMAC(const LPSTR lpHWAddrStr, unsigned char *HWAddr)
{
     unsigned int i, index = 0, value, temp;
    unsigned char c;

    _strlwr(lpHWAddrStr);                                  // 转换成小写

    for (i = 0; i < strlen(lpHWAddrStr); i++)
    {
        c = *(lpHWAddrStr + i);
        if (( c>=&#39;0&#39; && c<=&#39;9&#39; ) || ( c>=&#39;a&#39; && c<=&#39;f&#39; ))
        {
          if (c>=&#39;0&#39; && c<=&#39;9&#39;)  temp = c - &#39;0&#39;;                 // 数字
          if (c>=&#39;a&#39; && c<=&#39;f&#39;)  temp = c - &#39;a&#39; + 0xa;          // 字母
          if ( (index % 2) == 1 )
          {
             value = value*0x10 + temp;
             HWAddr[index/2] = value;
          }
          else value = temp;
          index++;
      }
          if (index == 12) break;
      }
}

// 开始填充各个字段
ARPPACKET ARPPacket;                                  // 定义ARPPACKET结构体变量

   memset(&ARPPacket, 0, sizeof(ARPPACKET));               // 数据包初始化

    formatStrToMAC(“DLC源MAC字符串”,ARPPacket.dlcHeader.SrcMAC);     // DLC帧头
    formatStrToMAC(“DLC目的MAC字符串”,ARPPacket.dlcHeader.DesMAC);

    formatStrToMAC(“ARP源MAC字符串”,ARPPacket.arpFrame.Send_HW_Addr);  // 源MAC
    ARPPacket.arpFrame.Send_Prot_Addr = inet_addr(srcIP);          // 源IP
    formatStrToMAC(“ARP目的MAC字符串”,ARPPacket.arpFrame.Targ_HW_Addr); // 目的MAC
    ARPPacket.arpFrame.Targ_Prot_Addr = inet_addr(desIP);          // 目的IP
   
    ARPPacket.arpFrame.Opcode = htons((unsigned short)arpType);      // arp包类型
   
    // 自动填充的常量
    ARPPacket.dlcHeader.Ethertype = htons((unsigned short)0x0806); // DLC Header的以太网类型
    ARPPacket.arpFrame.HW_Type = htons((unsigned short)1);        // 硬件类型
    ARPPacket.arpFrame.Prot_Type = htons((unsigned short)0x0800);   // 上层协议类型
    ARPPacket.arpFrame.HW_Addr_Len = (unsigned char)6;            // MAC地址长度
    ARPPacket.arpFrame.Prot_Addr_Len = (unsigned char)4;          // IP地址长度

That’s all ! ^_^
填充完毕之后,我们需要做的就是把我们的ARPPACKET结构体发送出去

2.发送ARP数据包:

我们发送ARP包就要用到winpcap的api了,具体步骤及函数是这样的,为了简单易懂,我把错误处理的地方都去掉了,详见代码
/**********************************************************************
*   Name & Params::
*         SendARPPacket()
*   Purpose:
*         发送ARP数据包
*   Remarks:
*         用的是winpcap的api函数
***********************************************************************/
void SendARPPacket()
{
    char *AdapterDeviceName =GetCurAdapterName();    // 首先获得获得网卡名字

    lpAdapter = PacketOpenAdapter(AdapterDeviceName);    // 根据网卡名字打开网卡

    lpPacket = PacketAllocatePacket();          // 给PACKET结构指针分配内存

    PacketInitPacket(lpPacket, &ARPPacket, sizeof(ARPPacket)); //初始化PACKET结构指针
                              // 其中的ARPPacket就是我们先前填充的ARP包

    PacketSetNumWrites(lpAdapter, 1);          // 每次只发送一个包

    PacketSendPacket(lpAdapter, lpPacket, true)     // Send !!!!! ^_^

    PacketFreePacket(lpPacket);              // 释放资源
    PacketCloseAdapter(lpAdapter);
}

呵呵,至此,关于ARP包最关键的部分就讲完了,你现在就可以来随心所欲的发送自己的ARP包了

既然作为一篇“科普文章”,接下来我再讲一讲与整个项目有关的附加步骤以及说明

三.附加步骤以及说明
1. 如何在VC中使用winpcap驱动
     虽然winpcap开发包使用起来非常简便,但是前期准备工作还是要费一番功夫的,缺一不可。^_^
     首先就是要安装它的驱动程序了,可以到它的主页下载,更新很快的
    [url]http://winpcap.polito.it/install/default.htm[/url]
    下载WinPcap auto-installer (driver +DLLs),直接安装就好了,或者我提供的代码包里面也有。
    希望以后用winpcap作开发的朋友,还需要下载 Developer&#39;s pack,解压即可。
   
      然后,需要设置我们工程的附加包含目录为我们下载Developer&#39;s pack开发包的Inclulde目录,连接器的附加依赖库设置为Developer&#39;s pack的lib目录。
     当然,因为我们的工作比较简单,就是借用winpcap发送数据包而已,所以只用从
winpcap开发包的include文件夹中,拷贝Packet32.h,到我们的工程来,并且包含它就可
以,但是要注意,Packet32.h本身还要包含一个Devioctl.h,也要一并拷贝进来,当然还有运
行库Packet.lib,一共就是需要拷贝3个文件了,如果加入库不用我多说了吧,在工程里面设
置,或者是在需要它的地方加入 #pragma comment(lib, "Packet.lib")了。

      整个项目其实可以分为四个部分,填充数据包、发送数据包、枚举系统网卡列表和
相关信息以及枚举系统ARP缓存列表,下面我再讲一下如何获得系统的网卡以及ARP列
表,这两个部分都要用到IP Helper的api,所以要包含<Iphlpapi.h>以及库文件Iphlpapi.lib,
其实都是很简单的,只用寥寥几行就OK了
2.    枚举系统网卡以及信息
最好是先定义关于网卡信息的一个结构体,这样显得结构比较清晰
// 网卡信息
typedef struct tagAdapterInfo      
{
          char szDeviceName[128];        // 名字
          char szIPAddrStr[16];         // IP
          char szHWAddrStr[18];         // MAC
          DWORD dwIndex;              // 编号      
}INFO_ADAPTER, *PINFO_ADAPTER;

/*********************************************************************
*   Name & Params::
*         AddAdapInfoToList
*         (
*            CListCtrl& list :  CARPPlayerDlg传入的list句柄
*         )
*   Purpose:
*         获得系统的网卡信息,并将其添加到list控件中
*   Remarks:
*         获得网卡IP及MAC用到了IpHelper api GetAdaptersInfo
******************************************************************/
void AddAdapInfoToList(CListCtrl& list)
{
    char tempChar;
    ULONG uListSize=1;
    PIP_ADAPTER_INFO pAdapter;        // 定义PIP_ADAPTER_INFO结构存储网卡信息
    int nAdapterIndex = 0;

    DWORD dwRet = GetAdaptersInfo((PIP_ADAPTER_INFO)&tempChar, &uListSize);//关键函数

    if (dwRet == ERROR_BUFFER_OVERFLOW)
    {
  PIP_ADAPTER_INFO pAdapterListBuffer = (PIP_ADAPTER_INFO)new(char[uListSize]);
  dwRet = GetAdaptersInfo(pAdapterListBuffer, &uListSize);
  if (dwRet == ERROR_SUCCESS)
  {
    pAdapter = pAdapterListBuffer;
    while (pAdapter)                               // 枚举网卡然后将相关条目添加到List中
    {
      // 网卡名字
       CString strTemp = pAdapter->AdapterName;              
       strTemp = "\\Device\\NPF_" + strTemp;                // 加上前缀
       list.InsertItem(nAdapterIndex,strTemp);            
       strcpy(AdapterList[nAdapterIndex].szDeviceName,strTemp);
       // IP
       strcpy(AdapterList[nAdapterIndex].szIPAddrStr,
                                 pAdapter->IpAddressList.IpAddress.String );
       list.SetItemText(nAdapterIndex,1,AdapterList[nAdapterIndex].szIPAddrStr);
       // MAC
       formatMACToStr( AdapterList[nAdapterIndex].szHWAddrStr, pAdapter->Address );
       list.SetItemText(nAdapterIndex,2,AdapterLis[nAdapterIndex].szHWAddrStr);
       // 网卡编号
       AdapterList[nAdapterIndex].dwIndex = pAdapter->Index;      

       pAdapter = pAdapter->Next;
       nAdapterIndex ++;
       }
    delete pAdapterListBuffer;
    }
}
}

2)获取ARP条目列表
// ARP条目信息
typedef struct tagARPInfo         
{
    char szIPAddrStr[16];          // IP
    char szHWAddrStr[18];         // MAC
    DWORD dwType;              // 类型
}INFO_ARP, *PINFO_ARP;


/**********************************************************************
*   Name & Params::
*         AddARPInfoToList
*         (
*            CListCtrl& list :         CARPPlayerDlg传入的list句柄
*            const short nAdapterIndex :  用户选中的网卡编号
*         )
*   Purpose:
*         读入系统的ARP缓存列表,.并添加到对话框中
*   Remarks:
*         用到了IpHelper api GetIpNetTable
*         而且用到了WinSock的api,所以要包含<WinSock2.h>
*****************************************************************/
void AddARPInfoToList(CListCtrl& list,const short nAdapterIndex)
{
    char tempChar;
    DWORD dwListSize = 1;
    DWORD dwRet;
    in_addr inaddr;
    list.DeleteAllItems();

    dwRet = GetIpNetTable((PMIB_IPNETTABLE)&tempChar, &dwListSize, TRUE);  // 关键函数
    if (dwRet == ERROR_INSUFFICIENT_BUFFER)
    {
      PMIB_IPNETTABLE pIpNetTable = (PMIB_IPNETTABLE)new(char[dwListSize]);
      dwRet = GetIpNetTable(pIpNetTable, &dwListSize, TRUE);
      if (dwRet == ERROR_SUCCESS)
      {
          for (int i=0; i<(int)pIpNetTable->dwNumEntries; i++)
          {
            // IP
             inaddr.S_un.S_addr = pIpNetTable->table[i].dwAddr;
             strcpy( ARPList[i].szIPAddrStr, inet_ntoa(inaddr) );  
             // MAC
             formatMACToStr( ARPList[i].szHWAddrStr, pIpNetTable->table[i].bPhysAddr );
             // Type
             ARPList[i].dwType = pIpNetTable->table[i].dwType;      

             if (AdapterList[nAdapterIndex].dwIndex != pIpNetTable->table[i].dwIndex)                                     continue;

             list.InsertItem(i,ARPList[i].szIPAddrStr);
             list.SetItemText(i,1,ARPList[i].szHWAddrStr);
             switch(ARPList[i].dwType) {        // 根据type的值来转换成字符显示
             case 3:
                list.SetItemText(i,2,"Dynamic");
                break;
             case 4:
                list.SetItemText(i,2,"Static");
                break;
             case 1:
                list.SetItemText(i,2,"Invalid");
             default:
                list.SetItemText(i,2,"Other");
             }
          }
      }
      delete pIpNetTable;
    }
}
      这样一来,我们基本上大功告成了,其他还有一些东西在这里就不讲了,大家可以下载我的代码看看就好了。
      下面我们来用ARP包玩一些小把戏 ^_^。
      (未完待续)

页: [1]
© 1999-2008 EvilOctal Security Team