PE文件结构及其加载机制

PE 视频学习笔记 PE 视频学习 1.认识PE 首先,先介绍什么是可执行文件(executable file):可以由操作系统进行加载执行的文件 而 PE(Portable Executable) 就是windows操作系统的可执行文件结构,一种可移植的可执行文件,即可在任何windows平台上运行 另外 **ELF(Executable and Linking Format)**是Linux系统的可执行文件结构 1.1PE文件格式的运用 病毒与反病毒 外挂与反外挂 加壳与脱壳 无源码修改功能、软件汉化。。。等 1. 阅读详情

PE文件结构及其加载机制(一)

一、PE文件结构

PE即Portable Executable,是win32环境自身所带的执行体文件格式,其部分特性继承自Unix的COFF(Common Object File Format)文件格式。PE表示该文件格式是跨win32平台的,即使Windows运行在非Intel的CPU上,任何Win32平台的PE装载器也能识别和使用该文件格式的文件。

所有Win32执行体(除了VxD和16位的DLL)都使用PE文件格式,如EXE文件、DLL文件等,包括NT的内核模式驱动程序(Kernel Mode Driver)。

PE文件至少包含两个段,即数据段和代码段。Windows NT 的应用程序有9个预定义的段,分别为 .text 、.bss 、.rdata 、.data 、.pdata 和.debug 段,这些段并不是都是必须的,当然,也可以根据需要定义更多的段(比如一些加壳程序)。

在应用程序中最常出现的段有以下6种:

.执行代码段,通常  .text (Microsoft)或 CODE(Borland)命名;

.数据段,通常以 .data 、.rdata 或 .bss(Microsoft)、DATA(Borland)命名;

.资源段,通常以 .rsrc命名;

.导出表,通常以 .edata命名;

.导入表,通常以 .idata命名;

.调试信息段,通常以 .debug命名;

 

PE文件的结构在磁盘和内存中是基本一样的,但在装入内存中时又不是完全复制。Windows装载器在装载的时候仅仅建立好虚拟地址和PE文件之间的映射关系,只有真正执行到某个内存页中的指令或访问某一页中的数据时,这个页才会被从磁盘提交到物理内存。但因为装载可执行文件时,有些数据在装入前会被预先处理(如需要重定位的代码),装入以后,数据之间的相对位置也可能发生改变。因此,一个节的偏移和大小在装入内存前后可能是完全不同的。

..

PE的基本结构就是这样了。

下面开始各个部分学习。

==================================================

(1)IMAGE_DOS_HEADER和Dos Stub

其实IMAGE_DOS_HEADER和Dos Stub没有什么重要的,只是IMAGE_DOS_HEADER中的第十九个成员指向IMAGE_NT_HEADERS的位置。

复制代码
   typedef struct IMAGE_DOS_HEADER
  {
        WORD e_magic;
        WORD e_cblp;
        WORD e_cp;
        WORD e_crlc;
        WORD e_cparhdr;
        WORD e_minalloc;
        WORD e_maxalloc;
        WORD e_ss;
        WORD e_sp;
        WORD e_csum;
        WORD e_ip;
        WORD e_cs;
        WORD e_lfarlc;
        WORD e_ovno;
        WORD e_res[4];
        WORD e_oemid;
        WORD e_oeminfo;
        WORD e_res2[10];
        DWORD e_lfanew;             //指向IMAGE_NT_HEADERS的所在
  }IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; 
复制代码

下面我们用一个具体的PE文件来看看。

这是64个字节(64Byte),下面是一些分析。

首先,只要是PE文件,那么开始两个字节就一定是4D 5A。

然后看最后四个字节,是E8000000,代表了地址是000000E8h,我们往下找找。

通过搜索,可以直接到达这个位置,一会我们再来看这个位置。

也就是说,00000040h到000000E8h之间的数据都是Dos Stub(称为dos残余程序)。

 

-----------------------------------------------------------------------------

(2)PE文件头

现在我们来看看IMAGE_NT_HEADERS的情况,看看e_lfanew指向的这里是什么含义,看看000000E8h(这个数值是不固定的,不同的PE程序的值可能不同,我们只要找到这个位置,读取它的值即可找到PE文件的头所在)指向的这里又是什么。

typedef struct IMAGE_NT_HEADERS
  {
        DWORD Signature;
        IMAGE_FILE_HEADER FileHeader;
        IMAGE_OPTIONAL_HEADER32 OptionalHeader;
  }IMAGE_NT_HEADERS,*PIMAGE_NT_HEADERS; 

首先我们看到的,这是一个结构体,而且结构体中还有结构体。

我们先看看它的总大小和在c32中的情况

【1】其中红色的部分就是DWORD Signature,表示字符“PE\0\0”,十六进制为00004550h,这个值也是不会变化的。

【2】绿色线部分表示IMAGE_FILE_HEADER FileHeader,我们具体来看看这个结构体代表了什么含义。

 

