pe格式从入门到图形化显示(三)-可选头



前言

通过分析和解析Windows PE格式,并使用qt进行图形化显示


一、什么是Windows PE格式可选头?

PE文件格式的可选头(Optional Header)是一个结构体,它包含了关于PE文件的额外信息,如文件的属性、内存布局、加载参数等。可选头的结构体有两个版本:IMAGE_OPTIONAL_HEADER32和IMAGE_OPTIONAL_HEADER64。它们的主要区别在于64位版本支持64位地址空间,而32位版本仅支持32位地址空间。

二、怎么区别32位版本和64位版本

要区分32位PE文件版本和64位PE文件版本,可以查看PE文件的可选头中的Magic字段。Magic字段是一个标识PE文件类型的幻数,它有两个值:

对于32位PE文件,Magic字段的值为0x010B。
对于64位PE文件,Magic字段的值为0x020B。
因此,只需检查PE文件的可选头中的Magic字段,就可以判断PE文件是32位版本还是64位版本。如果Magic字段的值为0x010B,则PE文件是32位版本;如果Magic字段的值为0x020B,则PE文件是64位版本。

三、解析可选头并显示

1.32位和64位区别

32位PE文件版本和64位PE文件版本的结构体主要区别在于它们的可选头结构体。32位PE文件使用IMAGE_OPTIONAL_HEADER32结构体,而64位PE文件使用IMAGE_OPTIONAL_HEADER64结构体。这两个结构体的主要区别在于它们的字段类型和大小。
以下是一些主要的区别:

1、对于32位PE文件,IMAGE_OPTIONAL_HEADER32结构体中的ImageBase字段是一个DWORD类型,表示PE文件默认装入的基地址而对于64位PE文件,IMAGE_OPTIONAL_HEADER64结构体中的ImageBase字段是一个ULONGLONG类型,表示PE文件默认装入的基地址。

2、对于32位PE文件,IMAGE_OPTIONAL_HEADER32结构体中的SizeOfStackReserve和SizeOfStackCommit字段是DWORD类型,表示线程的栈初始保留的虚拟内存大小和初始提交的虚拟内存大小。而对于64位PE文件,IMAGE_OPTIONAL_HEADER64结构体中的SizeOfStackReserve和SizeOfStackCommit字段是ULONGLONG类型,表示线程的栈初始保留的虚拟内存大小和初始提交的虚拟内存大小。

3、对于32位PE文件,IMAGE_OPTIONAL_HEADER32结构体中的SizeOfHeapReserve和SizeOfHeapCommit字段是DWORD类型,表示进程的堆保留的虚拟内存大小和初始提交的虚拟内存大小。而对于64位PE文件,IMAGE_OPTIONAL_HEADER64结构体中的SizeOfHeapReserve和SizeOfHeapCommit字段是ULONGLONG类型,表示进程的堆保留的虚拟内存大小和初始提交的虚拟内存大小。

2.32位可选头数据结构以及字段描述

Magic:指定PE文件的目标机器类型,如I386、AMD64、ARM等。
MajorLinkerVersion:表示PE文件的主要链接器版本号。
MinorLinkerVersion:表示PE文件的次要链接器版本号。
SizeOfCode:表示PE文件中代码段的大小。
SizeOfInitializedData:表示PE文件中已初始化数据段的大小。
SizeOfUninitializedData:表示PE文件中未初始化数据段的大小。
AddressOfEntryPoint:表示PE文件的入口点地址。
BaseOfCode:表示PE文件中代码段的基址。
BaseOfData:表示PE文件中数据段的基址。
ImageBase:表示PE文件在内存中的基址。
SectionAlignment:表示PE文件中节的对齐方式。
FileAlignment:表示PE文件中文件的对齐方式。
MajorOperatingSystemVersion:表示PE文件所需的主要操作系统版本号。
MinorOperatingSystemVersion:表示PE文件所需的次要操作系统版本号。
MajorImageVersion:表示PE文件的主要图像版本号。
MinorImageVersion:表示PE文件的次要图像版本号。
MajorSubsystemVersion:表示PE文件所需的主要子系统版本号。
MinorSubsystemVersion:表示PE文件所需的次要子系统版本号。
Win32VersionValue:表示PE文件的Win32版本值。
SizeOfImage:表示PE文件在内存中的大小。
SizeOfHeaders:表示PE文件中头部的大小。
CheckSum:表示PE文件的校验和。
Subsystem:表示PE文件所需的子系统类型,如GUI、CUI等。
DllCharacteristics:表示PE文件的DLL特性。
SizeOfStackReserve:表示PE文件的堆栈保留大小。
SizeOfStackCommit:表示PE文件的堆栈提交大小。
SizeOfHeapReserve:表示PE文件的堆保留大小。
SizeOfHeapCommit:表示PE文件的堆提交大小。
LoaderFlags:表示PE文件的加载器标志。
NumberOfRvaAndSizes:表示PE文件中数据目录的数量。
DataDirectory:表示PE文件中数据目录的数组。

