WinDivert+VS2015——安装、学习、示例

背景

导师布置一个主动测量的小任务:

  1. 在windows是实现主动修改某特定进程发出的IP数据包的IPID字段。

这个任务,说简单不简单,说复杂不复杂。主要是解决两个问题:

  • 如何确定特定进程的数据包?简单起见能确定到传输层就行。
  • 如何修改特定的数据包?

关键在于如何拦截ip层的数据包,并修改它。因为修改是对流的“主动”行为,winpcap类似的东西是做不来的。而且因为需要修改的是IP层的东西,因此常规的钩子程序也不好处理,因为钩子一般是去hook系统的socket函数,hook这些函数 只能修改应用层的内容。目前已有的技术手段有使用WFP框架的,或者类似的NIDS框架的。但是这个东西开发起来不是很顺手呀。

后面,得知有windivert 这个神器!!!!它是基于WFP开发的,但是提供很好使的API !它可以支持对IP数据包的capture和修改,以及发送
2021.6.23修改: 最新版本的windivert已经支持按照processID过滤数据包。

windivert的官网:https://reqrypt.org/windivert-doc.html
看看它的特点吧:

  • capture network packets
  • filter/drop network packets
  • sniff network packets
  • (re)inject network packets
  • modify network packets

还是很棒的呀!

windivert 快速学习

0.vs2013安装windivert

步骤:

  1. 下载windivert的二进制版本 https://reqrypt.org/download/WinDivert-1.4.3-A.zip ,并解压。
  2. 新建vs项目,设置项目属性,在项目的VC++ Directories里面,在包含目录添加windivert的include目录。在库目录添加windivert的x86_64目录。
    在这里插入图片描述
    在这里插入图片描述
  3. 在链接器——输入 ——添加新的依赖,增加WinDivert.lib
    在这里插入图片描述
  4. 测试一波。
    测试代码见文章末尾。

1. 几个重要的 api

  • WinDivertOpen
HANDLE WinDivertOpen(
    __in const char *filter,
    __in WINDIVERT_LAYER layer,
    __in INT16 priority,
    __in UINT64 flags
);

打开一个windivert对象,返回一个对象指针。打开的过程中,需要制定 过滤规则,过滤层,过滤器的优先级,以及windivert对象的工作模式。

过滤规则的编写:参见https://reqrypt.org/windivert-doc.html 第7部分

过滤层参数说明:

LayerDescription
WINDIVERT_LAYER_NETWORK = 0The network layer. This is the default. 网络层
WINDIVERT_LAYER_NETWORK_FORWARDThe network layer (forwarded packets).转发层

优先级的说明:其实这里说明的就是指明过滤规则的优先级。值越大,优先级越大。 对于一个数据包,如果它同时匹配多个Windivert对象的规则,那么,它依次被这些对象按照优先级从高到低的次序匹配, 直到遇到匹配的规则。
详细见文档解释:Different WinDivert handles can be assigned different priorities by the priority parameter. Packets are diverted to higher priority handles before lower priority handles. Packets injected by a handle are then diverted to the next priority handle, and so on, provided the packet matches the handle’s filter. A packet is only diverted once per priority level, so handles should not share priority levels unless they use mutually exclusive filters. Otherwise it is not defined which handle will receive the packet first. Higher priority values represent higher priorities, with WINDIVERT_PRIORITY_HIGHEST being the highest priority, 0 the middle (and a good default) priority, and WINDIVERT_PRIORITY_LOWEST the lowest priority.

过滤FLAG :该参数指明Windivert对象到底是用于监听、丢包、还是修改包模式。

FlagDescription
WINDIVERT_FLAG_SNIFFWinDivert进入监听模式,只是被动监听,其功能等同于Winpcap
WINDIVERT_FLAG_DROPWinDivert单纯地把满足过滤条件的包丢弃,此模式下不能读取包内容
WINDIVERT_FLAG_DEBUGWinDivert把满足过滤的条件的包扣下来,等待被修改然后重新注入
  • WinDivertRecv
     BOOL WinDivertRecv(
        __in HANDLE handle,
        __out PVOID pPacket,
        __in UINT packetLen,
        __out_opt PWINDIVERT_ADDRESS pAddr,
        __out_opt UINT *recvLen
    );

接收特定WinDivert对象的捕获的包的函数。
handle: WinDivertOpen的返回值
pPacket : 用于存储包的buffer,缓冲区,这个是用户提供的。
packetLen: 缓冲区的大小;如果包的实际长度大于此值,则截取packetLen个字节到pPacket。
pAddr :包性质说明结构。该结构体,指明目前抓取到的包的性质。说明如下:

typedef struct
{
    INT64  Timestamp;
    UINT32 IfIdx;
    UINT32 SubIfIdx;
    UINT8  Direction:1;
    UINT8  Loopback:1;
    UINT8  Impostor:1;
    UINT8  PseudoIPChecksum:1;
    UINT8  PseudoTCPChecksum:1;
    UINT8  PseudoUDPChecksum:1;
} WINDIVERT_ADDRESS, *PWINDIVERT_ADDRESS;

字段说明:
Timestamp: WinDivert捕获到该包的时间戳
IfIdx: 该包所在的网卡序号
SubIfIdx: 网卡子序号
Direction: 包的方向,主要有入包和出包之分。

含义
WINDIVERT_DIRECTION_OUTBOUNDwith value 0 for outbound packets.
WINDIVERT_DIRECTION_INBOUNDwith value 1 for inbound packets.

Loopback: 是否是回环包。Set to 1 for loopback packets, 0 otherwise
Impostor: 是否是已经修改的包。Set to 1 for impostor packets, 0 otherwise. 注意,如果是修改后的包,这个值会被值为1。这个值主要是为了防止出现同一个包先被WinDivert捕获到,然后WinDivertSend后,又被捕获到。

PseudoIPChecksum: Set to 1 for packets with a pseudo IPv4 checksum, 0 otherwise.
PseudoTCPChecksum: Set to 1 for packets with a pseudo TCP checksum, 0 otherwise.
PseudoTCPChecksum: Set to 1 for packets with a pseudo UDP checksum, 0 otherwise.

recvlen:实际拷贝到pPacket缓冲区的字节数。可能为0.

!!!注意:WinDivertRecv() should not be used on any WinDivert handle created with the WINDIVERT_FLAG_DROP set. !!!

  • WinDivertSend
 BOOL WinDivertSend(
    __in HANDLE handle,
    __in PVOID pPacket,
    __in UINT packetLen,
    __in PWINDIVERT_ADDRESS pAddr,
    __out_opt UINT *sendLen
);

handle: WinDivertOpen()返回值.
pPacket: 待发包的内容.
packetLen: pPacket的总长度.
pAddr: 待发包的性质 WINDIVERT_ADDRESS.
sendLen: The total number of bytes injected. Can be NULL if this information is not required.

注意:发包之前 ,一定要让包有正确的校验值。!!!

  • WinDivertClose 这个没啥好说的
BOOL WinDivertClose(
    __in HANDLE handle
);

2.一些辅助api

主要是一些包的解析、校验和的计算api.

  • WinDivertHelperParsePacket 头部解析api
BOOL WinDivertHelperParsePacket(
   __in PVOID pPacket,
   __in UINT packetLen,
   __out_opt PWINDIVERT_IPHDR *ppIpHdr,
   __out_opt PWINDIVERT_IPV6HDR *ppIpv6Hdr,
   __out_opt PWINDIVERT_ICMPHDR *ppIcmpHdr,
   __out_opt PWINDIVERT_ICMPV6HDR *ppIcmpv6Hdr,
   __out_opt PWINDIVERT_TCPHDR *ppTcpHdr,
   __out_opt PWINDIVERT_UDPHDR *ppUdpHdr,
   __out_opt PVOID *ppData,
   __out_opt UINT *pDataLen
);
  • WinDivertHelperParseIPv4Address ip地址转换api ,点分十进制转INT。
 BOOL WinDivertHelperParseIPv4Address(
    __in const char *addrStr,
    __out_opt UINT32 *pAddr
);
  • WinDivertHelperCalcChecksums 计算校验值
 UINT WinDivertHelperCalcChecksums(
    __inout PVOID pPacket,
    __in UINT packetLen,
    __in_opt PWINDIVERT_ADDRESS pAddr,
    __in UINT64 flags
);

!!!!注意!这个函数会直接在pPacket缓冲区中计算各个校验值。返回值是表明计算了多少个校验值。!!!

3. 基本流程

