You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linux C UDP Socket编程:如何在数据包数据中间插入0x00字节?

问题描述

正在进行Linux C UDP编程实验,尝试查询游戏服务器的当前状态,流程如下:

  • 向服务器发送固定消息,服务器回复包含挑战值的消息
  • 再发送原消息并附加该挑战值

已写出基础代码并能运行,但协议要求在数据包的数据中间插入空字节(0x00),目前代码缺少该字节(已通过Wireshark确认此问题)。现有代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
 
int main(int argc, char **argv){
 
 
  char *ip = "192.168.1.183";
  int port = 27015;
 
  int sockfd;
  struct sockaddr_in addr;
  char buffer[1024];
  char concbuf[1024];
  char challenge[10];
  socklen_t addr_size;
 
  sockfd = socket(AF_INET, SOCK_DGRAM, 0);
  memset(&addr, '\0', sizeof(addr));
  addr.sin_family = AF_INET;
  addr.sin_port = htons(port);
  addr.sin_addr.s_addr = inet_addr(ip);
 
  
  //Send this message to get a reply with a challenge value:
  bzero(buffer, 1024);
  strcpy(buffer, "ÿÿÿÿTSource Engine Query");
  sendto(sockfd, buffer, 25, 0, (struct sockaddr*)&addr, sizeof(addr));
  printf("[+]Data send: %s\n", buffer);
 
 
  //Recieve the challenge value:
  bzero(buffer, 1024);
  addr_size = sizeof(addr);
  recvfrom(sockfd, challenge, 9, 0, (struct sockaddr*)&addr, &addr_size);
  printf("[+]Data recv: %s\n", challenge);
 
 
  //Add the challenge value and message together: 
  char* conchal;
  char* min4 = (challenge +5); //Remove the first 5 bytes, not wanted.
  printf("[+]Strip : %s\n",min4);
  conchal = malloc(strlen(min4)+25);
  strcpy(conchal,"ÿÿÿÿTSource Engine Query"); //Would like to add a 0x00 after this
  strcat(conchal,min4); //Concatenate the challange value and the message.
  
  sendto(sockfd, conchal, 29, 0, (struct sockaddr*)&addr, sizeof(addr));
  printf("[+]Data send: %s\n", conchal);
  //Works, however, no 0x00 between the message and the challenge, which is needed.

  //This should return server information
  bzero(buffer, 1024);
  addr_size = sizeof(addr);
  recvfrom(sockfd, buffer, 1024, 0, (struct sockaddr*)&addr, &addr_size);
  printf("[+]Data recv: %s\n", buffer);
 
  
 
 
  return 0;
}

当前卡在如何在原消息和挑战值之间添加0x00字节这一步,请问最优实现方法是什么?(注:当前代码较为粗糙,仅处于实验阶段)

解决方案

核心问题是C标准库的字符串函数(strcpy/strcat)会把0x00当作字符串结束符,无法直接用来构造包含空字节的二进制数据。需要改用内存操作函数手动拼接数据,以下是两种可靠实现:

方法1:使用memcpy精准构造数据包

这是最推荐的方式,能明确控制每一个字节的内容:

// 替换原有的拼接代码部分
char* conchal;
char* min4 = (challenge +5); // 跳过前5字节的无效数据
printf("[+]Strip : %s\n",min4);

// 计算所需内存:原消息固定长度(24) + 1个0x00 + 挑战值长度
size_t base_msg_len = 24; // "ÿÿÿÿTSource Engine Query"的实际字节数是24
size_t chal_len = strlen(min4);
conchal = malloc(base_msg_len + 1 + chal_len);
if (!conchal) {
    perror("malloc failed");
    exit(EXIT_FAILURE);
}

// 1. 复制原消息到缓冲区起始位置
memcpy(conchal, "ÿÿÿÿTSource Engine Query", base_msg_len);
// 2. 在原消息末尾插入0x00字节
conchal[base_msg_len] = 0x00;
// 3. 复制挑战值到0x00之后的位置
memcpy(conchal + base_msg_len + 1, min4, chal_len);

// 发送时必须指定准确的总字节数,不能用strlen
sendto(sockfd, conchal, base_msg_len + 1 + chal_len, 0, (struct sockaddr*)&addr, sizeof(addr));
printf("[+]Data send (with 0x00): 原消息+0x00+%s\n", min4);

方法2:分步内存赋值(更直观)

如果觉得memcpy不够直观,可以用下标直接操作内存:

// 替换原有的拼接代码部分
char* conchal;
char* min4 = (challenge +5);
size_t base_msg_len = 24;
size_t chal_len = strlen(min4);

conchal = malloc(base_msg_len + 1 + chal_len);
if (!conchal) {
    perror("malloc failed");
    exit(EXIT_FAILURE);
}

// 复制原消息
memcpy(conchal, "ÿÿÿÿTSource Engine Query", base_msg_len);
// 手动插入空字节
conchal[base_msg_len] = '\0';
// 复制挑战值
memcpy(conchal + base_msg_len + 1, min4, chal_len);

// 发送时使用准确的总长度
sendto(sockfd, conchal, base_msg_len + 1 + chal_len, 0, (struct sockaddr*)&addr, sizeof(addr));

关键注意事项

  1. 禁止用strlen计算带空字节的数据包长度:strlen遇到0x00就会停止计数,必须手动记录固定长度或使用接收时的实际字节数。
  2. 发送时必须指定准确的字节数:不能用strlen(conchal),否则会因为中间的0x00导致发送长度不足。
  3. 内存分配要留足空间:确保malloc的大小能容纳所有数据,避免缓冲区溢出。

内容的提问来源于stack exchange,提问作者ObligedTester

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 03:07:02