ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [WINPCAP] 스니핑 프로그램
    Network/NetProg 2017. 10. 5. 01:02
    #WINPCAP을 이용한 패킷 스니핑 프로그램 개발# 



    * pcap함수 정리

    - pcap_findalldevs(pcap_if_t *alldevs, char *errbuf)

    네트워크 장치들을 찾아주는 함수다.

    실패하면 -1 반환, 성공 시 장치이름을 반환하고 없으면 NULL을 반환한다.


    - pcap_open_live(const char *device_name, int snaplen, int promisc, int to_ms, char *errbuf) 

    현재 네트워크에서 해당 네트워크 장치 패킷을 캡처하는 함수이다.

    int snaplen - 캡처할 패킷의 길이

    int promisc - 보통 1(true)로 설정한다. true로 설정하면 무차별모드로 설정되어 모든 패킷을 잡게된다.

    int to_ms - 패킷을 읽는 시간을 설정하는 부분이다. 0이 아닌 충분한 시간으로 설정해줘야 한다.


    - pcap_compile(pcap_t *use_dev,

                     struct bpf_program *filter_struc,

     char *FILTER_RULE, 

     int optimize,

    bpf_u_int32 netmask)

    문자열형식인 FILTER_RULE을 handle에 적용하기 위해 구조체형식으로 컴파일해주는 함수다.

    실패시 -1을 반환한다.


    struct bpf_program *filter_stuc - 구조체형식의 FILTER_RULE

    char *FILTER_RULE - 문자열형식의 FILTER_RULE

    Ex) host 127.0.0.1 and 8080

    자세한 양식은 https://www.winpcap.org/docs/docs_40_2/html/group__language.html 를 참고하길 바란다.


    int optimize - 결과코드의 최적화 수행여부 ( 보통은 1)

    bpf_u_int32 netmask - 브로드캐스트를 감청할 때 쓰일 수 있는 인자이다. (보통은 NULL)


    - pcap_setfilter(pcap_t *use_dev, struct bpf_program *filter_struc)

    구조체형식의 FILTER_RULE을 실제 handle에 적용하는 함수이다.


    - pcap_next_ex(pcap_t *use_dev, struct pcap_pkthdr **header, const unsigned **pkt_data)

    마지막에 캡처된 패킷 데이터를 가져오는 함수이다.

    실제로는 packet_handler 라는 콜백함수가 데이터들을 채워준다.

    실패시 -1 반환




    * HEADER구조 정의


    - Ethernet header 구조(총 14bytes)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    struct ether_add
    {
        unsigned char mac_add[6];
    };
    struct ether_header
    {
        struct ether_add src_mac;
        struct ether_add des_mac;
        unsigned short eth_type;
        //14bytes
    };
     
    cs



    mac_add[6] : 각각 6bytes의 길이를 가지고 있다.

    eth_type : 2bytes의 길이를 가지고있다. 

     short의 크기는 2byte이고, 음수의 값은 필요없으니 unsigned로 선언한다.



    -IP header 구조 총(20bytes)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    struct ip_header
    {
        unsigned char ip_version : 4;
        unsigned char ip_header_length : 4;
        unsigned char ip_TOS;
        unsigned short ip_total_length;
        unsigned short ip_iden;
        unsigned char flag_x : 1;
        unsigned char flag_D : 1;
        unsigned char flag_M : 1;
        unsigned char offset_part_1 : 5;
        unsigned char offset_part_2;
        unsigned char TTL;
        unsigned char ip_protocol;
        unsigned short chk_sum;
        struct in_addr ip_src_add;
        struct in_addr ip_des_add;
        //20bytes
    };
    cs

     




    -Bit filed?

    각 구조의 크기를 보면 Version은 4bit, Header Length도 4bit의 크기를 가진다.

    이에 대한 정보를 최대한 효율적으로 저장하려면 1byte인 char형을 써야할 것이다.


    하지만, char형도 그리 효율적이지 못하다. 

    1byte = 8bit 이므로 나머지 4비트는 버려지게 되는 것이다.


    그래서 C/C++은 Bit filed라는 것을 사용한다.

    선언은 unsigned char a:1 : 뒤에 할당 bit수를 적어주는 식으로 한다.

    unsigned로 선언하는 이유는 부호비트까지 사용하기 위해서 unsigned로 선언한다.


    이렇게 데이터를 나눠서 사용하면, char형은 8bit int형은 16bit까지 세세하게 효율적으로 사용할 수 있다.




    - Tcp header 구조 (총 20bytes)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    struct tcp_header
    {
        unsigned short src_port;
        unsigned short des_port;
        unsigned long sqn_num;
        unsigned long ack_num;
        unsigned char offset : 4;
        unsigned char ns : 1;
        unsigned char reserve : 3;
        unsigned char flag_cwr : 1;
        unsigned char flag_ece : 1;
        unsigned char flag_urgent : 1;
        unsigned char flag_ack : 1;
        unsigned char flag_push : 1;
        unsigned char flag_reset : 1;
        unsigned char flag_syn : 1;
        unsigned char flag_fin : 1;
        unsigned short window;
        unsigned short chk_sum;
        unsigned short urgent_point;
        //20bytes
    };
    cs




    * CODE

    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
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    #define _WINSOCK_DEPRECATED_NO_WARNINGS 
     
    #include "pcap.h"
    #include <stdio.h>
    #include <winsock2.h>
    #include <string.h>
     
    #pragma comment (lib,"ws2_32.lib")
    #pragma comment (lib,"wpcap.lib")
     
    #define BUF_SIZE 100
    #define IP_HEADER_JMP 14
    #define TCP_HEADER_JMP 20
    #define DATA_JMP 20    
    #define SNAPLEN 65536
    struct ether_add
    {
        unsigned char mac_add[6];
    };
    struct ether_header
    {
        struct ether_add src_mac;
        struct ether_add des_mac;
        unsigned short eth_type;
        //14bytes
    };
     
    struct ip_header
    {
        unsigned char ip_version : 4;
        unsigned char ip_header_length : 4;
        unsigned char ip_TOS;
        unsigned short ip_total_length;
        unsigned short ip_iden;
        unsigned char flag_x : 1;
        unsigned char flag_D : 1;
        unsigned char flag_M : 1;
        unsigned char offset_part_1 : 5;
        unsigned char offset_part_2;
        unsigned char TTL;
        unsigned char ip_protocol;
        unsigned short chk_sum;
        struct in_addr ip_src_add;
        struct in_addr ip_des_add;
        //20bytes
    };
     
    struct tcp_header
    {
        unsigned short src_port;
        unsigned short des_port;
        unsigned long sqn_num;
        unsigned long ack_num;
        unsigned char offset : 4;
        unsigned char ns : 1;
        unsigned char reserve : 3;
        unsigned char flag_cwr : 1;
        unsigned char flag_ece : 1;
        unsigned char flag_urgent : 1;
        unsigned char flag_ack : 1;
        unsigned char flag_push : 1;
        unsigned char flag_reset : 1;
        unsigned char flag_syn : 1;
        unsigned char flag_fin : 1;
        unsigned short window;
        unsigned short chk_sum;
        unsigned short urgent_point;
        //20bytes
    };
     
    void print_ether_header(const unsigned char *pkt_data);
    void print_ip_header(const unsigned char *pkt_data);
    void print_tcp_header(const unsigned char *pkt_data);
    void print_data(const unsigned char *pkt_data);
     
    int main(int argc, char **argv)
    {
        pcap_if_t *alldevs = NULL;
        pcap_if_t *dev;
        pcap_t *use_dev;
        char errbuf[BUF_SIZE];
        char FILTER_RULE[BUF_SIZE]="tcp";
        struct bpf_program rule_struct;
        int i,dev_num,res;
        struct pcap_pkthdr *header;
        const unsigned char *pkt_data;
        
        //port설정 인자값이 있으면 port룰 설정
        //없으면, 모든 패킷 감청
        if (argv[1])
        {
            strcpy(FILTER_RULE, "port ");
            strcat(FILTER_RULE, argv[1]); // FILTER_RULE (port)설정
        } 
     
     
        if (pcap_findalldevs(&alldevs, errbuf) < 0)
        {
            printf("Device Find Error\n");
            return -1;
        }
        
        for (dev = alldevs, i = 0; dev != NULL; dev = dev->next)
            printf("%d번 Device : %s (%s)\n"++i, dev->name,dev->description);
        
        printf("사용할 디바이스 번호 입력 : ");
        scanf("%d"&dev_num);
     
        for (dev = alldevs, i = 0; i < dev_num-1;  dev = dev->next,i++);
     
        if ((use_dev = pcap_open_live(dev->name, SNAPLEN, 11000, errbuf)) == NULL)
        {
            printf("pcap_open ERROR!\n");
            pcap_freealldevs(alldevs);
            return -1;
        }
        printf("pcap_open 성공!\n");
        printf("FILTER_RULE : %s\n", FILTER_RULE);
        //////////                    pcap_open_success                ////////////
     
     
        if (pcap_compile(use_dev, &rule_struct, FILTER_RULE, 1NULL< 0)
        {
            printf("pcap_compile ERROR!\n");
            pcap_freealldevs(alldevs);
            return -1;
        }
     
        if (pcap_setfilter(use_dev, &rule_struct) < 0)
        {
            printf("pcap_setfilter ERROR!\n");
            pcap_freealldevs(alldevs);
            return -1;
        }
     
        pcap_freealldevs(alldevs); //캡처 네트워크를 제외한 네트워크 해제
        
        
        while ((res = pcap_next_ex(use_dev, &header, &pkt_data)) >= 0)
        {
            if (res == 0continue;
     
            print_ether_header(pkt_data);
            pkt_data += IP_HEADER_JMP;
            print_ip_header(pkt_data);
            pkt_data += TCP_HEADER_JMP;
            print_tcp_header(pkt_data);
        }
        
    }
     
     
     
    ///////////////////////////////////print_function///////////////////////////////////////
    void print_ether_header(const unsigned char *pkt_data)
    {
        struct ether_header *eh;
        eh = (struct ether_header *)pkt_data;
        unsigned short ether_type = ntohs(eh->eth_type);
        if (ether_type == 0x0800printf("===== IPv4 =====\n");
        printf("Src MAC : ");
        for (int i = 0; i <= 5; i++printf("%02x ", eh->src_mac.mac_add[i]);
        printf("\nDes MAC : ");
        for (int i = 0; i <= 5; i++)printf("%02x ", eh->des_mac.mac_add[i]);
        printf("\n");
    }
     
    void print_ip_header(const unsigned char *pkt_data)
    {
        struct ip_header *ih;
        ih = (struct ip_header *)pkt_data;
        if (ih->ip_protocol == 0x06)
        {
            printf("(TCP)");
            printf("Src IP : %s\n",inet_ntoa(ih->ip_src_add));
            printf("(TCP)");
            printf("Des IP : %s\n", inet_ntoa(ih->ip_des_add));
        }
        if (ih->ip_protocol == 0x17)
        {
            printf("(UDP)");
            printf("Src IP : %s\n", inet_ntoa(ih->ip_src_add));
            printf("(UDP)");
            printf("Des IP : %s\n", inet_ntoa(ih->ip_des_add));
        }
    }
    void print_tcp_header(const unsigned char *pkt_data)
    {
        struct tcp_header *th;
        th = (struct tcp_header *)pkt_data;
        
        printf("Src Port : %d\n", ntohs(th->src_port));
        printf("Des Port : %d\n", ntohs(th->des_port));
        printf("====================\n\n");
    }
    cs


    * 실행

    1:1 채팅 프로그램으로 통신하는 상황을 스니핑하는 모습이다.








    Server에서 4540번 포트를 열고 1:1 통신한 패킷들이다.

    MAC/IP/Port 정보와 평문으로 전송된 패킷들이 그대로 잡히는 모습을 확인할 수 있다.

    'Network > NetProg' 카테고리의 다른 글

    ARP Spoofing Tool ( + 자동화 , 코드 보완 )  (3) 2020.02.06
    [C / lpcap] ARP Spoofing  (1) 2017.12.14

    댓글

Designed by Tistory.