目录

前言

1.流量结构

2.类C结构

3.指令类型

二、代码示例

1.引入头文件

2.设置全局变量

3.函数

1.高低字节交换

2. 十六字节拼接

3.将木马检测结果写入csv文件

4.获取文件夹下特定格式的文件名

5.逐层解析pcap包

6.main函数

总结


前言

最近这几天观察到了一个木马的网络通信特征,于是就打算通过代码实现针对该木马的检测过滤。刚开始学长提供了python编写的代码。但是在实际的工作中,每天所捕获的pcap包的数据总量很大,通常在5到15个G左右。这种情况下,python的运行时间极长,且占用大量的系统运行内存,甚至会出现卡死情况。于是我尝试用C去实现木马的过滤,因为C是偏底层的编程语言,可以自定义通信协议,所以其运行效率会更高。


一、木马通信特征

1.流量结构

该木马拥有其自定义的通信协议,通信数据包具有一定的结构,数据在构造后会通过异或XOR加密(加密密钥是第二个字节),部分命令会有附加数据(如上传文件),附加数据部分会通过GZIP方式压缩。

2.类C结构

struct  packet_format{char dec_xor[2];char unknow1[4];char constant_l;char random_32[32];char command_type[2];char unknow2[4];char error_status[2];char payload_length[4];char command_sub_type;char unknow3[4];char unknow4[4];char unknow5[4];char has_payload;char payload[payload_length];
};

3.指令类型

对该木马来说,指令解析和响应包的构造是在同一个函数实现的,在接收到服务端发送的数据包后逐字节解析后被传入该函数,对解析得到的指令类型执行对应的操作,其具体支持的指令类型如下表所示

说明 类型
上线信息 0x5C37
命令执行/运行插件 0x5C7C
交付文件 0xB616、0x1CE3
心跳(指定睡眠时间) 0xDAFE

二、代码示例

1.引入头文件

在编程时,由于预想到用到的功能会较多,本人又较懒,所以就直接调用了<bits/stdc++.h>这个万能头文件。但是由于本机的编译环境为VS2019,所以在编译这个文件时出现了错误,为解决这一问题,我在对应目录下手动创建了这个文件,详细方法参考以下链接VS2019 添加bits/stdc++.h万能头文件库

#include <bits/stdc++.h>    //万能头文件
#include <cstdint>
#include <io.h>

2.设置全局变量

全局变量中主要是将各长度的数据类型赋予别名,以方便后续代码中的调用,比如将long long型数据(64位比特)定义别名为u64,其次则是定义了IPv4地址和IPv6地址的长度即字节数 。

#define u64 unsigned long long
#define uint32 uint32_t
#define uint16 uint16_t
#define uint8 uint8_t
#define v4ADDRByte 4     //IPv4地址字节数
#define v6ADDRByte 16    //IPv6地址字节数

随后则是在TCP/IP协议栈中由下至上地定义一系列结构体,以针对抓到的pcap包逐层地进行解析 ,首先是对pcap文件类型进行一个头部的定义(单纯地从TCP/IP协议栈中去看的话,其实压根没有文件头这号人物,但是实际上操作系统会为各类型文件都配一个头部,若想实现pcap文件内容的读取,则需要根据其文件头去逐字节地将文件指针向下移,从而跳过这一部分)

/*Pcap文件头24B各字段说明:Magic:4B:0x1A 2B 3C 4D:用来标示文件的开始Major:2B,0x02 00:当前文件主要的版本号Minor:2B,0x04 00当前文件次要的版本号ThisZone:4B当地的标准时间;全零SigFigs:4B时间戳的精度;全零SnapLen:4B最大的存储长度LinkType:4B链路类型常用类型:0            BSD loopback devices, except for later OpenBSD1            Ethernet, and Linux loopback devices6            802.5 Token Ring7            ARCnet8            SLIP9            PPP*/
typedef struct pcap_header {uint32 magic;uint16 version_major;uint16 version_minor;uint32 thiszone;uint32 sigfigs;uint32 snaplen;uint32 linktype;
}PcapHeader;

由于一个pcap文件通常情况下是由一系列packet组成的,所以读取pcap内容时实际上是相当于在其内部遍历一遍所有的packet,挨个读取里面的数据。这也就相当于你在一个文件夹里存着好多好多小文件,需要一个个地点开看,因此需要把packet的头也加进去,好在提取内容的时候把它跳过。

