c - 如何在 C 中以二进制形式从 PE_file 导入信息

标签 c gcc

我正在用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;

这是错误的。

  1. 不要使用魔数(Magic Number),使用 sizeof 来获取正确的大小
  2. 检查 fread 的返回值,特别是在分析二进制文件时 格式,您必须确保您已经阅读了您所期望的内容。
  3. size 参数为 1 时,处理 fread 会容易得多,因为 仅当 size 参数为 1 时,fread 的返回值才与 读取的字节数。
  4. 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/

相关文章:

c - 使用 GCC 强制自动矢量化

linux - 在 qmake (5.0) 生成的 Makefile 中设置 LINK 变量

c - GNU gprof 有问题吗?

c - 更有效的 flooring double 方法来获取数组索引

c - 在 GCC 中分配或执行具有不同枚举类型的算术时如何发出警告?

在 C 中使用 typeof 创建一个特定的宏

c++ - 结构化绑定(bind)和基于范围的;在 gcc 中抑制未使用的警告

c - 转义常规字符

c++ - 如果我知道 1+2+3+..+n=n*(n+1)/2 的结果,如何得到 n?

c - 在 C i/o 中跳过代码行