Windivert的基本流程贼好使,就三大步。

  • 1.打开一个windivert对象,设置好过滤规则。
  • 2.编写一个循环:抓包——>修改包——>计算校验和——>发送注入后的包
  • 3.循环结束后,关闭windivert对象。
    HANDLE handle;          // WinDivert handle
    WINDIVERT_ADDRESS addr; // Packet address
    char packet[MAXBUF];    // Packet buffer
    UINT packetLen;

    handle = WinDivertOpen("...", 0, 0, 0);   // Open some filter
    if (handle == INVALID_HANDLE_VALUE)
    {
        // Handle error
        exit(1);
    }

    // Main capture-modify-inject loop:
    while (TRUE)
    {
        if (!WinDivertRecv(handle, packet, sizeof(packet), &addr, &packetLen))
        {
            // Handle recv error
            continue;
        }

        // Modify packet.

        WinDivertHelperCalcChecksums(packet, packetLen, &addr, 0);
        if (!WinDivertSend(handle, packet, packetLen, &addr, NULL))
        {
            // Handle send error
            continue;
        }
    }
    WinDivertClose(handle);

示例

#include <winsock2.h>
#include <windows.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>

#include "windivert.h"

#define MAXBUF          0xFFFF
#define PROXY_PORT      34010
#define ALT_PORT        43010
#define MAX_LINE        65

/*
 * Proxy server configuration.
 */
typedef struct
{
    UINT16 proxy_port;
    UINT16 alt_port;
} PROXY_CONFIG, *PPROXY_CONFIG;

typedef struct
{
    SOCKET s;
    UINT16 alt_port;
    struct in_addr dest;
} PROXY_CONNECTION_CONFIG, *PPROXY_CONNECTION_CONFIG;

typedef struct
{
    BOOL inbound;
    SOCKET s;
    SOCKET t;
} PROXY_TRANSFER_CONFIG, *PPROXY_TRANSFER_CONFIG;

/*
 * Lock to sync output.
 */
static HANDLE lock;

/*
 * Prototypes.
 */
static DWORD proxy(LPVOID arg);
static DWORD proxy_connection_handler(LPVOID arg);
static DWORD proxy_transfer_handler(LPVOID arg);

/*
 * Error handling.
 */