//pcap 数据包头部 16B
typedef struct packet_header {uint32 te_sec;uint32 ts_usec;uint32 capture_len;            //整个数据包的物理长度uint32 len;
}PacketHeader;

好了现在终于能进到协议栈里面了,最下面的是链路层(Q:为什么不是物理层?A:丫的物理层传输单元是比特流你去给我找个结构出来),帧头部结构是一个很简单的三维组

//以太网帧头部 14B
typedef struct ethhdr {unsigned char    dest_mac[6];    /* destination eth addr */unsigned char src_mac[6];     /* source ether addr    */unsigned short    frame_type;     /* 指定网络层版本  */
}FrameHeader;

然后是网络层,目前最常用的网络层协议无非就是IPv4和IPv6(事实上IPv6还是有点略多余,起码对这个木马的已有通信来看并没有使用过v6协议,但是为了让以后的我看这篇博客的时候不杠,我决定还是把v6的头也加进来)

//IPv4头部 20B
typedef struct ip4_hdr {uint8   ver_len;   //前4B为IP版本,后4B为头长度uint8   tos;uint16  total_len;uint16    id;uint16   frag_off;uint8  ttl;uint8   protocol;uint16 check;unsigned char saddr[4];unsigned char daddr[4];
}IPv4Header;//IPv6头部 40B
typedef struct ip6_hdr {uint32  var_tarclass_flowlab;uint16 payload_len;     //载荷长度uint8    next_header;uint8   hop_limit;unsigned char saddr[16];unsigned char daddr[16];
}IPv6Header;

接下来是传输层,虽然木马已知通信中只用了TCP,但是我也把UDP的头放进来了,道理同上 。有一点需要注意的是,TCP的头并不是20字节固定不变的,如果有选项字段的话TCP头部就会增长,最多可增至60字节。如果是在python中大可不必考虑长度变化,因为反正有封装好的scapy库给你兜底,但是在C里忽略这一点就可能导致代码运行时出现误差(没错就是我),关于误差的具体原因我会在后文详述。

//TCP头部 固定20B
typedef struct tcp_hdr {uint16 src_port;      //源端口uint16 dst_port;      //目的端口uint32 seq;uint32 ack;uint16 flag;uint16 window;uint16 checksum;      //校验和uint16 urgptr;// options可变项 12B
}TCPHeader;//UDP头部
typedef struct udp_hdr {uint16 src_port;uint16 dst_port;uint16 len;uint16 checksum;
}UDPHeader;

协议栈最后则是应用层,对于本文而言,应用层其实就是木马的攻击载荷,所以只需要把前面提到的木马的类C结构稍稍改一下就能拿来当作头部了。和之前提到的类C结构作比较,可以看到做出的改动其实就是把那些在后续过程中需要单字节计算的字段拆开了(比如command_type、payload_length)

//海莲花buni木马载荷头结构 65B
typedef struct apt32_payload {uint8 dec_xor1;uint8 dec_xor2;unsigned char unknow1[4];unsigned char constant_l;unsigned char random_32[32];uint8 command_type_1;uint8 command_type_2;unsigned char unknow2[4];unsigned char error_status[2];uint8 payload_length_1;uint8 payload_length_2;uint8 payload_length_3;uint8 payload_length_4;unsigned char command_sub_type;unsigned char unknow3[12];unsigned char has_payload;
}PAYLOAD;

接下来为方便最后的结果输出,定义一个结构体去承载检测出的对应木马特征(正常来说应该是两个,因为网络层有v4和v6两种协议,这两种协议的地址长度是不同的。在本文中只提供v4对应的结构体作为示例)

//结果五元组ipv4版本
typedef struct res_v4 {string path;              //木马特征包的文件路径uint32 frame_id;          //所属帧序号uint32 cmd_code;          //命令编码string cmd_label;         //对应命令含义unsigned char src_ip[4];unsigned char dst_ip[4];uint16 src_port;uint16 dst_port;uint8 protocol;
}Res4;

定义各类型数据包头部的合法长度,用以在后续检测木马通信包时判断所读取的数据是否合理。所谓各类型,其实就是两种IP协议v4和v6、与两种传输层协议TCP和UDP的排列组合。

