310 lines
11 KiB
C
310 lines
11 KiB
C
// 飞秋伪装(UDP应用)
|
||
/*
|
||
MAC -> 14
|
||
IP -> 20
|
||
UDP -> 8
|
||
UDP 数据报数据部分
|
||
*/
|
||
|
||
// 伪装飞秋数据报(UDP)
|
||
// 1. 伪装飞秋数据报的源IP和目的IP
|
||
// 2. 伪装飞秋数据报的源端口和目的端口
|
||
// 3. 伪装飞秋数据报的校验和
|
||
// 4. 伪装飞秋数据报的数据部分
|
||
// 5. 伪装飞秋数据报的长度
|
||
|
||
#include <arpa/inet.h>
|
||
#include <netinet/in.h>
|
||
#include <netinet/ether.h>
|
||
#include <netinet/ip.h>
|
||
#include <netinet/udp.h>
|
||
#include <netpacket/packet.h>
|
||
#include <sys/ioctl.h>
|
||
#include <net/if.h>
|
||
#include <unistd.h>
|
||
#include <string.h>
|
||
#include <stdio.h>
|
||
#include <pthread.h>
|
||
#include <sys/types.h>
|
||
#include <sys/stat.h>
|
||
#include <stdlib.h> // system
|
||
#include <iconv.h> // iconv, 用于转换编码
|
||
|
||
#include "fake_feiqiu_head.h"
|
||
|
||
ssize_t send_datapacket(int fd, unsigned char *buf, ssize_t buf_size, const char *ether_name);
|
||
unsigned short checksum(unsigned short *buf, int len);
|
||
char *convertToUTF8(const char *str); // 将字符串转换为UTF-8编码
|
||
char *convertToGB2312(const char *str); // 将字符串转换为GB2312编码
|
||
|
||
// 伪头部(UDP 校验时需要再 UDP 报文之间加上伪头部)
|
||
typedef struct pseudo_udp_head_struct
|
||
{
|
||
unsigned int saddr; // 源IP
|
||
unsigned int daddr; // 目的IP
|
||
unsigned char flag; // 0
|
||
unsigned char protocol; // 协议类型
|
||
unsigned short len; // UDP 首部长度 + 数据部分长度
|
||
} PSEUDO_UDP_HEAD;
|
||
|
||
int main(int argc, char const *argv[])
|
||
{
|
||
// 创建原始套接字
|
||
int sock_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
|
||
if (sock_fd < 0)
|
||
{
|
||
perror("raw socket");
|
||
return -1;
|
||
}
|
||
|
||
// 设置网卡名
|
||
char eth_name[128] = "";
|
||
printf("请输入要伪装的网卡名: ");
|
||
scanf("%s", eth_name);
|
||
|
||
char sender_ip[128] = "";
|
||
printf("请输入要伪装的发送者IP: ");
|
||
scanf("%s", sender_ip);
|
||
|
||
char sender_mac[128] = "";
|
||
printf("请输入要伪装的发送者MAC: ");
|
||
scanf("%s", sender_mac);
|
||
|
||
char receiver_ip[128] = "";
|
||
printf("请输入要伪装的接收者IP: ");
|
||
scanf("%s", receiver_ip);
|
||
|
||
char recv_mac[128] = "";
|
||
printf("请输入要伪装的接收者MAC: ");
|
||
scanf("%s", recv_mac);
|
||
|
||
char sender_name[128] = "";
|
||
printf("请输入要伪装的发送者名字: ");
|
||
scanf("%s", sender_name);
|
||
char sender_pc_name[128] = "";
|
||
printf("请输入要伪装的发送者电脑名字: ");
|
||
scanf("%s", sender_pc_name);
|
||
|
||
// mac 地址格式化
|
||
unsigned char dst_mac[8] = {0}; // 目的 MAC
|
||
unsigned char src_mac[8] = {0}; // 发送者 MAC
|
||
sscanf(sender_mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &src_mac[0], &src_mac[1], &src_mac[2], &src_mac[3], &src_mac[4], &src_mac[5]);
|
||
sscanf(recv_mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &dst_mac[0], &dst_mac[1], &dst_mac[2], &dst_mac[3], &dst_mac[4], &dst_mac[5]);
|
||
|
||
while (1)
|
||
{
|
||
|
||
unsigned char udp_buf[1500] = ""; // UDP 数据报
|
||
|
||
// 伪装飞秋数据报的数据部分
|
||
// char msg_data[1024] = "1_lbt6_47#128#704D7B3F6397#0#0#0#4001#9:1694470508:chai:chai:32:hi liangzai";
|
||
char msg_data[1024] = "";
|
||
char say_what[1024] = "";
|
||
printf("请输入要发送的内容:");
|
||
// scanf("%s", say_what);
|
||
fgets(say_what, sizeof(say_what), stdin); // 比 scanf 的优点是可以输入空格
|
||
say_what[strlen(say_what) - 1] = '\0'; // 去掉最后的换行符
|
||
|
||
if (strcmp(say_what, "exit") == 0)
|
||
{
|
||
break;
|
||
}
|
||
if (strcmp(say_what, "clear") == 0)
|
||
{
|
||
system("clear");
|
||
continue;
|
||
}
|
||
|
||
sprintf(msg_data, "1:%d:%s:%s:%d:%s", 123, convertToGB2312(sender_name), convertToGB2312(sender_pc_name), IPMSG_SENDMSG, convertToGB2312(say_what));
|
||
int msg_data_len = strlen(msg_data) + strlen(msg_data) % 2; // 整数补齐偶数位,strlen(msg_data)%2 : 偶数+0,奇数+1
|
||
printf("msg_data_len = %d ---> %s\n", msg_data_len, convertToUTF8(msg_data));
|
||
|
||
/* ---------------------组装 UDP 数据报的 UDP 首部--------------------- */
|
||
struct udphdr *udp_head = (struct udphdr *)(udp_buf + 14 + 20); // UDP 首部开始位置
|
||
udp_head->source = htons(2425); // 源端口
|
||
udp_head->dest = htons(2425); // 目的端口
|
||
udp_head->len = htons(8 + msg_data_len); // UDP 首部长度 + 数据部分长度
|
||
udp_head->check = htons(0); // UDP 首部校验和
|
||
|
||
/* ---------------------UDP 伪首部校验--------------------- */
|
||
// UDP 校验时需要再 UDP 报文之间加上伪头部
|
||
/*
|
||
UDP 校验中的伪头部(pseudo header)是在计算 UDP 校验和时使用的辅助数据。伪头部包含了源 IP 地址、目的 IP 地址、协议类型(通常是 UDP)和 UDP 报文长度等信息。
|
||
在计算 UDP 校验和时,将伪头部和 UDP 报文的内容拼接在一起,然后计算校验和。这样做的目的是增加校验和的安全性,使其更具可靠性。
|
||
*/
|
||
|
||
unsigned char pseudo_udp_buf[1056] = ""; // 伪头部
|
||
PSEUDO_UDP_HEAD *pseudo_udp_head = (PSEUDO_UDP_HEAD *)pseudo_udp_buf;
|
||
pseudo_udp_head->saddr = inet_addr(sender_ip); // 伪装源IP
|
||
pseudo_udp_head->daddr = inet_addr(receiver_ip); // 目的IP
|
||
pseudo_udp_head->flag = 0; // 0
|
||
pseudo_udp_head->protocol = 17; // 协议类型 UDP
|
||
pseudo_udp_head->len = htons(8 + msg_data_len); // UDP 首部长度 + 数据部分长度
|
||
|
||
memcpy(pseudo_udp_buf + 12, udp_head, 8); // 拷贝 UDP 首部到伪头部
|
||
memcpy(pseudo_udp_buf + 12 + 8, msg_data, msg_data_len); // 拷贝数据部分到伪头部
|
||
// 计算 UDP 首部校验和
|
||
udp_head->check = checksum((unsigned short *)pseudo_udp_buf, 12 + 8 + msg_data_len);
|
||
memcpy(udp_buf + 14 + 20 + 8, msg_data, msg_data_len); // 拷贝数据部分到 UDP 首部
|
||
|
||
/* ---------------------组装 UDP 数据报的 IP 首部--------------------- */
|
||
struct iphdr *ip_head = (struct iphdr *)(udp_buf + 14); // IP 首部开始位置
|
||
ip_head->version = 4; // 版本号 IPv4
|
||
ip_head->ihl = 5; // 首部长度 5 * 4 = 20 字节
|
||
ip_head->tos = 0; // 服务类型
|
||
ip_head->tot_len = htons(20 + 8 + msg_data_len); // IP 首部长度 + UDP 首部长度 + 数据部分长度
|
||
ip_head->id = htons(0); // 标识
|
||
ip_head->frag_off = htons(0); // 标志和片偏移
|
||
ip_head->ttl = 128; // 生存时间
|
||
ip_head->protocol = 17; // 协议类型 UDP
|
||
// ip 校验时不需要伪头部
|
||
ip_head->check = htons(0); // 原始校验和(暂时未知,赋值0)
|
||
ip_head->saddr = inet_addr(sender_ip); // 伪装源IP
|
||
ip_head->daddr = inet_addr(receiver_ip); // 目的IP
|
||
ip_head->check = checksum((unsigned short *)(udp_buf + 14), 20); // IP 首部校验和(计算 IP 首部的校验和)
|
||
|
||
/* ---------------------组装 UDP 数据报的 MAC 首部--------------------- */
|
||
struct ether_header *mac_head = (struct ether_header *)udp_buf; // MAC 首部开始位置
|
||
// unsigned char dst_mac[8] = {0xe8, 0x6a, 0x64, 0x6e, 0x93, 0x28}; // 主机 MAC (目的 MAC)
|
||
// unsigned char src_mac[8] = {0x4c, 0xe1, 0x73, 0x47, 0x16, 0x3a}; // 虚拟机 MAC (源 MAC)
|
||
// 使用 memcpy 函数将 dst_mac 的内容拷贝到 mac_head.ether_dhost 中
|
||
memcpy(mac_head->ether_dhost, dst_mac, 6); // 目的 MAC
|
||
memcpy(mac_head->ether_shost, src_mac, 6); // 源 MAC
|
||
mac_head->ether_type = htons(0x0800); // 2 个字节的数据需要大小端转换 (0x0800: IP 协议)
|
||
|
||
/* ---------------------发送数据--------------------- */
|
||
// int send_len = sendto(sock_fd, udp_buf, 14 + 20 + 8 + msg_data_len, 0, (struct sockaddr *)&sll, sizeof(sll));
|
||
int send_len = send_datapacket(sock_fd, udp_buf, 14 + 20 + 8 + msg_data_len, eth_name);
|
||
printf("send_len = %d\n", send_len);
|
||
}
|
||
|
||
close(sock_fd);
|
||
|
||
return 0;
|
||
}
|
||
|
||
ssize_t send_datapacket(int fd, unsigned char *buf, ssize_t buf_size, const char *ether_name)
|
||
{
|
||
// 1. 获取网络接口类型(通过网卡名查找网卡索引)
|
||
struct ifreq ether_req;
|
||
bzero(ðer_req, sizeof(ether_req));
|
||
strncpy(ether_req.ifr_name, ether_name, IF_NAMESIZE); // # define ifr_name ifr_ifrn.ifrn_name
|
||
|
||
if (ioctl(fd, SIOCGIFINDEX, ðer_req) == -1)
|
||
{
|
||
perror("ioctl");
|
||
return -1;
|
||
}
|
||
|
||
// 2. 选择发送数据的网络接口索引(选择合适的网卡索引)
|
||
struct sockaddr_ll sll;
|
||
bzero(&sll, sizeof(sll));
|
||
sll.sll_ifindex = ether_req.ifr_ifindex; // # define ifr_ifindex ifr_ifru.ifru_ivalue
|
||
|
||
// 3. 发送数据
|
||
ssize_t len = sendto(fd, buf, buf_size, 0, (struct sockaddr *)&sll, sizeof(sll));
|
||
return len;
|
||
}
|
||
|
||
// IP、UDP校验
|
||
// 数据报校验计算
|
||
// 接收传递的数据地址、长度
|
||
unsigned short checksum(unsigned short *buf, int len)
|
||
{
|
||
int nword = len / 2;
|
||
unsigned long sum;
|
||
|
||
if (len % 2 == 1)
|
||
nword++;
|
||
for (sum = 0; nword > 0; nword--)
|
||
{
|
||
sum += *buf;
|
||
buf++;
|
||
}
|
||
|
||
sum = (sum >> 16) + (sum & 0xffff);
|
||
sum += (sum >> 16);
|
||
return ~sum;
|
||
}
|
||
|
||
// 将字符串转换为UTF-8编码
|
||
char *convertToUTF8(const char *str)
|
||
{
|
||
// 输入字符串的长度
|
||
size_t inlen = strlen(str);
|
||
|
||
// 输出缓冲区的长度,假设为输入长度的3倍(UTF-8编码最多占用3个字节)
|
||
size_t outlen = inlen * 3;
|
||
|
||
// 创建转换句柄
|
||
iconv_t cd = iconv_open("UTF-8", "GB2312"); // 从 GB2312 转换为 UTF-8
|
||
|
||
// 分配输出缓冲区
|
||
char *outbuf = (char *)malloc(outlen);
|
||
if (outbuf == NULL)
|
||
{
|
||
perror("Memory allocation failed");
|
||
return NULL;
|
||
}
|
||
|
||
// 进行转换
|
||
char *inbuf = (char *)str;
|
||
char *outptr = outbuf;
|
||
|
||
if (iconv(cd, &inbuf, &inlen, &outptr, &outlen) == (size_t)-1)
|
||
{
|
||
perror("Conversion failed");
|
||
free(outbuf);
|
||
iconv_close(cd);
|
||
return NULL;
|
||
}
|
||
|
||
// 关闭转换句柄
|
||
iconv_close(cd);
|
||
|
||
// 添加字符串结束符
|
||
*outptr = '\0';
|
||
|
||
return outbuf;
|
||
}
|
||
|
||
// 将字符串转换为GB2312编码
|
||
char *convertToGB2312(const char *str)
|
||
{
|
||
// 输入字符串的长度
|
||
size_t inlen = strlen(str);
|
||
|
||
// 输出缓冲区的长度,假设为输入长度的3倍(UTF-8编码最多占用3个字节)
|
||
size_t outlen = inlen * 3;
|
||
|
||
// 创建转换句柄
|
||
iconv_t cd = iconv_open("GB2312", "UTF-8"); // 从 UTF-8 转换为 GB2312
|
||
|
||
// 分配输出缓冲区
|
||
char *outbuf = (char *)malloc(outlen);
|
||
if (outbuf == NULL)
|
||
{
|
||
perror("Memory allocation failed");
|
||
return NULL;
|
||
}
|
||
|
||
// 进行转换
|
||
char *inbuf = (char *)str;
|
||
char *outptr = outbuf;
|
||
|
||
if (iconv(cd, &inbuf, &inlen, &outptr, &outlen) == (size_t)-1)
|
||
{
|
||
perror("Conversion failed");
|
||
free(outbuf);
|
||
iconv_close(cd);
|
||
return NULL;
|
||
}
|
||
|
||
// 关闭转换句柄
|
||
iconv_close(cd);
|
||
|
||
// 添加字符串结束符
|
||
*outptr = '\0';
|
||
|
||
return outbuf;
|
||
} |