windows下的可执行文件格式详解内容摘要:
的值。 它首先决定每个段需要多少字节,并且最后将页面总数向上取整至最接近的 SectionAlignment 边界,然后总数就是每个段个别需求之和了。 SizeOfHeaders。 这个域表示文件中有多少空间用来保存所有的文件头部,包括 MSDOS 头部、PE 文件头部、 PE 可选头部以及 PE 段 头部。 文件中所有的段实体就开始于这个位置。 CheckSum。 校验和是用来在装载时验证可执行文件的,它是由链接器设置并检验的。 由于创建这些校验和的算法是私有信息,所以在此不进行讨论。 Subsystem。 用于标识该可执行文件目标子系统的域。 每个可能的子系统取值列于 的IMAGE_OPTIONAL_HEADER 结构之后。 DllCharacteristics。 用来表示一个 DLL 映像是否为进程和线程的初始化及终止包含入口点的标记。 SizeOfStackReserve、 SizeOfStackCommit、 SizeOfHeapReserve、 SizeOfHeapCommit。 这些域控制要保留的地址空间数量,并且负责栈和默认堆的申请。 在默认情况下,栈和堆都拥有 1 个页面的申请值以及 16 个页面的保留值。 这些值可以使用链接器开关 STACKSIZE:与 HEAPSIZE:来设置。 LoaderFlags。 告知装载器是否在装载时中止和调试,或者默认地正常运行。 NumberOfRvaAndSizes。 这个域标识了接下来的 DataDirectory 数组。 请 注意它被用来标识这个数组,而不是数组中的各个入口数字,这一点非常重要。 DataDirectory。 数据目录表示文件中其它可执行信息重要组成部分的位置。 它事实上就是一个IMAGE_DATA_DIRECTORY 结构的数组,位于可选头部结构的末尾。 当前的 PE 文件格式定义了 16 种可能的数据目录,这之中的 11 种现在在使用中。 数据目录 之中所定义的数据目录为: // // 目录入口 // 导出目录 define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // 导入目录 define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // 资源目录 define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // 异常目录 define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 // 安全目录 define IMAGE_DIRECTORY_ENTRY_SECURITY 4 // 重定位基本表 define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // 调 试目录 define IMAGE_DIRECTORY_ENTRY_DEBUG 6 // 描述字串 define IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 // 机器值( MIPS GP) define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 // TLS 目录 define IMAGE_DIRECTORY_ENTRY_TLS 9 // 载入配置目录 define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 基本上 ,每个数据目录都是一个被定义为 IMAGE_DATA_DIRECTORY 的结构。 虽然数据目录入口本身是相同的,但是每个特定的目录种类却是完全唯一的。 每个数据目录的定义在本文的以后部分被描述为 “预定义段 ”。 // typedef struct _IMAGE_DATA_DIRECTORY { ULONG VirtualAddress。 ULONG Size。 } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY。 每个数据目录入口指定了该目录的尺寸 和相对虚拟地址。 如果你要定义一个特定的目录的话,就需要从可选头部中的数据目录数组中决定相对的地址,然后使用虚拟地址来决定该目录位于哪个段中。 一旦你决定了哪个段包含了该目录,该段的段头部就会被用于查找数据目录的精确文件偏移量位置。 所以要获得一个数据目录的话,那么首先你需要了解段的概念。 我在下面会对其进行描述,这个讨论之后还有一个有关如何定位数据目录的示例。 PE 文件段 PE 文件规范由目前为止定义的那些头部以及一个名为 “段 ”的一般对象组成。 段包含了文件的内容,包括代码、数据、资源以及其它 可执行信息,每个段都有一个头部和一个实体(原始数据)。 我将在下面描述段头部的有关信息,但是段实体则缺少一个严格的文件结构。 因此,它们几乎可以被链接器按任何的方法组织,只要它的头部填充了足够能够解释数据的信息。 段头部 PE 文件格式中,所有的段头部位于可选头部之后。 每个段头部为 40 个字节长,并且没有任何的填充信息。 段头部被定义为以下的结构: // define IMAGE_SIZEOF_SHORT_NAME 8 typedef struct _IMAGE_SECTION_HEADER { UCHAR Name[IMAGE_SIZEOF_SHORT_NAME]。 union { ULONG PhysicalAddress。 ULONG VirtualSize。 } Misc。 ULONG VirtualAddress。 ULONG SizeOfRawData。 ULONG PointerToRawData。 ULONG PointerToRelocations。 ULONG PointerToLinenumbers。 USHORT NumberOfRelocations。 USHORT NumberOfLinenumbers。 ULONG Characteristics。 } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER。 你如何才能获得一个特定段的段头部信息。 既然段头部是被连续的组织起来的,而且没有一个特定的顺序,那么段头部必须由名称来定位。 以下的函数示范了如何从一个给定了段名称的 PE 映像文件中获得一个段头部: // BOOL WINAPI GetSectionHdrByName(LPVOID lpFile, IMAGE_SECTION_HEADER *sh, char *szSection) { PIMAGE_SECTION_HEADER psh。 int nSections = NumOfSections (lpFile)。 int i。 if ((psh = (PIMAGE_SECTION_HEADER)SECHDROFFSET(lpFile)) != NULL) { /* 由名称查找段 */ for (i = 0。 i nSections。 i++) { if (!strcmp(pshName, szSection)) { /* 向头部复制数据 */ CopyMemory((LPVOID)sh, (LPVOID)psh, sizeof(IMAGE_SECTION_HEADER))。 return TRUE。 } else psh++。 } } return FALSE。 } 这个函数通过 SECHDROFFSET 宏将第一个段头部定位,然后它开始在所有段中循环,并将要寻找的段名称和每个段的名称相比较,直到找到了正确的那一个为止。 当找到了段的时候,函数将内存映像文件的数据复制到传入函数的结 构中,然后 IMAGE_SECTION_HEADER 结构的各域就能够被直接存取了。 段头部的域 Name。 每个段都有一个 8 字符长的名称域,并且第一个字符必须是一个句点。 PhysicalAddress 或 VirtualSize。 第二个域是一个 union 域,现在已不使用了。 VirtualAddress。 这个域标识了进程地址空间中要装载这个段的虚拟地址。 实际的地址由将这个域的值加上可选头部结构中的 ImageBase 虚拟地址得到。 切记,如果这个映像文件是一个 DLL,那么这个DLL 就不一定会装载到 ImageBase 要求的位置。 所以一旦这个文件被装载进入了一个进程,实际的ImageBase 值应该通过使用 GetModuleHandle 来检验。 SizeOfRawData。 这个域表示了相对 FileAlignment 的段实体尺寸。 文件中实际的段实体尺寸将少于或等于 FileAlignment 的整倍数。 一旦映像被装载进入了一个进程的地址空间,段实体的尺寸将会变得少于或等于 FileAlignment 的整倍数。 PointerToRawData。 这是一个文件中段实体位置的偏移量。 PointerToRelocations、 PointerToLinenumbers、 NumberOfRelocations、 NumberOfLinenumbers。 这些域在 PE 格式中不使用。 Characteristics。 定义了段的特征。 这些值可以在 及本光盘(译注: MSDN 的光盘)的PE 格式规范中找到。 值 定义 0x00000020 代码段 0x00000040 已初始化数据段 0x00000080 未初始化数据段 0x04000000 该 段数据不能被缓存 0x08000000 该段不能被分页 0x10000000 共享段 0x20200000 可执行段 0x40000000 可读段 0x80000000 可写段 定位数据目录 数据目录存在于它们相应的数据段中。 典型地来说,数据目录是段实体中的第一个结构,但不是必需的。 由于这个缘故,如果你需要定位一个指定的数据目录的话,就需要从段头部和可选头部中获得信息。 为了让这个过程简单一点,我编写了以下的函数来定位任何一个在 之中定义的数据目录。 // LPVOID WINAPI ImageDirectoryOffset(LPVOID lpFile, DWORD dwIMAGE_DIRECTORY) { PIMAGE_OPTIONAL_HEADER poh。 PIMAGE_SECTION_HEADER psh。 int nSections = NumOfSections(lpFile)。 int i = 0。 LPVOID VAImageDir。 /* 必须为 0 到 (NumberOfRvaAndSizes1)之间 */ if (dwIMAGE_DIRECTORY = pohNumberOfRvaAndSizes) return NULL。 /* 获得可选头部和段头部的偏移量 */ poh = (PIMAGE_OPTIONAL_HEADER)OPTHDROFFSET(lpFile)。 psh = (PIMAGE_SECTION_HEADER)SECHDROFFSET(lpFile)。 /* 定位映像目录的相对虚拟地址 */ VAImageDir = (LPVOID)pohDataDirectory [dwIMAGE_DIRECTORY].VirtualAddress。 /* 定位包含映像目录的段 */ while (i++ nSections) { if (pshVirtualAddress = (DWORD)VAImageDir amp。 amp。 pshVirtualAddress + pshSizeOfRawData (DWORD)VAImageDir) break。 psh++。 } if (i nSections) return NULL。 /* 返回映像导入目录的偏移量 */ return (LPVOID)(((int)lpFile + (int)VAImageDir. pshVirtualAddress) + (int)pshPointerToRawData)。 } 该函数首先确认被请求的数据目录入口数字,然后它分别获取指向可选头部和第一个段头部的两个指针。 它从可选头部决定数据目录的虚拟地址,然后它使用这个值来 决定数据目录定位在哪个段实体之中。 如果适当的段实体已经被标识了,那么数据目录特定的位置就可以通过将它的相对虚拟地址转换为文件中地址的方法来找到 PE 文件格式详解 (下 ) 作。windows下的可执行文件格式详解
相关推荐
IFT+DELETE 删除被选择的选择项目,如果是文件,将被直接删除而不是放入回收站 CTRL+N 新建一个新的文件 CTRL+O 打开 “打开文件 ”对话框 CTRL+P 打开 “打印 ”对话框 CTRL+S 保存当前操作的文件 CTRL+X 剪切被选择的项目到剪贴板 CTRL+INSERT 或 CTRL+C 复制被选择的项目到剪贴板 SHIFT+INSERT 或 CTRL+V
e,删除其下的 (打印机 )和 {D62779904C6A11CF8D87 00AA0060F5BF}(计划任务 ),重新启动电脑,再 次访问网上邻居,你会发现快了很多。 自动关闭停止响应程序 有些时候, Win XP 会提示你某某程序停止响应,很烦,通过修改注册表 我们可以让其自行关闭,在 HKEY_CURRENT_USERControl PanelDesktop 中将字 符健值是
FAT32格式的分区不提供加密支持,如果你想使用加密操作,就需要把磁盘转换为 NTFS格式。 在 Windows XP 中新增了文件夹图片功能,它提供了比原来的图标内容更多丰富的图片资源供用户选择,你可以利用这一功能把自己喜欢的任意图片设为文件夹图标,方法是:在资源管理器选中任一文件夹,右键单击,选择“属性”命令,在打开的对话框中选择“自定义”选项卡
SafeMode/Fastdetect”行,然后选中启动选项中的 “/SAFEBOOT(F)”选项。 这样就为该项添加了安全模式功能。 如果需要额外的支持,还可以在 “/SAFEBOOT(F)”后面选择,例如选中 “NETWORK(W)”就可以实现网络支持的安全模式 做好设置之后单击 “确定 ”按钮,这样再开机时就会多出一个启动菜单,选择其中的 Microsoft Windows XP
下 ,运行 i386\winnt 进行安装 XP 时 ,安装 XP 时没有格式化分区选项。 文件复制完后,安装程序开始初始化 Windows 配置。 然后系统将会自动在 15 秒后重新启动。 (四)安装过程 Ⅲ 过 5 分钟后,当提示还需 33 分钟时将出现。 区域和语言设置选用默认值就可以了,直接点 “下一步 ”按钮。 这里输入你想好的姓名和单位,这里的姓名是你以后注册的用户名,点 “下一步
服务)的进程名是 , WinXP Home/Pro中默认安装的启动类型是手动,依赖 Remote Procedure Call 服务。 这个服务是为 WinXP 中的 MS Backup 备份程序提供支持,奇怪的是即使关掉它我的备份工作也可以顺利完成,用不着的话就禁用它吧。 Logon Netlogon(网域登 录服务)的进程名是 , WinXP Home/Pro