linux或者Android使用内核ioctl抓包

linux或者Android使用内核抓包c语言程序

本文连接:https://www.cnblogs.com/muphy/p/14928858.html

参考程序:http://www.nsfocus.net/index.php?act=magazine&do=view&mid=1797

设置包过滤参考:https://www.kernel.org/doc/Documentation/networking/filter.txt 

完整程序 ioctl.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <linux/in.h>
#include <linux/if_ether.h>
#include <net/if.h>
#include <linux/filter.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>

int main(int argc, char **argv)
{
    int sock, n;
    char buffer[2048];
    unsigned char *iphead, *ethhead;
    struct ifreq ethreq;

    //$tcpdump -i eth0 tcp src port 502 -dd  # 设置过滤 可以通过此命令获取c程序片段,复制到下面
    struct sock_filter BPF_code[] = {
        {0x28, 0, 0, 0x0000000c},
        {0x15, 0, 6, 0x000086dd},
        {0x30, 0, 0, 0x00000014},
        {0x15, 0, 15, 0x00000006},
        {0x28, 0, 0, 0x00000036},
        {0x15, 12, 0, 0x000001f6},
        {0x28, 0, 0, 0x00000038},
        {0x15, 10, 11, 0x000001f6},
        {0x15, 0, 10, 0x00000800},
        {0x30, 0, 0, 0x00000017},
        {0x15, 0, 8, 0x00000006},
        {0x28, 0, 0, 0x00000014},
        {0x45, 6, 0, 0x00001fff},
        {0xb1, 0, 0, 0x0000000e},
        {0x48, 0, 0, 0x0000000e},
        {0x15, 2, 0, 0x000001f6},
        {0x48, 0, 0, 0x00000010},
        {0x15, 0, 1, 0x000001f6},
        {0x6, 0, 0, 0x00040000},
        {0x6, 0, 0, 0x00000000}};
    struct sock_fprog Filter;

    Filter.len = sizeof(BPF_code) / sizeof(BPF_code[0]);
    Filter.filter = BPF_code;

    if ((sock = socket(PF_PACKET, SOCK_RAW,
                       htons(ETH_P_IP))) < 0)
    {
        perror("socket");
        exit(1);
    }

    /* Set the network card in promiscuos mode */
    strncpy(ethreq.ifr_name, "eth0", IFNAMSIZ);
    if (ioctl(sock, SIOCGIFFLAGS, &ethreq) == -1)
    {
        perror("ioctl");
        close(sock);
        exit(1);
    }
    ethreq.ifr_flags |= IFF_PROMISC;
    if (ioctl(sock, SIOCSIFFLAGS, &ethreq) == -1)
    {
        perror("ioctl");
        close(sock);
        exit(1);
    }

    /* Attach the filter to the socket */
    if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER,
                   &Filter, sizeof(Filter)) < 0)
    {
        perror("setsockopt");
        close(sock);
        exit(1);
    }

    while (1)
    {
        printf("----------\n");
        n = recvfrom(sock, buffer, 2048, 0, NULL, NULL);
        printf("%d bytes read\n", n);

        /* Check to see if the packet contains at least
     * complete Ethernet (14), IP (20) and TCP/UDP
     * (8) headers.
     */
        if (n < 42)
        {
            perror("recvfrom():");
            printf("Incomplete packet (errno is %d)\n",
                   errno);
            close(sock);
            exit(0);
        }

        ethhead = buffer;
        printf("Ethernet MAC: [%02X:%02X:%02X:%02X:%02X:%02X]", ethhead[0], ethhead[1], ethhead[2], ethhead[3], ethhead[4], ethhead[5]);
        printf("->[%02X:%02X:%02X:%02X:%02X:%02X]", ethhead[6], ethhead[7], ethhead[8], ethhead[9], ethhead[10], ethhead[11]);
        printf(" type[%04x]\n", (ntohs(ethhead[12] | ethhead[13] << 8)));

        iphead = buffer + 14; /* Skip Ethernet  header */
        if (*iphead == 0x45)
        { /* Double check for IPv4 * and no options present */
            printf("Layer-4 protocol %d\n", iphead[9]);
            printf("Version: %d HeaderLen: %d[%d] ", (*iphead >> 4), (*iphead & 0x0f), (*iphead & 0x0f) * 4);
            printf("TotalLen %d\n", (iphead[2] << 8 | iphead[3]));
            printf("IP [%d.%d.%d.%d:%d]", iphead[12], iphead[13], iphead[14], iphead[15], (iphead[20] << 8 | iphead[21]));
            printf("->[%d.%d.%d.%d:%d]\n", iphead[16], iphead[17], iphead[18], iphead[19], (iphead[22] << 8 | iphead[23]));
            for (int i = 0; i < n; ++i)
            {
                printf(" %02x", buffer[i] & 0xff);
                if ((i + 1) % 16 == 0)
                    printf("\n");
            }
            printf("\n");
        }
    }
}

抓包并转发到指定服务器工具

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <linux/in.h>
#include <linux/if_ether.h>
#include <net/if.h>
#include <linux/filter.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <pthread.h>

/*
 强调:当客户端连接服务器时,服务器会产生一个新的文件描述符(套接字)与客户端交互,这个新的套接字不是服务器端的监听套接字
 套接字是全双工的,在一个网络管道中的两端,每端都可以进行读写操作。
 */
typedef struct _recvmodel
{
    int sockfd;
    struct sockaddr_in *addr;
} RecvModel;

RecvModel model;
int trun_port;
char turn_ip[20];
char dev[20];
int filter_port = 502;
int DATA_START_INDEX = 54;

//send message
void send_msg(const u_char *msg, int len)
{
    printf("send start...\n");
    if (send(model.sockfd, msg, len, 0) == -1)
    {
        printf("send failed ! error message %s\n", strerror(errno));
    }
    printf("send end!\n");
}

//recv message
void *recv_thread()
{
    int flag = 0;
    char buf[1024] = {0};
    while (1)
    {
        flag = recv(model.sockfd, buf, sizeof(buf), 0);
        if (flag == 0)
        {
            printf("对方已经关闭连接!\n");
            return NULL;
        }
        else if (flag == -1)
        {
            printf("recv failed ! error message : %s\n", strerror(errno));
            return NULL;
        }
        printf("%s:%s", inet_ntoa(model.addr->sin_addr), buf);
        memset(buf, 0, sizeof(buf));
    }
    return NULL;
}

void *listen_thread(void *arg)
{
    int sock;
    char buffer[2048];
    unsigned char *iphead, *ethhead, *data;
    struct ifreq ethreq;

    //$tcpdump -i eth0 -dd  # 设置过滤
    struct sock_filter BPF_code[] = {{0x28, 0, 0, 0x0000000c},
                                     {0x15, 0, 5, 0x000086dd},
                                     {0x30, 0, 0, 0x00000014},
                                     {0x15, 6, 0, 0x00000006},
                                     {0x15, 0, 6, 0x0000002c},
                                     {0x30, 0, 0, 0x00000036},
                                     {0x15, 3, 4, 0x00000006},
                                     {0x15, 0, 3, 0x00000800},
                                     {0x30, 0, 0, 0x00000017},
                                     {0x15, 0, 1, 0x00000006},
                                     {0x6, 0, 0, 0x00040000},
                                     {0x6, 0, 0, 0x00000000}};
    struct sock_fprog Filter;

    Filter.len = sizeof(BPF_code) / sizeof(BPF_code[0]);
    Filter.filter = BPF_code;

    if ((sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0)
    {
        perror("socket");
        exit(1);
    }

    /* Set the network card in promiscuos mode */
    strncpy(ethreq.ifr_name, dev, IFNAMSIZ);
    if (ioctl(sock, SIOCGIFFLAGS, &ethreq) == -1)
    {
        perror("ioctl");
        close(sock);
        exit(1);
    }
    ethreq.ifr_flags |= IFF_PROMISC;
    if (ioctl(sock, SIOCSIFFLAGS, &ethreq) == -1)
    {
        perror("ioctl");
        close(sock);
        exit(1);
    }

    /* Attach the filter to the socket */
    if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &Filter, sizeof(Filter)) < 0)
    {
        perror("setsockopt");
        close(sock);
        exit(1);
    }

    while (1)
    {
        printf("--------------------------------------------------------\n");
        int n = recvfrom(sock, buffer, 2048, 0, NULL, NULL);
        int src_port, dest_port;
        printf("%d bytes read\n", n);

        /* Check to see if the packet contains at least
        * complete Ethernet (14), IP (20) and TCP/UDP
        * (8) headers.
        */
        if (n < 42)
        {
            perror("recvfrom():");
            printf("Incomplete packet (errno is %d)\n", errno);
            continue;
        }

        ethhead = buffer;
        iphead = buffer + 14; /* Skip Ethernet  header */

        printf("Ethernet MAC: [%02X:%02X:%02X:%02X:%02X:%02X]", ethhead[0], ethhead[1], ethhead[2], ethhead[3], ethhead[4], ethhead[5]);
        printf("->[%02X:%02X:%02X:%02X:%02X:%02X]", ethhead[6], ethhead[7], ethhead[8], ethhead[9], ethhead[10], ethhead[11]);
        printf(" type[%04x] iphead[%d]\n", (ntohs(ethhead[12] | ethhead[13] << 8)), ethhead[14]);

        if (*iphead != 0x45)
        {

            for (int i = 0; i < n; ++i)
            {
                printf(" %02x", ethhead[i] & 0xff);
                if ((i + 1) % 16 == 0)
                    printf("\n");
            }
            printf("\n");
            printf("不是tcp协议,跳过抓发!\n");
            continue;
        }
        src_port = iphead[20] << 8 | iphead[21];
        dest_port = iphead[22] << 8 | iphead[23];
        if (trun_port == src_port || trun_port == dest_port)
        {
            continue;
        }

        printf("Layer-4 protocol %d\n", iphead[9]);
        printf("Version: %d HeaderLen: %d[%d] ", (*iphead >> 4), (*iphead & 0x0f), (*iphead & 0x0f) * 4);
        printf("TotalLen %d\n", (iphead[2] << 8 | iphead[3]));
        printf("IP [%d.%d.%d.%d:%d]", iphead[12], iphead[13], iphead[14], iphead[15], src_port);
        printf("->[%d.%d.%d.%d:%d]\n", iphead[16], iphead[17], iphead[18], iphead[19], dest_port);
        if (iphead[9] != 6)
        {
            continue;
        }
        // printf("header-[54]:\n");
        // for (int i = 0; i < 54; ++i)
        // {
        //     printf(" %02x", buffer[i] & 0xff);
        //     if ((i + 1) % 27 == 0)
        //         printf("\n");
        // }
        data = buffer + DATA_START_INDEX;
        int l = n - DATA_START_INDEX;
        printf("data-[%d]:\n", l);
        for (int i = 0; i < l; ++i)
        {
            printf(" %02x", data[i] & 0xff);
            if ((i + 1) % 27 == 0)
                printf("\n");
        }
        printf("\n");
        if (l < 1)
        {
            continue;
        }
        if (filter_port != 0 && filter_port != src_port && filter_port != dest_port)
        {
            continue;
        }
        //send_msg(data, l);
        send_msg(buffer, n);
    }
}

