12558网页游戏私服论坛

 找回密码
 立即注册
游戏开服表 申请开服
游戏名称 游戏描述 开服状态 游戏福利 运营商 游戏链接
攻城掠地-仿官 全新玩法,觉醒武将,觉醒技能 每周新区 经典复古版本,长久稳定 进入游戏
巅峰新版攻 攻城掠地公益服 攻城掠地SF 新兵种、新武将(兵种) 进入游戏
攻城掠地公 散人玩家的天堂 新开 进入游戏
改版攻城掠 上线即可国战PK 稳定新区 全新改版,功能强大 进入游戏
少年江山 高福利高爆率 刚开一秒 江湖水落潜蛟龙 进入游戏
太古封魔录 开服送10亿钻石 福利多多 不用充钱也可升级 进入游戏
神魔之道 签到送元宝 稳定开新区 送豪华签到奖励 进入游戏
神奇三国 统帅三军,招揽名将 免费玩新区 激情国战,征战四方 进入游戏
龙符 三日豪礼领到爽 天天开新区 助你征战无双 进入游戏
王者之师 免费领豪华奖励 免费玩新区 6元送6888元宝 进入游戏
查看: 306|回复: 0

PE文件笔记五 PE文件头之扩展PE头

[复制链接]

516

主题

516

帖子

1042

积分

实习版主

Rank: 7Rank: 7Rank: 7

积分
1042
发表于 2021-7-26 01:04:58 | 显示全部楼层 |阅读模式
继承PE系列笔记的更新
PE其它笔记索引可前往:
PE文件笔记一 PE介绍
继承具体学习PE的各个结构细节,前面学完了标准PE头,接着学习扩展PE头
由于PE文件头的内容较多,故要拆分为多个笔记,此笔记主要为扩展PE头
PS:扩展PE头的成员较多,可以先看个大概后联合下面的实战分析来学习扩展PE头的成员
扩展PE头

扩展PE头所属

扩展PE头是PE文件头中的一个成员


32位所属

typedef struct _IMAGE_NT_HEADERS {    DWORD Signature;                                            //PE文件头标识    IMAGE_FILE_HEADER FileHeader;                               //标准PE头    IMAGE_OPTIONAL_HEADER32 OptionalHeader;                                //扩展PE头 32位} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;64位所属

typedef struct _IMAGE_NT_HEADERS64 {    DWORD Signature;                                       //PE文件头标识    IMAGE_FILE_HEADER FileHeader;                          //标准PE头            IMAGE_OPTIONAL_HEADER64 OptionalHeader;                //扩展PE头 64位} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;两种扩展PE头差异

两种结构

扩展PE头的结构根据步伐是32位或64位而分成了两种结构,而PE文件头则因扩展PE头的差异也被分成了两种结构
PE文件头结构说明_IMAGE_NT_HEADERS32位步伐对应的PE文件头结构_IMAGE_NT_HEADERS6464位步伐对应的PE文件头结构_IMAGE_NT_HEADERS对应C中的结构体(类型)说明"PE",0,0DOWRDPE标识IMAGE_FILE_HEADERIMAGE_FILE_HEADER标准PE头IMAGE_OPTIONAL_HEADER32IMAGE_OPTIONAL_HEADER32扩展PE头 32位_IMAGE_NT_HEADERS64对应C中的结构体(类型)说明"PE",0,0DOWRDPE标识,固定值不可变IMAGE_FILE_HEADERIMAGE_FILE_HEADER标准PE头IMAGE_OPTIONAL_HEADER64IMAGE_OPTIONAL_HEADER64扩展PE头 64位结构体比较

32位结构体

typedef struct _IMAGE_OPTIONAL_HEADER {    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];} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;64位结构体

typedef 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];} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;差异

成员\扩展PE头_IMAGE_OPTIONAL_HEADER_IMAGE_OPTIONAL_HEADER64BaseOfDataDWORD无此成员ImageBaseDWORDULONGLONGSizeOfStackReserveDWORDULONGLONGSizeOfStackCommitDWORDULONGLONGSizeOfHeapReserveDWORDULONGLONGSizeOfHeapCommitDWORDULONGLONG可以看到,64位相比于32位其实并没有太大的区别,只是删去了一个成员 以及 五个成员的数据类型由DWORD变为ULONGLONG
因为其区别并不明显,因此以32位结构体作为例子分析,64位结构体也近似相同
32位扩展PE头分析

