我正在制作一个用C解析PE结构的程序。示例(DOS标头是0x40(64(字节长,所以我尝试从binary_buf[0]
到binary_buf[39]
处理它。我应该读取什么数据类型的文件?
我不知道该写什么,因为无论我使用int还是char都是一样的。如果你能告诉我为什么我应该使用这种数据类型,我将不胜感激。
unsigned char *binary_buf = NULL;
fp = fopen(filename, "rb");
if (fp == NULL) {
printf("이 파일은 열 수 없습니다.n");
return 0;
}
fseek(fp, 0, SEEK_END);
size = ftell(fp);
fseek(fp, 0, SEEK_SET);
binary_buf = malloc(size+1);
fread(binary_buf, 1, size, fp);
fclose(fp);
printf("%d", binary_buf[0]); //77 = 0x4D == 'M'
谢谢你阅读我的问题。祝你今天过得愉快!
您正在读取一个二进制文件,unsigned char
数组似乎正是您所需要的。
请注意,分配一个额外的字节似乎不是这个作业所必需的,因为您不是从文件内容创建C字符串。
将PE头的内容读取为单个字节是最好的可移植方法:由于对齐和端序问题,头数据的特定布局可能无法由C结构正确匹配。
检查签名后,应该从标头中的已知偏移量中提取相关值,并使用适当的整数算法构造文件偏移量。
DOS标题为64字节长,布局如下:
typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header
WORD e_magic; // Magic number
WORD e_cblp; // Bytes on last page of file
WORD e_cp; // Pages in file
WORD e_crlc; // Relocations
WORD e_cparhdr; // Size of header in paragraphs
WORD e_minalloc; // Minimum extra paragraphs needed
WORD e_maxalloc; // Maximum extra paragraphs needed
WORD e_ss; // Initial (relative) SS value
WORD e_sp; // Initial SP value
WORD e_csum; // Checksum
WORD e_ip; // Initial IP value
WORD e_cs; // Initial (relative) CS value
WORD e_lfarlc; // File address of relocation table
WORD e_ovno; // Overlay number
WORD e_res[4]; // Reserved words
WORD e_oemid; // OEM identifier (for e_oeminfo)
WORD e_oeminfo; // OEM information; e_oemid specific
WORD e_res2[10]; // Reserved words
LONG e_lfanew; // File address of new exe header
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
其中WORD
是16位小端数整数,LONG
是32位小端整数。
这是一个修改版本:
#include <limits.h>
#include <stdio.h>
int read_PE_file(const char *filename) {
unsigned char *binary_buf = NULL;
FILE *fp = fopen(filename, "rb");
if (fp == NULL) {
fprintf(stderr, "Error opening file %sn", filename);
return -1;
}
fseek(fp, 0, SEEK_END);
long length = ftell(fp);
unsigned long size;
fseek(fp, 0, SEEK_SET);
if (length < 0) {
fprintf(stderr, "Error seeking file %sn", filename);
fclose(fp);
return -1;
}
size = length;
if (size < 64) {
fprintf(stderr, "file %s too short, size=%lun", filename, size);
fclose(fp);
return -1;
}
#if LONG_MAX > SIZE_MAX
if (size > SIZE_MAX) {
fprintf(stderr, "file %s too large, size=%lun", filename, size);
fclose(fp);
return -1;
}
#endif
if ((binary_buf = malloc(size)) == NULL) {
fprintf(stderr, "Error allocating %lu byte buffer for file %sn", size, filename);
fclose(fp);
return -1;
}
if (fread(binary_buf, 1, size, fp) != size) {
fprintf(stderr, "Error reading file %sn", filename);
free(binary_buf);
fclose(fp);
return -1;
}
fclose(fp);
if (binary_buf[0] != 0x4D || binary_buf[1] != 0x5A) {
fprintf(stderr, "File %s does not have MZ signaturen", filename);
free(binary_buf);
fclose(fp);
return -1;
}
unsigned long offset = binary_buf[60] +
(binary_buf[61] << 8) +
((unsigned long)binary_buf[62] << 16) +
((unsigned long)binary_buf[63] << 24);
if (offset > size) {
fprintf(stderr, "new executable offset %lu greater than file size %lu for file %sn", offset, size, filename);
free(binary_buf);
fclose(fp);
return -1;
}
printf("new executable offset: %lun", offset);
[...]
free(binary_buf);
return 0;
}