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

从EXE提取BMP后保存文件损坏:C语言代码修复求助

修复从EXE提取BMP后文件损坏的问题

原代码的核心问题

  • BMP头部缺失:找到"BM"签名后,未将签名和文件大小字段写入输出文件,直接读取后续内容保存,导致BMP缺少最关键的开头6字节(签名+文件大小),系统无法识别为有效文件。
  • 文件指针位置错误:读取"BM"签名后指针已移动2字节,读取文件大小后未回退到签名起始位置,导致读取的buffer仅包含BMP的部分内容。
  • 变量名冲突:内层重新定义FILE* file覆盖了外层的EXE文件指针,导致后续关闭的是输出文件而非原EXE文件,存在资源泄漏。
  • 写入长度错误:使用sizeof(buffer)固定写入3992字节,若实际读取的bytesread不足,会写入多余垃圾数据。

修复步骤及代码

  1. 找到"BM"签名后,将文件指针回退到签名起始位置,读取完整的BMP文件(包含所有头部和像素数据)。
  2. 使用无符号类型存储BMP文件大小,避免溢出风险。
  3. 重命名输出文件指针,避免变量名冲突。
  4. 读取和写入时使用实际的文件大小值,而非固定缓冲区大小。

修复后的代码:

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

// 定义BMP文件头核心结构(签名+文件大小)
#pragma pack(push, 1)  // 禁用字节对齐,确保结构与磁盘数据完全一致
struct BMPFileHeader {
    uint8_t signature[2];
    uint32_t file_size;
};
#pragma pack(pop)

int main() {
    FILE* exe_file = fopen("C:\\Program Files\\...", "rb");
    if (!exe_file) {
        printf("Nu s-a putut deschide fisierul.\n");
        return 1;
    }

    fseek(exe_file, 0, SEEK_END);
    long exe_size = ftell(exe_file);
    fseek(exe_file, 0, SEEK_SET);

    // 遍历EXE文件寻找BMP
    while (ftell(exe_file) < exe_size - sizeof(struct BMPFileHeader)) {
        struct BMPFileHeader header;
        size_t read_bytes = fread(&header, sizeof(header), 1, exe_file);
        if (read_bytes != 1) {
            break;
        }

        // 验证BMP签名
        if (memcmp(header.signature, "BM", 2) == 0) {
            // 回退到BMP数据的起始位置
            fseek(exe_file, -sizeof(header), SEEK_CUR);

            // 动态分配缓冲区存储完整BMP
            uint8_t* bmp_buffer = malloc(header.file_size);
            if (!bmp_buffer) {
                printf("Alocare memorie esuata.\n");
                fclose(exe_file);
                return 1;
            }

            // 读取完整的BMP数据
            read_bytes = fread(bmp_buffer, 1, header.file_size, exe_file);
            if (read_bytes == header.file_size) {
                // 保存BMP文件
                FILE* bmp_file = fopen("image1.bmp", "wb");
                if (bmp_file) {
                    fwrite(bmp_buffer, 1, header.file_size, bmp_file);
                    fclose(bmp_file);
                    printf("BMP salvat cu succes!\n");
                } else {
                    printf("Nu s-a putut crea fisierul BMP.\n");
                }
            } else {
                printf("Citire incompleta a BMP-ului.\n");
            }

            free(bmp_buffer);
            // 找到目标BMP后可退出循环,避免重复处理
            break;
        } else {
            // 回退1字节,避免漏掉可能重叠的"BM"签名
            fseek(exe_file, -1, SEEK_CUR);
        }
    }

    fclose(exe_file);
    return 0;
}

关键说明

  • #pragma pack用于确保结构体和磁盘上的BMP头字节对齐一致,避免编译器自动对齐导致的读取错误。
  • 找到"BM"签名后回退指针,读取完整的file_size字节,保证BMP文件的完整性。
  • 动态分配缓冲区适配不同大小的BMP,避免固定数组的局限性。
  • 读取和写入操作使用实际字节数,确保数据准确无误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 23:05:35