<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      運用Npcap庫實現SYN半開放掃描

      Npcap 是一款高性能的網絡捕獲和數據包分析庫,作為 Nmap 項目的一部分,Npcap 可用于捕獲、發送和分析網絡數據包。本章將介紹如何使用 Npcap 庫來實現半開放掃描功能。TCP SYN 半開放掃描是一種常見且廣泛使用的端口掃描技術,用于探測目標主機端口的開放狀態。由于這種方法并不完成完整的 TCP 三次握手過程,因此具有更高的隱蔽性和掃描效率。

      筆者原本想為大家整理并分享如何使用Nmap工具進行端口掃描的,但覺得僅僅講解Nmap的命令使用方法并不能讓大家更好地理解其工作原理。實際上,Nmap 的底層使用的是Npcap庫,因此筆者決定演示如何使用Npcap庫開發一個簡單的掃描功能,從而幫助大家更好地理解Nmap的原理。

      首先,若使用Nmap對目標主機進行SYN掃描,只需要執行nmap -sS 39.97.203.57命令即可,等待一段時間則可獲取到目標主機常規開放端口狀態,若要掃描特定端口開放狀態僅需要指定-p參數并攜帶掃描區間即可,如下命令所示;

      ┌──(lyshark?kali)-[~]
      └─$ sudo nmap -sS 39.97.203.57
      Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-08-08 15:28 CST
      Nmap scan report for 39.97.203.57
      Host is up (0.0038s latency).
      Not shown: 997 filtered tcp ports (no-response)
      PORT     STATE SERVICE
      80/tcp   open  http
      443/tcp  open  https
      1935/tcp open  rtmp
      
      ┌──(lyshark?kali)-[~]
      └─$ sudo nmap -sS -v 39.97.203.57 -p 1-2000
      Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-08-08 15:32 CST
      Scanning 39.97.203.57 [2000 ports]
      Discovered open port 80/tcp on 39.97.203.57
      Discovered open port 443/tcp on 39.97.203.57
      Discovered open port 1935/tcp on 39.97.203.57
      Completed SYN Stealth Scan at 15:32, 7.42s elapsed (2000 total ports)
      Nmap scan report for 39.97.203.57
      Host is up (0.0039s latency).
      Not shown: 1997 filtered tcp ports (no-response)
      PORT     STATE SERVICE
      80/tcp   open  http
      443/tcp  open  https
      1935/tcp open  rtmp
      

      Npcap庫的配置非常簡單,讀者僅需要去到官網下載,初次使用還需安裝Npcap 1.79 installer驅動程序,并下載Npcap SDK 1.13對應的開發工具包,如下圖所示;

      接著,讀者需要自行解壓SDK開發工具包,并配置VC++目錄包含目錄與庫目錄,如下圖所示;

      在進行開發之前,我們需要先定義三個結構體變量,首先定義eth_header數據包頭,以太網包頭(Ethernet Frame Header)用于傳輸控制信息和數據,它是數據鏈路層的一部分,負責在局域網中實現數據的可靠傳輸。

      接著定義ip_header數據包頭,IP頭(IP Header)用于傳輸控制信息和數據,IP頭是網絡層的一部分,負責實現跨越不同網絡的數據傳輸。

      最后定義tcp_header數據包頭,TCP頭(TCP Header)用于傳輸控制信息和數據,TCP頭是傳輸層的一部分,負責在主機之間提供可靠的、面向連接的通信。

      若要發送TCP數據包,必須要構造一個完整的通信協議頭,將以太網數據包頭、IP數據包頭、TCP數據包頭封裝起來即可,其定義部分如下所示,其中每一個變量均對應于協議的每一個參數。

      #include <winsock2.h>
      #include <Windows.h>
      #include <pcap.h>
      
      #pragma comment(lib,"ws2_32.lib")
      #pragma comment(lib, "packet.lib")
      #pragma comment(lib, "wpcap.lib")
      
      // 以太網頭部結構體
      struct eth_header
      {
        uint8_t dest[6];   // 目的MAC地址 (6字節)
        uint8_t src[6];    // 源MAC地址 (6字節)
        uint16_t type;     // 以太網類型字段,表示上層協議 (2字節)
      };
      
      // IPv4頭部結構體
      struct ip_header
      {
        uint8_t ihl : 4,     // 頭部長度 (4位),表示IP頭部的長度,以32位字為單位
            version : 4; // 版本 (4位),IPv4的版本號為4
        uint8_t tos;        // 服務類型 (1字節)
        uint16_t tot_len;   // 總長度 (2字節),表示整個IP數據報的長度,以字節為單位
        uint16_t id;        // 標識 (2字節),用于標識數據報片段
        uint16_t frag_off;  // 片段偏移 (2字節),用于數據報片段
        uint8_t ttl;        // 生存時間 (1字節),表示數據報在網絡中的生存時間
        uint8_t protocol;   // 協議 (1字節),表示上層協議 (例如,TCP為6,UDP為17)
        uint16_t check;     // 頭部校驗和 (2字節),用于檢驗頭部的完整性
        uint32_t saddr;     // 源地址 (4字節),表示發送方的IPv4地址
        uint32_t daddr;     // 目的地址 (4字節),表示接收方的IPv4地址
      };
      
      // TCP頭部結構體
      struct tcp_header
      {
        uint16_t source;    // 源端口號 (2字節)
        uint16_t dest;      // 目的端口號 (2字節)
        uint32_t seq;       // 序號 (4字節),表示數據段的序列號
        uint32_t ack_seq;   // 確認號 (4字節),表示期望接收的下一個序列號
        uint16_t res1 : 4,  // 保留位 (4位),通常設為0
        doff : 4,   // 數據偏移 (4位),表示TCP頭部的長度,以32位字為單位
        fin : 1,    // FIN標志 (1位),表示發送方沒有更多數據
        syn : 1,    // SYN標志 (1位),表示同步序號,用于建立連接
        rst : 1,    // RST標志 (1位),表示重置連接
        psh : 1,    // PSH標志 (1位),表示推送數據
        ack : 1,    // ACK標志 (1位),表示確認字段有效
        urg : 1,    // URG標志 (1位),表示緊急指針字段有效
        res2 : 2;   // 保留位 (2位),通常設為0
        uint16_t window;    // 窗口大小 (2字節),表示接收方的緩沖區大小
        uint16_t check;     // 校驗和 (2字節),用于檢驗TCP頭部和數據的完整性
        uint16_t urg_ptr;   // 緊急指針 (2字節),表示緊急數據的偏移量
      };
      
      unsigned short checksum(void *b, int len)
      {
        unsigned short *buf = (unsigned short *)b;
        unsigned int sum = 0;
        unsigned short result;
      
        for (sum = 0; len > 1; len -= 2)
          sum += *buf++;
        if (len == 1)
          sum += *(unsigned char*)buf;
        sum = (sum >> 16) + (sum & 0xFFFF);
        sum += (sum >> 16);
        result = ~sum;
        return result;
      }
      

      接著需要實現兩個通用函數,其中EnumAdapters用于枚舉當前系統中所有的網卡信息,并輸出其下標號與網卡描述信息,BindAdapters函數則用于根據用戶傳入的下標號對網卡進行動態綁定,函數中通過循環的方式查找網卡下標若匹配則將下標所對應的句柄存儲到temp_adapter變量內,最后通過pcap_open_live實現對網卡的打開。

      // 枚舉當前網卡
      int EnumAdapters()
      {
        pcap_if_t *allAdapters;
        pcap_if_t *ptr;
        int index = 0;
        char errbuf[PCAP_ERRBUF_SIZE];
      
        // 獲取本地機器設備列表
        if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &allAdapters, errbuf) != -1)
        {
          // 打印網卡信息列表
          for (ptr = allAdapters; ptr != NULL; ptr = ptr->next)
          {
            ++index;
            if (ptr->description)
            {
              printf("[ %d ] \t [ %s ] \n", index - 1, ptr->description);
            }
          }
        }
      
        pcap_freealldevs(allAdapters);
        return index;
      }
      
      // 根據編號綁定到對應網卡
      pcap_t* BindAdapters(int nChoose)
      {
        pcap_if_t *adapters, *temp_adapter;
        char errbuf[PCAP_ERRBUF_SIZE];
        pcap_t *handle = NULL;
      
        if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &adapters, errbuf) == -1)
        {
          return NULL;
        }
      
        // 遍歷找到指定的網卡
        temp_adapter = adapters;
        for (int x = 0; x < nChoose - 1 && temp_adapter != NULL; ++x)
        {
          temp_adapter = temp_adapter->next;
        }
      
        // 若找不到綁定設備則釋放句柄
        if (temp_adapter == NULL)
        {
          pcap_freealldevs(adapters);
          return NULL;
        }
      
        // 打開指定的網卡
        handle = pcap_open_live(temp_adapter->name, 65534, PCAP_OPENFLAG_PROMISCUOUS, 1000, errbuf);
        if (handle == NULL)
        {
          pcap_freealldevs(adapters);
          return NULL;
        }
      
        pcap_freealldevs(adapters);
        return handle;
      }
      

      抓包回調函數packet_handlerpcap_loop調用,當啟用抓包后若句柄返回數據則會通過回調函數通知用戶,用戶獲取到數據包header后,通過逐層解析即可得到所需要的字段,若要實現SYN快速探測則需要判斷tcph標志,若標志被返回則可通過RST斷開會話,并以此節約掃描時間。

      如下代碼,定義了一個網絡數據包回調函數 packet_handler,用于處理通過 pcap 庫捕獲的網絡數據包。函數首先打印數據包的長度,然后解析以太網頭部以檢查其類型是否為 IP(0x0800)。如果是 IP 數據包,進一步解析 IP 頭部并打印相關信息,包括 IP 版本、頭長度、源 IP 地址和目標 IP 地址。隨后檢查 IP 數據包的協議字段是否為 TCP(6),若是,則解析 TCP 頭部并打印源端口、目標端口、序列號、確認號、頭部長度、標志、窗口大小、校驗和及緊急指針等信息。

      // 網絡數據包回調函數
      void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)
      {
        // 打印數據包長度
        printf("數據包長度:%d\n", header->len);
      
        // 以太網頭部
        struct eth_header *eth = (struct eth_header *)(pkt_data);
      
        // 檢查以太網類型是否為 IP(0x0800)
        if (ntohs(eth->type) == 0x0800)
        {
          // IP 頭部
          struct ip_header *iph = (struct ip_header *)(pkt_data + sizeof(struct eth_header));
      
          // 打印 IP 頭部信息
          printf("IP 版本: %d | ", iph->version);
          printf("IP 頭長度: %d | ", iph->ihl * 4);
          printf("源IP地址: %s | ", inet_ntoa(*(struct in_addr *)&iph->saddr));
          printf("目標IP地址: %s\n", inet_ntoa(*(struct in_addr *)&iph->daddr));
      
          // 檢查協議是否為 TCP(6)
          if (iph->protocol == 6)
          {
            // TCP 頭部
            struct tcp_header *tcph = (struct tcp_header *)(pkt_data + sizeof(struct eth_header) + iph->ihl * 4);
      
            // 打印 TCP 頭部信息
            printf("源端口: %d | ", ntohs(tcph->source));
            printf("目標端口: %d | ", ntohs(tcph->dest));
            printf("序列號: %u | ", ntohl(tcph->seq));
            printf("確認號: %u | ", ntohl(tcph->ack_seq));
            printf("包頭長度: %d | ", tcph->doff * 4);
            printf("標志: ");
            if (tcph->fin) printf("FIN ");
            if (tcph->syn) printf("SYN ");
            if (tcph->rst) printf("RST ");
            if (tcph->psh) printf("PSH ");
            if (tcph->ack) printf("ACK ");
            if (tcph->urg) printf("URG ");
            printf("\n");
            printf("窗體長度: %d | ", ntohs(tcph->window));
            printf("校驗和: 0x%04x | ", ntohs(tcph->check));
            printf("緊急數據指針: %d\n", ntohs(tcph->urg_ptr));
          }
        }
        printf("\n");
      }
      

      最后來看下主函數是如何實現的,首先通過調用EnumAdapters函數獲取到網卡編號,并調用BindAdapters(4)函數綁定到指定的網卡之上,套接字的創建依然采用原生API接口來實現,只不過在調用sendto發送數據包時我們需要自行構建一個符合SYN掃描條件的數據包,在構建數據包時,以太網數據包用于指定網卡MAC地址等信息,IP數據包頭則用于指定IP地址等信息,TCP數據包頭則用于指定端口號信息,并僅需將tcph->syn = 1;設置為1,通過checksum計算校驗和,并將校驗好的packet包通過sendto函數發送到對端主機,如下所示;

      int main(int argc, char* argv[])
      {
        pcap_if_t *alldevs;
        pcap_t *adhandle;
        int i = 0;
      
        EnumAdapters();
      
        adhandle = BindAdapters(4);
      
        // 創建套接字
        SOCKET sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
        if (sock == INVALID_SOCKET)
        {
          return -1;
        }
      
        // 設置套接字屬性
        int one = 1;
        if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char *)&one, sizeof(one)) == SOCKET_ERROR)
        {
          return -1;
        }
      
        // ---------------------------------------------------------------
        // 構建網絡數據包
        // ---------------------------------------------------------------
      
        char packet[4096];
        memset(packet, 0, 4096);
      
        struct eth_header *eth = (struct eth_header *)packet;
        struct ip_header *iph = (struct ip_header *)(packet + sizeof(struct eth_header));
        struct tcp_header *tcph = (struct tcp_header *)(packet + sizeof(struct eth_header) + sizeof(struct ip_header));
      
        // ---------------------------------------------------------------
        // 構建以太網數據包頭
        // ---------------------------------------------------------------
        memset(eth->dest, 0xff, 6);  // 目標MAC地址
        memset(eth->src, 0x00, 6);   // 原MAC地址
        eth->type = htons(0x0800);   // IPv4
      
        // ---------------------------------------------------------------
        // 構建IP數據包頭
        // ---------------------------------------------------------------
        iph->ihl = 5;
        iph->version = 4;
        iph->tos = 0;
        iph->tot_len = sizeof(struct ip_header) + sizeof(struct tcp_header);
        iph->id = htons(54321);
        iph->frag_off = 0;
        iph->ttl = 255;
        iph->protocol = IPPROTO_TCP;
        iph->check = 0;
        iph->saddr = inet_addr("192.168.1.1");   // 原始IP地址
        iph->daddr = inet_addr("39.97.203.57");  // 目標IP地址
      
        // ---------------------------------------------------------------
        // 構建TCP數據包頭
        // ---------------------------------------------------------------
        tcph->source = htons(12345);           // 原始TCP端口
        tcph->dest = htons(80);                // 目標TCP端口
        tcph->seq = 0;
        tcph->ack_seq = 0;
        tcph->doff = 5; // TCP 頭部長度
        tcph->fin = 0;
        tcph->syn = 1;
        tcph->rst = 0;
        tcph->psh = 0;
        tcph->ack = 0;
        tcph->urg = 0;
        tcph->window = htons(5840);    // 分配Windows窗體數
        tcph->check = 0;               // 現在保留校驗和0,稍后用偽標頭填充
        tcph->urg_ptr = 0;
      
        // ---------------------------------------------------------------
        // 計算校驗和
        // ---------------------------------------------------------------
      
        // 計算IP校驗和
        iph->check = checksum((unsigned short *)packet, iph->tot_len);
      
        // TCP 校驗和
        struct
        {
          uint32_t src_addr;
          uint32_t dst_addr;
          uint8_t placeholder;
          uint8_t protocol;
          uint16_t tcp_length;
          struct tcp_header tcp;
        } pseudo_header;
      
        pseudo_header.src_addr = iph->saddr;
        pseudo_header.dst_addr = iph->daddr;
        pseudo_header.placeholder = 0;
        pseudo_header.protocol = IPPROTO_TCP;
        pseudo_header.tcp_length = htons(sizeof(struct tcp_header));
        memcpy(&pseudo_header.tcp, tcph, sizeof(struct tcp_header));
      
        tcph->check = checksum((unsigned short *)&pseudo_header, sizeof(pseudo_header));
      
        // ---------------------------------------------------------------
        // 發送數據包
        // ---------------------------------------------------------------
      
        struct sockaddr_in dest;
        dest.sin_family = AF_INET;
        dest.sin_addr.s_addr = iph->daddr;
      
        if (sendto(sock, packet, iph->tot_len, 0, (struct sockaddr *)&dest, sizeof(dest)) == SOCKET_ERROR)
        {
          return -1;
        }
      
        // ---------------------------------------------------------------
        // 啟用抓包
        // ---------------------------------------------------------------
      
        pcap_loop(adhandle, 10, packet_handler, NULL);
      
        pcap_close(adhandle);
        closesocket(sock);
        pcap_freealldevs(alldevs);
      
        system("pause");
        return 0;
      }
      

      讀者可自行編譯并運行上述代碼,當執行成功后則可看到數據包的方向及標志類型,如下圖所示。

      posted @ 2024-08-10 08:43  lyshark  閱讀(552)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 国产无套内射又大又猛又粗又爽 | 久久精品无码专区免费东京热 | 99精品久久久久久久婷婷| 欧美日产国产精品日产| 国产精品伦理一区二区三| 亚洲国产精品久久电影欧美 | 欧美三级不卡在线观线看高清| 成人3D动漫一区二区三区| 亚洲码欧洲码一二三四五| 久久夜色精品久久噜噜亚| 香蕉亚洲欧洲在线一区| 元码人妻精品一区二区三区9| 亚洲av成人区国产精品| 欧美熟妇乱子伦XX视频| 华人在线亚洲欧美精品| 亚洲国产精品日韩av专区| 国产精品久久人人做人人爽| 亚洲欧洲日韩精品在线| 亚洲av综合久久成人网| 日韩一区二区三区三级| 国产成人欧美一区二区三区在线| 人妻精品久久无码区| 日韩人妻系列无码专区| 亚洲精品男男一区二区| 国产寡妇偷人在线观看| 伊人狠狠色丁香婷婷综合| 赤峰市| 国产精品美女黑丝流水| 337P日本欧洲亚洲大胆精品555588| 亚洲真人无码永久在线| 亚洲第一无码专区天堂| 国产精品美女AV免费观看| 一区二区中文字幕久久| 免费无码va一区二区三区| 亚洲综合无码明星蕉在线视频| 亚洲国产午夜精品理论片妓女 | 国产在线观看免费观看| 少妇粗大进出白浆嘿嘿视频| 日韩欧美一中文字暮专区| 亚洲性一交一乱一伦视频| 久久国产免费观看精品3|