我正在用C语言制作PE文件格式分析器。 当我使用 Visual Studio 时,我可以让它变得更容易。 但是,我已经厌倦了不使用 Visual Studio 来改进我的 C 编程。 它是由GCC制作的(我的笔记本电脑是macbook)。
要分析PE文件格式,如你所知,我必须使用文件指针并将文件读取为'rb'类型。 我做到了,看起来效果很好......我想打印第一个和第二个单词(“MZ”),但它打印了未知的(对我来说)数字。
P.S 我写的代码与之前的代码略有不同,比之前的要小。但它打印 NULL。 这意味着我写的代码真的错了...请告诉我哪些部分是错误的
#include <stdio.h>
#include <stdlib.h>
// struct to save info of PE_File format
typedef struct _IMAGE_DOS_HEADER
{
unsigned short e_magic;
unsigned short e_cblp;
unsigned short e_cp;
unsigned short e_crlc;
unsigned short e_cparhdr;
unsigned short e_minalloc;
unsigned short e_maxalloc;
unsigned short e_ss;
unsigned short e_sp;
unsigned short e_csum;
unsigned short e_ip;
unsigned short e_cs;
unsigned short e_lfarlc;
unsigned short e_ovno;
unsigned short e_res[4];
unsigned short e_oemid;
unsigned short e_oeminfo;
unsigned short e_res2[10];
unsigned long e_lfanew;
} DOS_HEADER;
// I use two different functions.
// First one was made to import PE File format info from file that I used.
// Another was made to print some imformation. I use some comment because I didn't realize those.
DOS_HEADER get_dos_header(FILE *fp, char* fp_buffer);
void print_data_of_structures(DOS_HEADER/*, NT_HEADER, FILE_HEADER, OPTIONAL_HEADER, DATA_DIRECTORY*/);
int main(void)
{
DOS_HEADER dos_header;
char file_path[1000];
printf("Please input your file path : ");
scanf("%[^\n]s", file_path);
FILE* fp = NULL;
fp = fopen(file_path, "rb");
if(fp == NULL)
printf("Unalbe to open file :/\n");
// To calculate file size.
long fp_size = 0;
fseek(fp, 0, SEEK_END);
fp_size = ftell(fp);
rewind(fp);
// Declare to use as buffer
char* fp_buffer = malloc(sizeof(char) * (fp_size + 1));
// Use function to save analyzed information.
DOS_HEADER info_dos_header = get_dos_header(fp, fp_buffer);
// Print information.
print_data_of_structures(info_dos_header);
fclose(fp);
free(fp_buffer);
return 0;
}
DOS_HEADER get_dos_header(FILE* fp, char* fp_buffer)
{
DOS_HEADER raw_info_dos_header = {0, };
// Read hex info from fp 2 byte 1 time and save at fp_buffer.
fseek(fp, 0, SEEK_SET);
fread(fp_buffer, 2, 1, fp);
raw_info_dos_header.e_magic = fp_buffer;
return raw_info_dos_header;
}
void print_data_of_structures(DOS_HEADER info_dos_header/*, NT_HEADER info_nt_header, FILE_HEADER info_file_header, OPTIONAL_HEADER info_optional_header, DATA_DIRECTORY info_data_directory*/)
{
// print info_dos_header
printf("Print DOS_HEADER\n");
// I tried several print format(for example %hu, %x, %d) But I coudn't "MZ" or any numbers has realation with "MZ".
printf("%s", info_dos_header.e_magic);
}
最佳答案
您的代码有两个大问题:混合类型。
在DOS_HEADER
中,所有成员(除了最后一个)都是unsigned Short
类型。
这很重要。
在get_dos_header
中你正在做
fread(fp_buffer, 2, 1, fp);
raw_info_dos_header.e_magic = fp_buffer;
这是错误的。
- 不要使用魔数(Magic Number),使用
sizeof
来获取正确的大小 - 检查
fread
的返回值,特别是在分析二进制文件时 格式,您必须确保您已经阅读了您所期望的内容。 - 当
size
参数为 1 时,处理fread
会容易得多,因为 仅当size
参数为 1 时,fread
的返回值才与 读取的字节数。 e_magic
是一个无符号短整型
,fp_buffer
是一个char*
。这个作业是 不复制fp_buffer
指向的内容,您正在存储一个地址 就好像它是一个无符号短
值。您需要复制指向的内存 通过fp_buffer
。
而且我不明白你分配文件大小的缓冲区有什么意义 当你逐 block 阅读时。如果不分配的话会更容易 完全缓冲并使用大小大于您要读取的数组。
int get_dos_header(FILE* fp, DOS_HEADER *dos)
{
unsigned char buffer[8];
size_t ret = fread(buffer, 1, sizeof(dos->e_magic), fp);
if(ret != sizeof(dos->e_magic))
{
fprintf(stderr, "Invalid file size\n");
return 0;
}
memcpy(&dos->e_magic, buffer, sizeof(dos->e_magic));
// DO the others fread operation
...
return 1;
}
然后在main
中你可以这样做:
DOS_HEADER raw_info_dos_header = {0, };
if(get_dos_header(fp, &raw_info_dos_header) == 0)
{
fprintf(stderr, "failed to get the DOS header\n");
return 1;
}
...
第二个问题在print_data_of_structs
中:
printf("%s", info_dos_header.e_magic);
e_magic
是一个 unsigned Short
,%s
需要一个指向 char
的指针,它需要一个
字符串。 e_magic
绝对不是字符串。这会产生未定义的行为。
printf
应该如下所示:
printf("e_magic: %hu\n", info_dos_header.e_magic);
或
printf("e_magic: 0x%04hx\n", info_dos_header.e_magic);
以十六进制格式打印它。
我还建议您改用指针。你的结构很大并且传递了一个 指向函数的指针比将大型结构的副本传递给函数要便宜得多 功能。所以而不是
void print_data_of_structures(DOS_HEADER info_dos_header);
将其声明为
void print_data_of_structures(DOS_HEADER *info_dos_header);
并且也不要将可能失败的函数(例如 get_dos_header
)声明为
void
,否则如何告诉调用函数它失败了?它是
此类函数最好返回 int
(1 表示成功,0 表示失败)并且
期望一个指向存储信息的结构的指针(看看我如何
更改了上面的 get_dos_header
。
关于c - 如何在 C 中以二进制形式从 PE_file 导入信息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50072154/