프로그래밍/패킷 캡쳐

2.1 - 패킷을 잡아보자 !

hackability 2009. 5. 30. 02:14
이번글에서는 패킷을 잡을 수 있는 환경을 만들고 간단히 패킷을 잡아보려고 합니다.

패킷을 잡기 전에 몇 가지 준비를 하셔야 합니다.

1. WinPcap 설치. 네이버에서 WinpCap이라고 검색하시면 쉽게 다운받고 설치 하실 수 있습니다.

2. Include 폴더와 Lib 폴더를 프로젝트 폴더(3번에서 만들 프로젝트)안에 넣습니다.


















3. Visual Studio 2005 에서 콘솔로 프로젝트를 만드신뒤, 빈 main.cpp를 하나 만듭니다.
프로젝트 -> 속성 -> 구성 속성 -> C/C++ -> 일반 -> 추가 포함 디렉토리에 Include 폴더를 추가 합니다.




















위와 마찬가지로 프로젝트 -> 속성 -> 구성 속성 -> 링커 -> 일반 -> 추가 라이브러리 디렉토리에 Lib 폴더를 추가 합니다


이제 기본적인 세팅은 끝낫습니다.
소스는 다음과 같습니다.

/*

Modify: 2009 - 05 - 30

Programmed by centy

Blog: http://centy.tistory.com/

E-Mail: ktb88@naver.com

*/

//-- 해더 
#include <winsock2.h>
#include <windows.h>
#include <stdio.h>
#include "pcap.h"

#pragma comment(lib,"ws2_32.lib")
#pragma comment(lib,"wpcap.lib")

//-- 구조체,클래스

// IP 데이터들을 다루기 위한 클래스
class IP_ADDRESS
{
public: // 멤버 변수
UCHAR m_byte1;
UCHAR m_byte2;
UCHAR m_byte3;
UCHAR m_byte4;

public: // 멤버 함수
IP_ADDRESS() {}
~IP_ADDRESS() {}
};

// IP Protocol을 다루기 위한 구조체
typedef struct _IP_HEADER
{
UCHAR ver_ihl; // Version (4 bits) + Internet header length (4 bits)
UCHAR tos; // Type of service 
WORD tlen; // Total length 
WORD identification; // Identification
WORD flags_fo; // Flags (3 bits) + Fragment offset (13 bits)
UCHAR ttl; // Time to live
UCHAR proto; // Protocol
WORD crc; // Header checksum
IP_ADDRESS saddr; // Source address
IP_ADDRESS daddr; // Destination address
UINT op_pad; // Option + Padding
}IP_HEADER,*PIP_HEADER;

//-- 함수
// initpcap() - 캡처 장치를 초기화 시킨다.
BOOL initpcap();

//-- 전역 변수
pcap_t *adhandle;
struct pcap_pkthdr *header;
UCHAR *pkt;

//-- 프로그램 시작
int main()
{
if( initpcap() == FALSE ) return 1;

int res;
// 패킷을 캡처 한다
while((res = pcap_next_ex(adhandle, &header, (const UCHAR**)&pkt)) >= 0)
{
// 패킷 크기가 0 이면 아무런 행동을 취하지 않는다.
if( res == 0 ) continue;

// 패킷에 ip header를 추출한다. (pkt + ethernet size)
PIP_HEADER ih = (PIP_HEADER) ((UCHAR *)pkt + 14);

// 프로토콜을 검색
switch( ih->proto ) 
{
case IPPROTO_TCP: // TCP 라면
printf("TCP 패킷 획득 \n");
break;
case IPPROTO_UDP: // UDP 라면
printf("UDP 패킷 획득 \n");
break;
default:
printf("다른 형식 패킷 획득 [%d] \n",ih->proto);
break;
}
}
return 0;
}


BOOL initpcap()
{
pcap_if_t *alldevs;
char errbuf[256];

bpf_u_int32 NetMask;
struct bpf_program fcode;
pcap_if_t *d;

// PCAP 초기화
printf("!] PCAP을 초기화 중입니다... \n");

// 로컬에서 장치 목록을 검사합니다.
if (pcap_findalldevs(&alldevs, errbuf) == -1)
{
printf("?] pcap_findalldevs 에서 문제 발생 \n");
return FALSE;
}

// 선택된 어탭터로 점프 합니다. 보통 마지막이 사용하는 네트워크 카드가 되지만
// 무선인터넷이나 네트워크 카드를 2개 이상 사용한다면 사용자가 선택 할 수 있도록
// 수정되어야 합니다.
for(d=alldevs ; d->next!=NULL ; d=d->next) ;

// 네트워크 카드 출력
printf("!] 네트워크 카드 명 [ %s ] \n",d->description);

// 장치 열기
if ( (adhandle = pcap_open_live(d->name, // 장치 명
65536, // 패킷당 버퍼 사이즈
0, // promiscuous mode
0, // read timeout
errbuf // 에러 버퍼
) ) == NULL)
{
printf("?] [ %s ] 는 winpcap에서 지원하지 않습니다.\n",d->name);
pcap_freealldevs(alldevs); // 장치 목록 해제
return FALSE;
}

pcap_freealldevs(alldevs);

NetMask=0xffffff;

// 필터명으로 컴파일
if(pcap_compile(adhandle, &fcode, "tcp or udp", 1, NetMask) < 0)
{
printf("?] pcap_compile에서 문제 발생 \n");
return FALSE;
}

// 필터 set
if(pcap_setfilter(adhandle, &fcode)<0)
{
printf("?] pcap_setfilter에서 문제 발생 \n");
return FALSE;
}

printf("!] PCAP 초기화 완료... \n");
return TRUE;
}

실행 결과는 다음과 같습니다.



성공입니다! UDP 패킷과 TCP 패킷 그리고 128 Protocol을 사용하는 패킷도 잡히는군요. 
그런데 이렇게 보니 뭔가 멋이 없네요.... 다음 글에서 더욱 멋잇게 표현해보도록 하겠습니다.  :)