复制代码
typedef struct _IMAGE_FILE_HEADER {   
        WORD      Machine;                 //运行平台 
        WORD      NumberOfSections;        //块(section)数目      
        DWORD     TimeDateStamp;           //时间日期标记     
        DWORD     PointerToSymbolTable;    //COFF符号指针,这是程序调试信息    
        DWORD     NumberOfSymbols;         //符号数  
        WORD      SizeOfOptionalHeader;    //可选部首长度,是IMAGE_OPTIONAL_HEADER的长度    
        WORD      Characteristics;         //文件属性 
} 
复制代码

第一个表示这个程序运行需要的平台,来看看我刚才这个程序的值

这里表示运行的平台是Intel的CPU,下面是一个列表代表各种对应的平台的值:

第二个表示块的数目

0004当然就是4个节了,一会我们可以看看是哪四个节

第三个表示时间,我们先看看

也就是4F91318Fh,用计算器算一下就是1334915471,这个值应该是秒,我们换算一下,结果大约是42年

这个是程序的创建日期,减去42年,大约就是1970年,这个日期就是从1970到文件最后修改时间之间的秒数?

这个我可不知道,有待研究。

第六个SizeOfOptionalHeader表示之后OptionalHeader的大小,我们先来看看

00E0就是十进制的224,也就是说OptionalHeader的大小是224字节。

第七个值Characteristics表示文件属性,它的每一个bit都代表了某种含义。

复制代码
         Bit 0 :置1表示文件中没有重定向信息。每个段都有它们自己的重定向信息。
                 这个标志在可执行文件中没有使用,在可执行文件中是用一个叫做基址重定向目录表来表示重定向信息的,这将在下面介绍。
         Bit 1 :置1表示该文件是可执行文件(也就是说不是一个目标文件或库文件)。
         Bit 2 :置1表示没有行数信息;在可执行文件中没有使用。
         Bit 3 :置1表示没有局部符号信息;在可执行文件中没有使用。
         Bit 4 :
         Bit 7 
         Bit 8 :表示希望机器为32位机。这个值永远为1。
         Bit 9 :表示没有调试信息,在可执行文件中没有使用。
         Bit 10:置1表示该程序不能运行于可移动介质中(如软驱或CD-ROM)。在这    种情况下,OS必须把文件拷贝到交换文件中执行。
         Bit 11:置1表示程序不能在网上运行。在这种情况下,OS必须把文件拷贝到交换文件中执行。
         Bit 12:置1表示文件是一个系统文件例如驱动程序。在可执行文件中没有使用。
         Bit 13:置1表示文件是一个动态链接库(DLL)。
         Bit 14:表示文件被设计成不能运行于多处理器系统中。
         Bit 15:表示文件的字节顺序如果不是机器所期望的,那么在读出之前要进行
                 交换。在可执行文件中它们是不可信的(操作系统期望按正确的字节顺序执行程序)。
复制代码

010Fh就是0000000100001111

具体的我们来看一张图:

【3】下面是OptionalHeader,占224个字节

我们看看 它的结构是怎样的

复制代码
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_HEADER, *PIMAGE_OPTIONAL_HEADER;
复制代码

 

PE文件结构及其加载机制(二)

在学习之前,我们来看看上次的进度

以及对应的结构体

复制代码
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_HEADER, *PIMAGE_OPTIONAL_HEADER;
复制代码