//各协议类型包的合法长度
const int v4_tcp_len = sizeof(FrameHeader) + sizeof(IPv4Header) + sizeof(TCPHeader) + sizeof(PAYLOAD);
const int v4_udp_len = sizeof(FrameHeader) + sizeof(IPv4Header) + sizeof(UDPHeader) + sizeof(PAYLOAD);
const int v6_tcp_len = sizeof(FrameHeader) + sizeof(IPv6Header) + sizeof(TCPHeader) + sizeof(PAYLOAD);
const int v6_udp_len = sizeof(FrameHeader) + sizeof(IPv6Header) + sizeof(UDPHeader) + sizeof(PAYLOAD);

3.函数

1.高低字节交换

由于在intel处理器上,网络传输数据是小端存储的,所以在对长整型数据进行计算、十进制输出等操作之前,需要将高低字节进行转换。为稳妥起见,使用位移和与运算,将各字节的位置准确到二进制的层次(Q:为什么说是二进制层次?A:因为&运算是按位与,所以结果会精确到两个操作数的每一个比特)

//长整型高低字节交换
#define swap16(A) ((((uint16)(A) & 0xff00) >> 8) | (((uint16)(A) & 0x00ff) << 8))
#define swap32(A) ((((uint32)(A) & 0xff000000) >> 24) | (((uint32)(A) & 0x00ff0000) >> 8) | (((uint32)(A) & 0x0000ff00) << 8) | (((uint32)(A) & 0x000000ff) << 24))

2. 十六字节拼接

在前文提到过,木马载荷中payload_length这种字段是需要按字节分开进行异或加密的。但是在计算其所表达的数值的时候,需要将4个payload_length字节拼接成完整的字段再转换成十进制。举个例子:解密后的四个字节分别是0x12,0x34,0x56,0x78;那么在计算其数值时则需要将它们先逆序(小端存储)拼接成为完整的十六进制字段0x78563412,再计算其对应的十进制。函数的具体实现原理和高低字节转换差不多。

//十六进制字节拼接,参数由低位到高位
int rev_data(int a, int b, int c, int d)
{int e = 0;e = ((d << 24) & 0xff000000) | ((c << 16) & 0x00ff0000) | ((b << 8) & 0x0000ff00) | (a & 0x000000ff);return e;
}

3.将木马检测结果写入csv文件

当你很幸运地发现这个木马异常地活跃,也就是说你跑出了好多好多个木马通信包的时候,就需要一个精美的csv来存储你的结果了。

//结果写入out.csv
void out2csv(FILE* fp, PAYLOAD* pld_hdr, Res4* res4, Res6* res6, bool is_v4) {if (is_v4) {for (int i = 0; i < v4ADDRByte; i++) fprintf(fp, "%d%c", res4->src_ip[i], ".,"[i == v4ADDRByte - 1]);fprintf(fp, "%d", swap16(res4->src_port));for (int i = 0; i < v4ADDRByte; i++) fprintf(fp, "%d%c", res4->dst_ip[i], ".,"[i == v4ADDRByte - 1]);fprintf(fp, "%d", swap16(res4->dst_port));fprintf(fp, ",");fprintf(fp, "%s", res4->path.c_str());fprintf(fp, ",");fprintf(fp, "%d", res4->frame_id);fprintf(fp, ",");fprintf(fp, "0x%X", pld_hdr->command_type_2);fprintf(fp, "%X", pld_hdr->command_type_1);fprintf(fp, ",");fprintf(fp, "%s", res4->cmd_label.c_str());fprintf(fp, "\n");}
}

值得一提的是,参数is_v4是个bool型变量(非真即假),它是用来判断当前packet所承载的网络层协议是否是IPv4的,是则真,否则假。至于怎么能让csv文件换列这个问题,其实只需要地简单fprintf一个逗号就好了。

4.获取文件夹下特定格式的文件名

通常情况下(只要wireshark没坏掉),总是会有很多pcap文件待检测的。也就是说我们需要循环打开这么多的文件,而打开文件显然需要它的完整路径。这个函数就是用来获取某文件夹下所有指定格式的文件名的。(当然,除了pcap格式以外,别的格式也都支持)

