usrbin
컴퓨터 일기
usrbin
전체 방문자
오늘
어제

공지사항

  • whoami
  • 분류 전체보기 (127)
    • 깔짝할짝 (61)
    • 잡지식 (30)
    • Network (7)
      • Programming (3)
      • Study (4)
    • Mobile (13)
    • Reversing (5)
      • Win API (2)
      • 분석 (0)
    • Kernel (4)
      • linux (1)
      • Windows (3)
    • Programming (5)

블로그 메뉴

  • 홈
  • 방명록

인기 글

태그

  • suninatas
  • libpcap
  • xcz.kr
  • nethunter
  • pwntools
  • Scapy
  • Packet
  • pwnable.kr
  • System
  • Digital Forensics
  • Android
  • PWN
  • Hive Ransomware
  • BOF
  • Network Programming
  • Reversing
  • ftz
  • qt
  • HackCTF
  • network
  • sql injection
  • pcap
  • pcapng
  • forensics
  • Pwnable
  • HEVD
  • x64dbg
  • Follina
  • System Hacking
  • monitor mode

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
usrbin

컴퓨터 일기

[Network programming] pcap library를 사용한 패킷 정보 출력
Network/Programming

[Network programming] pcap library를 사용한 패킷 정보 출력

2020. 1. 23. 03:01

https://github.com/usrbin-sim/pcap_test

 

GitHub - usrbin-sim/pcap_test: pcap library test

pcap library test. Contribute to usrbin-sim/pcap_test development by creating an account on GitHub.

github.com

pcap을 이용한 네트워크 프로그래밍을 처음 시작할 때 짰던 코드인데, 다시 수정해서 공부할 겸 코드리뷰

 

프로그램 목적

>> 라이브 패킷 캡처를 이용하여, IPv4와 TCP 패킷에 대한 source, destination IP/MAC/Port, 그리고 데이터가 존재하는 경우 데이터까지 출력해준다.

 

packet.h - 패킷 구조체 및 출력용 함수

#pragma once
#include <stdint.h>
#include <stdio.h>

#pragma pack(push,1)
typedef struct {
    uint8_t dst_MAC[6];
    uint8_t src_MAC[6];
    uint16_t ether_type;
}Ether;
typedef struct {
    uint8_t v_l;
    uint8_t tos;
    uint16_t total_len;
    uint16_t id;
    uint16_t flag;
    uint8_t ttl;
    uint8_t protocol;
    uint16_t checksum;
    uint32_t src_ip;
    uint32_t dst_ip;
}IP;
typedef struct {
    uint16_t src_port;
    uint16_t dst_port;
    uint32_t seq;
    uint32_t ack;
    uint8_t offset_reserved;
    uint8_t flags;
    uint16_t window;
    uint16_t checksum;
    uint16_t urgent_ptr;
}TCP;
typedef struct {
    Ether eth;
    IP ip;
    TCP tcp;
}Packet;
#pragma pack(pop)

void usage() {
  printf("syntax: pcap_test <interface>\n");
  printf("sample: pcap_test wlan0\n");
}

void print_MAC(uint8_t *addr){
    printf(" >> %02X:%02X:%02X:%02X:%02X:%02X\n",
           addr[0],addr[1],addr[2],addr[3],
            addr[4],addr[5]);
}
void print_IP(uint32_t ip){
    printf(" >> %d.%d.%d.%d\n", ip&0xFF, (ip>>8)&0xFF, (ip>>16)&0xFF, (ip>>24)&0xFF);
}

Ethernet, IP, TCP 헤더 필드는 직접 구글링을 통해 몇바이트인지 확인을 하여 만들었다 각 헤더 필드에 대한 정리도 나중에 따로 정리해서 올려야겠다...

아무튼 Ether, IP, TCP 헤더를 각각 만들고, 이를 한번에 묶어주는 Packet 구조체를 만듬

#pragma pack(push, 1), #pragma pack(pop)을 사용한 이유는 패킷 필드들을 각 크기에 맞게 사용하기 위함이다. 안해주면 자동으로 큰거에 맞춰서 정렬이 되어서 이대로 패킷 포인터를 만들어 사용하면 잘못된 필드를 가리킬 수 있다

    Packet * packet = (Packet *)data;

    if(ntohs(packet->eth.ether_type) != 2048){ // If not IPv4
        continue;
    }

    uint8_t ip_header_len = (packet->ip.v_l & 0xF) * 4;
    uint8_t tcp_header_len = (packet->tcp.offset_reserved >> 4) * 4;

    uint16_t ip_len = ntohs(packet->ip.total_len);

    if(packet->ip.protocol != 6){ //if not TCP
        continue;  
    }

사용은 pacp_test.cpp의 main 함수 내에서 다음과 같이 사용했다. 라이브로 캡처한 패킷 데이터가 담겨있는 data 포인터를 Packet * 형으로 변환하면 쉽게 Ehter, IP, TCP에 접근할 수 있다.

따라서 두번째에 나오는 if문에서 처럼 packet->eth.ether_type 이런식으로 접근하여 사용할 수 있는 것

Ethernet이나 IP, TCP 필드의 경우에는 헤더를 정의 해 주었으므로 그냥 위처럼 packet 포인터를 통해 바로 접근할 수 있다. 하지만 만약 데이터가 존재하는 경우에는 tcp 헤더가 끝난 이후부터 데이터가 시작되기 때문에 각 헤더들의 길이를 계산해주어서 인덱스를 계산해주어야 한다.

//data
    if(ip_len-ip_header_len-tcp_header_len > 0){
        real_data = (unsigned char *)(packet + sizeof(Ether) + ip_header_len + tcp_header_len);
        printf("data >> \n");
        for(int i = 0; i < ip_len-ip_header_len-tcp_header_len; i++){
            printf("%02X ", real_data[i]);
            if(i % 16 == 0){
                printf("\n");
            }
        }printf("\n");
    }

데이터를 출력하는 부분. 더 위에 코드를 보면 ip 패킷 전체 길이와 ip 헤더 길이, tcp 헤더 길이를 구해준 것을 확인할 수 있다. ip 패킷 전체 길이에서 각 헤더 길이를 뺀 값이 0보다 크다면 tcp 헤더 뒤에 데이터가 더 붙어있다는 뜻이므로 이를 확인하여 0보다 크면 데이터를 출력해주도록 함

packet 포인터가 가리키는 데이터에서 ehter 헤더, ip 헤더, tcp 헤더를 제외한 그 이후의 패킷 부터가 데이터이기 때문에 Ether의 크기와 각 헤더의 사이즈를 더하여 인덱스를 뒤로 밀고 해당 위치부터 출력을 하면 TCP 데이터가 출력이 된다

프로그램을 돌린 화면

 

처음 이 코드를 짤때는 Packet 구조체를 만들 생각을 못해서 그냥 일일히 헤더 길이 더해서, 배열 미루고, 값 새로 저장하고 하면서 되게 복잡하게 코드를 짰었는데, 구조체를 깔끔하게 만들고 나니까 이처럼 간단하게 패킷의 다양한 헤더에 접근할 수 있게 되었다

저작자표시 비영리 변경금지 (새창열림)

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

[Scapy] IP scan  (0) 2020.01.26
[Network programming] Wireshark staitistics 따라하기  (0) 2020.01.24
    usrbin
    usrbin
    컴퓨터 할거야

    티스토리툴바