扩展PE头中的成员较多,一般情况只需掌握部分重点即可(重点为表格中加黑的成员)
下面的分析参考自官方文档:ns-winnt-image_optional_header32和《Windows PE 权威指南》
PS:下面的分析较为冗长,类似参考文档,可以先跳过,先看下面的实战分析根据实战里的数据到对应的成员参考其含义
成员数据宽度说明MagicWORD(2字节)镜像文件的状态,可用于判断步伐是32位还是64位MajorLinkerVersionBYTE(字节)链接器的主要版本号MinorLinkerVersionBYTE(字节)链接器的次要版本号SizeOfCodeDWORD(4字节)代码段的大小SizeOfInitializedDataDWORD(4字节)初始化数据段的大小SizeOfUninitializedDataDWORD(4字节)未初始化数据段的大小AddressOfEntryPointDWORD(4字节)步伐入口BaseOfCodeDWORD(4字节)代码开始的基址BaseOfDataDWORD(4字节)数据开始的基址ImageBaseDWORD(4字节)内存镜像基址SectionAlignmentDWORD(4字节)内存对齐FileAlignmentWORD(2字节)文件对齐MajorOperatingSystemVersionWORD(2字节)标识操作体系版本号 主版本号MinorOperatingSystemVersionWORD(2字节)标识操作体系版本号 次版本号MajorImageVersionWORD(2字节)PE文件自身的版本号MinorImageVersionWORD(2字节)PE文件自身的版本号MajorSubsystemVersionWORD(2字节)运行所需子体系版本号MinorSubsystemVersionWORD(2字节)运行所需子体系版本号Win32VersionValueDWORD(4字节)子体系版本的值,必须为0SizeOfImageDWORD(4字节)Image大小SizeOfHeadersDWORD(4字节)所有头+节表按照文件对齐后的大小CheckSumDWORD(4字节)校验和SubsystemWORD(2字节)子体系DllCharacteristicsWORD(2字节)文件特性 不只是针对DLL文件的SizeOfStackReserveDWORD(4字节)初始化时保存的栈大小SizeOfStackCommitDWORD(4字节)初始化时实际提交的大小SizeOfHeapReserveDWORD(4字节)初始化时保存的堆大小SizeOfHeapCommitDWORD(4字节)初始化时实践提交的大小LoaderFlagsDWORD(4字节)调试相关NumberOfRvaAndSizesDWORD(4字节)目次项数目DataDirectory[16]IMAGE_DATA_DIRECTORY[16]=128字节指向数据目次中第一个IMAGE_DATA_DIRECTORY结构的指针(数据目次项)Magic

镜像文件的状态。该成员可以是以下值之一
值含义IMAGE_NT_OPTIONAL_HDR_MAGIC该文件是一个可执行的映像。这个值在32位应用步伐中定义为IMAGE_NT_OPTIONAL_HDR32_MAGIC,在64位应用步伐中定义为IMAGE_NT_OPTIONAL_HDR64_MAGICIMAGE_NT_OPTIONAL_HDR32_MAGIC=0x10b该文件是一个可执行的映像(32位)IMAGE_NT_OPTIONAL_HDR64_MAGIC=0x20b该文件是一个可执行的映像(64位)IMAGE_ROM_OPTIONAL_HDR_MAGIC=0x107该文件是ROM镜像MajorLinkerVersion

链接器版本号
MinorLinkerVersion

链接器次要版本号
SizeOfCode

代码段的大小(以字节为单元),假如有多个代码段,则为所有这些代码段的总和。是文件对齐后的大小 编译器填的 没用(不一定正确)
SizeOfInitializedData

初始化数据段的大小(以字节为单元),假如有多个初始化数据段,则为所有这些数据段的总和。是文件对齐后的大小 编译器填的 没用(不一定正确)
SizeOfUninitializedData

未初始化数据段的大小(以字节为单元),假如有多个未初始化数据段,则为所有这些数据段的总和。是文件对齐后的大小 编译器填的 没用(不一定正确)
AddressOfEntryPoint

一个指向入口点函数的指针,相对于Image的基址。

  • 对于可执行文件,这是起始地点
  • 对于设备驱动步伐,这是初始化函数的地点
  • 入口点函数对于dll是可选的。当没有入口点存在时,该成员为零
BaseOfCode

指向代码段开头的指针,相对于ImageBase。编译器填的  没用(不一定正确)
BaseOfData

指向数据段开头的指针,相对于ImageBase。编译器填的  没用(不一定正确)
ImageBase

Image(PE文件)载入内存时第一个字节的首选地点。该值是64K字节的倍数

  • dll的默认值是0x10000000
  • 应用步伐的默认值为0x00400000,
  • Windows CE上的默认值为0x00010000
SectionAlignment

加载到内存中的节的对齐方式,以字节为单元。该值必须大于或即是FileAlignment(文件对齐)成员。默认值是体系的页面大小
FileAlignment

Image(PE文件)中各节的原始数据(以字节为单元)的对齐方式。该值应该是512到64K(包括)之间2的幂。缺省值是512。假如SectionAlignment成员小于体系页面大小,则该成员必须与SectionAlignment相同
MajorOperatingSystemVersion

所需操作体系的主要版本号
MinorOperatingSystemVersion

所需操作体系的次要版本号
MajorImageVersion

镜像(PE文件)的主版本号
MinorImageVersion

镜像(PE文件)的次要版本号
MajorSubsystemVersion

子体系的主要版本号
Win32VersionValue

该成员是保存的,并且必须为0
SizeOfImage

Image的大小,以字节为单元,包括所有头。必须是多个SectionAlignment
内存中整个PE文件的映射的尺寸,可比实际的值大,必须是SectionAlignment的整数倍
SizeOfHeaders

下列项的组合大小,舍入为“文件对齐”成员中指定值的倍数

  • IMAGE_DOS_HEADER(DOS MZ头) 中的最后一个成员e_lfanew
  • PE文件头标志 signature 的 大小 4字节
  • IMAGE_FILE_HEADER(标准PE头)的大小
  • 扩展PE头的大小
  • 所有节头(节表)的大小
SizeOfHeaders=
{
e_lfanew
+sizeof(signature)
+sizeof(_IMAGE_FILE_HEADER)
+sizeof(_IMAGE_OPTIONAL_HEADER)
+sizeof(_IMAGE_SECTION_HEADER)
}(文件对齐)
即 DOS部首+PE文件头+节表 按照文件对齐后的大小
CheckSum

Image(PE文件)校验和。以下文件在加载时举行验证:所有驱动步伐,在引导时加载的任何DLL,以及加载到关键体系进程中的任何DLL
Subsystem

运行此映像所需的子体系。定义了以下值:
宏定义值含义IMAGE_SUBSYSTEM_UNKNOWN0未知的子体系IMAGE_SUBSYSTEM_NATIVE1不必要子体系(设备驱动步伐和本机体系进程)IMAGE_SUBSYSTEM_WINDOWS_GUI2Windows图形用户界体面体系IMAGE_SUBSYSTEM_WINDOWS_CUI3Windows字符模式用户界面(CUI)子体系IMAGE_SUBSYSTEM_OS2_CUI5OS/2 CUI子体系IMAGE_SUBSYSTEM_POSIX_CUI7POSIX CUI子体系IMAGE_SUBSYSTEM_WINDOWS_CE_GUI9Windows CE体系IMAGE_SUBSYSTEM_EFI_APPLICATION10可扩展固件接口(EFI)应用步伐IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER11带有引导服务的EFI驱动步伐IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER12带有运行时服务的EFI驱动步伐IMAGE_SUBSYSTEM_EFI_ROM13EFI ROM镜像IMAGE_SUBSYSTEM_XBOX14Xbox体系IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION16启动应用步伐DllCharacteristics

官方文档版本

