记PE文件结构实验,模拟文件内存加载过程。

发布时间 2023-09-08 19:01:53作者: F145H

记录文件结构试验

前言:使用的模拟程序是notepad.exe,主要记录其中的思路和遇到其中的困难。
实验目的:模拟内存加载PE文件的过程,将每个区段模拟加载到内存之中。
根据文件结构中头表中的信息,读取并sekk指针到Segment头。然后循环遍历Segment头将内容加载到Virtual Address中,主要目的是为了熟悉PE头的结构,同时也练习自己的代码能力。
贴出来最后的代码如下,只支持部分PE文件的模拟加载。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define QWORD unsigned long long
#define DWORD unsigned int
#define WORD unsigned short
void show_memory(unsigned char* s, int len) {
    printf("Addres:  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F     0123456789ABCDEF");
    for (int i = 0; i < (len / 0x10) + 1; ++i) {
        printf("\n%06X: ", i * 0x10);
        for (int j = 0; j < 0x10; ++j) {
            printf("%02X", s[i * 0x10 + j]);
            if (j == 3 || j == 7 || j == 0xb)
                putchar('|');
            else
                putchar(' ');
        }
        putchar(' ');
        putchar(' ');
        putchar(' ');
        putchar(' ');
        for (int j = 0; j < 0x10; ++j) {
            if (s[i * 0x10 + j] >= 'A' && s[i * 0x10 + j] <= 'z')
                printf("%c", s[i * 0x10 + j]);
            else
                putchar('.');
        }
    }
}
int main() {
    const char* filename = "C:\\Users\\LENOVO\\Desktop\\Practice\\316Buffer\\notepad_xp.exe";
    FILE* fp = fopen(filename, "rb");
    unsigned char* VirtualBuffer;
    DWORD SizeOfImage;
    DWORD AddressOfNewEXEHeader;
    char SectionHeaderName[9] = { 0 };
    DWORD Misc;
    DWORD VirtualAddress;
    DWORD SizeOfRawData;
    DWORD PointerToRawData;
    DWORD Characteristics;
    WORD NumberOfSection;
    WORD SizeOfOptionalHeader;
    WORD SizeOfHeaders;

    if (fp == NULL) {
        printf("Failed to open the file");
        exit(1);
    }
    fseek(fp, 0x3C, SEEK_SET);
    fread(&AddressOfNewEXEHeader, 4, 1, fp);
    fseek(fp, AddressOfNewEXEHeader + 0x6, SEEK_SET); // seek for new NT header and NumberOfSection


    fread(&NumberOfSection, 2, 1, fp); // get NumberOfSection
    fseek(fp, 0xC, SEEK_CUR); // seek for opt size
    fread(&SizeOfOptionalHeader, 2, 1, fp);

    fseek(fp, AddressOfNewEXEHeader + 0x50, SEEK_SET);
    fread(&SizeOfImage, 4, 1, fp); // get img size
    fread(&SizeOfHeaders, 2, 1, fp); // get headers size


    VirtualBuffer = (unsigned char*)malloc(SizeOfImage); // //get vadr
    if (VirtualBuffer == NULL) {
        printf("Failed to malloc the size %X", SizeOfImage);
        exit(1);
    }
    memset(VirtualBuffer, 0, SizeOfImage);
    fseek(fp, 0, SEEK_SET);
    fread(&VirtualBuffer[i], 0x400, 1, fp);

    for (int i = 0; i < NumberOfSection; ++i) {
        fseek(fp, AddressOfNewEXEHeader + 0x18 + SizeOfOptionalHeader + i * 0x28, SEEK_SET);
        fread(&SectionHeaderName, 1, 8, fp);
        printf("段名称: %s\n", SectionHeaderName);
        fread(&Misc, 4, 1, fp);
        printf("Misc(实际大小): %X\n", Misc);
        fread(&VirtualAddress, 4, 1, fp);
        printf("虚拟地址: %X\n", VirtualAddress);
        fread(&SizeOfRawData, 4, 1, fp);
        printf("区段大小: %X\n", SizeOfRawData);
        fread(&PointerToRawData, 4, 1, fp);
        printf("文件中偏移: %X\n", PointerToRawData);
        fseek(fp, 0xC, SEEK_CUR);
        fread(&Characteristics, 4, 1, fp);
        printf("属性值: %8X\n\n", Characteristics);

        fseek(fp, PointerToRawData, SEEK_SET);
        fread(&VirtualBuffer[VirtualAddress], Misc, 1, fp);
    }
    show_memory(VirtualBuffer, 0x1000);
    free(VirtualBuffer);
}```
中途遇到了一个问题:是文件偏移为 75h 的 0d 0d 0a 读出来只有 0d 0a,莫名其妙少了一个 0d ,但是从此往后的内容又都是正确的,本人为此甚至尝试了多个编译器,均失败告终。最后查找到原因是因为打开方式为"r",fread检测到 0d 0a 时认为这是文件结束标识,于是结束了读取内容。导致此处丢失了一个 0d 。在网络上找到原因后,将"r"改为"rb",最后成功读取了文件内容。