struct IMAGE_OPTIONAL_HEADER32 {
    WORD Magic;
    BYTE MajorLinkerVersion;
    BYTE MinorLinkerVersion;
    DWORD SizeOfCode;
    DWORD SizeOfInitializedData;
    DWORD SizeOfUninitializedData;
    DWORD AddressOfEntryPoint;
    DWORD BaseOfCode;
    DWORD BaseOfData;
    DWORD ImageBase;
    DWORD SectionAlignment;
    DWORD FileAlignment;
    WORD MajorOperatingSystemVersion;
    WORD MinorOperatingSystemVersion;
    WORD MajorImageVersion;
    WORD MinorImageVersion;
    WORD MajorSubsystemVersion;
    WORD MinorSubsystemVersion;
    DWORD Win32VersionValue;
    DWORD SizeOfImage;
    DWORD SizeOfHeaders;
    DWORD CheckSum;
    WORD Subsystem;
    WORD DllCharacteristics;
    DWORD SizeOfStackReserve;
    DWORD SizeOfStackCommit;
    DWORD SizeOfHeapReserve;
    DWORD SizeOfHeapCommit;
    DWORD LoaderFlags;
    DWORD NumberOfRvaAndSizes;
    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
};

3.64位可选头数据结构以及字段描述

Magic:指定PE文件的目标机器类型,如AMD64等。
MajorLinkerVersion:表示PE文件的主要链接器版本号。
MinorLinkerVersion:表示PE文件的次要链接器版本号。
SizeOfCode:表示PE文件中代码段的大小。
SizeOfInitializedData:表示PE文件中已初始化数据段的大小。
SizeOfUninitializedData:表示PE文件中未初始化数据段的大小。
AddressOfEntryPoint:表示PE文件的入口点地址。
BaseOfCode:表示PE文件中代码段的基址。
ImageBase:表示PE文件在内存中的基址。
SectionAlignment:表示PE文件中节的对齐方式。
FileAlignment:表示PE文件中文件的对齐方式。
MajorOperatingSystemVersion:表示PE文件所需的主要操作系统版本号。
MinorOperatingSystemVersion:表示PE文件所需的次要操作系统版本号。
MajorImageVersion:表示PE文件的主要图像版本号。
MinorImageVersion:表示PE文件的次要图像版本号。
MajorSubsystemVersion:表示PE文件所需的主要子系统版本号。
MinorSubsystemVersion:表示PE文件所需的次要子系统版本号。
Win32VersionValue:表示PE文件的Win32版本值。
SizeOfImage:表示PE文件在内存中的大小。
SizeOfHeaders:表示PE文件中头部的大小。
CheckSum:表示PE文件的校验和。
Subsystem:表示PE文件所需的子系统类型,如GUI、CUI等。
DllCharacteristics:表示PE文件的DLL特性。
SizeOfStackReserve:表示PE文件的堆栈保留大小。
SizeOfStackCommit:表示PE文件的堆栈提交大小。
SizeOfHeapReserve:表示PE文件的堆保留大小。
SizeOfHeapCommit:表示PE文件的堆提交大小。
LoaderFlags:表示PE文件的加载器标志。
NumberOfRvaAndSizes:表示PE文件中数据目录的数量。
DataDirectory:表示PE文件中数据目录的数组。

struct IMAGE_OPTIONAL_HEADER64 {
    WORD Magic;
    BYTE MajorLinkerVersion;
    BYTE MinorLinkerVersion;
    DWORD SizeOfCode;
    DWORD SizeOfInitializedData;
    DWORD SizeOfUninitializedData;
    DWORD AddressOfEntryPoint;
    DWORD BaseOfCode;
    ULONGLONG ImageBase;
    DWORD SectionAlignment;
    DWORD FileAlignment;
    WORD MajorOperatingSystemVersion;
    WORD MinorOperatingSystemVersion;
    WORD MajorImageVersion;
    WORD MinorImageVersion;
    WORD MajorSubsystemVersion;
    WORD MinorSubsystemVersion;
    DWORD Win32VersionValue;
    DWORD SizeOfImage;
    DWORD SizeOfHeaders;
    DWORD CheckSum;
    WORD Subsystem;
    WORD DllCharacteristics;
    ULONGLONG SizeOfStackReserve;
    ULONGLONG SizeOfStackCommit;
    ULONGLONG SizeOfHeapReserve;
    ULONGLONG SizeOfHeapCommit;
    DWORD LoaderFlags;
    DWORD NumberOfRvaAndSizes;
    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
};

4.解析