Image的DLL特性,定义了以下值
宏定义值含义无0x0001保存,必须为0无0x0002保存,必须为0无0x0004保存,必须为0无0x0008保存,必须为0IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA0x0020具有64位地点空间的ASLRIMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE0x0040DLL可以在加载时重新定位IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY0x0080逼迫举行代码完备性查抄。假如你设置了这个标志,并且section只包含未初始化的数据,那么将该section的IMAGE_SECTION_HEADER的PointerToRawData成员设置为0;否则,由于无法验证数字签名,Image将无法加载IMAGE_DLLCHARACTERISTICS_NX_COMPAT0x0100该映像与数据执行预防(DEP)兼容IMAGE_DLLCHARACTERISTICS_NO_ISOLATION0x0200映像可以被隔离,但不应该被隔离IMAGE_DLLCHARACTERISTICS_NO_SEH0x0400该映像不使用结构化异常处理(SEH)。在此映像中不能调用任何处理步伐IMAGE_DLLCHARACTERISTICS_NO_BIND0x0800不要绑定映像IMAGE_DLL_CHARACTERISTICS_APPCONTAINER0x1000映像应该在AppContainer中执行IMAGE_DLLCHARACTERISTICS_WDM_DRIVER0x2000一个WDM驱动IMAGE_DLL_CHARACTERISTICS_GUARD_CF0x4000映像支持控制流掩护(Control Flow Guard)IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE0x8000该映像是终端服务器感知的PE权威指南版本



SizeOfStackReserve

为堆栈保存的字节数。只有SizeOfStackCommit成员指定的内存在加载时被提交;其余的页面每次只提供一个页面,直到达到这个预留大小
SizeOfStackCommit

要提交给堆栈的字节数
SizeOfHeapReserve

为本地堆保存的字节数。只有SizeOfHeapCommit成员指定的内存在加载时被提交;其余的页面每次只提供一个页面,直到达到这个预留大小
SizeOfHeapCommit

要为本地堆提交的字节数
LoaderFlags

该成员已逾期
NumberOfRvaAndSizes

可选头的其余部分中的目次条目数。每个条目都形貌了一个位置和大小
DataDirectory

指向数据目次中第一个IMAGE_DATA_DIRECTORY结构的指针
所需目次条目标索引号。该参数可以是以下值之一:
宏定义值含义IMAGE_DIRECTORY_ENTRY_ARCHITECTURE7特定于体系结构的数据,预留为0IMAGE_DIRECTORY_ENTRY_BASERELOC5基地点重定位表IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT11绑定导入表IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR14COM形貌符表IMAGE_DIRECTORY_ENTRY_DEBUG6调试表IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT13延迟导入表IMAGE_DIRECTORY_ENTRY_EXCEPTION3异常表IMAGE_DIRECTORY_ENTRY_EXPORT0导出表IMAGE_DIRECTORY_ENTRY_GLOBALPTR8全局指针的相对捏造地点IMAGE_DIRECTORY_ENTRY_IAT12导入地点表IMAGE_DIRECTORY_ENTRY_IMPORT1导入表IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG10加载配置表IMAGE_DIRECTORY_ENTRY_RESOURCE2资源表IMAGE_DIRECTORY_ENTRY_SECURITY4安全表IMAGE_DIRECTORY_ENTRY_TLS9线程本地存储表实战分析

获取数据

从先前分析的标准PE头的结尾开始看起,选中部分为扩展PE头,共占224字节

按顺序依次将数据填入对应的成员得到:
成员值Magic0x010BMajorLinkerVersion0x09MinorLinkerVersion0x00SizeOfCode0x00199200SizeOfInitializedData0x000BEC00SizeOfUninitializedData0x00000000AddressOfEntryPoint0x0016AF12BaseOfCode0x00001000BaseOfData0x0019B000ImageBase0x00400000SectionAlignment0x00001000FileAlignment0x00000200MajorOperatingSystemVersion0x0005MinorOperatingSystemVersion0x0000MajorImageVersion0x0000MinorImageVersion0x0000MajorSubsystemVersion0x0005MinorSubsystemVersion0x0000Win32VersionValue0x00000000SizeOfImage0x00298000SizeOfHeaders0x00000400CheckSum0x0025cd89Subsystem0x0002DllCharacteristics0x8140SizeOfStackReserve0x00100000SizeOfStackCommit0x00001000SizeOfHeapReserve0x00100000SizeOfHeapCommit0x00001000LoaderFlags0x00000000NumberOfRvaAndSizes0x00000010DataDirectory[16]留作之后的笔记分析数据