int main(int argc, char **argv)
{
    //打开socket
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1)
    {
        printf("open socket failed! error message:%s\n", strerror(errno));
        return -1;
    }
    //定义IP地址结构
    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    //设置TCP/IP连接
    addr.sin_family = AF_INET;
    //设置端口号
    printf("设置转发端口号:");
    scanf("%d", &trun_port);
    addr.sin_port = htons(trun_port);
    //设置允许连接地址
    do
    {
        printf("设置转发IP:");
        scanf("%s", turn_ip);
    } while (turn_ip[0] == '\0');
    printf("转发地址:ip:%s, port: %d\n", turn_ip, trun_port);

    addr.sin_addr.s_addr = inet_addr(turn_ip);

    printf("设置TCP抓包过滤端口(只是不转发,0表示所有端口都转发):");
    scanf("%d", &filter_port);
    printf("TCP抓包过滤端口:%d\n", filter_port);

    //设置允许连接地址
    do
    {
        printf("设置监听网卡(如:eth0):");
        scanf("%s", dev);
    } while (dev[0] == '\0');
    printf("监听网卡:%s\n", dev);

    //connect server
    int numx = connect(sockfd, (struct sockaddr *)&addr, sizeof(addr));
    if (numx == -1)
    {
        printf("connect server failed ! error message :%s\n", strerror(errno));
        goto END;
    }
    model.sockfd = sockfd;
    model.addr = &addr;
    printf("connect server ok ! \n");
    pthread_t thr1, thr2;
    if (pthread_create(&thr1, NULL, listen_thread, NULL) != 0)
    {
        printf("create thread failed ! \n");
        goto END;
    }
    printf("create listen_thread thread ok ! \n");
    if (pthread_create(&thr2, NULL, recv_thread, NULL) != 0)
    {
        printf("create thread failed ! \n");
        goto END;
    }
    printf("create recv_thread thread ok ! \n");
    pthread_join(thr1, NULL);
    pthread_join(thr2, NULL);
END:
    close(sockfd);
    return 0;
}
展开源码

 

测试

如果在Android编译,需要安卓gcc,这个apk下载后使用压缩软件winrar打开,将gcc.zip复制出来解压到/data(似乎这里读写权限没有问题)目录下(我的目录是/data/ruphy)并设置环境变量:

export PATH=$PATH:/data/ruphy/gcc/bin:/data/ruphy/gcc/arm-linux-androideabi/bin:/data/ruphy/gcc/libexec

雷电模拟器开启终端,使用gcc编译ioctl.c为ioctl.o可执行文件并执行启动抓包

 在Linux使用nc开启一个tcp服务,也可以不需要,因为模拟器可以上网,随便产生tcp连接即可

然后在模拟器使用telnet连接服务并通信

 

TCP/IP数据包格式

参考:https://blog.csdn.net/jrunw/article/details/56835404

黄色的是数据链路层的头部,一共14字节

绿色的部分是IP头部,一般是20字节

紫色部分是TCP头部,一般是20字节

最内部的是数据包内容

 

 

posted @ 2021-06-24 23:11  明月心~  阅读(707)  评论(0)    收藏  举报