typedef struct _IMAGE_OPTIONAL_HEADER  
{ 
    // 
    // Standard fields.   
    // 
+18h    WORD    Magic;         // 标志字, ROM 映像(0107h),普通可执行文件(010Bh) 
+1Ah    BYTE      MajorLinkerVersion;     // 链接程序的主版本号 
+1Bh    BYTE      MinorLinkerVersion;     // 链接程序的次版本号 
+1Ch    DWORD   SizeOfCode;     // 所有含代码的节的总大小 
+20h    DWORD   SizeOfInitializedData;    // 所有含已初始化数据的节的总大小 
+24h    DWORD   SizeOfUninitializedData; // 所有含未初始化数据的节的大小 
+28h    DWORD   AddressOfEntryPoint;    // 程序执行入口RVA 
+2Ch    DWORD   BaseOfCode;      // 代码的区块的起始RVA 
+30h    DWORD   BaseOfData;      // 数据的区块的起始RVA 
    // 
    // NT additional fields.    以下是属于NT结构增加的领域。 
    // 
+34h    DWORD   ImageBase;      // 程序的首选装载地址 
+38h    DWORD   SectionAlignment;      // 内存中的区块的对齐大小 
+3Ch    DWORD   FileAlignment;      // 文件中的区块的对齐大小 
+40h    WORD    MajorOperatingSystemVersion;  // 要求操作系统最低版本号的主版本号 
+42h    WORD    MinorOperatingSystemVersion;  // 要求操作系统最低版本号的副版本号 
+44h    WORD    MajorImageVersion;       // 可运行于操作系统的主版本号 
+46h    WORD    MinorImageVersion;       // 可运行于操作系统的次版本号 
+48h    WORD    MajorSubsystemVersion;  // 要求最低子系统版本的主版本号 
+4Ah    WORD    MinorSubsystemVersion;  // 要求最低子系统版本的次版本号 
+4Ch    DWORD   Win32VersionValue;       // 莫须有字段,不被病毒利用的话一般为0 
+50h    DWORD   SizeOfImage;       // 映像装入内存后的总尺寸 
+54h    DWORD   SizeOfHeaders;       // 所有头+ 区块表的尺寸大小 
+58h    DWORD   CheckSum;       // 映像的校检和 
+5Ch    WORD    Subsystem;       // 可执行文件期望的子系统 
+5Eh    WORD    DllCharacteristics;       // DllMain()函数何时被调用,默认为0 
+60h    DWORD   SizeOfStackReserve;       // 初始化时的栈大小 
+64h    DWORD   SizeOfStackCommit;       // 初始化时实际提交的栈大小 
+68h    DWORD   SizeOfHeapReserve;        // 初始化时保留的堆大小 
+6Ch    DWORD   SizeOfHeapCommit;        // 初始化时实际提交的堆大小 
+70h    DWORD   LoaderFlags;        // 与调试有关,默认为0  
+74h    DWORD   NumberOfRvaAndSizes;  // 下边数据目录的项数,这个字段自Windows NT 发布以来        // 一直是16 
+78h    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; 
       // 数据目录表 
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32; 
 

同样的,我们先在msdn中查看下这个结构体

第一个值,表示文件的格式,它可能的值有

IMAGE_NT_OPTIONAL_HDR_MAGIC,这个值包括两个值,分别为IMAGE_NT_OPTIONAL_HDR32_MAGIC、IMAGE_NT_OPTIONAL_HDR64_MAGIC,分别表示是32位的应用程序和64位的应用程序,具体的十六进制值为0x10b和0x20b。

还有一个值是IMAGE_ROM_OPTIONAL_HDR_MAGIC,表示这是一个ROM文件,其值为0x107。

总结为一张图

对于这个文件,它的值是

表示32位的应用程序。

第二个值是MajorLinkerVersion,表示主版本号的链接器,这个值一般来说是不重要的。

对于这个文件,它的值为

第三个值是MinorLinkerVersion,表示次版本号的连接器,这个值一般来说是不重要的。

它的值

第四个值是SizeOfCode,表示The size of the code section, in bytes, or the sum of all such sections if there are multiple code sections.

代码段的总大小,单位为字节,如果是多个部分,则表示它们的总和。

94208字节,即92kb。

第五个值是SizeOfInitializedData,表示所有含已初始化数据的节的大小。

The size of the initialized data section, in bytes, or the sum of all such sections if there are multiple initialized data sections.

77824字节,76kb。

第六个值是SizeOfUninitializedData,表示未初始化数据的节的大小。

The size of the uninitialized data section, in bytes, or the sum of all such sections if there are multiple uninitialized data sections.

第七个值是AddressOfEntryPoint,表示程序的入口点。

A pointer to the entry point function, relative to the image base address. For executable files, this is the starting address. For device drivers, this is the address of the initialization function. The entry point function is optional for DLLs. When no entry point is present, this member is zero.

我们用PEiD来看看这个值

如果看过《C++反汇编与逆向分析技术揭秘》的童鞋就会知道,PEiD是如何工作的。

第八个值是BaseOfCode,表示代码段的起始RVA。

即RVA为00001000,如果加上ImageBase的话,就可以知道这个位置在内存中的位置为00401000,我们用OD打开这个程序看看

第九个值是BaseOfData,表示数据段的起始RVA。

同样,我们用OD来查看下,00018000+00400000=00418000

第十个值是ImageBase,表示程序的建议装载地址。

用PEiD查看

PE文件结构及其加载机制(三)

上次我们学习了IMAGE_OPTIONAL_HEADER的前十个参数,下面我们继续学习。
第十一个值SectionAlignment,表示节对齐粒度。这个值一定要大于或等于文件对齐粒度。
The alignment of sections loaded in memory, in bytes. This value must be greater than or equal to the FileAlignment member.
The default value is the page size for the system.

原来是4096B,也就是4kb了。

第十二个值是FileAlignment,表示文件对齐粒度。

The alignment of the raw data of sections in the image file, in bytes. The value should be a power of 2 between 512 and 64K (inclusive). The default is 512. If the SectionAlignment member is less than the system page size, this member must be the same as SectionAlignment.

这个值应该是512B的倍数。

第十三个值是MajorOperatingSystemVersion,所需操作系统的主版本号。

The major version number of the required operating system.

第十四个值是MinorOperatingSystemVersion,所需操作系统的副版本号。

The minor version number of the required operating system.

第十五个值是MajorImageVersion

The major version number of the image.

第十六个值是MinorImageVersion

The minor version number of the image.

第十七个值是MajorSubsystemVersion

The major version number of the subsystem.

第十八个值为MinorSubsystemVersion

The minor version number of the subsystem.

第十九个值为Win32VersionValue,保留值,且必须为零。

This member is reserved and must be 0.

 

 

 

第二十个值为SizeOfImage,4个字节,表示程序调入后占用内存大小(字节),等于所有段的长度之和。

The size of the image, in bytes, including all headers. Must be a multiple of SectionAlignment.

 

0x2B000=?

好吧,两三天了,终于弄明白这个值了,由于在实验过程中,为了防止意外,所以复制了一个副本在当前文件夹下,通过二进制的对比,发现这两个文件的SizeOfImage值是不一样的,所以走了弯路。

既然错了文件,那么我还是以这个文件为例吧,因为其他的部分都一样,所以就不修改其他的部分了。

0x25000+0x5188=0x2A188,再考虑内存对齐,我们试着用这个值除以对齐粒度0x1000,看是否能除尽。

结果是不能除尽,所以要求大一点,结果这个SizeOfImage就变成了0x2B000。

第二十一个值为SizeOfHeaders,占用4个字节,表示所有头加节表的大小。

The combined size of the following items, rounded to a multiple of the value specified in the FileAlignment member.

 

  • 4 byte signature
  • size of IMAGE_FILE_HEADER
  • size of optional header
  • size of all section headers

 

也就是0x1000了。

 

第二十二个值为CheckSum,占用四个字节。

The image file checksum. The following files are validated(验证) at load time: all drivers, any DLL loaded at boot time, and any DLL loaded into a critical (关键)system process.

 

 

第二十三个值为Subsystem,占用两个字节。表示文件运行所需的子系统。

 The subsystem required to run this image. The following values are defined.

 

Value Meaning
IMAGE_SUBSYSTEM_UNKNOWN 0

Unknown subsystem.

IMAGE_SUBSYSTEM_NATIVE 1

No subsystem required (device drivers and native system processes).

IMAGE_SUBSYSTEM_WINDOWS_GUI 2

Windows graphical user interface (GUI) subsystem.

IMAGE_SUBSYSTEM_WINDOWS_CUI 3

Windows character-mode user interface (CUI) subsystem.

IMAGE_SUBSYSTEM_OS2_CUI 5

OS/2 CUI subsystem.

IMAGE_SUBSYSTEM_POSIX_CUI 7

POSIX CUI subsystem.

IMAGE_SUBSYSTEM_WINDOWS_CE_GUI 9

Windows CE system.

IMAGE_SUBSYSTEM_EFI_APPLICATION 10

Extensible Firmware Interface (EFI) application.

IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11

EFI driver with boot services.

IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12

EFI driver with run-time services.

IMAGE_SUBSYSTEM_EFI_ROM 13

EFI ROM image.

IMAGE_SUBSYSTEM_XBOX 14

Xbox system.

IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION 16

Boot application.

 

 

 

 

第二十四个值为DllCharacteristics,占用两个字节。表示dll文件的属性值。

The DLL characteristics of the image. The following values are defined.

 

Value Meaning
0x0001

Reserved.(保留)

0x0002

Reserved.

0x0004

Reserved.

0x0008

Reserved.

IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE 0x0040

The DLL can be relocated at load time.(允许在载入的时候进行重定位)

IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY 0x0080

Code integrity checks are forced. If you set this flag and a section contains only uninitialized data, set the PointerToRawData member of IMAGE_SECTION_HEADER for that section to zero; otherwise, the image will fail to load because the digital signature cannot be verified.

IMAGE_DLLCHARACTERISTICS_NX_COMPAT 0x0100

The image is compatible(兼容) with data execution prevention (DEP).

IMAGE_DLLCHARACTERISTICS_NO_ISOLATION 0x0200

The image is isolation(隔离) aware, but should not be isolated.

IMAGE_DLLCHARACTERISTICS_NO_SEH 0x0400

The image does not use structured exception handling (SEH). No handlers can be called in this image.

IMAGE_DLLCHARACTERISTICS_NO_BIND 0x0800

Do not bind the image.

0x1000

Reserved.

IMAGE_DLLCHARACTERISTICS_WDM_DRIVER 0x2000

A WDM driver.

0x4000

Reserved.

IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000

The image is terminal server aware.

 

 

 

第二十五个值为SizeOfStackReserve,占用4个字节。表示初始化是的堆栈大小。

The number of bytes to reserve for the stack. Only the memory specified by the SizeOfStackCommit member is committed at load time; the rest is made available one page at a time until this reserve size is reached.

 

0x00100000=1MB

第二十六个值为SizeOfStackCommit,占用四个字节。表示初始化时实际提交的堆栈大小。

The number of bytes to commit for the stack.

 

0x1000字节=4kb

第二十七个值为SizeOfHeapReserve,占用四个字节。初始化时保留堆的大小。

The number of bytes to reserve for the local heap. Only the memory specified by the SizeOfHeapCommit member is committed at load time; the rest is made available one page at a time until this reserve size is reached.

 

第二十八个值为SizeOfHeapCommit,占用四个字节。初始化时实际提交的堆得大小。

The number of bytes to commit for the local heap.

 

第二十九个值为LoaderFlags,占用4个字节。未使用。

This member is obsolete. 

第三十个值为NumberOfRvaAndSizes,占用四个字节。表示下面个成员数据目录结构的数量。

 

这个值一般就直接是16.

 


下面是最后一个成员DataDirectory,占用128个字节,为一个IMAGE_DATA_DIRECTORY structure结构体数组(16个)。

A pointer to the first IMAGE_DATA_DIRECTORY structure in the data directory.

 

 

typedef struct _IMAGE_DATA_DIRECTORY {
     DWORD VirtualAddress;
     DWORD Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

 

这个结构体有两个成员,一个成员占用4个字节,也就是8个字节。这个数组有16个数据,也就是16*8=128字节。

我们来看第一个。

IMAGE_DIRECTORY_ENTRY_EXPORT    导出表

这个程序没有导出函数,所以没有导出表。

第二个IMAGE_DIRECTORY_ENTRY_IMPORT  导入表

这个程序需要用到dll中的函数

 

我们用PEiD来查看下

 

结果是一样的。这个是RVA,表示偏移地址哦。

 

第三个IMAGE_DIRECTORY_ENTRY_RESOURCE   资源目录

从上面这张图也可以看出。RVA为00025000,大小为5188byte

 

第四个IMAGE_DIRECTORY_ENTRY_EXCEPTION  异常目录

 

未使用。

 


第五个 IMAGE_DIRECTORY_ENTRY_SECURITY  安全目录

 

 

第六个 IMAGE_DIRECTORY_ENTRY_BASERELOC   重定位表

 

 

第七个 IMAGE_DIRECTORY_ENTRY_DEBUG  调试信息

 

 

第八个 IMAGE_DIRECTORY_ENTRY_COPYRIGHT 版权信息

 

 

第九个  IMAGE_DIRECTORY_ENTRY_GLOBALPTR 

 

 

第十个 IMAGE_DIRECTORY_ENTRY_TLS  线程的本地存储器

 

 

第十一个 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 载入配置目录

Load configuration table address and size

 

 

第十二个 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT  绑定导入表地址和大小

Bound import table address and size

 

 

第十三个 IMAGE_DIRECTORY_ENTRY_IAT  导入函数地址表Import Address Table

Import address table address and size

 

用Exeinfo PE 查看

 

 

第十四个 IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT

Delay import descriptor address and size

 

 

 

第十五个 IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR

The CLR header address and size

 

 

第十六个 IMAGE_NUMBEROF_DIRECTORY_ENTRIES   保留值

 

 

到此,整个PE文件头结束了。

PE文件结构及其加载机制(四)

下面我们开始学习节表。

不知道还记不记得在前面哪个结构体中出现过节的数量?

 

嘿嘿,忘记了吧,我们翻开以前的记录,看看。

原来是

typedef struct IMAGE_NT_HEADERS
  {
        DWORD Signature;
        IMAGE_FILE_HEADER FileHeader;
        IMAGE_OPTIONAL_HEADER32 OptionalHeader;
  }IMAGE_NT_HEADERS,*PIMAGE_NT_HEADERS; 

中的

复制代码
typedef struct _IMAGE_FILE_HEADER {   
        WORD      Machine;                 //运行平台 
        WORD      NumberOfSections;        //块(section)数目      
        DWORD     TimeDateStamp;           //时间日期标记     
        DWORD     PointerToSymbolTable;    //COFF符号指针,这是程序调试信息    
        DWORD     NumberOfSymbols;         //符号数  
        WORD      SizeOfOptionalHeader;    //可选部首长度,是IMAGE_OPTIONAL_HEADER的长度    
        WORD      Characteristics;         //文件属性 
}
复制代码

第二个成员就是了。

我们回去找找这个程序的这个值是多少。

原来是四个节啊,当然了,也可以说四个段。

果然是四个段。

好了,复习完需要的知识,我们就继续学习。

 

================================================

typedef  struct  _IMAGE_SECTION_HEADER {
   BYTE   Name[IMAGE_SIZEOF_SHORT_NAME];
   union  {
     DWORD  PhysicalAddress;
     DWORD  VirtualSize;
   } Misc;
   DWORD  VirtualAddress;
   DWORD  SizeOfRawData;
   DWORD  PointerToRawData;
   DWORD  PointerToRelocations;
   DWORD  PointerToLinenumbers;
   WORD   NumberOfRelocations;
   WORD   NumberOfLinenumbers;
   DWORD  Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

 同样的,这也是一个结构体,而且有几个节,就有几个这种类似的结构体。

"#define IMAGE_SIZEOF_SHORT_NAME 8"    原来是个8

IMAGE_SECTION_HEADER的结构如下
 
typedef struct _IMAGE_SECTION_HEADER  
{ 
        BYTE Name[IMAGE_SIZEOF_SHORT_NAME];     // 节表名称,如“.text”  
        //IMAGE_SIZEOF_SHORT_NAME=8 
        union 
         { 
                DWORD PhysicalAddress;        // 物理地址 
                DWORD VirtualSize;                // 真实长度,这两个值是一个联合结构,可以使用其中的任何一个,一 
                                                              // 般是取后一个 
        } Misc; 
        DWORD VirtualAddress;              // 节区的RVA 地址 
        DWORD SizeOfRawData;            // 在文件中对齐后的尺寸 
        DWORD PointerToRawData;        // 在文件中的偏移量 
        DWORD PointerToRelocations;     // 在OBJ文件中使用,重定位的偏移 
        DWORD PointerToLinenumbers;   // 行号表的偏移(供调试使用地) 
        WORD NumberOfRelocations;      // 在OBJ文件中使用,重定位项数目 
        WORD NumberOfLinenumbers;    // 行号表中行号的数目 
        DWORD Characteristics;              // 节属性如可读,可写,可执行等} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;  
Name 里面存的是区块的名字
.text code 什么的就是放代码用的
.data 就是放数据,已经初始化好的
.idata 就是输入表 ,很多加壳程序会修改输入表,hook api 在程序运行api时,让壳取得一定时间的权限来反跟踪,脱壳的一大步骤就是还原输入表。
.edata 输出表
.bbs 未初始化的数据
VirtualSizes是一个非常牛逼的成员,其中的值是区块没有按FileAlignment对其前的大小,通过它可以推算出区块中还有多少没有被使用,很多病毒会在未被是用的空间里
插入自己的代码。
Characteristics 表示该区块的属性 可读啊 可写啊什么的
 
//   IMAGE_SCN_TYPE_REG        0x00000000 // Reserved. 
//   IMAGE_SCN_TYPE_DSECT       0x00000001 // Reserved. 
//   IMAGE_SCN_TYPE_NOLOAD       0x00000002 // Reserved. 
//   IMAGE_SCN_TYPE_GROUP       0x00000004 // Reserved. 
#define IMAGE_SCN_TYPE_NO_PAD       0x00000008 // Reserved. 
//   IMAGE_SCN_TYPE_COPY        0x00000010 // Reserved. 
 
#define IMAGE_SCN_CNT_CODE        0x00000020 // Section contains code. 
                           //区段包含代码 
#define IMAGE_SCN_CNT_INITIALIZED_DATA  0x00000040 // Section contains initialized data. 
                           //区段包含已初始化数据 
#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 // Section contains uninitialized data. 
                           //区段包含未初始化数据 
#define IMAGE_SCN_LNK_OTHER        0x00000100 // Reserved. 
#define IMAGE_SCN_LNK_INFO        0x00000200 // Section contains comments 
                           // or some other type of information. 
//   IMAGE_SCN_TYPE_OVER        0x00000400 // Reserved. 
#define IMAGE_SCN_LNK_REMOVE       0x00000800 // Section contents will not become part of image. 
#define IMAGE_SCN_LNK_COMDAT       0x00001000 // Section contents comdat. 
//                    0x00002000 // Reserved. 
//   IMAGE_SCN_MEM_PROTECTED - Obsolete 0x00004000 
#define IMAGE_SCN_NO_DEFER_SPEC_EXC    0x00004000 // Reset speculative exceptions handling bits 
                           // in the TLB entries for this section. 
#define IMAGE_SCN_GPREL          0x00008000 // Section content can be accessed relative to GP 
#define IMAGE_SCN_MEM_FARDATA       0x00008000 
//   IMAGE_SCN_MEM_SYSHEAP - Obsolete 0x00010000 
#define IMAGE_SCN_MEM_PURGEABLE      0x00020000 
#define IMAGE_SCN_MEM_16BIT        0x00020000 
#define IMAGE_SCN_MEM_LOCKED       0x00040000 
#define IMAGE_SCN_MEM_PRELOAD       0x00080000 
 
#define IMAGE_SCN_ALIGN_1BYTES      0x00100000 // 
#define IMAGE_SCN_ALIGN_2BYTES      0x00200000 // 
#define IMAGE_SCN_ALIGN_4BYTES      0x00300000 // 
#define IMAGE_SCN_ALIGN_8BYTES      0x00400000 // 
#define IMAGE_SCN_ALIGN_16BYTES      0x00500000 // Default alignment if no others are specified. 
#define IMAGE_SCN_ALIGN_32BYTES      0x00600000 // 
#define IMAGE_SCN_ALIGN_64BYTES      0x00700000 // 
#define IMAGE_SCN_ALIGN_128BYTES     0x00800000 // 
#define IMAGE_SCN_ALIGN_256BYTES     0x00900000 // 
#define IMAGE_SCN_ALIGN_512BYTES     0x00A00000 // 
#define IMAGE_SCN_ALIGN_1024BYTES     0x00B00000 // 
#define IMAGE_SCN_ALIGN_2048BYTES     0x00C00000 // 
#define IMAGE_SCN_ALIGN_4096BYTES     0x00D00000 // 
#define IMAGE_SCN_ALIGN_8192BYTES     0x00E00000 // 
// Unused                 0x00F00000 
 
#define IMAGE_SCN_LNK_NRELOC_OVFL     0x01000000 // Section contains extended relocations. 
#define IMAGE_SCN_MEM_DISCARDABLE     0x02000000 // Section can be discarded. 
                           //该区段可丢弃 
#define IMAGE_SCN_MEM_NOT_CACHED     0x04000000 // Section is not cachable. 
#define IMAGE_SCN_MEM_NOT_PAGED      0x08000000 // Section is not pageable. 
#define IMAGE_SCN_MEM_SHARED       0x10000000 // Section is shareable. 
                           //该区段可共享 
#define IMAGE_SCN_MEM_EXECUTE       0x20000000 // Section is executable. 
                           //该区段可执行 
#define IMAGE_SCN_MEM_READ        0x40000000 // Section is readable. 
                           //该区段可读 
#define IMAGE_SCN_MEM_WRITE        0x80000000 // Section is writeable. 
                           //该区段可写 
 
最后写个程序把这个结构读出来
由于我比较懒就只读了Name这个成员,有些加壳软件会修改Name这个字段使读出来的东西乱七八糟,比如UPX的压缩壳,会把Name字段改成UPX0,UPX1这样
 
#include "windows.h" 
#include "stdio.h" 
 
int main(int argc, char* argv[]) 
{ 
    FILE *p; 
    int i; 
    unsigned long Signature; 
    IMAGE_FILE_HEADER myfileheader; 
    IMAGE_DOS_HEADER mydosheader; 
    IMAGE_OPTIONAL_HEADER myoptionalheader; 
    IMAGE_SECTION_HEADER mysectionheader; 
 
    p = fopen("test.exe","r+b"); 
    if(p == NULL)return -1; 
 
    fread(&mydosheader,sizeof(mydosheader),1,p); 
    fseek(p,mydosheader.e_lfanew,SEEK_SET); 
    fread(&Signature,sizeof(Signature),1,p); 
 
    fseek(p,mydosheader.e_lfanew+sizeof(Signature),SEEK_SET);//指向IMAGE_FILE_HEADER结构的偏移 
    fread(&myfileheader,sizeof(myfileheader),1,p); 
 
    fseek(p,mydosheader.e_lfanew+sizeof(Signature)+sizeof(myfileheader)+sizeof(myoptionalheader),SEEK_SET); 
    printf("Signature          : %04X\n",Signature); 
    printf("IMAGE_SECTION_HEADER       结构:\n"); 
    for(i=0;i<myfileheader.NumberOfSections;i++){ 
        fread(&mysectionheader,sizeof(mysectionheader),1,p); 
        printf("Name               : %s\n",mysectionheader.Name); 
    } 
    fclose(p); 
    return 0; 
} 







编写PE文件解析器(三) 下面有几个表网上资料比较少,因为几乎用不到,我查文档写写吧,这篇写得比较久很抱歉。 7、IMAGE_DIRECTORY_ENTRY_EXCEPTION【异常处理表】 CPU特定的并且基于表的异常处理。用于除x86之外的其它CPU上。偏移到一个IMAGE_XXX_RUNTIME_FUNCTION_ENTRY数组,根据文件头的Machine来确定结构,64位用IMAGE_IA64_RUNT 阅读详情

相关推荐

PE文件结构简述

简述: PE文件结构分为五个部分: DOS文件头 DOS加载模块 PE文件头 区段表 区段 PE文件中显示的所有地址基本都是RVA,倘若想要换算成VA一般需要加上基地址ImageBase与文件偏移地址RVA。 虚拟地址(VA=virtual address):每个32位PE文件被加载到内存的时候都会被分配4GB的虚拟内存,虚拟地址等于“程序的相对虚拟地址+基地址”。 相对虚拟地址(RVA=relatively virtual address):相对虚拟地址是相比较于文件开头的地

Shanfenglan's blog 35万+

PE文件结构详解

Windows程序的各种界面称为资源,包括加速键(Accelerator)、位图(Bitmap)、光标(Cursor)、对话框(DialogBox)、图标(Icon)、菜单(Menu)、串表(StringTable)、工具栏(Toolbar)和版本信息(VersionInformation)等。执行PE文件前,加载程序在进行重定位的时候,会用PE文件在内存中的实际映像地址减PE文件所要求的映像地址,根据重定位类型的不同将差值添加到相应的地址数据中。...

神棍之路 1万+

零代码搭建专业知识库:Wiki.js+cpolar让团队协作像写笔记一样简单

"项目文档又找不到了!“团队负责人小张第N次在群里看到这样的抱怨——技术文档分散在邮件、网盘和个人电脑里,新人入职要花一周熟悉文档位置,远程协作时版本混乱更是家常便饭。Wiki.js与cpolar内网穿透服务的出现,就像给团队协作装上了"中央大脑”,用写Markdown笔记的简单方式,搭建一个专业的知识库系统。普通人对知识管理的需求其实很简单:方便记录、容易查找、大家能用。但传统方案把这个过程搞得异常复杂:建服务器、配环境、学语法、搞权限……大部分团队还没开始就放弃了。

Yawesh的博客 2036

PE文件结构

什么是可执行文件 可执行文件(executable file)指的是可以由操作系统进行加载执行的文件 windows平台:PE(Portable Executable)文件结构 Linux平台:ELF(Executable and Linking Format)文件结构 一些用到的概念 地址空间:这个地址空间指的是PE文件被加载到内存的空间,是一个虚拟的地址空...

南宫封清的博客 5933

常学常新:《Attention Is All You Need》万字解读!

常学常新:《Attention Is All You Need》万字解读!

hunteritself的博客 3641

工业相机与ABB机器人Socket通信实战:手把手教你用RobotStudio 6.08搭建视觉引导工作站

本文详细介绍了工业相机与ABB机器人通过Socket通信实现视觉引导工作站的实战教程。使用RobotStudio 6.08平台,涵盖工作站搭建、坐标系标定、RAPID代码开发及TCP/IP通信配置,特别解析了欧拉角与四元数转换等关键技术难点,助力智能制造产线升级。

weixin_42531516的博客 407

windows PE文件结构及其加载机制

1. 概述PE文件的全称是Portable Executable,意为可移植的可执行的文件,常见的EXE、DLL、OCX、SYS、COM都是PE文件,PE文件是微软Windows操作系统上的程序文件(可能是间接被执行,如DLL)。它是1993年Windows NT系统引入的新可执行文件格式,到现在已经经过20多年了。虽然使用PE作为可执行文件格式的Windows操作系统已经更换了很多版本,其结构的变

liuyez123的博客 2万+

用树莓派Pico低成本更新USB-C PD控制器固件实战指南

固件更新是嵌入式系统开发与维护中的核心环节,它直接决定了硬件设备的功能、性能与兼容性。其原理通常是通过特定的通信接口(如SWD、JTAG、UART或USB)与设备内部的Bootloader建立连接,将新的程序代码安全写入非易失性存储器。在USB Power Delivery(PD)和Type-C生态中,固件更新技术尤为重要,它能修复协议握手Bug、适配新设备并提升供电策略的灵活性。本文聚焦于一个典型的工程实践场景:如何利用广泛普及且成本极低的树莓派Pico开发板,作为USB-C协议到I²C协议的转换桥,实现

weixin_27869497的博客 452

PE文件结构及其加载机制(四)

下面我们开始学习节表。 不知道还记不记得在前面哪个结构体中出现过节的数量?   嘿嘿,忘记了吧,我们翻开以前的记录,看看。 原来是 typedef struct IMAGE_NT_HEADERS   {    DWORD Signature;    IMAGE_FILE_HEADER FileHeader;    IMAGE_OPTION

肖邦的夜曲的专栏 370

S/4HANA Private Cloud 与 On-Premise 的 Key User Custom Fields 运输与升级避坑指南

本文探讨了SAP S/4HANA Cloud Private Edition和On-Premise系统中Key User Custom Fields的管理要点。文章指出,Custom Fields涉及元数据生成、对象一致性、传输治理等完整链路,操作不当会导致字段丢失或升级失败。关键建议包括:使用ATO Fiori App管理扩展项与传输绑定,配置正确的job user权限,避免在多系统并行开发同一字段。特别强调升级时需执行CFD_REGENERATE_IN_ONPREMISE报表,并通过标准传输机制推进变更

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 195

rosbag分析传感器数据的时间同步情况方法

ROS传感器时间同步分析流程:通过rosbaginfo初步检查bag文件信息,使用rqt_bag可视化时间线分布,采用rostopicecho或Python脚本提取各传感器时间戳并计算时间差统计值(均值/最大差/标准差),最后分析接收与采样时间延迟。量化评估同步精度,识别固定偏移或随机抖动问题,确保多传感器数据对齐,为后续融合处理提供可靠数据基础。

start_up_go的博客 201

PE文件结构及其加载机制(三)

上次我们学习了IMAGE_OPTIONAL_HEADER的前十个参数,下面我们继续学习。第十一个值SectionAlignment,表示节对齐粒度。这个值一定要大于或等于文件对齐粒度。The alignment of sections loaded in memory, in bytes. This value must be greater than or equal to the FileAl

肖邦的夜曲的专栏 846

手把手教你学Simulink--双足机器人的反步控制方法仿真

本文介绍了在Simulink中基于反步控制方法进行双足机器人仿真研究的步骤。主要内容包括:1)准备工作,包括MATLAB/Simulink安装和相关工具箱配置;2)构建简化双足机器人模型;3)设计反步控制器,阐述其递归设计原理及Lyapunov函数构造方法;4)通过MATLAB Function块实现控制逻辑并连接模型;5)仿真参数配置和结果分析。文章强调反步控制适用于非线性系统,通过逐步构造虚拟控制律保证系统稳定性,并指出需要多次调试和查阅文献来优化控制效果。该教程为研究双足机器人运动控制提供了实用的仿真

MHD0815的博客 151

PE文件结构及其加载机制(一)

一、PE文件结构 PE即Portable Executable,是win32环境自身所带的执行体文件格式,其部分特性继承自Unix的COFF(Common Object File Format)文件格式。PE表示该文件格式是跨win32平台的,即使Windows运行在非Intel的CPU上,任何Win32平台的PE装载器也能识别和使用该文件格式的文件。 所有Win32执行体(除了VxD和16位

肖邦的夜曲的专栏 619

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

PE文件结构及其加载机制(二)

以及对应的结构体 typedef struct _IMAGE_OPTIONAL_HEADER { WORD Magic; BYTE MajorLinkerVersion; BYTE MinorLinkerVersion; DWORD SizeOfC

肖邦的夜曲的专栏 466

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

上一篇: OD常用断点
下一篇: PE文件加载和修改
vbsourcecode
博客等级 码龄17年 19粉丝 3原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值