Chào mừng đến với Diễn đàn lập trình - Cộng đồng lập trình.
Kết quả 1 đến 7 của 7
  1. #1

    Kiến thức cơ bản về Winpcap

    Tut viết từ năm ngoái, nên có nhiều sai xót, văn vẻ lủng củng, mọi người thông cảm và giúp mình bổ sung.


    Giới thiệu Winpcap

    WinPcap là gì ?

    WinPcap là thư viện mã nguồn mở được sử dụng để bắt các gói dữ liệu và phân tích mạng cho nền tảng Win32.


    • Thu thập những gói dữ liuệ thô, 1 là ngay trên chính máy đang chạy truyền dữ liệu đi và 1 là sự trao đổi bởi những máy khác trên môi trường chia sẻ.

    • Lọc gói dữ liệu theo những luật của người dùng khi chúng được truyền tới ứng dụng.

    • Tuyền những gói dữ liệu thô tới mạng.

    • Thu thập thông tin thống kê lưu lượng mạng.


    Những khả năng này co được thông qua trình điều khiển thiết bị đã được cài đặt bên trong phần Network của nhân Win32 cùng với 2 DLL.


    Những loại chương trình sử dụng WinPcap

    Giao diện lập trình WinPcap được sử dụng bởi nhiều tiện ích mạng như phân tích, xử lý sự cố, bảo mật , theo dõi. Cụ thể :


    • Trình phân tích mạng và giao thức.
    • Giám sát mạng.
    • Theo dõi băng thông.
    • Traffic generator.
    • user-level bridges and routers.
    • Hệ thống phát hiện xâm nhập mạng NIDS
    • Network scanner.
    • Công cụ bảo mật.

    Cài đặt và sử dụng WinPcap

    Tạo ứng dụng sử dụng thư viện wpcap.dll trong VC++

    Include pcap.h.
    Include thư mục chứa các thành phần cần Inlcude thêm :



    Inlcude thư mục chứa các thư viện cần thêm :



    Nếu chương trình sử dụng những hàm Win32 trong Winpcap , thì include WPCAP trong khai báo tiền xử lý :



    Nếu chương trình sử dụng khả năng remote capture của Winpcap, thì include HAVE_REMOTE trong khai báo tiền xử lý tương tự như ảnh trên. Không include trực tiếp remote-ext.h.
    Liên kết tới file wpcap.lib trong \lib nếu ứng dụng dành tro x86 hoặc \lib\x64 nếu ứng dụng dành cho x64 ; và file ws2_32.lib.


  2. #2
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    Liệt kê các device

    Thường thì việc đầu tiền của các ứng dụng sử dụng Winpcap là liệt kê các network adapter. Cả libpcap và Winpcap đều cung cấp hàm pcap_findalldevs_ex cho mục đích này , nó trả lại 1 danh sách liên kết của cấu trúc pcap_if .
    Ví dụ :

    File Stdafx.h :


    Mã:
    #pragma once #include "targetver.h" #include <stdio.h>#include <tchar.h>#include <pcap.h>#include <WinSock2.h>
    File TestWinpcap.cpp :


    Mã:
    // TestWinpcap.cpp : Defines the entry point for the console application.// #include "stdafx.h" #define  IPTOSBUFFERS 12 WCHAR * Address2String(SOCKADDR * Sockaddr){    WCHAR wcAddr[256];    DWORD dwSize = sizeof(wcAddr);    if (WSAAddressToString(Sockaddr,sizeof(SOCKADDR_STORAGE /*Sử dụng cho cả IPv6 và IPv4*/),NULL,wcAddr,&dwSize) == 0)    {        return wcAddr;    }    return L"";} int _tmain(int argc, _TCHAR* argv[]){    WSADATA wsaData;    // Khởi động Winsock2    if (WSAStartup(MAKEWORD(2,2),&wsaData) != 0)    {        printf("WSAStartup(0 loi, ma %d",WSAGetLastError());        return -1;    }     pcap_if_t *LinkedListDevices;   // danh sách liên kết của cấu trúc     // pcap_addr_t chứa thông tin network adapters    char ErrorBuffer[PCAP_ERRBUF_SIZE + 1]; //  Buffer nhận nguyên nhân lỗi    // Tìm các network adapters     if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL , &LinkedListDevices , ErrorBuffer) != 0 )    {        ErrorBuffer[PCAP_ERRBUF_SIZE + 1] = NULL;        printf("pcap_findalldevs_ex() loi, ma %d",ErrorBuffer);        goto Exit;    }     pcap_if_t *Temp;    int index = 0;    pcap_addr_t *Addr;    for (Temp = LinkedListDevices ; Temp != NULL ; Temp = Temp->next)    {        // in tên và mô tả của network adapters        printf("%i
    Name : %s
    Description : %s
    ",++index,Temp->name,Temp->description);        // có phải địa chỉ loopback hay không ?         printf("\tLoopback : %s
    
    ",Temp->flags & PCAP_IF_LOOPBACK ? "Yes" : "No");         for (Addr = Temp->addresses ; Addr != NULL ; Addr = Addr->next)        {             if (Addr->addr)             {                 printf("\tAddress: %S
    ",Address2String(Addr->addr));             }             if (Addr->broadaddr)             {                 printf("\tbroadaddr :%S
    ",Address2String(Addr->broadaddr));             }             if (Addr->dstaddr)             {                 printf("\tdstaddr : %S
    ",Address2String(Addr->dstaddr));             }             if (Addr->netmask)             {                 printf("\tnetmask : %S
    
    ",Address2String(Addr->netmask));             }         }    }      Exit:    // Ngừng sử dụng Winsock 2    if (WSACleanup() != 0)    {        printf("WSACleanup(0 loi, ma %d",WSAGetLastError());        return -1;    }    // Giải phóng bộ nhớ của danh sách liên kết     pcap_freealldevs(LinkedListDevices);     system("pause");    return 0;}
    Output :




    Mở 1 adapter và capture packet

    Để mở 1 capture device ta sử dụng hàm pcap_open().
    Hàm pcap_open() có 1 vài tham số đáng chú ý :
    • snaplen : Chỉ định phần packet được capture. Trên 1 vài OS ( như xBSD và Win32 ) , trình điều khiển packet có thể được cấu hình để capture chỉ phần đầu của packet, điều này làm giảm lượng dữ liệu capture được. Do đó , để tăng hiệu quả , chúng ta sử dụng giá trị 65536, giá trị này lớn hơn cả giá trị lớn nhất của MTU. Theo cách này , chúng ta đảm bảo rằng ứng dụng luôn capture được toàn bộ packet.
    • flags : Cờ quan trọng nhất là cờ chỉ định adapter sẽ trong chế độ không phân biệt ( promiscuous mode ). Thường thì adapter chỉ capture các packet đi tới nó, các packet trao đổi qua lại giữa các host sẽ bị bỏ qua. Vì vậy, khi adapter trong chế độ không phân biệt, nó sẽ capture mọi packet cho dù packet đó đi tới nó hoặc không. Điều này có nghĩa , trên môi trường được chia sẻ, ( như non-switched Ethernet) , Winpcap có thể capture các packet của các host khác. Chế độ không phân biệt là mặc định cho hầu hết các ứng dụng capture, nên chúng ta sử dụng chế độ này trong ví dụ.
    • to_ms : Thời gian timeout của hàm đọc( ms ). Hàm đọc trên 1 adapter ( ví dụ , hàm pcap_dispatch() hoặc pcap_next_ex()) sẽ luôn return sau khoảng thời gian timeout , ngay cả khi không capture được packet nào. Tham số to_ms cũng khai báo khoảng thời gian giữa các báo cáo thống kê nếu adapter trong chế độ thống kê ( statistical mode ). to_ms = 0 nghĩa là không có thời gian timeout, hàm đọc sẽ không return nếu không capture được packet nào. to_ms = -1 nghĩa là hàm đọc sẽ return ngay lập tức.
    Một khi adapter đã được mở , để capture sử dụng hàm pcap_dispatch() hoặc pcap_loop(). Hai hàm này khá giống nhau, hàm pcap_dispatch() return ( mặc dù không đảm bảo ) khi thời gian timeout hết hạn, trong khi hàm pcap_loop() không return cho tới khi capture được cnt ( tham số số lượng ) packet.
    Cả 2 hàm đều có 1 tham số CALLBACK , packet_handle , trỏ tới 1 hàm sẽ nhận các packet. Hàm này được kích hoạt bởi libpcap khi có 1 packet đến từ mạng và nhận 1 trạng thái chung ( generic status ) ( tương ứng với tham số user của hàm pcap_loop() hoặc pcap_dispatch() ) , 1 header với 1 vài thông tin trên packet như timestamp , độ dài và dữ liệu thực sự của packet bao gồm tất cả các header giao thức.
    Chú ý rằng frame CRC thường không xuất hiện, vì nó bị xóa bởi network adapter sau sự xác nhận frame. Cũng chú ý rằng, hầu hết các adapter bỏ packet với CRC sai, do đó Winpcap thường không thể capture đc chúng.
    Ví dụ sau , triết xuất timestamp và độ dài của mỗi packet để in lên màn hình.
    Có 1 nhược điểm khi sử dụng hàm pcap_loop() , là hàm handler được gọi bởi pạket capture driver, nên ta không thể điều khiển trực tiếp chúng. Có 1 cách tiếp cận khác là sử dụng hàm pcap_next_ex() , sẽ có ở chương sau.
    Ví dụ :

    File Stdafx.h :


    Mã:
    #pragma once #include "targetver.h" #include <stdio.h>#include <tchar.h>#include <pcap.h>#include <WinSock2.h>

    Mã:
    File TestWinpcap.cpp :// TestWinpcap.cpp : Defines the entry point for the console application.// #include "stdafx.h"int index = 0;WCHAR * Address2String(SOCKADDR * Sockaddr){    WCHAR wcAddr[256];    DWORD dwSize = sizeof(wcAddr);    if (WSAAddressToString(Sockaddr,sizeof(SOCKADDR_STORAGE /*Sử dụng cho cả IPv6 và IPv4*/),NULL,wcAddr,&dwSize) == 0)    {        return wcAddr;    }    return L"";} void PrintAdapters(pcap_if_t * LinkedListDevices){    pcap_if_t *Temp;    index = 0;    pcap_addr_t *Addr;    for (Temp = LinkedListDevices ; Temp != NULL ; Temp = Temp->next)    {        // in tên và mô tả của network adapters        printf("%i
    Name : %s
    Description : %s
    ",++index,Temp->name,Temp->description);        // có phải địa chỉ loopback hay không ?         printf("\tLoopback : %s
    
    ",Temp->flags & PCAP_IF_LOOPBACK ? "Yes" : "No");         for (Addr = Temp->addresses ; Addr != NULL ; Addr = Addr->next)        {            if (Addr->addr)            {                printf("\tAddress: %S
    ",Address2String(Addr->addr));            }            if (Addr->broadaddr)            {                printf("\tbroadaddr :%S
    ",Address2String(Addr->broadaddr));            }            if (Addr->dstaddr)            {                printf("\tdstaddr : %S
    ",Address2String(Addr->dstaddr));            }            if (Addr->netmask)            {                printf("\tnetmask : %S
    
    ",Address2String(Addr->netmask));            }         }    }}  void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data){    struct tm ltime;    char timestr[16];    time_t local_tv_sec;     /*     * unused variables     */    (VOID)(param);    (VOID)(pkt_data);     /* convert the timestamp to readable format */    local_tv_sec = header->ts.tv_sec;    localtime_s(&ltime, &local_tv_sec);    strftime( timestr, sizeof timestr, "%H:%M:%S", &ltime);        printf("%s,%.6d len:%d
    ", timestr, header->ts.tv_usec, header->len);    }   int _tmain(int argc, _TCHAR* argv[]){    WSADATA wsaData;    // Khởi động Winsock2    if (WSAStartup(MAKEWORD(2,2),&wsaData) != 0)    {        printf("WSAStartup(0 loi, ma %d",WSAGetLastError());        return -1;    }     pcap_if_t *LinkedListDevices;   // danh sách liên kết của cấu trúc     // pcap_addr_t chứa thông tin network adapters    char ErrorBuffer[PCAP_ERRBUF_SIZE + 1]; //  Buffer nhận nguyên nhân lỗi    // Tìm các network adapters     if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL , &LinkedListDevices , ErrorBuffer) != 0 )    {        ErrorBuffer[PCAP_ERRBUF_SIZE + 1] = NULL;        printf("pcap_findalldevs_ex() loi, ma %s",ErrorBuffer);        goto Exit;    }     // Gọi hàm hiển thị các adapter        PrintAdapters(LinkedListDevices);     // Chọn adapter để capture    printf("Chon adapter tu 1 - %i",index);    int SelectedIndex;    scanf_s("%d",&SelectedIndex);    if (SelectedIndex < 1 || SelectedIndex > index)    {        printf("So hieu adapter da chon khong co
    ");        goto Exit;    }    pcap_if_t * Temp;    // Chuyển con trỏ trỏ tới adapter đã chọn    for (Temp = LinkedListDevices , index = 0 ; index < SelectedIndex -1 ; index ++ , Temp = Temp->next);    // gọi pcap_open() để mở adapter    // Tham số 1 : Tên adapter kiểu char*.    // Tham số 2 : Độ dài packet có thể capture , chọn 65536 để đảm bảo capture đc toàn bộ packet.    // Tham sô 3 : Cờ áp đặt chế độ cho adapter để capture.    //              PCAP_OPENFLAG_PROMISCUOUS : Chế độ không phân biệt , sẽ capture mọi packet    //              mà adadpter trao đổi giữa network hoặc host khác.    // Tham số 4 : Thời gian đọc timeout.    // Tham số 5 : Buffer nhận lỗi nếu có.    pcap_t *Handle = pcap_open(Temp->name,65536,PCAP_OPENFLAG_PROMISCUOUS,1000,NULL,ErrorBuffer);    if (Handle == NULL)    {        ErrorBuffer[PCAP_ERRBUF_SIZE + 1] = NULL;        printf("pcap_open() loi , ma %s
    ",ErrorBuffer);        goto Exit;    }     printf("Dang capture tren adapter : %s
    ",Temp->description);     // Bắt đầu capture packet trên adapter đã chọn.    // Tham số 1 là handle trả lại từ hàm pcap_open().    // Tham số 2 là số lượng packet cần capture, sau khi capture đc lượng     // packet này, hàm sẽ return    // Tham số 3 là con trỏ tới hàm CALLBACK nhận packet đến.    //     pcap_loop(Handle, 5, packet_handler, NULL);     Exit:    // Ngừng sử dụng Winsock 2    if (WSACleanup() != 0)    {        printf("WSACleanup(0 loi, ma %d",WSAGetLastError());        return -1;    }    // Giải phóng bộ nhớ của danh sách liên kết     pcap_freealldevs(LinkedListDevices);     system("pause");    return 0;}
    Output :


  3. #3
    Ngày tham gia
    Sep 2015
    Đang ở
    Hà Nội
    Bài viết
    0
    Capture packet không sử dụng hàm CALLBACK

    Ở chương trước, cơ chế capture packet dựa trên hàm pcap_loop() có thể là lựa chọn tốt cho vài trường hợp. Nhưng điều khiển 1 hàm CALLBACK sẽ khiến chương trình phức tạp hơn và đôi khi không thực tế , đặc biệt trong trường hợp ứng dụng multithread hoặc C++ class.
    Trong trường hợp này, pcap_next_ex() nhận packet 1 cách trực tiếp - sử dụng pcap_next_ex() có lợi thế là nó sẽ nhận packet chỉ khi ta muốn.
    Tham số của hàm cũng tương tự như hàm CALLBACK, nó nhận 1 tham số là miêu tả của adapter và 2 con trỏ được khởi tạo và return ( 1 là trỏ tới cấu trúc pcap_pkthdr , 1 là trỏ tới buffer nhận data của packet ).
    Tại sao không sử dụng pcap_next() ? Vì hàm này có 1 vài nhược điểm. Đầu tiền là nó không hiệu quả, nó ẩn phương pháp CALLBACK, nhưng vẫn dựa trên hàm pcap_dispatch(). Thứ 2 là nó không thể phát hiện EOF, vậy nếu nó ko hữu dụng khi capture các packet từ 1 file.
    Lưu ý, hàm pcap_next_ex() trả lại các giá trị khác nhau khi thành công, hay khi hết timeout , hay khi lỗi và khi có điều kiện EOF.

    Ví dụ :

    File Stdafx.h :


    Mã:
    #pragma once #include "targetver.h" #include <stdio.h>#include <tchar.h>#include <pcap.h>#include <WinSock2.h>
    File TestWinpcap.cpp :


    Mã:
    // TestWinpcap.cpp : Defines the entry point for the console application.// #include "stdafx.h"int index = 0;WCHAR * Address2String(SOCKADDR * Sockaddr){    WCHAR wcAddr[256];    DWORD dwSize = sizeof(wcAddr);    if (WSAAddressToString(Sockaddr,sizeof(SOCKADDR_STORAGE /*Sử dụng cho cả IPv6 và IPv4*/),NULL,wcAddr,&dwSize) == 0)    {        return wcAddr;    }    return L"";} void PrintAdapters(pcap_if_t * LinkedListDevices){    pcap_if_t *Temp;    index = 0;    pcap_addr_t *Addr;    for (Temp = LinkedListDevices ; Temp != NULL ; Temp = Temp->next)    {        // in tên và mô tả của network adapters        printf("%i
    Name : %s
    Description : %s
    ",++index,Temp->name,Temp->description);        // có phải địa chỉ loopback hay không ?         printf("\tLoopback : %s
    
    ",Temp->flags & PCAP_IF_LOOPBACK ? "Yes" : "No");         for (Addr = Temp->addresses ; Addr != NULL ; Addr = Addr->next)        {            if (Addr->addr)            {                printf("\tAddress: %S
    ",Address2String(Addr->addr));            }            if (Addr->broadaddr)            {                printf("\tbroadaddr :%S
    ",Address2String(Addr->broadaddr));            }            if (Addr->dstaddr)            {                printf("\tdstaddr : %S
    ",Address2String(Addr->dstaddr));            }            if (Addr->netmask)            {                printf("\tnetmask : %S
    
    ",Address2String(Addr->netmask));            }         }    }}   int _tmain(int argc, _TCHAR* argv[]){    WSADATA wsaData;    // Khởi động Winsock2    if (WSAStartup(MAKEWORD(2,2),&wsaData) != 0)    {        printf("WSAStartup(0 loi, ma %d",WSAGetLastError());        return -1;    }     pcap_if_t *LinkedListDevices;   // danh sách liên kết của cấu trúc     // pcap_addr_t chứa thông tin network adapters    char ErrorBuffer[PCAP_ERRBUF_SIZE + 1]; //  Buffer nhận nguyên nhân lỗi    // Tìm các network adapters     if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL , &LinkedListDevices , ErrorBuffer) != 0 )    {        ErrorBuffer[PCAP_ERRBUF_SIZE + 1] = NULL;        printf("pcap_findalldevs_ex() loi, ma %s",ErrorBuffer);        goto Exit;    }     // Gọi hàm hiển thị các adapter        PrintAdapters(LinkedListDevices);     // Chọn adapter để capture    printf("Chon adapter tu 1 - %i",index);    int SelectedIndex;    scanf_s("%d",&SelectedIndex);    if (SelectedIndex < 1 || SelectedIndex > index)    {        printf("So hieu adapter da chon khong co
    ");        goto Exit;    }    pcap_if_t * Temp;    // Chuyển con trỏ trỏ tới adapter đã chọn    for (Temp = LinkedListDevices , index = 0 ; index < SelectedIndex -1 ; index ++ , Temp = Temp->next);    // gọi pcap_open() để mở adapter    // Tham số 1 : Tên adapter kiểu char*.    // Tham số 2 : Độ dài packet có thể capture , chọn 65536 để đảm bảo capture đc toàn bộ packet.    // Tham sô 3 : Cờ áp đặt chế độ cho adapter để capture.    //              PCAP_OPENFLAG_PROMISCUOUS : Chế độ không phân biệt , sẽ capture mọi packet    //              mà adadpter trao đổi giữa network hoặc host khác.    // Tham số 4 : Thời gian đọc timeout.    // Tham số 5 : Buffer nhận lỗi nếu có.    pcap_t *Handle = pcap_open(Temp->name,65536,PCAP_OPENFLAG_PROMISCUOUS,1000,NULL,ErrorBuffer);    if (Handle == NULL)    {        ErrorBuffer[PCAP_ERRBUF_SIZE + 1] = NULL;        printf("pcap_open() loi , ma %s
    ",ErrorBuffer);        goto Exit;    }     printf("Dang capture tren adapter : %s
    ",Temp->description);     int iRt;    pcap_pkthdr * pPacketHeader;    const u_char *ucPacketData;    time_t local_tv_sec;W    tm ltime;    char timestr[16];    while (iRt = pcap_next_ex(Handle,&pPacketHeader,&ucPacketData) >= 0)    {        if(iRt == 0)            continue; // Hết thời gian timeout                // Convert timestamp sang string        local_tv_sec = pPacketHeader->ts.tv_sec;        localtime_s(&ltime, &local_tv_sec);        strftime( timestr, sizeof timestr, "%H:%M:%S", &ltime);         printf("%s,%.6d len:%d
    ", timestr, pPacketHeader->ts.tv_usec, pPacketHeader->len);            // Nếu lỗi        if (iRt == -1)        printf("pcap_next_ex() loi, %s
    ",pcap_geterr(Handle));    }     Exit:    // Ngừng sử dụng Winsock 2    if (WSACleanup() != 0)    {        printf("WSACleanup(0 loi, ma %d",WSAGetLastError());        return -1;    }    // Giải phóng bộ nhớ của danh sách liên kết     pcap_freealldevs(LinkedListDevices);     system("pause");    return 0;}
    Output :




    Lọc traffic

    Một tính năng mạnh mẽ mà Winpcap ( libpcap cũng vậy ) cung cấp là bộ lọc traffic.
    Các hàm được sử dụng để filter traffic là pcap_compile() và pcap_setfilter().

    Ví dụ :

    File Stdafx.h :

    Mã:
    // stdafx.h : include file for standard system include files,// or project specific include files that are used frequently, but// are changed infrequently// #pragma once #include "targetver.h" #include <stdio.h>#include <tchar.h>#include <pcap.h>#include <WinSock2.h> // TODO: reference additional headers your program requires here
    File TestWinpcap.cpp :


    Mã:
    // TestWinpcap.cpp : Defines the entry point for the console application.// #include "stdafx.h" // Toàn cụcint index = 0; /* 4 bytes IP address -  cấu trúc mô tả địa chỉ Ipv4 ở dạng 4 bytes */typedef struct ip_address{    u_char byte1;    u_char byte2;    u_char byte3;    u_char byte4;}ip_address; /* IPv4 header */typedef struct ip_header{    u_char  ver_ihl;        // Version (4 bits) + Internet header length (4 bits)    u_char  tos;            // Type of service     u_short tlen;           // Total length     u_short identification; // Identification    u_short flags_fo;       // Flags (3 bits) + Fragment offset (13 bits)    u_char  ttl;            // Time to live    u_char  proto;          // Protocol    u_short crc;            // Header checksum    ip_address  saddr;      // Source address    ip_address  daddr;      // Destination address    u_int   op_pad;         // Option + Padding}ip_header; /* UDP header*/typedef struct udp_header{    u_short sport;          // Source port    u_short dport;          // Destination port    u_short len;            // Datagram length    u_short crc;            // Checksum}udp_header;     WCHAR * Address2String(SOCKADDR * Sockaddr){    WCHAR wcAddr[256];    DWORD dwSize = sizeof(wcAddr);    if (WSAAddressToString(Sockaddr,sizeof(SOCKADDR_STORAGE /*Sử dụng cho cả IPv6 và IPv4*/),NULL,wcAddr,&dwSize) == 0)    {        return wcAddr;    }    return L"";} void PrintAdapters(pcap_if_t * LinkedListDevices){    pcap_if_t *Temp;    index = 0;    pcap_addr_t *Addr;    for (Temp = LinkedListDevices ; Temp != NULL ; Temp = Temp->next)    {        // in tên và mô tả của network adapters        printf("%i
    Name : %s
    Description : %s
    ",++index,Temp->name,Temp->description);        // có phải địa chỉ loopback hay không ?         printf("\tLoopback : %s
    
    ",Temp->flags & PCAP_IF_LOOPBACK ? "Yes" : "No");         for (Addr = Temp->addresses ; Addr != NULL ; Addr = Addr->next)        {            if (Addr->addr)            {                printf("\tAddress: %S
    ",Address2String(Addr->addr));            }            if (Addr->broadaddr)            {                printf("\tbroadaddr :%S
    ",Address2String(Addr->broadaddr));            }            if (Addr->dstaddr)            {                printf("\tdstaddr : %S
    ",Address2String(Addr->dstaddr));            }            if (Addr->netmask)            {                printf("\tnetmask : %S
    
    ",Address2String(Addr->netmask));            }         }    }}   void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data){    struct tm ltime;    char timestr[16];    ip_header *ih;    udp_header *uh;    u_int ip_len;    u_short sport,dport;    time_t local_tv_sec;     /*     * Unused variable     */    (VOID)(param);     /* convert the timestamp to readable format */    local_tv_sec = header->ts.tv_sec;    localtime_s(&ltime, &local_tv_sec);    strftime( timestr, sizeof timestr, "%H:%M:%S", &ltime);     /* print timestamp and length of the packet */    printf("%s.%.6d len:%d ", timestr, header->ts.tv_usec, header->len);     /* retireve the position of the ip header */    ih = (ip_header *) (pkt_data +        14); //length of ethernet header     /* retireve the position of the udp header */    ip_len = (ih->ver_ihl & 0xf) * 4;    uh = (udp_header *) ((u_char*)ih + ip_len);     /* convert from network byte order to host byte order */    sport = ntohs( uh->sport );    dport = ntohs( uh->dport );     /* print ip addresses and udp ports */    printf("%d.%d.%d.%d.%d -> %d.%d.%d.%d.%d
    ",        ih->saddr.byte1,        ih->saddr.byte2,        ih->saddr.byte3,        ih->saddr.byte4,        sport,        ih->daddr.byte1,        ih->daddr.byte2,        ih->daddr.byte3,        ih->daddr.byte4,        dport);    }   int _tmain(int argc, _TCHAR* argv[]){    WSADATA wsaData;    // Khởi động Winsock2    if (WSAStartup(MAKEWORD(2,2),&wsaData) != 0)    {        printf("WSAStartup(0 loi, ma %d",WSAGetLastError());        return -1;    }     pcap_if_t *LinkedListDevices;   // danh sách liên kết của cấu trúc     // pcap_addr_t chứa thông tin network adapters    char ErrorBuffer[PCAP_ERRBUF_SIZE + 1]; //  Buffer nhận nguyên nhân lỗi    // Tìm các network adapters     if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL , &LinkedListDevices , ErrorBuffer) != 0 )    {        ErrorBuffer[PCAP_ERRBUF_SIZE + 1] = NULL;        printf("pcap_findalldevs_ex() loi, ma %s",ErrorBuffer);        goto Exit;    }     // Gọi hàm hiển thị các adapter        PrintAdapters(LinkedListDevices);     // Chọn adapter để capture    printf("Chon adapter tu 1 - %i : ",index);    int SelectedIndex;    scanf_s("%d",&SelectedIndex);    if (SelectedIndex < 1 || SelectedIndex > index)    {        printf("So hieu adapter da chon khong co
    ");        goto Exit;    }    pcap_if_t * Temp;    // Chuyển con trỏ trỏ tới adapter đã chọn    for (Temp = LinkedListDevices , index = 0 ; index < SelectedIndex -1 ; index ++ , Temp = Temp->next);    // gọi pcap_open() để mở adapter    // Tham số 1 : Tên adapter kiểu char*.    // Tham số 2 : Độ dài packet có thể capture , chọn 65536 để đảm bảo capture đc toàn bộ packet.    // Tham sô 3 : Cờ áp đặt chế độ cho adapter để capture.    //              PCAP_OPENFLAG_PROMISCUOUS : Chế độ không phân biệt , sẽ capture mọi packet    //              mà adadpter trao đổi giữa network hoặc host khác.    // Tham số 4 : Thời gian đọc timeout.    // Tham số 5 : Buffer nhận lỗi nếu có.    pcap_t *Handle = pcap_open(Temp->name,65536,PCAP_OPENFLAG_PROMISCUOUS,1000,NULL,ErrorBuffer);    if (Handle == NULL)    {        ErrorBuffer[PCAP_ERRBUF_SIZE + 1] = NULL;        printf("pcap_open() loi , ma %s
    ",ErrorBuffer);        goto Exit;    }    // Ta kiểm tra Mac layer để chắc chắn rằng là mạng Ethernet có độ dài    // Mac header là 14 bytes    // IP Header có vị trí ngay sau Mac header.     // Để có được UDP header có 1 chút phức tạp, vì Ip header không có độ    // dài cố định , nên ta lấy độ dài của Internet header , là 1 trường    // trong IP header , để xác định vị trí của UDP header.    //     if (pcap_datalink(Handle) != DLT_EN10MB)    {        printf("Chuong trinh chi ho tro capture packet 
    tren mang Ethernet.
    ");        goto Exit;    }     u_int netmask;     if(Temp->addresses->next != NULL)        /* Retrieve the mask of the first address of the interface */        netmask=((struct sockaddr_in *)(Temp->addresses->next->netmask))->sin_addr.S_un.S_addr;    else        /* If the interface is without addresses we suppose to be in a C class network */        netmask=0xffffff;      char packet_filter[] = "ip and udp"; // Chỉ capture các packte có giao    // thức là UDP và IPv4.    struct bpf_program fcode;     if (pcap_compile(Handle,&fcode,packet_filter,TRUE,netmask) < 0)    {        printf("pcap_compile() loi
    ");        goto Exit;    }     if (pcap_setfilter(Handle,&fcode) < 0)    {        printf("pcap_setfilter() loi. 
    ");        goto Exit;    }     // Ngừng sử dụng Winsock 2    if (WSACleanup() != 0)    {        printf("WSACleanup(0 loi, ma %d",WSAGetLastError());        return -1;    }    // Giải phóng bộ nhớ của danh sách liên kết         printf("Dang capture tren adapter : %s
    ",Temp->description);    pcap_freealldevs(LinkedListDevices);     // Bắt đầu capture packet trên adapter đã chọn.    // Tham số 1 là handle trả lại từ hàm pcap_open().    // Tham số 2 là số lượng packet cần capture, sau khi capture đc lượng     // packet này, hàm sẽ return    // Tham số 3 là con trỏ tới hàm CALLBACK nhận packet đến.    //          pcap_loop(Handle,0,packet_handler,NULL);           // Phương pháp capture packet không thông qua hàm CALLBACK    /*int iRt;    pcap_pkthdr * pPacketHeader;    const u_char *ucPacketData;    time_t local_tv_sec;    tm ltime;    char timestr[16];    while (iRt = pcap_next_ex(Handle,&pPacketHeader,&ucPacketData) >= 0)    {        if(iRt == 0)            continue; // Hết thời gian timeout                // Convert timestamp sang string        local_tv_sec = pPacketHeader->ts.tv_sec;        localtime_s(&ltime, &local_tv_sec);        strftime( timestr, sizeof timestr, "%H:%M:%S", &ltime);         printf("%s,%.6d len:%d
    ", timestr, pPacketHeader->ts.tv_usec, pPacketHeader->len);            // Nếu lỗi        if (iRt == -1)        printf("pcap_next_ex() loi, %s
    ",pcap_geterr(Handle));    }*/     Exit:    // Ngừng sử dụng Winsock 2    if (WSACleanup() != 0)    {        printf("WSACleanup(0 loi, ma %d",WSAGetLastError());        return -1;    }    // Giải phóng bộ nhớ của danh sách liên kết     pcap_freealldevs(LinkedListDevices);     system("pause");    return 0;}
    Output :



    Mỗi dòng là 1 packet.

  4. #4
    Xử lý dump file

    Hiện tại , tính năng này đang bị vô hiệu hóa vì gặp phải 1 vài vấn đề với kernel buffer mới.
    Ví dụ :

    File Stdafx.h :


    Mã:
    // stdafx.h : include file for standard system include files,// or project specific include files that are used frequently, but// are changed infrequently// #pragma once #include "targetver.h" #include <stdio.h>#include <tchar.h>#include <pcap.h>#include <WinSock2.h>   // TODO: reference additional headers your program requires here
    File TestWinpcap.cpp :


    Mã:
    // TestWinpcap.cpp : Defines the entry point for the console application.// #include "stdafx.h" // Toàn cụcint index = 0; /* 4 bytes IP address -  cấu trúc mô tả địa chỉ Ipv4 ở dạng 4 bytes */typedef struct ip_address{    u_char byte1;    u_char byte2;    u_char byte3;    u_char byte4;}ip_address; /* IPv4 header */typedef struct ip_header{    u_char  ver_ihl;        // Version (4 bits) + Internet header length (4 bits)    u_char  tos;            // Type of service     u_short tlen;           // Total length     u_short identification; // Identification    u_short flags_fo;       // Flags (3 bits) + Fragment offset (13 bits)    u_char  ttl;            // Time to live    u_char  proto;          // Protocol    u_short crc;            // Header checksum    ip_address  saddr;      // Source address    ip_address  daddr;      // Destination address    u_int   op_pad;         // Option + Padding}ip_header; /* UDP header*/typedef struct udp_header{    u_short sport;          // Source port    u_short dport;          // Destination port    u_short len;            // Datagram length    u_short crc;            // Checksum}udp_header;     WCHAR * Address2String(SOCKADDR * Sockaddr){    WCHAR wcAddr[256];    DWORD dwSize = sizeof(wcAddr);    if (WSAAddressToString(Sockaddr,sizeof(SOCKADDR_STORAGE /*Sử dụng cho cả IPv6 và IPv4*/),NULL,wcAddr,&dwSize) == 0)    {        return wcAddr;    }    return L"";} void PrintAdapters(pcap_if_t * LinkedListDevices){    pcap_if_t *Temp;    index = 0;    pcap_addr_t *Addr;    for (Temp = LinkedListDevices ; Temp != NULL ; Temp = Temp->next)    {        // in tên và mô tả của network adapters        printf("%i
    Name : %s
    Description : %s
    ",++index,Temp->name,Temp->description);        // có phải địa chỉ loopback hay không ?         printf("\tLoopback : %s
    
    ",Temp->flags & PCAP_IF_LOOPBACK ? "Yes" : "No");         for (Addr = Temp->addresses ; Addr != NULL ; Addr = Addr->next)        {            if (Addr->addr)            {                printf("\tAddress: %S
    ",Address2String(Addr->addr));            }            if (Addr->broadaddr)            {                printf("\tbroadaddr :%S
    ",Address2String(Addr->broadaddr));            }            if (Addr->dstaddr)            {                printf("\tdstaddr : %S
    ",Address2String(Addr->dstaddr));            }            if (Addr->netmask)            {                printf("\tnetmask : %S
    
    ",Address2String(Addr->netmask));            }         }    }}   void packet_handler(u_char *DumpFile, const struct pcap_pkthdr *header, const u_char *pkt_data){/*    struct tm ltime;    char timestr[16];    ip_header *ih;    udp_header *uh;    u_int ip_len;    u_short sport,dport;    time_t local_tv_sec;     / *     * Unused variable     * /    (VOID)(param);     / * convert the timestamp to readable format * /    local_tv_sec = header->ts.tv_sec;    localtime_s(&ltime, &local_tv_sec);    strftime( timestr, sizeof timestr, "%H:%M:%S", &ltime);     / * print timestamp and length of the packet * /    printf("%s.%.6d len:%d ", timestr, header->ts.tv_usec, header->len);     / * retireve the position of the ip header * /    ih = (ip_header *) (pkt_data +        14); //length of ethernet header     / * retireve the position of the udp header * /    ip_len = (ih->ver_ihl & 0xf) * 4;    uh = (udp_header *) ((u_char*)ih + ip_len);     / * convert from network byte order to host byte order * /    sport = ntohs( uh->sport );    dport = ntohs( uh->dport );     / * print ip addresses and udp ports * /    printf("%d.%d.%d.%d.%d -> %d.%d.%d.%d.%d
    ",        ih->saddr.byte1,        ih->saddr.byte2,        ih->saddr.byte3,        ih->saddr.byte4,        sport,        ih->daddr.byte1,        ih->daddr.byte2,        ih->daddr.byte3,        ih->daddr.byte4,        dport);*/     // Lưu dữ liệu packet vào dump file    // Các tham số của hàm pcap_dump() tương ứng với các tham số của hàm     // CALLBACK    //      pcap_dump(DumpFile,header,pkt_data); }   int _tmain(int argc, _TCHAR* argv[]){    WSADATA wsaData;    // Khởi động Winsock2    if (WSAStartup(MAKEWORD(2,2),&wsaData) != 0)    {        printf("WSAStartup(0 loi, ma %d",WSAGetLastError());        return -1;    }     pcap_if_t *LinkedListDevices;   // danh sách liên kết của cấu trúc     // pcap_addr_t chứa thông tin network adapters    char ErrorBuffer[PCAP_ERRBUF_SIZE + 1]; //  Buffer nhận nguyên nhân lỗi    // Tìm các network adapters     if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL , &LinkedListDevices , ErrorBuffer) != 0 )    {        ErrorBuffer[PCAP_ERRBUF_SIZE + 1] = NULL;        printf("pcap_findalldevs_ex() loi, ma %s",ErrorBuffer);        goto Exit;    }     // Gọi hàm hiển thị các adapter        PrintAdapters(LinkedListDevices);     // Chọn adapter để capture    printf("Chon adapter tu 1 - %i : ",index);    int SelectedIndex;    scanf_s("%d",&SelectedIndex);    if (SelectedIndex < 1 || SelectedIndex > index)    {        printf("So hieu adapter da chon khong co
    ");        goto Exit;    }    pcap_if_t * Temp;    // Chuyển con trỏ trỏ tới adapter đã chọn    for (Temp = LinkedListDevices , index = 0 ; index < SelectedIndex -1 ; index ++ , Temp = Temp->next);    // gọi pcap_open() để mở adapter    // Tham số 1 : Tên adapter kiểu char*.    // Tham số 2 : Độ dài packet có thể capture , chọn 65536 để đảm bảo capture đc toàn bộ packet.    // Tham sô 3 : Cờ áp đặt chế độ cho adapter để capture.    //              PCAP_OPENFLAG_PROMISCUOUS : Chế độ không phân biệt , sẽ capture mọi packet    //              mà adadpter trao đổi giữa network hoặc host khác.    // Tham số 4 : Thời gian đọc timeout.    // Tham số 5 : Buffer nhận lỗi nếu có.    pcap_t *Handle = pcap_open(Temp->name,65536,PCAP_OPENFLAG_PROMISCUOUS,1000,NULL,ErrorBuffer);    if (Handle == NULL)    {        ErrorBuffer[PCAP_ERRBUF_SIZE + 1] = NULL;        printf("pcap_open() loi , ma %s
    ",ErrorBuffer);        goto Exit;    }     // Liên kết dump file với handle của adapter đã mở.    pcap_dumper_t *DumpFile = pcap_dump_open(Handle,"DumpFile.txt");      // Ta kiểm tra Mac layer để chắc chắn rằng là mạng Ethernet có độ dài    // Mac header là 14 bytes    // IP Header có vị trí ngay sau Mac header.     // Để có được UDP header có 1 chút phức tạp, vì Ip header không có độ    // dài cố định , nên ta lấy độ dài của Internet header , là 1 trường    // trong IP header , để xác định vị trí của UDP header.    //     if (pcap_datalink(Handle) != DLT_EN10MB)    {        printf("Chuong trinh chi ho tro capture packet 
    tren mang Ethernet.
    ");        goto Exit;    }     u_int netmask;     if(Temp->addresses/*->next*/ != NULL)        /* Retrieve the mask of the first address of the interface */        netmask=((struct sockaddr_in *)(Temp->addresses/*->next*/->netmask))->sin_addr.S_un.S_addr;    else        /* If the interface is without addresses we suppose to be in a C class network */        netmask=0xffffff;      char packet_filter[] = "ip and udp"; // Chỉ capture các packte có giao    // thức là UDP và IPv4.    struct bpf_program fcode;     if (pcap_compile(Handle,&fcode,packet_filter,TRUE,netmask) < 0)    {        printf("pcap_compile() loi
    ");        goto Exit;    }     if (pcap_setfilter(Handle,&fcode) < 0)    {        printf("pcap_setfilter() loi. 
    ");        goto Exit;    }     // Ngừng sử dụng Winsock 2    if (WSACleanup() != 0)    {        printf("WSACleanup(0 loi, ma %d",WSAGetLastError());        return -1;    }    // Giải phóng bộ nhớ của danh sách liên kết         printf("Dang capture tren adapter : %s
    ",Temp->description);    pcap_freealldevs(LinkedListDevices);     // Bắt đầu capture packet trên adapter đã chọn.    // Tham số 1 là handle trả lại từ hàm pcap_open().    // Tham số 2 là số lượng packet cần capture, sau khi capture đc lượng     // packet này, hàm sẽ return    // Tham số 3 là con trỏ tới hàm CALLBACK nhận packet đến.    // Tham số 4 là handle của dump file đã liên kết với adapter.            pcap_loop(Handle,0,packet_handler,(u_char*)DumpFile);          // Phương pháp capture packet không thông qua hàm CALLBACK    /*int iRt;    pcap_pkthdr * pPacketHeader;    const u_char *ucPacketData;    time_t local_tv_sec;    tm ltime;    char timestr[16];    while (iRt = pcap_next_ex(Handle,&pPacketHeader,&ucPacketData) >= 0)    {        if(iRt == 0)            continue; // Hết thời gian timeout                // Convert timestamp sang string        local_tv_sec = pPacketHeader->ts.tv_sec;        localtime_s(&ltime, &local_tv_sec);        strftime( timestr, sizeof timestr, "%H:%M:%S", &ltime);         printf("%s,%.6d len:%d
    ", timestr, pPacketHeader->ts.tv_usec, pPacketHeader->len);            // Nếu lỗi        if (iRt == -1)        printf("pcap_next_ex() loi, %s
    ",pcap_geterr(Handle));    }*/     Exit:    // Ngừng sử dụng Winsock 2    if (WSACleanup() != 0)    {        printf("WSACleanup(0 loi, ma %d",WSAGetLastError());        return -1;    }    // Giải phóng bộ nhớ của danh sách liên kết     pcap_freealldevs(LinkedListDevices);     system("pause");    return 0;}
    Output :



  5. #5
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    tks a nhiều lắm, nhưng mà có thể cho em hỏi 1 vấn đề là với Winpcap mình có thể chặn 1 Packet đi ko ?

  6. #6
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    Trích dẫn Gửi bởi raymondle
    tks a nhiều lắm, nhưng mà có thể cho em hỏi 1 vấn đề là với Winpcap mình có thể chặn 1 Packet đi ko ?
    Theo như kiến thức của mình thì Winpcap có khả năng bắt, lọc, lưu và gửi 1 package, việc chặn 1 package thì mình chưa rõ. Tài liệu này mình dịch rất kém, hồi đó mới bắt đầu thói quen viết tài liệu.

    Bạn có thể tham khảo thêm tại :

    Mã:
    http://www.winpcap.org/docs/default.htm

  7. #7
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    ^
    Demo một chương trình ghi nhật kí Ymsg đi bác. :x Cái này tiện lắm đấy. [IMG]images/smilies/18.gif[/IMG]

 

 

Quyền viết bài

  • Bạn Không thể gửi Chủ đề mới
  • Bạn Không thể Gửi trả lời
  • Bạn Không thể Gửi file đính kèm
  • Bạn Không thể Sửa bài viết của mình
  •