鉴于篇幅和实用性考虑,只分析比较紧张的成员
Magic

Magic的值为0x010B,根据前面的分析可知:该文件是一个可执行的映像(32位)
AddressOfEntryPoint

AddressOfEntryPoint的值为0x0016AF12,根据前面的分析可知:一个指向入口点函数的指针,相对于Image的基址是0x0016AF12
而Image的基址就是后面的 ImageBase = 0x00400000
于是该指针的的绝对地点为基址+偏移=0x00400000+0x0016AF12=0x0056AF12
于是得到了该步伐的步伐入口点为0x0056AF12,为了验证其正确性,使用OD打开步伐

可以看到OD自动停止在了步伐入口点0x0056AF12
PS:假如OD停息到了其它地方,则必要设置一下OD的停止点:
选项→调试设置(或使用快捷键Alt+0)

变乱→主模块入口点

ImageBase

ImageBase的值为0x00400000,根据前面的分析可知:ImageBase恰好是应用步伐的默认值0x00400000
且ImageBase=0x00400000是64K字节的倍数
SectionAlignment、FileAlignment、SizeOfHeaders

有关内存对齐和文件对齐的相关内容 在PE文件笔记二 PE文件的两种状态已经学习过了,这里不再赘述
SizeOfImage

SizeOfImage的值为0x00298000,根据前面的分析可知:
SizeOfImage表示内存中整个PE文件的映射的尺寸,可比实际的值大,必须是SectionAlignment的整数倍
于是打开步伐,并使用WinHex查看其在内存中的状态(在PE文件笔记二 PE文件的两种状态中已经演示过,这里不再赘述,直接看结果)
用WinHex附加上步伐后,拉到最底部,查看文件的最大偏移量

可以看到此时的最大偏移量为697FFF,用最大偏移量减去ImageBase 0x400000得到相对偏移为297FFF=SizeOfImage-1
验证了SizeOfImage可以比实际的值大
再验证SizeOfImage为内存对齐SectionAlignment的整数倍:
SizeOfImage/SectionAlignment=0x00298000/0x1000=0x298,可以整除,验证完毕
CheckSum

CheckSum从头部开始 两两字节不断相加,一直相加到最后,期间假如溢出,则直接舍去溢出部分,最后加完的结果再加上整个文件的长度就得到了CheckSum,操作体系就是通过这种方式来查验文件是否被修改

但只对以下文件在加载时举行验证:所有驱动步伐,在引导时加载的任何DLL,以及加载到关键体系进程中的任何DLL
此时步伐自己并不属于上面提到的文件类型,于是此时的CheckSum并不生效
由于CheckSum的计算比较麻烦,于是这里就略去CheckSum计算的验证,简朴说明了CheckSum的计算原理
下面来验证一下CheckSum的作用范围,此时步伐的CheckSum应该是无效的
CheckSum的值为0x0025cd89,将它修改为0
1.找到CheckSum

2.选中CheckSum,鼠标右键→编辑

3.填充选块

4.填充0

5.修改完毕

6.保存,然后打开步伐
使用快捷键 Ctrl+S 保存,确定

打开步伐,仍然可以正常运行,验证完毕

Subsystem

Subsystem的值为0x0002,根据前面的分析可知:运行该步伐所需子体系为:Windows图形用户界体面体系
DllCharacteristics

DllCharacteristics的值为0x8140
通过PE权威指南

转化为二进制得到:1000000101000000
数据位为1的位数有:第6位,第8位,第15位
根据前面的分析可知:DLL可以在加载时重新定位、该映像与数据执行预防(DEP)兼容、该映像是终端服务器感知的
通过官方文档

DllCharacteristics的值为0x8140=0x8000+0x0100+0x0040
根据前面的分析可知:DLL可以在加载时重新定位、该映像与数据执行预防(DEP)兼容、该映像是终端服务器感知的
自写代码解析PE文件头

