从EXE提取BMP后保存文件损坏:C语言代码修复求助
修复从EXE提取BMP后文件损坏的问题
原代码的核心问题
- BMP头部缺失:找到"BM"签名后,未将签名和文件大小字段写入输出文件,直接读取后续内容保存,导致BMP缺少最关键的开头6字节(签名+文件大小),系统无法识别为有效文件。
- 文件指针位置错误:读取"BM"签名后指针已移动2字节,读取文件大小后未回退到签名起始位置,导致读取的buffer仅包含BMP的部分内容。
- 变量名冲突:内层重新定义
FILE* file覆盖了外层的EXE文件指针,导致后续关闭的是输出文件而非原EXE文件,存在资源泄漏。 - 写入长度错误:使用
sizeof(buffer)固定写入3992字节,若实际读取的bytesread不足,会写入多余垃圾数据。
修复步骤及代码
- 找到"BM"签名后,将文件指针回退到签名起始位置,读取完整的BMP文件(包含所有头部和像素数据)。
- 使用无符号类型存储BMP文件大小,避免溢出风险。
- 重命名输出文件指针,避免变量名冲突。
- 读取和写入时使用实际的文件大小值,而非固定缓冲区大小。
修复后的代码:
#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
相关产品推荐
相关产品推荐

