精华内容
下载资源
问答
  • windows PE 文件格式

    2012-07-04 10:07:19
    windows PE 文件格式.版本V8.2
  • Windows PE文件详解

    2012-06-04 22:41:35
    Windows PE文件结构格式,意义,详细描述PE文件
  • windows PE文件格式详解

    2021-04-21 21:16:13
    PE文件格式详解
  • windows PE文件结构

    2011-05-11 09:00:08
    PE(“portable executable”,可移植的可执行文件文件格式,是微软WindwosNT,Windows95和Win32子集①中的可执行的二进制文件的格式;在WindowsNT中,驱动程序也是这种格式。它还能被应用于各种目标文件②和库文件...
  • Windows PE文件中的验证码签名格式
  • Windows PE文件格式学习入门教程
  • windows pe 文件格式

    2008-01-05 11:22:41
    windows 可运行程序(PE文件格式,从网上抠下来的,有兴趣的可以看看...
  • Windows PE文件结构解析

    2014-07-03 21:23:53
    解析PE文件结构(开发语言为C++,开发工具为QtCreator),代码完成了PE文件各个头结构的解析,数据目录解析,导出表,导入表,资源表等常见表的解析。代码中难免有BUG,由于时间关系,本人未修复,但是对于那些想...
  • windows pe文件格式

    2011-07-26 08:28:29
    windows系统的可执行文件的格式,对于hack及开发人员深入编程来说,比较有参考价值
  • Windows PE文件分析以及读取工具制作教学视频,包含使用C++和Delphi制作读取PE文件结构信息工具,难得一好视频,视频在百度云上存储分享。
  • WindowsPE文件结构及其加密的研究
  • windows PE文件解释程序

    2009-08-09 03:22:24
    该程序可从二进制PE文件中分析代码入口地址,及反汇编功能等等!
  • 翻斗车 转储 Windows PE 文件信息
  • 本软件是一个用来分析PE程序文件的输出函数表,及其...(PE是指Windows操作系统中的可执行文件,比如.exe,.dll,.sys,.ocx)。 详细使用方法请参考阅读readme.txt。 如有问题反馈,欢迎邮件联系:Andee@hstream-tech.com
  • visual c++修改windows二进制PE文件的例子 显示进程的PID,SIZE之类的东西
  • windows PE文件结构及其加载机制

    万次阅读 多人点赞 2016-04-29 15:00:50
    1. 概述PE文件的全称是Portable Executable,意为可移植的可执行的文件,常见的EXE、DLL、OCX、SYS、COM都是PE文件PE文件是微软Windows操作系统上的程序文件(可能是间接被执行,如DLL)。它是1993年Windows NT...

    1. 概述

    PE文件的全称是Portable Executable,意为可移植的可执行的文件,常见的EXE、DLL、OCX、SYS、COM都是PE文件,PE文件是微软Windows操作系统上的程序文件(可能是间接被执行,如DLL)。它是1993年Windows NT系统引入的新可执行文件格式,到现在已经经过20多年了。虽然使用PE作为可执行文件格式的Windows操作系统已经更换了很多版本,其结构的变化、新特性的增加、文件格式的转换,以及内核的重新定位等,都发生了翻天覆地的变化,硬件架构也从16位发展到现在的64位架构,而这些变化对PE格式的影响却不大。由于PE格式有较好的数据组织方式和数据管理算法,面对如此多的变化却能保持其设计的优雅。

    众所周知,Windows NT继承自VAX® VMS®和UNIX。Windows NT的许多创建者在到Microsoft之前都曾为这些平台设计和编写程序。当他们设计Windows NT时,很自然会使用以前写过的和测试过的工具以尽快开始他们的新项目。这些工具产生的和使用的可执行文件和目标模块的格式被称为COFF(Common Object File Format的首字母,通用目标文件格式)。Microsoft编译器生成的OBJ文件就使用COFF格式。

    PE文件之所以被称为“可移植”是因为Windows NT在各种平台(x86、MIPS®、Alpha等等)上的所有实现都使用同样的可执行文件格式。当然,像CPU指令的二进制编码之类的内容会有所不同。重要的是操作系统加载器和编程工具不需要针对遇到的每种新的CPU再完全重写。Windows NT及其以后版本,Windows 95及其以后版本和Windows CE一直到现在的win10都使用了这个相同的格式,所以说在很大程度上,这个目的达到了。对于64位的Windows,PE格式只是进行了很少的修改。这种新的格式被叫做PE32+。没有加入新的域,只有一个域被去除。剩下的改变只是一些域从32位扩展到了64位。在这种情况下,你能写出和32位与64位PE文件都能一起工作的代码。对于C++代码,Windows头文件的能力使这些改变很不明显。EXE和DLL文件之间的不同完全是语义上的。它们都使用完全相同的PE格式。仅有的区别是用了一个单个的位来指出这个文件应该被作为EXE还是一个DLL。甚至DLL文件的扩展名也是不固定的,一些具有完全不同的扩展名的文件也是DLL,比如.OCX控件和控制面板程序(.CPL文件)。

    PE文件格式主要来自于UNIX操作系统所通用的COFF规范,同时为了保证与旧版本MS-DOS及Windows操作系统的兼容,也保留了MS-DOS中那熟悉的MZ头部。PE格式被公开在WINNT.H头文件中(非常零散)。在WINNT.H文件的中间有一个“Image Format”节。这个节以MS-DOS MZ格式和PE格式开头,后面才是新的PE格式。WINNT.H提供了PE文件使用的原始数据结构的定义。

    2. PE文件分析相关的概念

    在详细了解PE文件结构之前,我们需要先了解几个基本的概念。理解这些概念有利于我们更好地把握和分析PE中的数据结构。

    2.1. 地址

    PE中涉及的地址有四类,他们分别是:

    • 虚拟内存地址(VA)
    • 相对虚拟地址(RVA)
    • 文件偏移地址(FOA)
    • 特殊地址

    2.1.1. 虚拟地址(Virtual Addresses)

    由于Windows NT推出时程序是运行在保护模式下,用户的PE文件被操作系统加载进内存后,PE对应的进程支配了自己独立的4GB虚拟空间。在这个空间中定位的地址称为虚拟内存地址(Virual Address,VA)。到了现在系统运行在X64架构的硬件上(长模式),内存访问可以采用线性地址的方式,同时可访问的内存也突破了4GB的限制,但是独立的进程拥有独立的虚拟地址空间的内存管理机制还在沿用。在PE中,进程本身的VA被解释为:进程的基地址 + 相对虚拟内存地址。

    2.1.2. 相对虚拟地址(Relative Virtual Addresses)

    PE格式大量地使用所谓的RVA(相对虚拟地址)。一个RVA,亦即一个“Relative Virtual Addresses(相对虚拟地址)”,是在你不知道基地址时,被用来描述一个内存地址的。它是需要加上基地址才能获得线性地址的数值。基地址就是PE映象文件被装入内存的地址,并且可能会随着一次又一次的调用而变化。

    在一个可执行文件中,有许多在内存中的地址必须被指定的位置。例如,当引用一个全局变量时就必须指定它的地址。PE文件可以被加载到进程地址空间的任何位置。虽然它们有一个首选加载地址,但你不能依赖于可执行文件真的会被加载到那个位置。因为这个原因,指定一个地址而不依赖于可执行文件的加载位置就很重要。

    为了消除PE文件中对内存地址的硬编码,于是产生了RVA。一个RVA是在内存中相对于PE文件被加载的地址的一个偏移。例如,如果一个EXE文件被加载到地址0x400000,它的代码节位于地址0x401000处。那么代码节的RVA就是:

    (目标地址) 0x401000 - (加载地址)0x400000 = (RVA)0x1000.

    因为PE-文件中的各部分(各节)不需要像已载入的映象文件那样对齐,事情变得复杂起来。例如,文件中的各节常按照512(十六进制的0x200)字节边界对齐,而已载入的映象文件则可能按照4096(十六进制的0x1000)字节边界对齐。参见下面的“SectionAlignment(节对齐)”和“FileAlignment(文件对齐)”。

    因此,为了在PE文件中找到一个特定RVA地址的信息,你得按照文件已被载入时的那样来计算偏移量,但要按照文件的偏移量来跳过。

    试举一例,假若你已知道执行开始处位于RVA 0x1560地址处,并且想从那里开始的代码处反汇编。为了从文件中找到这个地址,你得先查明在RAM(内存)中各节是按照4096字节对齐的,并且“.code”节是从RVA 0x1000地址处开始,有16384字节长;然后你才知道RVA 0x1560地址位于此节的偏移量0x560处。你还要查明在文件中那节是按512字节边界对齐,且“.code”节在文件中从偏移量0x800处开始,然后你就知道在文件中代码的执行开始处就在0x800+0x560=0xd60字节处。

    然后你反汇编它并发现访问一个变量的线性地址位于0x1051d0处。二进制文件的线性地址在装入时将被重定位,并常被假定使用的是优先载入地址。因为你已查明优先载入地址为0x100000,因此我们可开始处理RVA 0x51d0了。因数据节开始于RVA 0x5000处,且有2048字节长,所以它处于数据节中。又因数据节在文件中开始于偏移量0x4800处,所以该变量就可以在文件中的0x4800+0x51d0-0x5000=0x49d0处找到。

    2.1.3. 文件偏移地址

    文件偏移地址(File Offset Address,FOA)和内存无关,他是指某个位置距离文件头的偏移。

    2.1.4. 特殊地址

    在PE结构中海油一种特殊地址,其计算方法并不是从文件头算起,也不是从内存的某个位置的基地址算起,而是从特定的位置算起。这个地址在PE结构中很少见,如:在资源表里就出现过这样的地址。

    2.2. 节(Section)

    无论是结构化程序设计,还是面向对象程序设计,都是倡导程序和数据的独立性,因此,程序中的代码和数据通通常是分开存放的。为了保证程序执行的安全,保证内核的稳定,Windows操作系统通常对不同用途的数据设置不同的权限。比如:代码段中的字节码在程序运行的时候,一般不允许用户进行修改,数据段则允许在程序运行过程中读和写,常量只能读等。Windows操作系统在加载可执行程序时,会为这些具有不同属性的数据分别分配标记有不同属性的页面(当然,相同属性的数据可能会被放到同一个页面),以确保程序运行时的安全。正式基于这个原因,PE中才出现了所谓的节的概念。

    节就是存放不同类型数据(比如代码、数据、常量、资源等)的地方,不同的节具有不同的访问权限。节是PE文件中存放代码和数据的基本单元。例如:一个目标文件中的所有代码可以组合成单个节,或者每个函数独占一格节(如果编译器允许)。增加节的数目会增加文件的开销,但是链接器在链接代码的时候就会有更大的选择余地。一个节中的所有原始数据必须被加载到连续的内存空间中。

    从操作系统加载角度来看,节是相同属性数据的组合。与数据目录不同的是,尽管有些数据类型不同,分别属于不同的数据目录,但是由于其访问属性相同,便被归类到同一个节中。这个节最终可能会占用一个或多个页面;但无论有多少个,所有相关页面均会被赋予相同的页面属性。这些属性包括只读、只写、可读、可写等。

    Windows操作系统在装载PE文件时会对相同和不同类型的节数据执行抛弃、合并、新增、复制等操作。这些不同的操作交叉组合导致了内存中的节和文件中的节会出现很大的不同。例如:”.data”的数据在磁盘中不存在,但是在内存中存在,而”.reloc”重定位表数据却恰恰相反。

    2.3. 对齐(Alignment)

    对齐这个概念并非只在PE文件中出现,许多文件格式都会有对齐的要求。有的对齐是为了美观,有的对齐则是为了效率。PE中规定了三类的对齐:数据在内存中的对齐、数据在文件中的对齐、资源文件中资源数据的对齐。

    2.3.1. 内存对齐(SectionAligment)

    PE 文件头里边的SectionAligment 定义了内存中区块的对齐值。由于Windows操作系统对内存属性的设置以页为单位,所以通常情况下,PE 文件被映射到内存中时,节在内存中的对齐单位必须至少是一个页的大小。对于32位的windows操作系统来说,这个值是4KB(1000h),而对64位操作系统来说,这个值就是8KB(2000h)。

    2.3.2. 文件对齐(FileAligment)

    PE 文件头里边的FileAligment 定义了磁盘区块的对齐值。每一个区块从对齐值的倍数的偏移位置开始存放。而区块的实际代码或数据的大小不一定刚好是这么多,所以在多余的地方一般以00h 来填充,这就是区块间的间隙。为了提高磁盘利用率,对齐单位通常小于内存,以一个物理扇区的大小作为对齐粒度,512字节,200h。

    2.3.3. 资源数据对齐

    资源字节码部分一般要求以双字(4字节)方式对齐。

    3. PE文件结构

    PE 文件格式被组织为一个线性的数据流,它由一个MS-DOS 头部开始,接着是一个是模式的程序残余以及一个PE 文件标志,这之后紧接着PE文件头和可选头部。这些之后是所有的段头部,段头部之后跟随着所有的段实体。文件的结束处是一些其它的区域,其中是一些混杂的信息,包括重分配信息、符号表信息、行号信息以及字串表数据。

    如下图所示,PE文件结构被划分为四大部份,包括:DOS部分、PE头、节表、和节数据。

    这里写图片描述

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

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

    • 执行代码段,通常 .text (Microsoft)或 CODE(Borland)命名;
    • 数据段,通常以 .data
      、.rdata 或 .bss(Microsoft)、DATA(Borland)命名;
    • 资源段,通常以 .rsrc命名;
    • 导出表,通常以 .edata命名;
    • 导入表,通常以 .idata命名;
    • 调试信息段,通常以 .debug命名;

    PE文件一个方便的特点是磁盘上的数据结构和加载到内存中的数据结构是相同的。加载一个可执行文件到内存中 (例如,通过调用LoadLibrary)主要就是映射一个PE文件中的几个确定的区域到地址空间中。因此,一个数据结构比如IMAGE_NT_HEADERS (稍后我们会研究到)在磁盘上和在内存中是一样的。关键的一点是如果你知道怎么在一个PE文件中找到一些东西,当这个PE文件被加载到内存中后你几乎能找到相同的信息。

    要注意到PE文件并不仅仅是被映射到内存中作为一个内存映射文件。代替的,Windows加载器分析这个PE文件并决定映射这个文件的哪些部分。当映射到内存中时文件中偏移位置较高的数据映射到较高的内存地址处。一个项目在磁盘文件中的偏移也许不同于它被加载到内存中时的偏移。然而,所有被表现出来的信息都允许你进行从磁盘文件偏移到内存偏移的转换 (参见下图)。

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

    这里写图片描述

    这里写图片描述

    4. PE文件结构分析

    4.1. PE文件准备

    为了对PE文件结构进行更好的分析,我们首先准备一个例子,这次我们通过在WIN10 X64环境下使用VS2015编译生成的一个X64架构的release程序来进行分析。这个例子是一个在WIN10 X64下通过TLS实现反调试的小程序。程序清单如下:

    #include <Windows.h>
    #include <tchar.h>
    
    #pragma comment(lib,"ntdll.lib")
    
    extern "C" NTSTATUS NTAPI NtQueryInformationProcess(HANDLE hProcess, ULONG InfoClass, PVOID Buffer, ULONG Length, PULONG ReturnLength);
    
    #define NtCurrentProcess() (HANDLE)-1
    
    
    void NTAPI __stdcall TLS_CALLBACK(PVOID DllHandle, DWORD Reason, PVOID Reserved)
    {
        if (IsDebuggerPresent())
        {
            MessageBoxA(NULL, "TLS_CALLBACK: Debugger Detected!", "TLS Callback", MB_OK);
    //      ExitProcess(1);
        }
        else
        {
            MessageBoxA(NULL, "TLS_CALLBACK: No Debugger Present!...", "TLS Callback", MB_OK);
        }
    }
    
    void NTAPI __stdcall TLS_CALLBACK_2(PVOID DllHandle, DWORD Reason, PVOID Reserved)
    {
        HANDLE DebugPort = NULL;
        if (!NtQueryInformationProcess(
            NtCurrentProcess(),
            7,          // ProcessDebugPort
            &DebugPort, // If debugger is present, it will be set to -1 | Otherwise, it is set to NULL
            sizeof(HANDLE),
            NULL))
        {
            if (DebugPort)
            {
                MessageBoxA(NULL, "TLS_CALLBACK2: Debugger detected!", "TLS callback", MB_ICONSTOP);
            }
    
            else
            {
                MessageBoxA(NULL, "TLS_CALLBACK2: No debugger detected", "TLS callback", MB_ICONINFORMATION);
            }
        }
    }
    
    //linker spec通知链接器PE文件要创建TLS目录,注意X86和X64的区别
    #ifdef _M_IX86
    #pragma comment (linker, "/INCLUDE:__tls_used")
    #pragma comment (linker, "/INCLUDE:__tls_callback")
    #else
    #pragma comment (linker, "/INCLUDE:_tls_used")
    #pragma comment (linker, "/INCLUDE:_tls_callback")
    #endif
    //创建TLS段
    EXTERN_C
    #ifdef _M_X64
    #pragma const_seg (".CRT$XLB")
    const
    #else
    #pragma data_seg (".CRT$XLB")
    #endif
    //end linker
    
    //tls import定义多个回调函数
    PIMAGE_TLS_CALLBACK _tls_callback[] = { TLS_CALLBACK, TLS_CALLBACK_2, 0 };
    #pragma data_seg ()
    #pragma const_seg ()
    //end 
    
    int APIENTRY _tWinMain(HINSTANCE hInstance,
        HINSTANCE hPrevInstance,
        LPTSTR    lpCmdLine,
        int       nCmdShow)
    {
    
        MessageBoxA(NULL, "Hello Wolrd!...:)", "main()", MB_OK);
        return 0;
    
    }

    程序是一个简单的windows小程序,通过使用TLS回调函数来检测调试器的存在,并弹出窗口提示检测到的状态,主程序只是一个简单的hello world消息窗。程序中涉及到PE文件中几个重要的节。程序通过在WIN10 X64环境下使用VS2015编译生成的一个X64架构的release版本tlstest.exe,程序大小为12.0 KB (12,288 字节)。

    这里写图片描述

    4.2. MS-DOS 文件头

    在 image 文件的最开始处就是 DOS 文件头,DOS 文件头包含了 DOS stub 小程序。在 WinNT.h 文件里定义了一个结构来描述 DOS 文件头。

    typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header
        WORD   e_magic;             // 00000000  4D 5A,Magic number
        WORD   e_cblp;          // 00000002  90 00,Bytes on last page of file
        WORD   e_cp;             // 00000004  03 00,Pages in file
        WORD   e_crlc;            // 00000006  00 00,Relocations
        WORD   e_cparhdr;           // 00000008  04 00,Size of header in paragraphs
        WORD   e_minalloc;        // 0000000A  00 00,Minimum extra paragraphs needed
        WORD   e_maxalloc;          // 0000000C  FF FF,Maximum extra paragraphs needed
        WORD   e_ss;                // 0000000E  00 00,Initial (relative) SS value
        WORD   e_sp;             // 00000010  B8 00,Initial SP value
        WORD   e_csum;          // 00000012  00 00,Checksum
        WORD   e_ip;                // 00000014  00 00,Initial IP value
        WORD   e_cs;                // 00000016  00 00,Initial (relative) CS value
        WORD   e_lfarlc;        // 00000018  40 00,File address of relocation table
        WORD   e_ovno;           // 0000001A  00 00,Overlay number
    WORD   e_res[4];            // 0000001C  00 00 00 00,Reserved words
            // 00000020  00 00 00 00
        WORD   e_oemid;             // 00000024  00 00,OEM identifier (for e_oeminfo)
        WORD   e_oeminfo;           // 00000026  00 00,OEM information; e_oemid specific
    WORD   e_res2[10];          // 00000028  00 00 00 00,Reserved words
            // 0000002C  00 00 00 00
            // 00000030  00 00 00 00
            // 00000034  00 00 00 00
            // 00000038  00 00 00 00
        LONG    e_lfanew;           // 0000003C  F8 00 00 00,File address of new exe header
    } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

    这个结构名叫 IMAGE_DOS_HEADER 共 64 bytes,以 IMAGE_DOS_HEADER 结构描述的 DOS 文件头结构从 image 的 0x00000000 - 0x0000003F(64 bytes)

    结构的 e_magic 域是 DOS 头文件签名,它的值是:0x5A4D 代表字符 MZ,它在 WinNT.h 里定义为:

    #define IMAGE_DOS_SIGNATURE                 0x5A4D      // MZ

    e_lfanew 域是一个 offset 值,它指出 NT 文件头的位置。

    下面看看tlstest.exe 的 DOS 文件头内容:

    这里写图片描述

    绿色部分是 DOS 签名,蓝色部分是 PE header offset(NT 文件头)值,也就是 IMAGE_DOS_HEADER 里的 e_lfanew 值,表明 NT 文件头在 image 文件的 0x000000F8 处。

    4.2.1. DOS stub 程序

    在 DOS 文件头下面紧跟着一小段 stub 程序,其内容随着链接时使用的链接器不同而不同,在PE中并没有与之对应的相关结构。在本例中从 0x00000040 - 0x0000004D 共 14 bytes是代码,其后是显示数据等内容,这段 dos stub 程序是这样的:

    00000040  0E                push cs
    00000041  1F                pop ds
    00000042  BA0E00       mov dx,0xe
    00000045  B409            mov ah,0x9
    00000047  CD21           int 0x21
    00000049  B8014C       mov ax,0x4c01
    0000004C  CD21          int 0x21

    当 windows 的 PE 文件放在 DOS 上执行时,将会执行这一段 DOS stub 程序,作用是打印信息:This program cannot be run in DOS mode…. 然后调用 int 21 来终止执行返回到 DOS,看看它是怎样运行的:

    00000014  00 00      // ip
    00000016  00 00      // cs
    00000018  40 00      // e_lfarlc

    这个 DOS 执行环境中,CS 和 IP 被初始化为 0(对应值在IMAGE_DOS_HEADER结构中的e_ip、e_cs字段),e_lfarlc 是 DOS 环境的 relocate 表,它的值是 0x40 ,那么信息字符串的位置是:0x0040 + 0x000e = 0x4e,在 image 文件 0x0000004e 正好这字符串的位置。

    4.3. NT 文件头

    NT 文件头是 PE 文件头的核心部分,由 IMAGE_DOS_HEADER 结构的 e_lfanew 域指出它的位置。

    同样 NT 文件头部分由一个结构 IMAGE_NT_HEADER 来描述,在 WinNT.h 里定义如下:

    typedef struct _IMAGE_NT_HEADERS64 {
        DWORD Signature;
        IMAGE_FILE_HEADER FileHeader;
        IMAGE_OPTIONAL_HEADER64 OptionalHeader;
    } IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;
    typedef struct _IMAGE_NT_HEADERS {
        DWORD Signature;
        IMAGE_FILE_HEADER FileHeader;
        IMAGE_OPTIONAL_HEADER32 OptionalHeader;
    } IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
    #ifdef _WIN64
    typedef IMAGE_NT_HEADERS64                  IMAGE_NT_HEADERS;
    typedef PIMAGE_NT_HEADERS64                PIMAGE_NT_HEADERS;
    #else
    typedef IMAGE_NT_HEADERS32                  IMAGE_NT_HEADERS;
    typedef PIMAGE_NT_HEADERS32                PIMAGE_NT_HEADERS;
    #endif

    可见这个结构分为 32 和 64 位版本,IMAGE_NT_HEADER 结构分为三大部分:

    • PE 文件签名:Signature
    • IMAGE_FILE_HEADER 文件头:FileHeader
    • IMAGE_OPTINAL_HEADER(32/64) 可选头:OptionalHeader

    IMAGE_NT_HEADERS32 和 IMAGE_NT_HEADERS64 的匹别在于 IMAGE_OPTIONAL_HEADER 结构,分别为:IMAGE_OPTIONAL_HEADERS32 和 IMAGE_OPTIONAL_HEADERS64

    在 Win32 下 IMAGE_NT_HEADERS32 是 248 bytes,在 Win64 下 IMAGE_NT_HEADERS64 是 264 bytes,因此 tlstest.exe的 NT 文件头从 0x000000F8 - 0x000001FF 共 264 bytes

    4.3.1. PE 签名

    在 WinNT.h 文件里定义了 PE 文件的签名,它是:

    #define IMAGE_NT_SIGNATURE                  0x00004550  // PE00

    这个签名值是 32 位,值为:0x00004550 即:PE 的 ASCII 码,下面看看 tlstest.exe 中的 PE 签名:

    这里写图片描述

    4.3.2. IMAGE_FILE_HEADER 文件头结构

    PE 签名接着是 IMAGE_FILE_HEADER 结构,它在 WinNT.h 中的定义为:

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

    这个 IMAGE_FILE_HEADER 对 PE 文件大致的描述,这个结构共 20 bytes,它的域描述如下:

    size描述
    MachineWORDIMAGE_FILE_MACHINE_xxx表示目标平台 processor 类型,例:IMAGE_FILE_MACHINE_I386
    NumberOfSectionsWORD节数量表示映象中有多少个 section
    TimeDataStampDWORD从1970年1月1日0:00 以来的总秒数表示文件创建的时间
    PointerToSymbolTableDWORDCOFF 符号表偏移量在 image 文件中很少见,总是为 0
    NumberOfSymbolsDWORDCOFF 符号表的个数如果存在的话,表示符号表的个数
    SizeOfOptionalHeaderWORDIMAGE_OPTIONAL_HEADER 结构大小该域表示 IMAGE_NT_HEADER 中的 IMAGE_OPTIONAL_HEADER 结构的大小
    CharacteristicsWORDIMAGE_FILE_xxx表示文件属性,例如:IMAGE_FILE_DLL 属性

    IMAGE_FILE_HEADER 结构中比较重要的域是:Machine 和 SizeOfOptionalHeader, Machine 可以用来判断目标平台,比如:值为 0x8664 是代表 AMD64(即:x64 平台)它也适合 Intel64 平台。SizeOfOptionalHeader 指出 IMAGE_OPTIONAL_HEADER 结构的大小。

    WinNT.h 中定义了一些常量值用来描述 Machine,以 IMAGE_FILE_MACHINE_XXX 开头,下面是一些典型的常量值:

    #define IMAGE_FILE_MACHINE_UNKNOWN           0
    #define IMAGE_FILE_MACHINE_I386                   0x014c  // Intel 386.
    #define IMAGE_FILE_MACHINE_ALPHA                0x0184  // Alpha_AXP
    #define IMAGE_FILE_MACHINE_POWERPC            0x01F0  // IBM PowerPC Little-Endian
    #define IMAGE_FILE_MACHINE_AMD64                0x8664  // AMD64 (K8)

    WinNT.h 中还针对 Characteristics 域定义了一些常量值,以 IMAGE_FILE_XXX 开头,代表目标 image 文件的类型,下面是一些常见的值:

    #define IMAGE_FILE_RELOCS_STRIPPED              0x0001  // Relocation info stripped from file.
    #define IMAGE_FILE_EXECUTABLE_IMAGE          0x0002  // File is executable  (i.e. no unresolved externel references).
    #define IMAGE_FILE_LINE_NUMS_STRIPPED        0x0004  // Line nunbers stripped from file.
    #define IMAGE_FILE_LOCAL_SYMS_STRIPPED     0x0008  // Local symbols stripped from file.
    #define IMAGE_FILE_AGGRESIVE_WS_TRIM         0x0010  // Agressively trim working set
    #define IMAGE_FILE_LARGE_ADDRESS_AWARE  0x0020  // App can handle >2gb addresses
    #define IMAGE_FILE_BYTES_REVERSED_LO         0x0080  // Bytes of machine word are reversed.
    #define IMAGE_FILE_32BIT_MACHINE                 0x0100  // 32 bit word machine.
    #define IMAGE_FILE_DEBUG_STRIPPED               0x0200  // Debugging info stripped from file in .DBG file
    #define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP   0x0400  // If Image is on removable media, copy and run from the swap file.
    #define IMAGE_FILE_NET_RUN_FROM_SWAP        0x0800  // If Image is on Net, copy and run from the swap file.
    #define IMAGE_FILE_SYSTEM                            0x1000  // System File.
    #define IMAGE_FILE_DLL                                 0x2000  // File is a DLL.
    #define IMAGE_FILE_UP_SYSTEM_ONLY              0x4000  // File should only be run on a UP machine
    #define IMAGE_FILE_BYTES_REVERSED_HI         0x8000  // Bytes of machine word are reversed.

    可以看出Characteristics是以每一位表示文件属性,它的每一个bit代表的含义如下:

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

    NumberOfSections 表示 image 有多个 section,另一个重要的域是:SizeOfOptionalHeader 它指出接下来 IMAGE_OPTIONAL_HEADER 的大小,它有两个 size:Win32 的 0xDC 和 Win64 的 0xF0.

    下面是 tlstest.exe的 IMAGE_FILE_HEADER 结构,从 0x000000F8 - 0x0000010F 共 20 bytes:

    这里写图片描述

    将这些值分解为:

    000000FC  64 86                   // Machine
    000000FE  07 00                   // NumberOfSections
    00000100  F1 71 1E 57           // TimeDateStamp
    00000104  00 00 00 00           // PointerToSymbolTable
    00000108  00 00 00 00           // NumberOfSymbols
    0000010C  F0 00                   // SizeOfOptionalHeader
    0000010E  22 00                   // Characteristics
    • Machine 是 0x0x8664,它的值是 IMAGE_FILE_MACHINE_AMD64,说明这个 image
      文件的目标平台是 AMD64,即:X64 平台
    • NumberOfSections 是 0x08,说明 image 文件内含有 8 个 sections
    • SizeOfOptionalHeader 是 0xF0,说明接下来的 IMAGE_OPTIONAL_HEADERS64 将是
      0xF0(224 bytes)

    它的 Characteristics 是 0x0022 = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_LARGE_ADDRESS_AWARE,说明这个 image 是 64 位可执行的映像。可以在 >2G 地址上,并且指明了接下来的 IMAGE_OPTIONAL_HEADER 结构是 0xf0 bytes(240 个字节)。

    4.3.3. IMAGE_OPTIONAL_HEADER64 结构

    在 IMAGE_FILE_HEADER 结构里已经指明了 image 是 64 位,并且 IMAGE_OPTIONAL_HEADER 的大小是 240 bytes,那么这个结构就是 IMAGE_OPTIONAL_HEADER64 结构。
    可以根据 IMAGE_FILE_HEAER 结构的 Machine 来判断 image 是 Win32 还是 Win64 平台的。但是 Microsoft 官方推荐及认可的方法是从 IMAGE_OPTIONAL_HEADER 里的 magic 的值来判断目标平台 。

    在 WinNT.h 里 IMAGE_OPTIONAL_HEADER64 的定义如下:

    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;

    64 位的 IMAGE_OPTIONAL_HEADER64 里没有 BaseOfData 域,其它的与 IMAGE_OPTIONAL_HEADER32 结构的域是一样的,只是一些域扩展为 64 位值,它们包括:

    • ImageBase
    • SizeOfStackReserve
    • SizeOfStackCommit
    • SizeOfHeapRerserve
    • SizeOfHeapCommit

    这些域在 64 位结构里被定义为 ULONGLONG 类型。

    IMAGE_OPTIONAL_HEADER64 的定义的各个域含义如下:

    偏移大小字段描述
    02MagicThe unsigned integer that identifies the state of the image file. The most common number is 0x10B, which identifies it as a normal executable file. 0x107 identifies it as a ROM image, and 0x20B identifies it as a PE32+ executable. 确定这是什么类型的头。两个最常用的值是0x10b和0x20b.
    21MajorLinkerVersionThe linker major version number. 创建可执行文件的链接器的主版本号。对于Microsoft的链接器生成的PE文件,这个版本号的Visual Studio的版本号相一致
    31MinorLinkerVersionThe linker minor version number. 创建可执行文件的链接器的次版本号。
    44SizeOfCodeThe size of the code (text) section, or the sum of all code sections if there are multiple sections. 所有具有IMAGE_SCN_CNT_CODE属性的节的总的大小。
    84SizeOfInitializedDataThe size of the initialized data section, or the sum of all such sections if there are multiple data sections. 所有包含已初始数据的节的总的大小。
    124SizeOfUninitializedDataThe size of the uninitialized data section (BSS), or the sum of all such sections if there are multiple BSS sections. 所有包含未初始化数据的节的总的大小。这个域总是0,因为链接器可以把未初始化数据附加到常规数据节的末尾。
    164AddressOfEntryPointThe address of the entry point relative to the image base when the executable file is loaded into memory. For program images, this is the starting address. For device drivers, this is the address of the initialization function. An entry point is optional for DLLs. When no entry point is present, this field must be zero. 文件中将被执行的第一个代码字节的RVA。对于DLL,这个进入点将在进程初始化和关闭时以及线程被创建和销毁时调用。在大多数可执行文件中,这个地址并不直接指向main,WinMain或DllMain函数,而是指向运行时库代码,由运行时库调用前述函数。在DLL中,这个域可以被设为0。链接器选项/NOENTRY可以设置这个域为0。
    204BaseOfCodeThe address that is relative to the image base of the beginning-of-code section when it is loaded into memory. 加载到内存后代码的第一个字节的RVA
    244BaseOfDataThe address that is relative to the image base of the beginning-of-data section when it is loaded into memory. 理论上,它表示加载到内存后数据的第一个字节的RVA。然而,这个域的值对于不同版本的Microsoft链接器是不一致的。在64位的可执行文件中这个域不出现。
    28/244/8ImageBaseThe preferred address of the first byte of image when loaded into memory; must be a multiple of 64 K. The default for DLLs is 0x10000000. The default for Windows CE EXEs is 0x00010000. The default for Windows NT, Windows 2000, Windows XP, Windows 95, Windows 98, and Windows Me is 0x00400000. 文件在内存中的首选加载地址。加载器尽可能地把PE文件加载到这个地址(就是说,如果当前这块内存没有被占用,它是对齐的并且是一个合法的地址,等等)。如果可执行文件被加载到这个地址,加载器就可以跳过进行基址重定位这一步。在Win32下,对于EXE,缺省的ImageBase是0x400000。对于DLL,缺省是0x10000000。在链接时可以通过/BASE 选项来指定ImageBase,或者以后用REBASE工具重新设置。
    32/324SectionAlignmentThe alignment (in bytes) of sections when they are loaded into memory. It must be greater than or equal to FileAlignment. The default is the page size for the architecture. 加载到内存后节的对齐大小。这个值必须大于等于FileAlignment(下一个域)。缺省的对齐值是目标CPU的页大上。对于运行在Windows 9x或Windows Me下的用户模式可执行文件,最小对齐大小是一页(4KB)。这个域可以通过链接器选项/ALIGN来设置。
    36/364FileAlignmentThe alignment factor (in bytes) that is used to align the raw data of sections in the image file. The value should be a power of 2 between 512 and 64 K, inclusive. The default is 512. If the SectionAlignment is less than the architecture’s page size, then FileAlignment must match SectionAlignment. 在PE文件中节的对齐大小。对于x86下的可执行文件,这个值通常是0x200或0x1000。不同版本的Microsoft链接器缺省值不同。这个值必须是2的幂,并且如果SectionAlignment小于CPU的页大小,这个域必须和SectionAlignment相匹配。链接器选项/OPT:WIN98可设置x86可执行文件的文件对齐为0x1000,/OPT:NOWIN98设置文件对齐为0x200。
    40/402MajorOperatingSystemVersionThe major version number of the required operating system. 所要求的操作系统的主版本号。随着那么多版本Windows的出现,这个域的值就变得很不确切。
    42/422MinorOperatingSystemVersionThe minor version number of the required operating system. 所要求的操作系统的次版本号。
    44/442MajorImageVersionThe major version number of the image. 这个文件的主版本号。不被系统使用并可设为0。可以通过链接器选项/VERSION来设置。
    46/462MinorImageVersionThe minor version number of the image. 这个文件的次版本号。
    48/482MajorSubsystemVersionThe major version number of the subsystem. 可执行文件所要求的操作子系统的主版本号。它曾经被用来表示需要较新的Windows 95或Windows NT用户界面,而不是老版本的Windows NT界面。今天随着各种不同版本Windows的出现,这个域已不被系统使用,并且通常被设为4。可通过链接器选项/SUBSYSTEM设置这个域的值。
    50/502MinorSubsystemVersionThe minor version number of the subsystem. 可执行文件所要求的操作子系统的次版本号。
    52/524Win32VersionValueReserved, must be zero. 另一个不被使用的域,通常设为0。
    56/564SizeOfImageThe size (in bytes) of the image, including all headers, as the image is loaded in memory. It must be a multiple of SectionAlignment. 映像的大小。它表示了加载文件到内存中时系统必须保留的内存的数量。这个域的值必须是SectionAlignmnet的倍数。
    60/604SizeOfHeadersThe combined size of an MS-DOS stub, PE header, and section headers rounded up to a multiple of FileAlignment. MS-DOS头,PE头和节表的总的大小。PE文件中所有这些项目出现在任何代码或数据节之前。这个域的值被调整为文件对齐大小的整数倍。
    64/644CheckSumThe image file checksum. The algorithm for computing the checksum is incorporated into IMAGHELP.DLL. The following are checked for validation at load time: all drivers, any DLL loaded at boot time, and any DLL that is loaded into a critical Windows process. 映像的校验和。IMAGEHLP.DLL中的CheckSumMappedFile函数可以计算出这个值。校验和用于内核模式的驱动和一些系统DLL。对于其它的,这个域可以为0。当使用链接器选项/RELEASE时校验和被放入文件中。
    68/682SubsystemThe subsystem that is required to run this image. For more information, see “Windows Subsystem” later in this specification. 指示可执行文件期望的子系统(用户界面类型)的枚举值。这个域只用于EXE。一些重要的值包括:
    IMAGE_SUBSYSTEM_NATIVE // 映像不需要子系统
    IMAGE_SUBSYSTEM_WINDOWS_GUI // 使用Windows GUI IMAGE_SUBSYSTEM_WINDOWS_CUI // 作为控制台程序运行。
    // 运行时,操作系统创建一个控制台
    // 窗口并提供stdin,stdout和stderr
    // 文件句柄。
    70/702DllCharacteristicsFor more information, see “DLL Characteristics” later in this specification. 标记DLL的特性。对应于IMAGE_DLLCHARACTERISTICS_xxx定义。当前的值是:
    IMAGE_DLLCHARACTERISTICS_NO_BIND // 不要绑定这个映像
    IMAGE_DLLCHARACTERISTICS_WDM_DRIVER // WDM模式的驱动程序
    IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE // 当终端服务加载一个不是
    // Terminal- Services-aware 的应用程
    // 序时,它也加载一个包含兼容代码
    // 的DLL。
    72/724/8SizeOfStackReserveThe size of the stack to reserve. Only SizeOfStackCommit is committed; the rest is made available one page at a time until the reserve size is reached. 在EXE文件中,为线程保留的堆栈大小。缺省是1MB,但并不是所有的内存一开始都被提交。
    76/804/8SizeOfStackCommitThe size of the stack to commit. 在EXE文件中,为堆栈初始提交的内存数量。缺省情况下,这个域是4KB。
    80/884/8SizeOfHeapReserveThe size of the local heap space to reserve. Only SizeOfHeapCommit is committed; the rest is made available one page at a time until the reserve size is reached. 在EXE文件中,为默认进程堆初始保留的内存大小。缺省是1MB。然而在当前版本的Windows中,堆不经过用户干涉就能超出这里指定的大小。
    84/964/8SizeOfHeapCommitThe size of the local heap space to commit. 在EXE文件中,提交到堆的内存大小。缺省情况下,这里的值是4KB。
    88/1044LoaderFlagsReserved, must be zero. 不使用。
    92/1084NumberOfRvaAndSizesThe number of data-directory entries in the remainder of the optional header. Each describes a location and size. 在IMAGE_NT_HEADERS结构的末尾是一个IMAGE_DATA_DIRECTORY结构数组。此域包含了这个数组的元素个数。自从最早的Windows NT发布以来这个域的值一直是16。

    上面表格中的 offset 值两个,前面的是 IMAGE_OPTIONAL_HEADER32 的 offset 值,后面的是 IMAGE_OPTIONAL_HEADER64,这是因为在 64 位版本中一些域被扩展为 64 位值,而 BaseOfData 域在 64 位版中是不存在的。
    Magic 域是一个幻数值,在 WinNT.h 里定义了一些常量值:

    #define IMAGE_NT_OPTIONAL_HDR32_MAGIC      0x10b
    #define IMAGE_NT_OPTIONAL_HDR64_MAGIC      0x20b
    #define IMAGE_ROM_OPTIONAL_HDR_MAGIC       0x107
    • 值 0x10b 说明这个 image 是 32 位的,PE 文件格式是 PE32
    • 值 0x20b 说明这个 image 是 64 位的,PE 文件格式是 PE32+

    PE32+ 代表的扩展的 PE 文件格式,扩展为 64 位。在 PE 文件规范中并没有 PE64 这种文件格式,Microsoft 官方的判断 image 文件是 32 位还是 64 位的方法就是通过 Magic 的值来确定。

    在这些基本的域里可以获得 linker 的版本,text 节,data 节以及 bss 节的大小,下面看一看tlstest.exe 的 IMAGE_OPTIONAL_HEADER64 结构,从 0x00000110 - 0x000001FF

    这里写图片描述

    这里写图片描述

    Magic 是 0x020B 表明这个 image 文件是 64 位的 PE32+格式,这里看出 linker 的版本是 14.00
    .text 节的 size 是 0x00001000 bytes,.data 节的 size 是 0x00022000 bytes,还有一个重要的信息,代码的 RVA 入口在 0x00001338,它是基于 ImageBase 的 RVA 值。tlstest.exe 的 ImageBase 是0x0000000140000000,那么 tlstest.exe 映象的入口在:ImageBase + AddressOfEntryPoint = 0x0000000140000000 + 0x00001338 = 0x0000000140001338,这个地址是 __scrt_common_main() 的入口。

    上面的 SectionAlinment 域值为 0x1000 是表示映象被加载到 virtual address 以是 0x1000(4K byte)为单位的倍数,也就是加载在 virtual address 的 4K 边界上。例如:tlstest.exe映象的 .text 节被加载到以 ImageBase(virtual address 为 0x00000001_40000000)为基址的第 1 个 4K 边界上(即:0x00000001_40001000 处),.rdata 节加载到第 2 个 4K 边界上(即:0x00000001_40002000 处)。FileAlinment 域的值为 0x200 表示执行映象从 0x200 为边界开始加载到 virtual address 上。例如,t.exe 映象中 code 位于文件映象的 0x400 处(0x200 边界上),因此,t.exe 文件映象 code 从 0x400 处开始加载到 virtual address。

    4.3.3.1. IMAGE_DATA_DIRECTORY表格

    这里写图片描述

    在 IMAGE_OPTIONAL_HEADER64 未端是一组 IMAGE_DATA_DIRECTORY 结构的数组,上图所示:从 0x00000180 到 0x000001FF。在 WinNT.h 里定义为:

    //
    // Directory format.
    //
    typedef struct _IMAGE_DATA_DIRECTORY {
        DWORD   VirtualAddress;
        DWORD   Size;
    } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
    #define IMAGE_NUMBEROF_DIRECTORY_ENTRIES    16

    这个结构十分重要,它用来描述 windows 执行映象中所使用的各种表格的位置和大小。VirtualAddress 域是一个 RVA(Relative Virtual Address)值,更明白一点就是:它是一个偏移量(基于 PE 文件头),Size 域表示这个表格有多大。IMAGE_NUMBEROF_DIRECTORY_ENTRIES 的值为 16,因此有 16 个 Directory,也就是表示,在执行映象中最多可以使用 16 个表格。

    这 16 个 Driectory 指引出 16 不同格式的 table,实际上这 16 个表格是固定的,对于这些表格 Microsoft 都作了统一的规定,在 WinNT.h 里都作了定义:

    // Directory Entries
    #define IMAGE_DIRECTORY_ENTRY_EXPORT              0   // Export Directory
    #define IMAGE_DIRECTORY_ENTRY_IMPORT              1   // Import Directory
    #define IMAGE_DIRECTORY_ENTRY_RESOURCE          2   // Resource Directory
    #define IMAGE_DIRECTORY_ENTRY_EXCEPTION         3   // Exception Directory
    #define IMAGE_DIRECTORY_ENTRY_SECURITY           4   // Security Directory
    #define IMAGE_DIRECTORY_ENTRY_BASERELOC         5   // Base Relocation Table
    #define IMAGE_DIRECTORY_ENTRY_DEBUG                6   // Debug Directory
    //      IMAGE_DIRECTORY_ENTRY_COPYRIGHT           7   // (X86 usage)
    #define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE    7   // Architecture Specific Data
    #define IMAGE_DIRECTORY_ENTRY_GLOBALPTR         8   // RVA of GP
    #define IMAGE_DIRECTORY_ENTRY_TLS                    9   // TLS Directory
    #define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG    10   // Load Configuration Directory
    #define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT  11   // Bound Import Directory in headers
    #define IMAGE_DIRECTORY_ENTRY_IAT                   12   // Import Address Table
    #define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT   13   // Delay Load Import Descriptors
    #define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14   // COM Runtime descriptor

    从定义上得出,第 0 项是 export table(导出表),第 1 项是 import table(导入表)等等,在 Microsoft 的 MSDN 网站里有一个知识点介绍:http://msdn.microsoft.com/en-us/library/ms680305(VS.85).aspx
    下面,我将这些表格归纳如下:

    表项表格
    0export table
    1import table
    2resource table
    3exception table
    4certificate table
    5base relocation table
    6debug
    7architecute
    8global pointer
    9TLS table
    10load configuration table
    11bound import
    12import address table
    13delay import descriptor
    14CLR runtime header
    15reserved, must bo zero

    在 WinNT.h 有对这些 table 的结构的全部定义。

    那么,下面我们来看一看tlstest.exe 映象中使用了哪些表?

    这里写图片描述

    上面表格显示我们的示例程序 t.exe 仅仅使用了 8 个 driectory 表格:import table、resource table 、exception table 、relocation table 、debug table、TLS table、load configuration table以及 import address table。

    4.4. section 表

    IMAGE_NT_HEADER 结构后面紧接着就是 section table(节表)结构。现在来看一看tlstest.exe 的 section 表,从 0x00000200 - 0x0000033F,共 320 bytes

    这个节表结构在 WinNT.h 中定义为

    //
    // Section header format.
    //
    #define IMAGE_SIZEOF_SHORT_NAME              8
    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_SECTION_HEADER          40

    每个 section 表的大小为 40 bytes,section 表的作用是指出 image 映象 section 所在tlstest.exe 映象的 IMAGE_FILE_HEADER 结构的 NumberOfSections 域里已经指出tlstest.exe 映象中包含有 8 个 sections,因此整个 section 表的大小为:320 bytes。

    tlstest.exe的 section 表如下:

    这里写图片描述

    这 8 个 section 分别是:

    • .text 节
    • .rdata 节
    • .data 节
    • .pdata 节
    • .tls 节
    • .gfids 节
    • .rsrc 节
    • .reloc 节
      这里写图片描述

    在 IMAGE_SECTION_HEADER 结构的第 1 个域 Name,用来标识 section table 的名字。它的长度固定为 8 bytes(前面定义的宏),这将意味着,不存在超过 8 bytes 的节表名。接下来使用 VirtualSize 来用表示 section talbe 大小。VirtualAddress 表示 section table 的 RVA,它是基于 ImageBase 的 RVA 值,它指出 section 的所在,SizeOfRawData 是在 image 文件里占有的空间,它是 FileAlignment 的倍数,即:0x200 的倍数,也就是说 0x200 的边界。PointerToRawData是 section 在 image 文件的位置,同样也是 FileAligment 即:0x200 边界上。

    size描述
    Name8 bytesSection 表名字
    VirtualSizeDWORDSection 表的大小
    VirtualAddressDWORDSection 表的 RVA,即:section 表的位置
    SizeOfRawDataDWORDsection 表占用映像的大小,这个 size 是以 0x200 为单位的
    PointerToRawDataDWORDsection 表在映像中的物理位置,即是:file 位置,而非 virtual 位置
    PointerToRelocationDOWRD
    PointerToLinenumberDWORD
    NumberOfRelocationWORD
    NumberOfLineumbersWORD
    CharacteristicsDWORDsection 的属性 flags,可用于 ‘

    所有的 Characteristics 都在 WinNT.h 中有定义,下面是一些常用的 flags:

    #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_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.

    下面以 .text 节为例,看看tlstest.exe的 .text 是什么。

    这里写图片描述

    .text 节的 Name 是 “.text”,VirtualSize 是 0x00000E08 bytes,.text 节在 RVA 为 0x00001000 的位置上,section 的分配单位为 0x1000(4K bytes),第 1 个 section 一般都分配在 0x1000 位置上,SizeOfRawData 为 0x1000,这是映像文件分配单位。PointerToRawData 为 0x400,说明 .text 节在映像文件的 0x400 处。Characteristics 是 0x60000020,说明 .text 是 executable/readable/code 属性。

    展开全文
  • 信息系统安全与对抗实践 Windows PE文件格式及相关工具 内容提要 PE文件的概念 PE文件与其在内存中的对应 使用工具查看PE结构 2 PE文件 PE文件Windows操作系统下使用的可执行文件格式它是微软在UNIX平 台的通用...
  • Windows PE镜像文件如何测试.docx
  • icoextract是使用Python编写的Windows PE文件(.exe / .dll)的图标提取器。 它还包括用于Linux桌面的缩略图脚本( exe-thumbnailer )。 这个项目的灵感来自 , 和其他。 icoextract的目标是: 轻的 便携式(跨...
  • 这是Windows PE格式的文件加载器应用程序,提供与OS内部可执行文件加载器类似的功能,但从用户模式运行。 它将可执行文件映射到内存,打补丁并初始化几种机制,然后将控制流传递给加载的映像。 该项目是为教育目的而...
  • Windows PE文件各个节(Section)分析

    千次阅读 2017-03-30 14:51:38
    PE(Portable Executable),即可移植的执行体。PE文件通常包括以下节(Section).textbss/BSS,text/CODE,.rdata,.data,.idata,.edata,.rsrc,.reloc

    PE(Portable Executable),即可移植的执行体。所有Windows下可执行文件,均使用PE文件结构。

    PE文件通常包括以下节(Section)

    .textbss/BSS

    BSS段(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域。BSS是英文Block Started by Symbol的简称。BSS段属于静态内存分配。

    .text/CODE
    代码段(text segment)通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域属于只读。在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。需要注意的是,borland这里叫做code,而不是text 。

    .rdata
    只读数据段。
    The .rdata section is used for at least two things. First, in Microsoft linker-produced EXEs, the .rdata section holds the debug directory, which is only present in EXE files.
    The other useful portion of an .rdata section is the description string. If you specified a DESCRIPTION entry in your program’s DEF file, the specified description string appears in the .rdata section.

    .data
    数据段(data segment)通常是指用来存放程序中已初始化的全局变量的一块内存区域。数据段属于静态内存分配。

    .idata
    The .idata section contains information about functions (and data) that the module imports from other DLLs.
    导入段。包含程序需要的所有DLL文件信息。

    .edata
    The .edata section is a list of the functions and data that the PE file exports for other modules.
    导出段。包含所有提供给其他程序使用的函数和数据。

    .rsrc
    The .rsrc section contains all the resources for the module.
    资源数据段,程序用到什么资源数据都在这里。

    .reloc
    The .reloc section holds a table of base relocations. A base relocation is an adjustment to an instruction or initialized variable value that’s needed if the loader couldn’t load the file where the linker assumed it would. If the loader is able to load the image at the linker’s preferred base address, the loader completely ignores the relocation information in this section.
    重定位段。如果加载PE文件失败,将基于此段进行重新调整。

    参考文献
    1.https://msdn.microsoft.com/en-us/library/ms809762.aspx

    展开全文
  • WINDOWS PE文件结构详细介绍(一)

    千次阅读 2011-05-12 19:57:00
    因为我们现在的c++是在WIN32平台下面运行的,为了以后的学习,有必要先了解一下WINDOWS PE文件结构,这些相关资料来于深入Windows编程>这本书。 PE的意思就是Portable Executable (可移值的执行体),是...

    因为我们现在的c++是在WIN32平台下面运行的,为了以后的学习,有必要先了解一下WINDOWS PE文件结构,这些相关资料来于< Delphi深入Windows编程>这本书。

    PE的意思就是Portable Executable (可移值的执行体),是Win32环境自身所带的执行体文件格式。PE的一些特殊性继承自UNIXCOFF(Common Object File Format)文件格式。“Portable Executable”(可移值的执行体)意味着此文件格式是跨Win32平台的,即使Windows动作在非IntelCPU上,任何Win32平台的PE装载器都能识别和使用该文件格式。当然移值到不同CPUPE执行体必须会有一些改变。所有Win32执行体(除了VxD16位的DLL)都使用PE文件格式,包括WindowsNT的内核模式驱动程序(Kernel Mode Drivers)。PE文件的结构如下: 
     
       
    下面来分析一下PE文件格式的总体层次分布。
        (1)
    所有PE文件必须以一个简单的Dos Header(DOS文件头部) 开始,一旦程序在DOS下执行,DOS就能识别出这是有效的执行体,然后运行紧随Dos Header之后的DOS stub(DOS 插桩程序)DOS stub实际上是个有效的DOS下的EXE代码,在不支持PE文件格式的操作系统中,将简单显示一个错误提示,类似于字符串“This program requires Windows”或者程序员可根据自己的意图实现完整的DOS代码。通常,简单调用中断21h服务9号子功能来显示字符串“This program cannot run is DOS mode”


        (2)
    紧接着DOS Stub的是PE Header(PE文件头部)PE HeaderPE相关结构IMAGE_NT_HEADER的简称,其中包含了许多PE装载器用到的重要域。在更加深入地研究PE文件格式后,本书将对这些重要域详细地解释。执行体在支持PE文件结构的操作系统中执行时,PE装载器将从DOS Header中找到PE Header的起始偏移量。因而跳过了DOS stub直接定位到真正的文件头PE Header


        (3)PE
    文件的真正内容划分成块,称为Sections()。每节是一块拥有共同属性的数据,例如代码/数据、读/写等。可以把PE文件想像成一个逻辑磁盘,PE Header是磁盘的Boot扇区,而Sections就是各种文件,每种文件自然就有不同属性如只读、系统、隐藏、文档等。值得注意的是,节的划分是基于各组数据的共同属性,而不是逻辑概念。所以,不必太关心节中类似于“data”“code”或其他的逻辑概念,如果数据和代码拥有相同的属性,就可以被归入同一个节中,亦即节名称仅仅是个区别不同节的符号而已,“data”“code”等的命名只为了便于识别,惟有节的属性决定了节的特性和功能。如果某块数据想赋为只读属性,就可以将该数据放入为只读的节中,当PE装载器映射节内容时,会检查相关节属性并置对应内存块为指定属性。


        (4)
    如果将PE文件格式视为一个逻辑磁盘,PE HeaderBoot扇区,而Sections是各种文件,但仍缺足够信息来定位磁盘上的不同文件。例如,什么是PE文件格式中等价于目录的东西?那就是PE Header接下来的数据结构Section Table(节表)。每个结构包含对应节的属性、文件偏移量、虚拟偏移量等。如果PE文件里有5个字节,那么此结构数组内就有5个成员。因此,便可以把节表视为逻辑磁盘中的根目录,每个数组成员等价于根目录中的目录项。


       
    以上就是PE文件格式的物理分布,下面总结一下装载PE文件的主要流程。

    1)当PE文件被执行,PE装载器检查DOS Header里面的PE Header偏移量。如果找到,则跳转到PE Header,否则提示这不是PE文件。

    2PE装载器检查PE Header的有效性。如果有效,就跳转到PE Header的尾部。

    3)紧跳PE Header的是节表,PE装载器读取其中的节信息,并采用文件映射方法将这些节映射到内存,同时附上节表里指定的节属性。

    4PE文件映射入内存后,PE装载器将处理PE文件中类似Import Table(引入表的逻辑部分。)


    以上便是关于PE文件结构的介绍,下篇,我们将介绍,c++编译器是如何将c++的一些变量和代码组织到pe文件结构里面。

    展开全文
  • windows PE Image 文件分析

    千次阅读 2012-03-10 16:22:30
    上面是 windows PE 可执行文件格式的结构图,分为 4 个部分:DOS 文件头、NT 文件头、Section 表以及 Directory 表格。 windows 的 executable image 文件使用的是这种 PE 格式,而 object 文件使用的是 ...

    转自:http://www.mouseos.com/windows/PE_image1.html


    上面是 windows PE 可执行文件格式的结构图,分为 4 个部分:DOS 文件头NT 文件头Section 表以及 Directory 表格

    windows 的 executable image 文件使用的是这种 PE 格式,而 object 文件使用的是 COFF 文件格式。

     

    这里仍然是延续我的风格,以实例看 image 文件格式,这次以 mircrosoft visual studio 2010 的 VC++ 9.0 编译出来经典 windows 程序为例:

    这个例子是:

    // helloworld.cpp : Defines the entry point for the application.
    //

    #include "stdafx.h"
    #include "helloworld.h"

    #define MAX_LOADSTRING 100

    // Global Variables:
    HINSTANCE hInst;        // current instance
    TCHAR szTitle[MAX_LOADSTRING];     // The title bar text
    TCHAR szWindowClass[MAX_LOADSTRING];   // the main window class name

    // Forward declarations of functions included in this code module:
    ATOM    MyRegisterClass(HINSTANCE hInstance);
    BOOL    InitInstance(HINSTANCE, int);
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
    INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);

    int APIENTRY _tWinMain(HINSTANCE hInstance,
                         HINSTANCE hPrevInstance,
                         LPTSTR    lpCmdLine,
                         int       nCmdShow)
    {
     UNREFERENCED_PARAMETER(hPrevInstance);
     UNREFERENCED_PARAMETER(lpCmdLine);

      // TODO: Place code here.
     MSG msg;
     HACCEL hAccelTable;

     // Initialize global strings
     LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
     LoadString(hInstance, IDC_HELLOWORLD, szWindowClass, MAX_LOADSTRING);
     MyRegisterClass(hInstance);

     // Perform application initialization:
     if (!InitInstance (hInstance, nCmdShow))
     {
      return FALSE;
     }

     hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_HELLOWORLD));

     // Main message loop:
     while (GetMessage(&msg, NULL, 0, 0))
     {
      if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
      {
       TranslateMessage(&msg);
       DispatchMessage(&msg);
      }
     }

     return (int) msg.wParam;
    }

     

    //
    //  FUNCTION: MyRegisterClass()
    //
    //  PURPOSE: Registers the window class.
    //
    //  COMMENTS:
    //
    //    This function and its usage are only necessary if you want this code
    //    to be compatible with Win32 systems prior to the 'RegisterClassEx'
    //    function that was added to Windows 95. It is important to call this function
    //    so that the application will get 'well formed' small icons associated
    //    with it.
    //
    ATOM MyRegisterClass(HINSTANCE hInstance)
    {
     WNDCLASSEX wcex;

     wcex.cbSize = sizeof(WNDCLASSEX);

     wcex.style   = CS_HREDRAW | CS_VREDRAW;
     wcex.lpfnWndProc = WndProc;
     wcex.cbClsExtra  = 0;
     wcex.cbWndExtra  = 0;
     wcex.hInstance  = hInstance;
     wcex.hIcon   = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_HELLOWORLD));
     wcex.hCursor  = LoadCursor(NULL, IDC_ARROW);
     wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
     wcex.lpszMenuName = MAKEINTRESOURCE(IDC_HELLOWORLD);
     wcex.lpszClassName = szWindowClass;
     wcex.hIconSm  = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

     return RegisterClassEx(&wcex);
    }

    //
    //   FUNCTION: InitInstance(HINSTANCE, int)
    //
    //   PURPOSE: Saves instance handle and creates main window
    //
    //   COMMENTS:
    //
    //        In this function, we save the instance handle in a global variable and
    //        create and display the main program window.
    //
    BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
    {
       HWND hWnd;

       hInst = hInstance; // Store instance handle in our global variable

       hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
          CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

       if (!hWnd)
       {
          return FALSE;
       }

       ShowWindow(hWnd, nCmdShow);
       UpdateWindow(hWnd);

       return TRUE;
    }

    //
    //  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
    //
    //  PURPOSE:  Processes messages for the main window.
    //
    //  WM_COMMAND - process the application menu
    //  WM_PAINT - Paint the main window
    //  WM_DESTROY - post a quit message and return
    //
    //
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
     int wmId, wmEvent;
     PAINTSTRUCT ps;
     HDC hDC;
     RECT rect;

     switch (message)
     {
     case WM_COMMAND:
      wmId    = LOWORD(wParam);
      wmEvent = HIWORD(wParam);
      // Parse the menu selections:
      switch (wmId)
      {
      case IDM_ABOUT:
       DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
       break;
      case IDM_EXIT:
       DestroyWindow(hWnd);
       break;
      default:
       return DefWindowProc(hWnd, message, wParam, lParam);
      }
      break;
     case WM_PAINT:
      hDC = BeginPaint(hWnd, &ps);
      // TODO: Add any drawing code here...
      GetClientRect(hWnd, &rect);
      DrawText(hDC, TEXT("hello, world"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
      EndPaint(hWnd, &ps);
      break;
     case WM_DESTROY:
      PostQuitMessage(0);
      break;
     default:
      return DefWindowProc(hWnd, message, wParam, lParam);
     }
     return 0;
    }

    // Message handler for about box.
    INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
    {
     UNREFERENCED_PARAMETER(lParam);
     switch (message)
     {
     case WM_INITDIALOG:
      return (INT_PTR)TRUE;

     case WM_COMMAND:
      if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
      {
       EndDialog(hDlg, LOWORD(wParam));
       return (INT_PTR)TRUE;
      }
      break;
     }
     return (INT_PTR)FALSE;
    }

    在窗口中间显示“hello, world”,使用的是 Win32 debug 版本编译,生成的 helloworld.exe 大小是 88,576 bytes

     

    1. MS-DOS 文件头

    在 image 文件的最开始处就是 DOS 文件头,DOS 文件头包含了 DOS stub 小程序。 在 WinNT.h 文件里定义了一个结构来描述 DOS 文件头。

    typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header
        WORD   e_magic;                     // Magic number
        WORD   e_cblp;                      // Bytes on last page of file
        WORD   e_cp;                        // Pages in file
        WORD   e_crlc;                      // Relocations
        WORD   e_cparhdr;                   // Size of header in paragraphs
        WORD   e_minalloc;                  // Minimum extra paragraphs needed
        WORD   e_maxalloc;                  // Maximum extra paragraphs needed
        WORD   e_ss;                        // Initial (relative) SS value
        WORD   e_sp;                        // Initial SP value
        WORD   e_csum;                      // Checksum
        WORD   e_ip;                        // Initial IP value
        WORD   e_cs;                        // Initial (relative) CS value
        WORD   e_lfarlc;                    // File address of relocation table
        WORD   e_ovno;                      // Overlay number
        WORD   e_res[4];                    // Reserved words
        WORD   e_oemid;                     // OEM identifier (for e_oeminfo)
        WORD   e_oeminfo;                   // OEM information; e_oemid specific
        WORD   e_res2[10];                  // Reserved words
        LONG   e_lfanew;                    // File address of new exe header
      } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

    这个结构名叫 IMAGE_DOS_HEADER 共 64 bytes,以 IMAGE_DOS_HEADER 结构描述的 DOS 文件头结构从 image 的 0x00000000 - 0x0000003F(64 bytes)

    结构的 e_magic 域是 DOS 头文件签名,它的值是:0x5A4D 代表字符 MZ,它在 WinNT.h 里定义为:

    #define IMAGE_DOS_SIGNATURE                 0x5A4D      // MZ

    e_lfanew 域是一个 offset 值,它指出 NT 文件头的位置。

    下面看看 helloworld.exe 的 DOS 文件头内容:

    Offset(h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F

    00000000  4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00  MZ..........??..
    00000010  B8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00  ?.......@.......
    00000020  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
    00000030  00 00 00 00 00 00 00 00 00 00 00 00 F0 00 00 00  ............e...

    红色部分是 DOS 签名蓝色部分 PE header offset(NT 文件头)值,也就是 IMAGE_DOS_HEADER 里的 e_lfanew 值,表明 NT 文件头在 image 文件的 0x000000F0 处。


    1.1 DOS stub 程序

    在 DOS 文件头下面紧跟着一小段 stub 程序,从 0x00000040 - 0x0000004D 共 14 bytes,这段 dos stub 程序是这样的:

    00000040  0E                push cs
    00000041  1F                pop ds
    00000042  BA0E00            mov dx,0xe
    00000045  B409              mov ah,0x9
    00000047  CD21              int 0x21
    00000049  B8014C            mov ax,0x4c01
    0000004C  CD21              int 0x21

    当 windows 的 PE 文件放在 DOS 上执行时,将会执行这一段 DOS stub 程序,作用是打印信息:This program cannot be run in DOS mode.... 然后调用 int 21 来终止执行返回到 DOS

    看看它是怎样运行的:

    00000014  00 00      // ip
    00000016  00 00      // cs
    00000018  40 00      // e_lfarlc

    这个 DOS 执行环境中,CS 和 IP 被初始化为 0e_lfarlc 是 DOS 环境的 relocate 表,它的值是 0x40 ,那么信息字符串的位置是:0x0040 + 0x000e = 0x4e,在 image 文件的 0x0000004e 正好这字符串的位置。

     

    2. NT 文件头

    NT 文件头是 PE 文件头的核心部分,由 IMAGE_DOS_HEADER 结构的 e_lfanew 域指出它的位置。

    同样 NT 文件头部分由一个结构 IMAGE_NT_HEADER 来描述,在 WinNT.h 里定义如下:

    typedef struct _IMAGE_NT_HEADERS64 {
        DWORD Signature;
        IMAGE_FILE_HEADER FileHeader;
        IMAGE_OPTIONAL_HEADER64 OptionalHeader;
    } IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;

    typedef struct _IMAGE_NT_HEADERS {
        DWORD Signature;
        IMAGE_FILE_HEADER FileHeader;
        IMAGE_OPTIONAL_HEADER32 OptionalHeader;
    IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

    可见这个结构分为 32 和 64 位版本,IMAGE_NT_HEADER 结构分为三大部分:

    • PE 文件签名:Signature
    • IMAGE_FILE_HEADER 文件头:FileHeader
    • IMAGE_OPTINAL_HEADER(32/64) 可选头:OptionalHeader

    IMAGE_NT_HEADERS32 和 IMAGE_NT_HEADERS64 的匹别在于 IMAGE_OPTIONAL_HEADER 结构,分别为:IMAGE_OPTIONAL_HEADERS32 和 IMAGE_OPTIONAL_HEADERS64

    在 Win32 下 IMAGE_NT_HEADERS32 是 248 bytes,在 Win64 下 IMAGE_NT_HEADERS64 是 264 bytes,因此 helloworld.exe 的 NT 文件头从 0x000000F0 - 0x000001E7 共 248 bytes


    2.1 PE 签名

    在 WinNT.h 文件里定义了 PE 文件的签名,它是:

    #define IMAGE_NT_SIGNATURE                  0x00004550  // PE00

    这个签名值是 32 位,值为:0x00004550 即:PE 的 ASCII 码,下面看看 helloworld.exe 中的 PE 签名:


    2.2 IMAGE_FILE_HEADER 文件头结构

    PE 签名接着是 IMAGE_FILE_HEADER 结构,它在 WinNT.h 中的定义为:

    typedef struct _IMAGE_FILE_HEADER {
        WORD    Machine;
        WORD    NumberOfSections;
        DWORD   TimeDateStamp;
        DWORD   PointerToSymbolTable;
        DWORD   NumberOfSymbols;
        WORD    SizeOfOptionalHeader;
        WORD    Characteristics;
    } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

    这个 IMAGE_FILE_HEADER 对 PE 文件大致的描述,这个结构共 20 bytes,它的域描述如下:

    size
    描述
    Machine
    WORD
    IMAGE_FILE_MACHINE_xxx
    表示目标平台 processor 类型,例: IMAGE_FILE_MACHINE_I386
    NumberOfSections
    WORD
    节数量
    表示映象中有多少个 section
    TimeDataStamp
    DWORD
    从1970年1月1日0:00 以来的总秒数
    表示文件创建的时间
    PointerToSymbolTable
    DWORD
    COFF 符号表偏移量
    在 image 文件中很少见,总是为 0
    NumberOfSymbols
    DWORD
    COFF 符号表的个数
    如果存在的话,表示符号表的个数
    SizeOfOptionalHeader
    WORD
    IMAGE_OPTIONAL_HEADER 结构大小
    该域表示  IMAGE_NT_HEADER 中的  IMAGE_OPTIONAL_HEADER 结构的大小
    Characteristics
    WORD
    IMAGE_FILE_xxx
    表示文件属性,例如: IMAGE_FILE_DLL 属性

    WinNT.h 中定义了一些常量值用来描述 Machine,以 IMAGE_FILE_MACHINE_XXX 开头,下面是一些典型的常量值:

    #define IMAGE_FILE_MACHINE_UNKNOWN           0
    #define IMAGE_FILE_MACHINE_I386              0x014c  // Intel 386.
    #define IMAGE_FILE_MACHINE_ALPHA             0x0184  // Alpha_AXP
    #define IMAGE_FILE_MACHINE_POWERPC           0x01F0  // IBM PowerPC Little-Endian
    #define IMAGE_FILE_MACHINE_AMD64             0x8664  // AMD64 (K8)

    WinNT.h 中还针对 Characteristics 域定义了一些常量值,以 IMAGE_FILE_XXX 开头,代表目标 image 文件的类型,下面是一些常见的值:

    #define IMAGE_FILE_RELOCS_STRIPPED           0x0001  // Relocation info stripped from file.
    #define IMAGE_FILE_EXECUTABLE_IMAGE          0x0002  // File is executable  (i.e. no unresolved externel references).
    #define IMAGE_FILE_LINE_NUMS_STRIPPED        0x0004  // Line nunbers stripped from file.
    #define IMAGE_FILE_LOCAL_SYMS_STRIPPED       0x0008  // Local symbols stripped from file.
    #define IMAGE_FILE_AGGRESIVE_WS_TRIM         0x0010  // Agressively trim working set
    #define IMAGE_FILE_LARGE_ADDRESS_AWARE       0x0020  // App can handle >2gb addresses
    #define IMAGE_FILE_BYTES_REVERSED_LO         0x0080  // Bytes of machine word are reversed.
    #define IMAGE_FILE_32BIT_MACHINE             0x0100  // 32 bit word machine.
    #define IMAGE_FILE_DEBUG_STRIPPED            0x0200  // Debugging info stripped from file in .DBG file
    #define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP   0x0400  // If Image is on removable media, copy and run from the swap file.
    #define IMAGE_FILE_NET_RUN_FROM_SWAP         0x0800  // If Image is on Net, copy and run from the swap file.
    #define IMAGE_FILE_SYSTEM                    0x1000  // System File.
    #define IMAGE_FILE_DLL                       0x2000  // File is a DLL.
    #define IMAGE_FILE_UP_SYSTEM_ONLY            0x4000  // File should only be run on a UP machine
    #define IMAGE_FILE_BYTES_REVERSED_HI         0x8000  // Bytes of machine word are reversed.

    NumberOfSections 表示 image 有多个 section,另一个重要的域是:SizeOfOptionalHeader 它指出接下来 IMAGE_OPTIONAL_HEADER 的大小,它有两个 size:Win32 的 0xDC 和 Win64 的 0xF0

    下面是 helloworld.exe 的 IMAGE_FILE_HEADER 结构,从 0x000000F4 - 0x00000107 共 20 bytes:

    将这些值分解为:

    000000F4  4C 01                // Machine
    000000F8  07 00                // NumberOfSections
    000000FA  6C C6 26 4C          // TimeDateStamp
    000000FE  00 00 00 00          // PointerToSymbolTable
    00000100  00 00 00 00          // NumberOfSymbols
    00000104  E0 00                // SizeOfOptionalHeader
    00000106  02 01                // Characteristics

    • Machine 是 0x014C,它的值是 IMAGE_FILE_MACHINE_I386,说明这个 image 文件的目标平台是 i386,即:Win32 平台
    • NumberOfSections 是 0x07,说明 image 文件内含有 7 个 sections
    • SizeOfOptionalHeader 是 0xE0,说明接下来的 IMAGE_OPTIONAL_HEADERS32 将是 0xE0224 bytes

    它的 Characteristics 是 0x102 IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_32BIT_MACHINE,说明这个 image 是 32 位可执行的映像。


    2.3 IMAGE_OPTIONAL_HEADER32 结构

    在 IMAGE_FILE_HEADER 结构里已经指明了 image 是 32 位,并且 IMAGE_OPTIONAL_HEADER 的大小是 224 bytes,那么这个结构就是 IMAGE_OPTIONAL_HEADER32 结构。

    可以根据 IMAGE_FILE_HEAER 结构的 Machine 来判断 image 是 Win32 还是 Win64 平台的。但是 Microsoft 官方推荐及认可的方法是从 IMAGE_OPTIONAL_HEADER 里的 magic 的值来判断目标平台 。

    在 WinNT.h 里 IMAGE_OPTIONAL_HEADER32 的定义如下:

    typedef struct _IMAGE_OPTIONAL_HEADER {
        //
        // Standard fields.
        //

        WORD    Magic;
        BYTE    MajorLinkerVersion;
        BYTE    MinorLinkerVersion;
        DWORD   SizeOfCode;
        DWORD   SizeOfInitializedData;
        DWORD   SizeOfUninitializedData;
        DWORD   AddressOfEntryPoint;
        DWORD   BaseOfCode;
        DWORD   BaseOfData;

        //
        // NT additional fields.
        //

        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 位的 IMAGE_OPTIONAL_HEADER64 里没有 BaseOfData 域,其它的与 IMAGE_OPTIONAL_HEADER32 结构的域是一样的,只是一些域扩展为 64 位值,它们包括:

    • ImageBase
    • SizeOfStackReserve
    • SizeOfStackCommit
    • SizeOfHeapRerserve
    • SizeOfHeapCommit

    这些域在 64 位结构里被定义为 ULONGLONG 类型。

    从 IMAGE_OPTIONAL_HEADER32 的定义可以看出,这个结构分为 基本域 部分和 附加域 部分,它的基本域含义如下:

    Offset

    Size

    Field

    Description

    0

    2

    Magic

    The unsigned integer that identifies the state of the image file. The most common number is 0x10B, which identifies it as a normal executable file. 0x107 identifies it as a ROM image, and 0x20B identifies it as a PE32+ executable.

    2

    1

    MajorLinkerVersion

    The linker major version number.

    3

    1

    MinorLinkerVersion

    The linker minor version number.

    4

    4

    SizeOfCode

    The size of the code (text) section, or the sum of all code sections if there are multiple sections.

    8

    4

    SizeOfInitializedData

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

    12

    4

    SizeOfUninitializedData

    The size of the uninitialized data section (BSS), or the sum of all such sections if there are multiple BSS sections.

    16

    4

    AddressOfEntryPoint

    The address of the entry point relative to the image base when the executable file is loaded into memory. For program images, this is the starting address. For device drivers, this is the address of the initialization function. An entry point is optional for DLLs. When no entry point is present, this field must be zero.

    20

    4

    BaseOfCode

    The address that is relative to the image base of the beginning-of-code section when it is loaded into memory.

    Magic 域是一个幻数值,在 WinNT.h 里定义了一些常量值:

    #define IMAGE_NT_OPTIONAL_HDR32_MAGIC      0x10b
    #define IMAGE_NT_OPTIONAL_HDR64_MAGIC      0x20b
    #define IMAGE_ROM_OPTIONAL_HDR_MAGIC       0x107

    • 值 0x10b 说明这个 image 是 32 位的,PE 文件格式是 PE32
    • 值 0x20b 说明这个 image 是 64 位的,PE 文件格式是 PE32+

    PE32+ 代表的扩展的 PE 文件格式,扩展为 64 位。在 PE 文件规范中并没有 PE64 这种文件格式,Microsoft 官方的判断 image 文件是 32 位还是 64 位的方法就是通过 Magic 的值来确定。

    在这些基本的域里可以获得 linker 的版本,text 节,data 节以及 bss 节的大小,

    下面看一看 helloworld.exe 的 IMAGE_OPTIONAL_HEADER32 结构的基本域,从 0x00000108 - 0x0000011F

    00000108  0B 01             // Magic
    0000010A  0A                // MajorLinkerVersion
    0000010B  00                // MinorLinkerVersion
    0000010C  00 3C 00 00       // SizeOfCode
    00000110  00 20 01 00       // SizeOfInitializeData
    00000114  00 00 00 00       // SizeOfUninitializeData
    00000118  0D 12 01 00       // AddressOfEntryPoint
    0000011C  00 10 00 00       // BaseOfCode

    Magic 是 0x010B 表明这个 image 文件是 32 位的 PE32 格式,这里看出 linker 的版本是 10.00

    .text 节的 size 是 0x00003C00 bytes,.data 节的 size 是 0x00012000 bytes,还有一个重要的信息,代码的 RVA 入口在 0x0001120D,它是基于 ImageBase 的 RVA 值。代码的基址在 0x00001000,这个是RVA(Relative Virtual Address)值。

    下面再来看一看 IMAGE_OPTIONAL_HEADER32 结构的附加域

    Offset

    Size

    Field

    Description

    24

    4

    BaseOfData

    The address that is relative to the image base of the beginning-of-data section when it is loaded into memory.

    28/24

    4/8

    ImageBase

    The preferred address of the first byte of image when loaded into memory; must be a multiple of 64 K. The default for DLLs is 0x10000000. The default for Windows CE EXEs is 0x00010000. The default for Windows NT, Windows 2000, Windows XP, Windows 95, Windows 98, and Windows Me is 0x00400000.

    32/32

    4

    SectionAlignment

    The alignment (in bytes) of sections when they are loaded into memory. It must be greater than or equal to FileAlignment. The default is the page size for the architecture.

    36/36

    4

    FileAlignment

    The alignment factor (in bytes) that is used to align the raw data of sections in the image file. The value should be a power of 2 between 512 and 64 K, inclusive. The default is 512. If the SectionAlignment is less than the architecture’s page size, then FileAlignment must match SectionAlignment.

    40/40

    2

    MajorOperatingSystemVersion

    The major version number of the required operating system.

    42/42

    2

    MinorOperatingSystemVersion

    The minor version number of the required operating system.

    44/44

    2

    MajorImageVersion

    The major version number of the image.

    46/46

    2

    MinorImageVersion

    The minor version number of the image.

    48/48

    2

    MajorSubsystemVersion

    The major version number of the subsystem.

    50/50

    2

    MinorSubsystemVersion

    The minor version number of the subsystem.

    52/52

    4

    Win32VersionValue

    Reserved, must be zero.

    56/56

    4

    SizeOfImage

    The size (in bytes) of the image, including all headers, as the image is loaded in memory. It must be a multiple of SectionAlignment.

    60/60

    4

    SizeOfHeaders

    The combined size of an MS?DOS stub, PE header, and section headers rounded up to a multiple of FileAlignment.

    64/64

    4

    CheckSum

    The image file checksum. The algorithm for computing the checksum is incorporated into IMAGHELP.DLL. The following are checked for validation at load time: all drivers, any DLL loaded at boot time, and any DLL that is loaded into a critical Windows process.

    68/68

    2

    Subsystem

    The subsystem that is required to run this image. For more information, see “Windows Subsystem” later in this specification.

    70/70

    2

    DllCharacteristics

    For more information, see “DLL Characteristics” later in this specification.

    72/72

    4/8

    SizeOfStackReserve

    The size of the stack to reserve. Only SizeOfStackCommit is committed; the rest is made available one page at a time until the reserve size is reached.

    76/80

    4/8

    SizeOfStackCommit

    The size of the stack to commit.

    80/88

    4/8

    SizeOfHeapReserve

    The size of the local heap space to reserve. Only SizeOfHeapCommit is committed; the rest is made available one page at a time until the reserve size is reached.

    84/96

    4/8

    SizeOfHeapCommit

    The size of the local heap space to commit.

    88/104

    4

    LoaderFlags

    Reserved, must be zero.

    92/108

    4

    NumberOfRvaAndSizes

    The number of data-directory entries in the remainder of the optional header. Each describes a location and size.

    上面表格中的 offset 值两个,前面的是 IMAGE_OPTIONAL_HEADER32 的 offset 值,后面的是 IMAGE_OPTIONAL_HEADER64,这是因为在 64 位版本中一些域被扩展为 64 位值,而 BaseOfData 域在 64 位版中是不存在的。

    下面是 helloworld.exe 的 IMAGE_OPTIONAL_HEADER32 剩余部分,从 0x00000120 - 0x000001E7

    00000120  00 10 00 00           // BaseOfData
    00000124  00 00 40 00           // ImageBase
    00000128  00 10 00 00           // SectionAlignment 
    0000012C  00 02 00 00           // FileAlignment
    00000130  05 00                 // MajorOperatingSystemVersion
    00000132  01 00                 // MinorOperatingSystemVersion
    00000134  00 00                 // MajorImageVersion
    00000136  00 00                 // MinorImageVersion
    00000138  05 00                 // MajorSubsystemVersion
    0000013A  01 00                 // MinorSubsystemVersion
    0000013C  00 00 00 00           // Win32VersionVAlue
    00000140  00 90 02 00           // SizeOfImage 
    00000144  00 04 00 00           // SizeOfHeaders
    00000148  00 00 00 00           // CheckSum
    0000014C  02 00                 // Subsystem
    0000014E  40 81                 // DllCharacteristics
    00000150  00 00 10 00           // SizeOfStackReserve
    00000154  00 10 00 00           // SizeOfStackCommit
    00000158  00 00 10 00           // SizeOfHeapReserve
    0000015C  00 10 00 00           // SizeOfHeapCommit
    00000160  00 00 00 00           // LoaderFlags
    00000164  10 00 00 00           // NumberOfRvaAndSizes

    00000168  00 00 00 00           // DataDirectory[0] 
    0000016C  00 00 00 00
    00000170  00 80 01 00           // DataDirectory[1] 
    00000174  50 00 00 00 

    00000178  00 90 01 00           // DataDirectory[2] 
    0000017C  1C E7 00 00

    00000180  00 00 00 00           // DataDirectory[3] 
    00000184  00 00 00 00 
    00000188  00 00 00 00           // DataDirectory[4] 
    0000018C  00 00 00 00
    00000190  00 80 02 00           // DataDirectory[5] 
    00000194  40 03 00 00 

    00000198  20 57 01 00           // DataDirectory[6] 
    0000019C  1C 00 00 00

    000001A0  00 00 00 00           // DataDirectory[7] 
    000001A4  00 00 00 00 
    000001A8  00 00 00 00           // DataDirectory[8] 
    000001AC  00 00 00 00
    000001B0  00 00 00 00           // DataDirectory[9] 
    000001B4  00 00 00 00 
    000001B8  00 00 00 00           // DataDirectory[10] 
    000001BC  00 00 00 00 
    000001C0  00 00 00 00           // DataDirectory[11] 
    000001C4  00 00 00 00 
    000001C8  30 82 01 00           // DataDirectory[12] 
    000001CC  E0 01 00 00 

    000001D0  00 00 00 00           // DataDirectory[13] 
    000001D4  00 00 00 00 
    000001D8  00 00 00 00           // DataDirectory[14] 
    000001DC  00 00 00 00
    000001E0  00 00 00 00           // DataDirectory[15] 
    000001E4  00 00 00 00

    helloworld.exe 的 ImageBase 是 0x00400000,那么 helloworld.exe 映象的入口在:ImageBase + AddressOfEntryPoint = 0x00400000 + 0x0001120D = 0x0041120D,这个地址是 _wWinMainCRTStartup() 的入口。

    上面的 SectionAlinment 域值为 0x1000 是表示映象被加载到 virtual address 以是 0x1000(4K byte)为单位的倍数,也就是加载在 virtual address 的 4K 边界上。FileAlinment 域的值为 0x200 表示执行映象从 0x200 为边界开始加载到 virtual address 上。


    2.3.1 Directory 表格

    在 IMAGE_OPTIONAL_HEADER32 未端是一组 IMAGE_DATA_DIRECTORY 结构的数组,在 WinNT.h 里定义为:

    //
    // Directory format.
    //

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

    #define IMAGE_NUMBEROF_DIRECTORY_ENTRIES    16

    IMAGE_NUMBEROF_DIRECTORY_ENTRIES 的值为 16,因此有 16 个 Directory,Directory 结构中的 VirtualAddress 是一个 RVA 值。

    这 16 个 Driectory 指引出 16 不同格式的 table,这 16 个 table 分别是:

    表项
    表格
    0
    export table
    1
    import table
    2
    resource table
    3
    exception table
    4
    certificate table
    5
    base relocation table
    6
    debug
    7
    architecute
    8
    global pointer
    9
    TLS table
    10
    load configuration table
    11
    bound import
    12
    import address table
    13
    delay import descriptor
    14
    CLR runtime header
    15
    reserved, must bo zero

    在 WinNT.h 有对这些 table 的结构的全部定义。

    在我们的实例 helloworld.exe 中使用了 5 个 Driectory,也就是使用了 5 个 Data table,它们是:

    • import table
    • resource table
    • base relocation table
    • debug table
    • import address table
    import table
    resource table
    base relocation bale
    debug table
    import address table
    VirtualAddress
    0x00018000
    0x00019000
    0x00028000
    0x00015720
    0x00018230
    size
    0x50
    0xE71C
    0x340
    0x1C
    0x1E0

    上面表格显示了 Directory 指示的 Data table 在 virtual address 上的位置

     

    3. section 表

    现在来看一看 helloworld.exe 的 section 表,从 0x000001E8 - 0x000002FF,共 280 bytes

    这个节表结构在 WinNT.h 中定义为

    //
    // Section header format.
    //

    #define IMAGE_SIZEOF_SHORT_NAME              8

    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_SECTION_HEADER          40

    每个 section 表的大小为 40 bytes,section 表的作用是指出 image 映象 section 所在

    在 helloworld.exe 映象的 IMAGE_FILE_HEADER 结构的 NumberOfSections 域里已经指出 helloworld.exe 映象中包含有 7 个 sections,因此整个 section 表的大小为:280 bytes

    helloworld.exe 的 section 表如下:

    这 7 个 section 分别是:

    • .textbss 节
    • .text 节
    • .rdata 节
    • .data 节
    • .idata 节
    • .rsrc 节
    • .reloc 节
    .textbss 节
    .text 节
    .rdata 节
    .data 节
    .idata 节
    .rsrc 节
    .reloc 节
    VirtualSize
    0x00010000
    0x00003BDB
    0x00001CD1
    0x00000764
    0x00000AAE
    0x0000E71C
    0x00000564
    VirtualAddress
    0x00001000
    0x00011000
    0x00015000
    0x00017000
    0x00018000
    0x00019000
    0x00028000
    SizeOfRawData
    0
    0x00003C00
    0x00001E00
    0x00000200
    0x00000C00
    0x0000E800
    0x00000600
    PointerToRawData
    0
    0x00000400
    0x00004000
    0x00005E00
    0x00006000
    0x00006C00
    0x00015400
    PointerToRelocations
    0
    0
    0
    0
    0
    0
    0
    PointerToLinenumbers
    0
    0
    0
    0
    0
    0
    0
    NumberOfRelocations
    0
    0
    0
    0
    0
    0
    0
    NumberOfLinenumbers
    0
    0
    0
    0
    0
    0
    0
    Characteristics
    0xE00000A0
    0x60000020
    0x40000040
    0xC0000040
    0xC0000040
    0x40000040
    0x42000040

    IMAGE_SECTION_HEADER 结构里的 name 指出 section 的名字,这个 section 名 8 个节字长。

    VirtualAddress 是一个基于 ImageBase 的 RVA 值,它指出 section 的所在,VirtualSize 指出 section 的大小,SizeOfRawData 是在 image 文件里占有的空间,它是 FileAlignment 的倍数,即:0x200 的倍数,也就是说 0x200 的边界。PointerToRawData 是 section 在 image 文件的位置,同样也是 FileAligment 即:0x200 边界上。

    展开全文
  • windows PE文件格式研究及PEDUMP的实现.大学生毕业论文+源代码.zip
  • 可执行文件格式详解 Windows PE和Linux ELF.zip
  • Unicorn PE是基于的工具项目/框架,旨在模拟Windows PE文件(尤其是打包文件)的代码执行。 特征 将PE映像从emu内存中转储到文件中,修复导入表,解密VMProtect字符串,解密VMProtect导入。 对异常的部分支持。 ...
  • 深入浅出Windows PE(一) PE文件

    千次阅读 2012-04-10 22:29:08
    深入浅出Windows PE(一) PE文件头  PE文件头记录了PE文件中的所有数据组织方式,它类似于一本书的目录,通过目录我们可以快速定位到某个具体的章节;通过PE文件头部分对某些数据结构的描述,我们也可以定位到...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 43,327
精华内容 17,330
关键字:

windowspe文件下载