在先前代码的根本上,进一步改进
// PE.cpp : Defines the entry point for the console application.//#include #include #include //在VC6这个比较旧的情况里,没有定义64位的这个宏,必要自己定义,在VS2019中无需自己定义#define IMAGE_FILE_MACHINE_AMD64  0x8664int main(int argc, char* argv[]){        //创建DOS对应的结构体指针        _IMAGE_DOS_HEADER* dos;        //读取文件,返回文件句柄        HANDLE hFile = CreateFileA("C:\\Users\\lyl610abc\\Desktop\\dbgview64.exe", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);        //根据文件句柄创建映射        HANDLE hMap = CreateFileMappingA(hFile, NULL, PAGE_READONLY, 0, 0, 0);        //映射内容        LPVOID pFile = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);        //类型转换,用结构体的方式来读取        dos = (_IMAGE_DOS_HEADER*)pFile;        //输出dos->e_magic,以十六进制输出        printf("dos->e_magic:%X\n", dos->e_magic);        //创建指向PE文件头标志的指针        DWORD* peId;        //让PE文件头标志指针指向其对应的地点=DOS首地点+偏移        peId = (DWORD*)((UINT)dos + dos->e_lfanew);        //输出PE文件头标志,其值应为4550,否则不是PE文件        printf("peId:%X\n", *peId);        //创建指向可选PE头的第一个成员magic的指针        WORD* magic;        //让magic指针指向其对应的地点=PE文件头标志地点+PE文件头标志大小+标准PE头大小        magic = (WORD*)((UINT)peId + sizeof(DWORD) + sizeof(_IMAGE_FILE_HEADER));        //输出magic,其值为0x10b代表32位步伐,其值为0x20b代表64位步伐        printf("magic:%X\n", *magic);        //根据magic判断为32位步伐还是64位步伐        switch (*magic) {        case IMAGE_NT_OPTIONAL_HDR32_MAGIC:        {                printf("32位步伐\n");                //确定为32位步伐后,就可以使用_IMAGE_NT_HEADERS来接收数据了                //创建指向PE文件头的指针                _IMAGE_NT_HEADERS* nt;                //让PE文件头指针指向其对应的地点                nt = (_IMAGE_NT_HEADERS*)peId;                printf("Machine:%X\n", nt->FileHeader.Machine);                printf("Magic:%X\n", nt->OptionalHeader.Magic);                break;        }        case IMAGE_NT_OPTIONAL_HDR64_MAGIC:        {                printf("64位步伐\n");                //确定为64位步伐后,就可以使用_IMAGE_NT_HEADERS64来接收数据了                //创建指向PE文件头的指针                _IMAGE_NT_HEADERS64* nt;                nt = (_IMAGE_NT_HEADERS64*)peId;                printf("Machine:%X\n", nt->FileHeader.Machine);                printf("Magic:%X\n", nt->OptionalHeader.Magic);                break;        }        default:        {                printf("error!\n");                break;        }        }        return 0;}运行结果

32位步伐


64位步伐


代码说明

代码基于上一次的笔记PE文件笔记四 PE文件头之标准PE头改进了判断步伐32位或64位的方法,并没有什么太大的变动,有关代码的分析在上一次笔记已经给出,这里也就不再赘述
总结


  • 扩展PE头根据步伐是32位或64位而对应两种不同的结构
  • 根据扩展PE头的第一个成员Magic可以判断出步伐是32位的还是64位的
  • 两种扩展PE头结构实际相差不多,掌握了32位的结构其实也相当于掌握了64位的结构
  • 扩展PE头英文虽然为optional header,译为可选头,但它其实必不可少且极其紧张
  • 扩展PE头中的DataDirectory内容涉及较多,留作之后
附件

附上本笔记中分析的EverEdit文件:点我下载

来源:http://www.12558.net
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
楼主热帖
回复

使用道具 举报

*滑块验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|12558网页游戏私服论坛 |网站地图

GMT+8, 2024-4-26 11:39 , Processed in 0.171875 second(s), 31 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表