bool PEParser::parserFileData(const QByteArray &fileData)
{
    //判断是否是MZ开头的文件
    if (fileData.left(2) != "MZ")
    {
        return false;
    }
    //解析DOS头
    parserDOSHeader(fileData.left(sizeof(IMAGE_DOS_HEADER)));
    //DOSStub数据
    m_dosStubData = fileData.mid(sizeof(IMAGE_DOS_HEADER), m_dosHeader.e_lfanew - sizeof(IMAGE_DOS_HEADER));
    long peAddress = m_dosHeader.e_lfanew;
    if (fileData.mid(peAddress, 2) != "PE")
    {
        return false;
    }
    m_fileData = fileData;
    //去除前4个字节的PE头标识
    long fileHeaderIndex = peAddress + 4;
    //记录文件头索引
    m_fileHeaderIndex = fileHeaderIndex;
    //解析标准PE文件头
    paserFileHeader(fileData.mid(fileHeaderIndex, sizeof(IMAGE_FILE_HEADER)));
    //解析扩展PE文件头
    long optionHeaderIndex = fileHeaderIndex + sizeof(IMAGE_FILE_HEADER);
    //记录扩展PE文件头索引
    m_optionHeaderIndex = optionHeaderIndex;
    //解析扩展PE文件头
    parserOptionHeader(fileData.mid(optionHeaderIndex, m_fileHeader.SizeOfOptionalHeader));
    return true;
}

void PEParser::parserOptionHeader(const QByteArray &peHeaderData)
{
    WORD magic = 0;
    QByteArray magicData = peHeaderData.mid(0, 2);
    memcpy(&magic, magicData.data(), magicData.size());
    m_directories.clear();
    if (magic == PEType::PE32 && peHeaderData.size() == sizeof(IMAGE_OPTIONAL_HEADER32))
    {
        const IMAGE_OPTIONAL_HEADER32 *peHeader = reinterpret_cast<const IMAGE_OPTIONAL_HEADER32 *>(peHeaderData.data());
        emit sendX86PEOptionHeader(*peHeader);
        m_optionalHeader32 = *peHeader;
        m_fileAlignment = peHeader->FileAlignment;
        m_imageBase = peHeader->ImageBase;
        m_sectionAlignment = peHeader->SectionAlignment;
        m_x86Flag = true;
    }
    else if (magic == PEType::PE64 && peHeaderData.size() == sizeof(IMAGE_OPTIONAL_HEADER64))
    {
        const IMAGE_OPTIONAL_HEADER64 *peHeader = reinterpret_cast<const IMAGE_OPTIONAL_HEADER64 *>(peHeaderData.data());
        emit sendX64PEOptionHeader(*peHeader);
        m_optionalHeader64 = *peHeader;
        m_fileAlignment = peHeader->FileAlignment;
        m_imageBase = peHeader->ImageBase;
        m_sectionAlignment = peHeader->SectionAlignment;
        m_x86Flag = false;
    }
}

5.显示

void MainWindow::showX86OptionalHeader(const IMAGE_OPTIONAL_HEADER32 &header)
{
    ui->lineEdit_sizeOfCode->setText(QString::asprintf("%08lX", header.SizeOfCode));
    ui->lineEdit_sizeOfImage->setText(QString::asprintf("%08lX",header.SizeOfImage));
    ui->lineEdit_baseOfCode->setText(QString::asprintf("%08lX", header.BaseOfCode));
    ui->lineEdit_baseOfData->setText(QString::asprintf("%08lX", header.BaseOfData));
    ui->lineEdit_entry->setText(QString::asprintf("%08lX", header.AddressOfEntryPoint));
    ui->lineEdit_imageBase->setText(QString::asprintf("%08lX", header.ImageBase));
    ui->lineEdit_sizeOfHead->setText(QString::asprintf("%08lX", header.SizeOfHeaders));
    ui->lineEdit_sectionAlign->setText(QString::asprintf("%08lX", header.SectionAlignment));
    ui->lineEdit_fileAlign->setText(QString::asprintf("%08lX", header.FileAlignment));
    ui->lineEdit_checkSum->setText(QString::asprintf("%08lX", header.CheckSum));
    ui->lineEdit_baseInfo->setText("PE 32 文件");
}

void MainWindow::showX64OptionalHeader(const IMAGE_OPTIONAL_HEADER64 &header)
{
    ui->lineEdit_sizeOfCode->setText(QString::asprintf("%08lX", header.SizeOfCode));
    ui->lineEdit_sizeOfImage->setText(QString::asprintf("%08lX",header.SizeOfImage));
    ui->lineEdit_baseOfCode->setText(QString::asprintf("%08lX", header.BaseOfCode));
    ui->lineEdit_entry->setText(QString::asprintf("%08lX", header.AddressOfEntryPoint));
    ui->lineEdit_imageBase->setText(QString::asprintf("%08lX", header.ImageBase));
    ui->lineEdit_sizeOfHead->setText(QString::asprintf("%08lX", header.SizeOfHeaders));
    ui->lineEdit_sectionAlign->setText(QString::asprintf("%08lX", header.SectionAlignment));
    ui->lineEdit_fileAlign->setText(QString::asprintf("%08lX", header.FileAlignment));
    ui->lineEdit_checkSum->setText(QString::asprintf("%08lX", header.CheckSum));
    ui->lineEdit_baseInfo->setText("PE 64 文件");
}

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mrack

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值