static void message(const char *msg, ...)
{
    va_list args;
    va_start(args, msg);
    WaitForSingleObject(lock, INFINITE);
    vfprintf(stderr, msg, args);
    putc('\n', stderr);
    ReleaseMutex(lock);
    va_end(args);
}
#define error(msg, ...)                         \
    do {                                        \
        message("error: " msg, ## __VA_ARGS__); \
        exit(EXIT_FAILURE);                     \
    } while (FALSE)
#define warning(msg, ...)                       \
    message("warning: " msg, ## __VA_ARGS__)

/*
 * Cleanup completed I/O requests.
 */
static void cleanup(HANDLE ioport, OVERLAPPED *ignore)
{
    OVERLAPPED *overlapped;
    DWORD iolen;
    ULONG_PTR iokey = 0;

    while (GetQueuedCompletionStatus(ioport, &iolen, &iokey, &overlapped, 0))
    {
        if (overlapped != ignore)
        {
            free(overlapped);
        }
    }
}

/*
 * Entry.
 */
int __cdecl main(int argc, char **argv)
{
    HANDLE handle, thread;
    UINT16 port, proxy_port, alt_port;
    int r;
    char filter[256];
    INT16 priority = 123;       // Arbitrary.
    PPROXY_CONFIG config;
    unsigned char packet[MAXBUF];
    UINT packet_len;
    WINDIVERT_ADDRESS addr;
    PWINDIVERT_IPHDR ip_header;
    PWINDIVERT_TCPHDR tcp_header;
    OVERLAPPED *poverlapped;
    OVERLAPPED overlapped;
    HANDLE ioport, event;
    DWORD len;

    // Init.
    if (argc != 2)
    {
        fprintf(stderr, "usage: %s dest-port\n", argv[0]);
        exit(EXIT_FAILURE);
    }
    port = (UINT16)atoi(argv[1]);
    if (port < 0 || port > 0xFFFF)
    {
        fprintf(stderr, "error: invalid port number (%d)\n", port);
        exit(EXIT_FAILURE);
    }
    proxy_port = (port == PROXY_PORT? PROXY_PORT+1: PROXY_PORT);
    alt_port = (port == ALT_PORT? ALT_PORT+1: ALT_PORT);
    lock = CreateMutex(NULL, FALSE, NULL);
    if (lock == NULL)
    {
        fprintf(stderr, "error: failed to create mutex (%d)\n",
            GetLastError());
        exit(EXIT_FAILURE);
    }
    ioport = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
    if (ioport == NULL)
    {
        error("failed to create I/O completion port (%d)", GetLastError());
    }
    event = CreateEvent(NULL, FALSE, FALSE, NULL);
    if (event == NULL)
    {
        error("failed to create event (%d)", GetLastError());
    }

    // Divert all traffic to/from `port', `proxy_port' and `alt_port'.
    r = snprintf(filter, sizeof(filter),
        "tcp and "
        "(tcp.DstPort == %d or tcp.DstPort == %d or tcp.DstPort == %d or "
         "tcp.SrcPort == %d or tcp.SrcPort == %d or tcp.SrcPort == %d)",
        port, proxy_port, alt_port, port, proxy_port, alt_port);
    if (r < 0 || r >= sizeof(filter))
    {
        error("failed to create filter string");
    }
    handle = WinDivertOpen(filter, WINDIVERT_LAYER_NETWORK, priority, 0);
    if (handle == INVALID_HANDLE_VALUE)
    {
        error("failed to open the WinDivert device (%d)", GetLastError());
    }
    if (CreateIoCompletionPort(handle, ioport, 0, 0) == NULL)
    {
        error("failed to associate I/O completion port (%d)", GetLastError());
    }

    // Spawn proxy thread,
    config = (PPROXY_CONFIG)malloc(sizeof(PROXY_CONFIG));
    if (config == NULL)
    {
        error("failed to allocate memory");
    }
    config->proxy_port = proxy_port;
    config->alt_port = alt_port;
    thread = CreateThread(NULL, 1, (LPTHREAD_START_ROUTINE)proxy,
        (LPVOID)config, 0, NULL);
    if (thread == NULL)
    {
        error("failed to create thread (%d)", GetLastError());
    }
    CloseHandle(thread);

    // Main loop:
    while (TRUE)
    {
        memset(&overlapped, 0, sizeof(overlapped));
        ResetEvent(event);
        overlapped.hEvent = event;
        if (!WinDivertRecvEx(handle, packet, sizeof(packet), 0, &addr,
                &packet_len, &overlapped))
        {
            if (GetLastError() != ERROR_IO_PENDING)
            {
read_failed:
                warning("failed to read packet (%d)", GetLastError());
                continue;
            }

            // Timeout = 1s
            while (WaitForSingleObject(event, 1000) == WAIT_TIMEOUT)
            {
                cleanup(ioport, &overlapped);
            }
            if (!GetOverlappedResult(handle, &overlapped, &len, FALSE))
            {
                goto read_failed;
            }
            packet_len = len;
        }
        cleanup(ioport, &overlapped);

        if (!WinDivertHelperParsePacket(packet, packet_len, &ip_header, NULL,
                NULL, NULL, &tcp_header, NULL, NULL, NULL))
        {
            warning("failed to parse packet (%d)", GetLastError());
            continue;
        }

        switch (addr.Direction)
        {
            case WINDIVERT_DIRECTION_OUTBOUND:
                if (tcp_header->DstPort == htons(port))
                {
                    // Reflect: PORT ---> PROXY
                    UINT32 dst_addr = ip_header->DstAddr;
                    tcp_header->DstPort = htons(proxy_port);
                    ip_header->DstAddr = ip_header->SrcAddr;
                    ip_header->SrcAddr = dst_addr;
                    addr.Direction = WINDIVERT_DIRECTION_INBOUND;
                }
                else if (tcp_header->SrcPort == htons(proxy_port))
                {
                    // Reflect: PROXY ---> PORT
                    UINT32 dst_addr = ip_header->DstAddr;
                    tcp_header->SrcPort = htons(port);
                    ip_header->DstAddr = ip_header->SrcAddr;
                    ip_header->SrcAddr = dst_addr;
                    addr.Direction = WINDIVERT_DIRECTION_INBOUND;
                }
                else if (tcp_header->DstPort == htons(alt_port))
                {
                    // Redirect: ALT ---> PORT
                    tcp_header->DstPort = htons(port);
                }
                break;
            
            case WINDIVERT_DIRECTION_INBOUND:
                if (tcp_header->SrcPort == htons(port))
                {
                    // Redirect: PORT ---> ALT
                    tcp_header->SrcPort = htons(alt_port);
                }
                break;
        }

        WinDivertHelperCalcChecksums(packet, packet_len, &addr, 0);
        poverlapped = (OVERLAPPED *)malloc(sizeof(OVERLAPPED));
        if (poverlapped == NULL)
        {
            error("failed to allocate memory");
        }
        memset(poverlapped, 0, sizeof(OVERLAPPED));
        if (WinDivertSendEx(handle, packet, packet_len, 0, &addr, NULL,
                poverlapped))
        {
            continue;
        }
        if (GetLastError() != ERROR_IO_PENDING)
        {
            warning("failed to send packet (%d)", GetLastError());
            continue;
        }
    }

    return 0;
}

/*
 * Proxy server thread.
 */
static DWORD proxy(LPVOID arg)
{
    PPROXY_CONFIG config = (PPROXY_CONFIG)arg;
    UINT16 proxy_port = config->proxy_port;
    UINT16 alt_port = config->alt_port;
    int on = 1;
    WSADATA wsa_data;
    WORD wsa_version = MAKEWORD(2, 2);
    struct sockaddr_in addr;
    SOCKET s;
    HANDLE thread;
    
    free(config);

    if (WSAStartup(wsa_version, &wsa_data) != 0)
    {
        error("failed to start WSA (%d)", GetLastError());
    }
    
    s = socket(AF_INET, SOCK_STREAM, 0);
    if (s == INVALID_SOCKET)
    {
        error("failed to create socket (%d)", WSAGetLastError());
    }

    if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(int))
            == SOCKET_ERROR)
    {
        error("failed to re-use address (%d)", GetLastError());
    }

    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(proxy_port);
    if (bind(s, (SOCKADDR *)&addr, sizeof(addr)) == SOCKET_ERROR)
    {
        error("failed to bind socket (%d)", WSAGetLastError());
    }

    if (listen(s, 16) == SOCKET_ERROR)
    {
        error("failed to listen socket (%d)", WSAGetLastError());
    }

    while (TRUE)
    {
        // Wait for a new connection.
        PPROXY_CONNECTION_CONFIG config;
        int size = sizeof(addr);
        SOCKET t = accept(s, (SOCKADDR *)&addr, &size);
        if (t == INVALID_SOCKET)
        {
            warning("failed to accept socket (%d)", WSAGetLastError());
            continue;
        }

        // Spawn proxy connection handler thread.
        config = (PPROXY_CONNECTION_CONFIG)
            malloc(sizeof(PROXY_CONNECTION_CONFIG));
        if (config == NULL)
        {
            error("failed to allocate memory");
        }
        config->s = t;
        config->alt_port = alt_port;
        config->dest = addr.sin_addr;
        thread = CreateThread(NULL, 1,
            (LPTHREAD_START_ROUTINE)proxy_connection_handler,
            (LPVOID)config, 0, NULL);
        if (thread == NULL)
        {
            warning("failed to create thread (%d)", GetLastError());
            closesocket(t);
            free(config);
            continue;
        }
        CloseHandle(thread);
    }
}

/*
 * Proxy connection handler thread.
 */
static DWORD proxy_connection_handler(LPVOID arg)
{
    PPROXY_TRANSFER_CONFIG config1, config2;
    HANDLE thread;
    PPROXY_CONNECTION_CONFIG config = (PPROXY_CONNECTION_CONFIG)arg;
    SOCKET s = config->s, t;
    UINT16 alt_port = config->alt_port;
    struct in_addr dest = config->dest;
    struct sockaddr_in addr;
    
    free(config);

    t = socket(AF_INET, SOCK_STREAM, 0);
    if (t == INVALID_SOCKET)
    {
        warning("failed to create socket (%d)", WSAGetLastError());
        closesocket(s);
        return 0;
    }

    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(alt_port);
    addr.sin_addr = dest;
    if (connect(t, (SOCKADDR *)&addr, sizeof(addr)) == SOCKET_ERROR)
    {
        warning("failed to connect socket (%d)", WSAGetLastError());
        closesocket(s);
        closesocket(t);
        return 0;
    }

    config1 = (PPROXY_TRANSFER_CONFIG)malloc(sizeof(PROXY_TRANSFER_CONFIG));
    config2 = (PPROXY_TRANSFER_CONFIG)malloc(sizeof(PROXY_TRANSFER_CONFIG));
    if (config1 == NULL || config2 == NULL)
    {
        error("failed to allocate memory");
    }
    config1->inbound = FALSE;
    config2->inbound = TRUE;
    config2->t = config1->s = s;
    config2->s = config1->t = t;
    thread = CreateThread(NULL, 1,
        (LPTHREAD_START_ROUTINE)proxy_transfer_handler, (LPVOID)config1, 0,
        NULL);
    if (thread == NULL)
    {
        warning("failed to create thread (%d)", GetLastError());
        closesocket(s);
        closesocket(t);
        free(config1);
        free(config2);
        return 0;
    }
    proxy_transfer_handler((LPVOID)config2);
    WaitForSingleObject(thread, INFINITE);
    CloseHandle(thread);
    closesocket(s);
    closesocket(t);
    return 0;
}