//获取文件夹下特定格式的文件名
void get_need_file(string path, vector<string>& file, string ext)
{intptr_t file_handle = 0;struct _finddata_t file_info;string temp;if ((file_handle = _findfirst(temp.assign(path).append("/*" + ext).c_str(), &file_info)) != -1){do{file.push_back(temp.assign(path).append("/").append(file_info.name));} while (_findnext(file_handle, &file_info) == 0);_findclose(file_handle);}
}

这个函数的具体讲解可参考C++遍历文件夹获取指定格式文件名

5.逐层解析pcap包

好了终于把所有的伏笔都埋好了,现在就到我们的重头戏了:解析pcap包。首先传递进来两个参数,一个是待检测的pcap包的路径:pacp_path,一个是用来存放结果的csv的文件指针:out然后按照上文中的全局变量去定义指向各类型头部的指针

void solver(string pacp_path, FILE* out) {//创建各种类型的header方便提取字段PacketHeader* pkt_hdr = (PacketHeader*)malloc(sizeof(PacketHeader));FrameHeader* ethhdr = (FrameHeader*)malloc(sizeof(FrameHeader));IPv4Header* ip4_hdr = (IPv4Header*)malloc(sizeof(IPv4Header));IPv6Header* ip6_hdr = (IPv6Header*)malloc(sizeof(IPv6Header));TCPHeader* tcp_hdr = (TCPHeader*)malloc(sizeof(TCPHeader));UDPHeader* udp_hdr = (UDPHeader*)malloc(sizeof(UDPHeader));PAYLOAD* pld_hdr = (PAYLOAD*)malloc(sizeof(PAYLOAD));Res4* res4 = (Res4*)malloc(sizeof(Res4));Res6* res6 = (Res6*)malloc(sizeof(Res6));

通过传入的路径参数打开对应的pcap文件

 FILE* pFile = fopen(pacp_path.c_str(), "rb");  //c_str与C兼容,C中没有string类型    'rb'以字节方式读取文件中数据if (pFile == NULL) {cout << "文件读取错误!" <<  endl;exit(1);}//读取Pacp文件头长度24Bu64 packet_len = sizeof(PcapHeader);uint32 count = 0;

紧接着开启一个while循环去遍历这一pcap文件中的每个packet

 //重定位文件指针,跳过文件前24B,逐包读取pcap文件while (fseek(pFile, packet_len, SEEK_SET) == 0) {count++;//读取本包数据FILE* temp = pFile;memset(res4, 0, sizeof(Res4));memset(res6, 0, sizeof(Res6));//packet_headermemset(pkt_hdr, 0, sizeof(PacketHeader));if (fread(pkt_hdr, sizeof(PacketHeader), 1, temp) != 1) {cout << "读取包头部数据失败" << endl;break;}//帧的长度,同时确保while循环中的文件指针在后移(以实现读取下一个packet的数据)packet_len += sizeof(PacketHeader) + pkt_hdr->capture_len;

解析链路层、网络层、传输层。(Q:说了这么半天解析解析,到底什么是解析啊?A:其实所谓的解析就是将文件中的数据读到之前所定义的头部结构中,这其中的关键只在于你这个赋值等式两头的数据位置是要一致的,比如说我要解析以太帧,那么我就要确保我所调用的fread函数中指针的位置是确确实实指向以太帧的首字节。这样的话我就可以通过头部结构体的各个字段去推理出长度、下层协议、地址等重要的变量)

     //解析以太帧memset(ethhdr, 0, sizeof(FrameHeader));if (fread(ethhdr, sizeof(FrameHeader), 1, temp) != 1) {cout << "读取以太帧头部数据失败" << endl;continue;}//解析IP层//判断类型v4或v6,读取对应头部数据bool is_v4;if (ethhdr->frame_type == 0x0008) {is_v4 = true;}else if (ethhdr->frame_type == 0xdd86) {is_v4 = false;}else {cout << "不是ip包,未能解析" << endl;continue;    //指向下一个packet}memset(ip4_hdr, 0, sizeof(IPv4Header));memset(ip6_hdr, 0, sizeof(IPv6Header));bool is_tcp;if (is_v4) {if (fread(ip4_hdr, sizeof(IPv4Header), 1, temp) != 1) {cout << "读取IPv4头失败" << endl;continue;}memcpy(res4->src_ip, ip4_hdr->saddr, 4);memcpy(res4->dst_ip, ip4_hdr->daddr, 4);res4->protocol = ip4_hdr->protocol;is_tcp = ip4_hdr->protocol == 0x06;     //判断协议类型是否为TCP}else {if (fread(ip6_hdr, sizeof(IPv6Header), 1, temp) != 1) {cout << "读取IPv6头失败" << endl;continue;}memcpy(res6->src_ip, ip6_hdr->saddr, 16);memcpy(res6->dst_ip, ip6_hdr->daddr, 16);res6->protocol = ip6_hdr->next_header;is_tcp = ip6_hdr->next_header == 0x06;     //判断协议类型是否为TCP}//解析传输层//判断传输协议类型,读取对应头部数据memset(tcp_hdr, 0, sizeof(TCPHeader));memset(udp_hdr, 0, sizeof(UDPHeader));if (is_tcp) { //TCP协议if (fread(tcp_hdr, sizeof(TCPHeader), 1, temp) != 1) {cout << "读取TCP头失败" << endl;continue;}if (is_v4) res4->src_port = tcp_hdr->src_port, res4->dst_port = tcp_hdr->dst_port;else res6->src_port = tcp_hdr->src_port, res6->dst_port = tcp_hdr->dst_port;}else { //UDP协议if (fread(udp_hdr, sizeof(UDPHeader), 1, temp) != 1) {cout << "读取UDP头失败" << endl;continue;}if (is_v4) res4->src_port = udp_hdr->src_port, res4->dst_port = udp_hdr->dst_port;else res6->src_port = udp_hdr->src_port, res6->dst_port = udp_hdr->dst_port;}

读取完这几层的数据之后,为了稳妥起见,我们先判断一下实际上所读到的数据长度是否和理论上的长度一致 ,如果不一致就说明当前这个packet长得奇奇怪怪的,我们就直接抬走下一位(continue;)

     //检查包的长度if (is_v4) {if (is_tcp) { if (pkt_hdr->capture_len < v4_tcp_len) continue; }else { if (pkt_hdr->capture_len < v4_udp_len) continue;}}else {if (is_tcp) { if (pkt_hdr->capture_len < v6_tcp_len) continue; }else { if (pkt_hdr->capture_len < v6_udp_len) continue; }}

做完这些之后我们就试着去读取木马的攻击载荷。为什么说是试着呢,因为其实读到的东西不一定真的是木马载荷的。这个代码逻辑其实就是把数据硬往这个payload结构体里面去塞,然后通过字段值去判断它对不对。

关于怎么去判断对不对这个问题,答案很简单。就是根据长度字段payload_length去计算。我先算一遍实际的载荷长度_payload,然后再根据目前塞进来的payload_length字段去计算一遍它所表示的长度,如果两者相等,就说明我这个数据塞对地方了,就说明当前这个packet就是木马通信数据。

     //读取木马攻击载荷memset(pld_hdr, 0, sizeof(PAYLOAD));if (fread(pld_hdr, sizeof(PAYLOAD), 1, temp) != 1) {cout << "读取payload头失败" << endl;continue;}//求实际载荷长度int _paylen = pkt_hdr->capture_len - 119;//求理论载荷长度pld_hdr->payload_length_1 = pld_hdr->dec_xor2 ^ pld_hdr->payload_length_1;pld_hdr->payload_length_2 = pld_hdr->dec_xor2 ^ pld_hdr->payload_length_2;pld_hdr->payload_length_3 = pld_hdr->dec_xor2 ^ pld_hdr->payload_length_3;pld_hdr->payload_length_4 = pld_hdr->dec_xor2 ^ pld_hdr->payload_length_4;int paylen = rev_data(pld_hdr->payload_length_1, pld_hdr->payload_length_2, pld_hdr->payload_length_3, pld_hdr->payload_length_4);pld_hdr->command_type_1 = pld_hdr->dec_xor2 ^ pld_hdr->command_type_1;pld_hdr->command_type_2 = pld_hdr->dec_xor2 ^ pld_hdr->command_type_2;

值得一提的是这个实际载荷长度_payload的求解,它是用当前帧的总长度去减去所有的头的长度(frame头14B + IPv4头部20B + TCP固定头部20B + 木马头部65B = 119)。那么问题来了,之前不是说TCP的头部长度不是固定的吗,为什么在这里只减去固定长度20B,万一TCP头部是32B、60B怎么办?解决办法很简单,再写几个cpp,把tcp的头结构改一下,该减几B就减几B。

至于我为什么要把payload_length和command_type这两个字段拆成字节去和dec_xor异或,因为这个木马把dec_xor这个字节作为密钥,载荷的全部字节均与这个密钥异或加密形成的,那么如果我要解密的话,显然需要将所有字节都与这个密钥重新异或一遍(异或的逆运算是异或)

当确认是木马通信数据后,需要做的就是这个木马到底干了什么,也就是说把它所传递的命令给解析出来。做法很简单就是去比较pld_hdr->command_type字段,看看是不是木马特征中所提到的那五种,这里拿出第一种(0x5C37 : 上线信息)做例子

     if (paylen == _paylen) {if (pld_hdr->command_type_1 == 0x37 && pld_hdr->command_type_2 == 0x5C) {if (is_v4) {res4->frame_id = count;res4->cmd_label = "上线信息";res4->path = pacp_path;//输出结果cout << res4->path << " 序号 " << res4->frame_id << endl;printf("命令码: 0x%X", pld_hdr->command_type_2);printf("%X", pld_hdr->command_type_1);printf("上线信息");printf("%s", res4->cmd_label.c_str());cout << endl << "源ip:";for (int i = 0; i < v4ADDRByte; i++) printf("%d%c", res4->src_ip[i], ".,"[i == v4ADDRByte - 1]);printf(" ");printf("源端口:%d", swap16(res4->src_port));printf(",目的ip:");for (int i = 0; i < v4ADDRByte; i++) printf("%d%c", res4->dst_ip[i], ".,"[i == v4ADDRByte - 1]);printf(" ");printf("目的端口:%d", swap16(res4->dst_port));cout << endl << endl;}}

最后将检测结果写入csv

         //结果写入csvif (is_v4) out2csv(out, pld_hdr, res4, NULL, is_v4);

6.main函数

int main(void) {string file_path = R"(F:\数据分析_邮件还原\3 数据(含初始数据&中间及最终分析结果)-供教员测试程序用\1 捕获的邮件数据包\jy给出的TOM数据(以做进一步测试)\初始数据)";vector<string> my_file;string need_extension = ".pcap";string out_path = "./out.csv";FILE* out = fopen(out_path.c_str(), "w");fprintf(out, "源ip,源port,目的ip,目的port,文件路径,帧序号,指令编码,指令含义\n");get_need_file(file_path, my_file, need_extension);for (int i = 0; i < my_file.size(); i++){cout << "File " << i + 1 << " is:" << endl;cout << my_file[i] << endl;solver(my_file[i], out);}if (my_file.size() == 0){cout << "No file can be found!" << endl;}else{cout << endl << "Find " << my_file.size() << " file(s)." << endl;}cout << endl << endl << "过滤完成" << endl;return 0;
}

总结

这是我的第一篇博客,可能在大佬的眼中会觉得很菜,而且我也确实很菜,但是不管怎么说,这三四天来把这些东西断断续续地写完还是非常有成就感的。这一套代码编下来之后,怎么说呢,最大的感触就是不管什么事可能乍一看头皮很麻,其实真去经历了的话感觉也就那样。人缺乏的不是能力而是选择开始的这份勇气。再有一点就是,遇到困难问百度,度哥是不会让你失望的哈哈哈哈哈哈哈哈哈哈哈哈哈。

C++实现pcap包解析,并提取指定特征帧相关推荐

  1. pcap文件解析工具_【免费毕设】PHP网络数据包分析工具的设计与开发(源代码+论文)...

    点击上方"蓝字"关注我们目录 系统设计 网络数据包分析系统的设计 整个网络数据报分析工具采用模块化的设计思想,原因是许多程序太长或太复杂,很难写在单一单元中.如果把代码分为较小的功 ...

  2. python解析pcap包已text格式输出_python分析pcap包

    前两天需要分析一个pcap包,写了一段python脚本,将每个包的基本信息(源/目的MAC.源/目的IP.源/目的端口)提取出来. 在实现过程中为了省事用了dpkt开发包,不过只用了几个简单的函数,具 ...

  3. java 生成.pcap_java抓包后对pcap文件解析示例

    这是自己写的简单的解析pcap文件,方便读取pcap文件,大家参考使用吧 复制代码 代码如下: InputStream is = DataParser.class.getClassLoader().g ...

  4. python读取word指定内容_python解析html提取数据,并生成word文档实例解析

    简介 今天试着用ptyhon做了一个抓取网页内容,并生成word文档的功能,功能很简单,做一下记录以备以后用到. 生成word用到了第三方组件python-docx,所以先进行第三方组件的安装.由于w ...

  5. python scapy 抓包_Python3下基于Scapy库完成网卡抓包解析

    Scapy是一个可以让用户发送.侦听和解析并伪装网络报文的Python程序.这些功能可以用于制作侦测.扫描和攻击网络的工具. 在 Python 代码中可以通过 sniff 函数调用抓包分析,并对抓到的 ...

  6. wireshark官方文档第 9 章数据包解析

    第 9 章数据包解析 9.1. 数据包解析的工作原理 对于一个已封装好的协议包,每个解析器(dissector)对其负责的一部分协议进行解码,然后将解码过程交给后续的解析器. 每个解析都从帧(Fram ...

  7. Pcap包按相同五元组信息提取流量

    我们将网络流量分类的输入空间分为三类:分组分类(Packet Classification,PC).流量内容分类(Flow Content Classification,FCC)和流量时间序列分类(F ...

  8. 教你动手写UDP协议栈 - UDP数据包解析<1>

    前景 为啥要自己写一个mini UDP的协议栈?因为我们干偷偷摸摸的事情,哈哈哈!!! 其实是为了不跑一个庞大的LWIP协议栈,通过自己写的mini udp协议栈截取数据包给设备升级.这样节省了很多资 ...

  9. SSL加密包解析的几个概念梳理

    1.DPI技术初识 DPI(Deep PacketInspection)深度包检测技术是在传统IP数据包检测技术(OSI L2-L4之间包含的数据包元素的检测分析)之上增加了对应用层数据的应用协议识别 ...

最新文章

  1. css sprites之圆角
  2. jeecms v9 vue环境搭建
  3. 图解windbg查看Win7结构体
  4. VTK:几何对象之OpenVROrientedCylinder
  5. [代码示例]用Fine Uploader+ASP.NET MVC实现ajax文件上传
  6. 假笨说-谨防JDK8重复类定义造成的内存泄漏
  7. verilog实现步进电机脉冲分配器(三相六拍)基于Nexys4DDR开发板
  8. springMVC的流程
  9. 直播丨墨天轮邂逅MySQL之父,腾讯云CDB/CynosDB技术揭秘之自主可控、前沿探索
  10. R语言分类算法之随机森林(Random Forest)
  11. ubuntu中bash,sh,./,bash区别
  12. 计算机仿真塞曼效应实验报告,实验报告模板
  13. xlsx表格怎么做汇总统计_excel考勤统计表汇总怎么做
  14. 触摸精灵3.9.5版本运行已停止解决方法
  15. 机器学习理论之(1):概率分布,信息熵,朴素贝叶斯
  16. http压力测试工具及使用说明
  17. 三菱je -c中映射表的作用_linux内核页表映射机制:线性地址如何转为物理地址?...
  18. Python代码实现飞机大战
  19. 常见积分和导数的推导
  20. Java校招期望薪资_2019互联网校招薪资出炉,整体超越 BAT、华为

热门文章

  1. 归并排序(Merge Sort)图解,归并排序算法
  2. ViLT:Vision-and-Language Transformer Withoout Convolution or Region Supervision
  3. Adobe Photoshop 软件下载
  4. 凡客签约鸟叔,打造不怕过气的“快时尚”理念
  5. 3776 水果拼盘(贪心)
  6. 矿物绝缘电缆有哪些应用领域
  7. 年省成本超600万,解密时代中国HR的数字化大招
  8. 第二数学归纳法:硬币问题和堆垛游戏
  9. UiPath MySql
  10. django使用xadmin