Как импортировать информацию из PE_file в двоичном виде в C - PullRequest
0 голосов
/ 28 апреля 2018

Я делаю анализатор формата файлов PE на языке Си. Когда я использовал Visual Studio , я мог сделать это намного проще. НО, я устал делать это без Visual Studio , чтобы улучшить свое программирование на Си. Это было сделано GCC (Мой ноутбук - MacBook).

Для анализа формата файла PE, как вы знаете, я должен использовать указатель файла и читать файл как 'rb' . Я сделал это, и, похоже, сработало хорошо ... Я хотел напечатать первое и второе слова ("MZ"), но он напечатал неизвестные (для меня) цифры.

P.S Я пишу немного другой код, ссылающийся на предыдущий, меньший, чем раньше. Но он печатает NULL. Это означает, что я написал код действительно неправильно ... PLZ, скажите мне, какие части неправильны

#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);
}

1 Ответ

0 голосов
/ 28 апреля 2018

У вас 2 большие проблемы с вашим кодом: вы смешиваете типы.

В DOS_HEADER все члены (кроме последнего) имеют тип unsigned short. Это важно.

В get_dos_header вы делаете

fread(fp_buffer, 2, 1, fp);
raw_info_dos_header.e_magic = fp_buffer;

что не так.

  1. Не используйте магические числа, используйте sizeof, чтобы получить правильные размеры
  2. Проверьте возвращаемое значение fread, особенно если вы анализируете двоичный файл формат, вы должны быть уверены, что вы прочитали именно то, что вы ожидаете.
  3. Намного легче иметь дело с fread, когда аргумент size равен 1, потому что только когда аргумент size равен 1, возвращаемое значение fread соответствует количество прочитанных байтов.
  4. e_magic - это unsigned short, fp_buffer - это char*. Это назначение не копируя содержимое, указанное fp_buffer, вы сохраняете адрес как если бы это было значение unsigned short. Вам нужно скопировать указанную память fp_buffer.

Также я не вижу смысла в том, чтобы вы выделяли буфер размером с файл когда вы читаете кусок за куском. Было бы проще, если бы вы не выделяли создайте буфер и используйте массив размером больше, чем вы собираетесь читать.

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_structures:

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 выше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...