«

PE文件详解 - DOS头

ljierui 发布于 阅读:101 技术杂谈


1、PE文件详解

1.1、名词解析

名词 解析
泛指一个数据结构的起始位置,这个头可能是指一个文件的起始结构,也可能是指结构中的起始字段
偏移 多用于文件中,用于指定文件中的某个位置,例如一个文件的大小为0x10字节,那么偏移0XB就是指这个文件的第11个字节
x86平台内存中管理数据的最小单位,大小一般为4kb
区段 区段是指PE文件结构中的一个数据段,在PE文件结构中,不同类型的数据往往会被保存在不同的区段中
映像 泛指映射在内存中的PE结构的可执行文件(如exe,dll,sys,ocx)
字段 指的是数据结构中的最小单位

1.2、MS-DOS头

#include<stdio.h>

// 设置结构体对其方式
#pragma pack(push,1)
typedef struct {
    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;         // 初始的SS值
    unsigned short e_sp;         // 初始的SP值
    unsigned short e_csum;       // 校验和
    unsigned short e_ip;         // 初始的IP值
    unsigned short e_cs;         // 初始的CS值
    unsigned short e_lfarlc;     // 重定位表的文件地址
    unsigned short e_ovno;       // 覆盖号
    unsigned short e_res[4];     // 保留字段
    unsigned short e_oemid;      // OEM标识符
    unsigned short e_oeminfo;    // OEM信息
    unsigned short e_res2[10];   // 保留字段
    unsigned int e_lfanew;       // 新的PE头的文件地址
}IMAGE_DOS_HEADER;
#pragma pack(pop)

int main() {
    IMAGE_DOS_HEADER doHeader;

    // 打开PE文件,读取DOS头
    FILE* file = fopen("1.exe","rb");

    if (file == NULL)
    {
        printf("无法打开文件");
        return 1;
    }
    fread(&doHeader, sizeof(IMAGE_DOS_HEADER), 1, file);
    printf("e_magic: 0x%X\n", doHeader.e_magic);
    printf("e_cblp: %u\n", doHeader.e_cblp);
    printf("e_cp: %u\n", doHeader.e_cp);
    printf("e_crlc: %u\n", doHeader.e_crlc);
    printf("e_lfanew: %lx\n", doHeader.e_lfanew);
    return 0;
}

1.2.1、通过代码读取DOS头

#include<stdio.h>
#include<Windows.h>

int main()
{
    FILE* pFile = NULL;
    char* buffer;
    int nFileLength = 0;
    errno_t err = fopen_s(&pFile, "E:\\C_code\\MyDemo\\Debug\\MyDemo.exe", "rb");
    if (err != 0)
    {
        // 处理文件打开错误
        printf("Failed to open file.\n");
        return 1;
    }
    // fseek()设置文件指针的位置。这里将文件指针移动到文件末尾
    // SEEK_END 指定偏移量为0
    fseek(pFile, 0, SEEK_END);
    // ftell() 获取文件指针的当前位置,也就是文件的长度
    nFileLength = ftell(pFile);
    // rewind() 将文件指针重置到文件开头
    rewind(pFile);
    // 存储缓冲区大小
    // 计算方式:文件长度乘以sizeof(char)(sizeof(char)表示char类型的大小,通常是1字节),再加1字节用于存储字符串结束符\0
    int imageLength = nFileLength * sizeof(char) + 1;
    // 动态分配内存 : malloc函数动态分配了一块内存,大小为imageLength字节
    buffer = (char*)malloc(imageLength);
    // memset() :将分配的内存初始化为0。
    memset(buffer, 0, nFileLength * sizeof(char) + 1);
    // fread函数用于从文件中读取数据。这里将文件中的内容读取到之前分配的缓冲区buffer中,每次读取1字节,总共读取imageLength个字节。
    fread(buffer, 1, imageLength, pFile);

    // 定义指向 PIMAGE_DOS_HEADER的指针 ReadDosHeader
    PIMAGE_DOS_HEADER ReadDosHeader;
    // 因为buffer是char类型,所以要转成指针类型
    // 目的是将缓冲区中的数据解释为IMAGE_DOS_HEADER结构
    ReadDosHeader = (PIMAGE_DOS_HEADER)buffer;

    // 打印指针中的数据
    printf("MS-DOS Info:\n");
    printf("MZ标志位:%x\n", ReadDosHeader->e_magic);
    printf("PE头位置:%x\n", ReadDosHeader->e_lfanew);

    // 释放动态内存
    free(buffer);
    // 关闭文件
    fclose(pFile);
    return 0;

}

PE文件

推荐阅读: