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

遍历目录检测文件签名:file_sign函数异常排查及实现疑问

问题分析与解决方案

核心错误原因

你当前的实现存在一个关键问题:把十六进制字符串直接当作二进制字节流来比较。

  • 你定义的given_signature是ASCII字符串,比如"98"对应的是两个字节的0x39('9'的ASCII码)和0x38('8'的ASCII码),但实际要匹配的是二进制的0x98单字节。
  • memcmp是直接逐字节比较内存内容,所以用它去对比文件二进制数据和ASCII格式的签名字符串,永远不可能匹配成功。

修正方案:将十六进制签名转为二进制数组

正确的做法是把十六进制签名转换成对应的二进制字节数组,再和文件内容对比。以下是两种可行的实现方式:

方式一:直接定义二进制数组(最简洁高效)

直接把十六进制签名转成二进制字面量,省去解析步骤:

// 每个十六进制对对应一个字节,共16字节
unsigned char given_signature[] = {0x98, 0x1d, 0x00, 0x00, 0xec, 0x33, 0xff, 0xff, 0xfb, 0x06, 0x00, 0x00, 0x00, 0x46, 0x0e, 0x10};
#define SIGNATURE_LEN 16

修改后的file_sign函数:

int file_sign(char* path){
    FILE* file = fopen(path, "rb");
    if(!file){
        printf("Failed to open file: %s\n", path);
        return -1;
    }

    fseek(file, 0, SEEK_END);
    long filelen = ftell(file);
    fseek(file, 0, SEEK_SET);

    // 提前判断文件长度是否小于签名长度,避免后续越界
    if(filelen < SIGNATURE_LEN){
        fclose(file);
        return 0;
    }

    unsigned char* buffer = malloc(filelen);
    if(!buffer){
        printf("Memory allocation failed\n");
        fclose(file);
        return -1;
    }

    size_t read_bytes = fread(buffer, 1, filelen, file);
    // 检查文件是否完整读取
    if(read_bytes != filelen){
        printf("Incomplete read for file: %s\n", path);
        free(buffer);
        fclose(file);
        return -1;
    }

    fclose(file);

    // 遍历文件内容,逐位置对比二进制签名
    for(long i = 0; i <= filelen - SIGNATURE_LEN; i++){
        if(memcmp(buffer + i, given_signature, SIGNATURE_LEN) == 0){
            printf("Signature found in %s\n", path);
            // 若只需找第一个匹配,可在此处添加break退出循环
        }
    }

    free(buffer);
    return 0;
}

方式二:从十六进制字符串数组解析二进制(对应你的思路)

如果你坚持用十六进制字符串数组的形式,可以写一个辅助函数把每个十六进制字符串转成单字节,再进行对比:

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>

// 把两位十六进制字符串转成字节
unsigned char hex_str_to_byte(const char* hex_str){
    unsigned char byte = 0;
    // 处理第一个字符
    char c = toupper(hex_str[0]);
    byte |= (c >= 'A' ? (c - 'A' + 10) : (c - '0')) << 4;
    // 处理第二个字符
    c = toupper(hex_str[1]);
    byte |= (c >= 'A' ? (c - 'A' + 10) : (c - '0'));
    return byte;
}

// 定义十六进制字符串数组
char* given_signature_hex[] = {"98", "1d", "00", "00", "ec", "33", "ff", "ff", "fb", "06", "00", "00", "00", "46", "0e", "10"};
#define SIGNATURE_HEX_COUNT 16

int file_sign(char* path){
    FILE* file = fopen(path, "rb");
    if(!file){
        printf("Failed to open file: %s\n", path);
        return -1;
    }

    fseek(file, 0, SEEK_END);
    long filelen = ftell(file);
    fseek(file, 0, SEEK_SET);

    if(filelen < SIGNATURE_HEX_COUNT){
        fclose(file);
        return 0;
    }

    unsigned char* buffer = malloc(filelen);
    if(!buffer){
        printf("Memory allocation failed\n");
        fclose(file);
        return -1;
    }

    size_t read_bytes = fread(buffer, 1, filelen, file);
    if(read_bytes != filelen){
        printf("Incomplete read for file: %s\n", path);
        free(buffer);
        fclose(file);
        return -1;
    }

    fclose(file);

    // 先把十六进制数组转成二进制数组
    unsigned char signature_bin[SIGNATURE_HEX_COUNT];
    for(int i=0; i<SIGNATURE_HEX_COUNT; i++){
        signature_bin[i] = hex_str_to_byte(given_signature_hex[i]);
    }

    // 对比逻辑与方式一一致
    for(long i = 0; i <= filelen - SIGNATURE_HEX_COUNT; i++){
        if(memcmp(buffer + i, signature_bin, SIGNATURE_HEX_COUNT) == 0){
            printf("Signature found in %s\n", path);
        }
    }

    free(buffer);
    return 0;
}

额外优化建议

  • 内存优化:不需要把整个文件读入内存,可以每次读入与签名长度相当的内容滑动对比,避免大文件占用过多内存。
  • 遍历边界:原代码中i < filelen -16会漏掉最后一个可能的匹配位置,应改为i <= filelen - SIGNATURE_LEN(当文件长度刚好等于签名长度时,i=0是唯一的匹配位置)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 07:20:15