/*
 * Handle the transfer of data from one socket to another.
 */
static DWORD proxy_transfer_handler(LPVOID arg)
{
    PPROXY_TRANSFER_CONFIG config = (PPROXY_TRANSFER_CONFIG)arg;
    BOOL inbound = config->inbound;
    SOCKET s = config->s, t = config->t;
    char buf[8192];
    int len, len2, i;
    HANDLE console;

    free(config);

    while (TRUE)
    {
        // Read data from s.
        len = recv(s, buf, sizeof(buf), 0);
        if (len == SOCKET_ERROR)
        {
            warning("failed to recv from socket (%d)", WSAGetLastError());
            shutdown(s, SD_BOTH);
            shutdown(t, SD_BOTH);
            return 0;
        }
        if (len == 0)
        {
            shutdown(s, SD_RECEIVE);
            shutdown(t, SD_SEND);
            return 0;
        }

        // Dump stream information to the screen.
        console = GetStdHandle(STD_OUTPUT_HANDLE);
        WaitForSingleObject(lock, INFINITE);
        printf("[%.4d] ", len);
        SetConsoleTextAttribute(console,
            (inbound? FOREGROUND_RED: FOREGROUND_GREEN));
        for (i = 0; i < len && i < MAX_LINE; i++)
        {
            putchar((isprint(buf[i])? buf[i]: '.'));
        }
        SetConsoleTextAttribute(console,
            FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
        printf("%s\n", (len > MAX_LINE? "...": ""));
        ReleaseMutex(lock);

        // Send data to t.
        for (i = 0; i < len; )
        {
            len2 = send(t, buf+i, len-i, 0);
            if (len2 == SOCKET_ERROR)
            {
                warning("failed to send to socket (%d)", WSAGetLastError());
                shutdown(s, SD_BOTH);
                shutdown(t, SD_BOTH);
                return 0;
            }
            i += len2;
        }
    }

    return 0;
}
要拦截 Windows 系统上所有进入或出去的 TCP 和 HTTP 请求,您可以使用 Python 的第三方库 WinDivert 或 PyDivert。这些库允许您在 Windows 系统上捕获和操作网络数据包。 以下是一些可能的步骤来实现这个目标: 1. 安装 WinDivert 或 PyDivert 库。您可以使用 pip 命令来安装 PyDivert: ``` pip install pydivert ``` 而 WinDivert 库需要手动下载并安装。 2. 使用 WinDivert 或 PyDivert 库创建一个 Divert 对象。Divert 对象允许您捕获和操作网络数据包。您可以使用以下代码创建一个 Divert 对象: ``` from pydivert import WinDivert, WinDivertLayer, WinDivertFlags with WinDivert("tcp.DstPort == 80", layer=WinDivertLayer.Network, flags=WinDivertFlags.SNIFF) as w: for packet in w: # 处理网络数据包 ``` 以上代码将创建一个 Divert 对象,用于捕获所有目标端口为 80 的 TCP 流量。您可以将此条件更改为其他条件来捕获其他类型的流量。 3. 在 Divert 对象的循环中,处理捕获的网络数据包。您可以使用第三方库,如 dpkt 或 scapy,来解析和操作网络数据包。例如,以下代码使用 dpkt 库解析 TCP 流量,获取源和目标 IP 地址和端口: ``` import dpkt with WinDivert("tcp.DstPort == 80", layer=WinDivertLayer.Network, flags=WinDivertFlags.SNIFF) as w: for packet in w: ip = dpkt.ip.IP(packet.raw) tcp = ip.tcp src_ip = dpkt.inet_ntoa(ip.src) dst_ip = dpkt.inet_ntoa(ip.dst) src_port = tcp.sport dst_port = tcp.dport # 处理网络数据包 ``` 您可以使用类似的代码来处理 HTTP 流量。例如,您可以检查 TCP 流量的目标端口是否为 80 或 443,并解析 HTTP 请求和响应。 请注意,拦截和操作网络数据包可能会对系统性能产生影响,并可能需要管理员权限。因此,请小心操作,并确保您的程序不会干扰网络通信或泄露敏感信息。
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值