精华内容
下载资源
问答
  • windowsPE入门精通

    2011-08-27 08:11:51
    轻松掌握windowsPE,了解系统的安装,在优盘中安装系统。
  • Windows PE 工具包概述

    2014-10-02 08:52:17
    Windows PE 工具包概述Windows R 预安装环境工具包(Windows PE 工具包)包含最新版本的 Windows PE 3 0 技 术和工具 此版本 Windows 7 保持一致
  • Windows PE/COFF

    2019-05-16 18:38:00
    Windows PE/COFF Windows的二进制文件格式PE/COFF 在32位Windows平台下,微软引入了一种叫PE(Portable ...PE文件格式事实上ELF同根同源,他们都是由COFF(Common Object File Format)格式发展而来的,更加具...

    Windows PE/COFF

    Windows的二进制文件格式PE/COFF

    在32位Windows平台下,微软引入了一种叫PE(Portable Executable)的可执行格式。作为Win32平台的标准可执行文件格式,PE有着跟ELF一样良好的平台扩展性和灵活性。PE文件格式事实上与ELF同根同源,他们都是由COFF(Common Object File Format)格式发展而来的,更加具体地讲是来源于当时著名的DEC(Digital Equipment Corporation)的VAX/VMS上的COFF文件格式。因为当微软开始开发Windows NT的时候,最初的成员都是来自于DEC公司的VAX/VMS小组,所以他们很自然就将原来系统上熟悉的工具和文件格式都搬了过来,并且在此基础上做重新设计和改动。

    请注意,上面在讲到PE文件格式的时候,只是说Windows平台下的可执行文件采用该格式。事实上,在Windows平台,VISUAL C++编译器产生的目标文件仍然使用COFF格式。由于PE是COFF的一种扩展,所以它们的结构在很大程度上相同,甚至跟ELF文件的基本结构也相同,都是基于段的结构。所以我们下面在讨论Windows平台上的文件结构时,目标文件默认为COFF格式,而可执行文件为PE格式。但很多时候我们可以将它们统称为PE/COFF文件。

    随着64位Windows的发布,微软对64位Windows平台上的PE文件结构稍微做了一些修改,这个新的文件格式叫做PE32+。新的PE32+并没有添加任何结构,最大的变化就是把那些原来32位的字段变成了64位,比如文件头中与地址相关的字段。

    PE的前身——COFF

    COFF文件结构

    几乎跟ELF文件一样,COFF也是由文件头及后面的若干个段组成,再加上文件末尾的符号表、调试信息的内容就构成了COFF文件的基本结构,我们在COFF文件中几乎都可以找到与ELF文件结构相对应的地方。COFF文件的文件头部包括了两部分,一个是描述文件总体结构和属性的映像头(Image Header),另外一个是描述该文件中包含的段属性的段表(Section Table)。文件头后面紧跟着的就是文件的段,包括代码段、数据段等,最后还有符号表等。

    // 文件头
    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;
    
    // 段头
    typedef struct _IMAGE_SECTION_HEADER {
        BYTE Name[8];
        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;

    链接指示信息

    ".drectve"段的内容是编译器传递给链接器的指令(Derective),即编译器希望告诉链接器应该怎样链接这个目标文件。段名后面就是段的属性,包括地址、长度、位置等,最后一个属性是标志位“flags”,即IMAGE_SECTION_HEADER里面的Characteristics成员。".drectve"段的标志位为“0x100A00”,它是表中的标志位的组合。

    标志位 宏定义 意义
    0x00100000 IMAGE_SCN_ALIGN_1BYTES 1个字节对齐。相当于不对齐
    0x00000800 IMAGE_SCN_LNK_REMOVE 最终链接成映像文件时抛弃该段
    0x00000200 IMAGE_SCN_LNK_INFO 该段包含的是注释或其他信息

    调试信息

    COFF文件中所有以“.debug”开始的段都包含着调试信息。比如".debug\(S"表示包含的是符号相关的调试信息段;".debug\)P"表示包含的是预编译头文件相关的调试信息段;".debug$T"表示包含的是类型相关的调试信息段。调试信息段的具体格式被定义在PE格式文件标准中。

    大家都有符号表

    最后部分是COFF符号表,内容几乎跟ELF文件的符号表一样,主要就是符号名、符号的类型、所在的位置。

    Windows下的ELF——PE

    PE文件是基于COFF的扩展,它比COFF文件多 几个结构。最主要的变化有两个:第一个是文件最开始的部分不是COFF文件头,而是DOS MZ 可执行文件格式的文件头和桩代码(DOS MZ File Header and Stub);第二个变化是原来的COFF文件头中的“IMAGE_FILE_HEADER”部分扩展成了PE文件文件头结构,这个结构包括了原来的“Image Header”及新增的PE扩展头部结构(PE Optional Header)

    DOS下的可执行文件的扩展名与Windows下的可执行文件扩展名一样,都是“.exe”,但是DOS下的可执行文件格式是“MZ”格式,与Windows下的PE格式完全不同,虽然它们使用相同的扩展名。在Windows发展的早期,那时候DOS系统还如日中天,而且早期的Windows版本还不能脱离DOS环境独立运行,所以为了照顾DOS系统,那些为Windows编写的程序必须尽量兼容原有的DOS系统,所以PE文件在设计之初就背负着历史的累赘。PE文件中“Image DOS Header”和“DOS Stub”这两个结构就是为了兼容DOS系统而设计的,其中“Image DOS Header”结构跟DOS的“MZ”可执行结构的头部完全一样,其结构中有前两个字节是e_magic结构,它是里面包含了MZ两个字母的ASCII码;e_cs和e_ip两个成员指向程序的入口地址。然而PE文件中这两个成员却是指向“DOS Stub”,它是一段可以在DOS下运行的一小段代码,向终端输出一行字:“This program cannot be run in DOS”。

    // PE真正的文件头
    typedef struct _IMAGE_NT_HEADERS {
        DWORD Signature; // 标记,对应"PE\0\0"的ASCII码
        IMAGE_FILE_HEADER FileHeader;
        IMAGE_OPTIONAL_HEADER OptionalHeader; //很多成员,有些部分跟PE文件的装载与运行相关
    } IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS;
    
    

    PE数据目录

    在Windows系统装载PE可执行文件时,往往需要很快的找到一些装载所需要的数据结构,比如导入表、导出表、资源、重定位表等。这些常用的数据的位置和长度都被保存在了一个叫数据目录(Data Directory)的结构里面,其实它就是前面“IMAGE_OPTIONAL_HEADER”结构里面的DataDirectory成员。

    typedef struct _IMAGE_DATA_DIRECTORY {
        DWORD VirtualAddress;
        DWORD Size;
    } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
    
    #define IMAGE_DATA_DIRECTORY_ENTRIES 16

    转载于:https://www.cnblogs.com/fr-ruiyang/p/10877330.html

    展开全文
  • 读取Windows PE格式文件有关的各种例程。 在Windows操作系统上,有用于从PE文件(Windows的可执行文件格式)中读取信息的内置例程。 该项目中的例程复制了该内置功能,但使用了Lua。 这使您可以从任何支持Lua的...
  • 5 windows PE COFF

    2020-07-18 22:44:17
    PE与ELF同根同源,都由COF格式发展而来 DEC的VAX/VMS上的COFF文件格式。 微软开发Windows NT时,成员都来自于DEC公司的 VAX/VMS小组, 他们很自然就将原来系统上熟悉的工具和文件格式都搬过来, 在此基础上做重新

    5.1 Windows的二进制文件格式PE/COFF

    • 32位Windows,微软引入PE的可执行格式
    • Win32的标准可执行文件格式
      • ELF一样平台扩展性和灵活性
    • PE与ELF同根,都由COFF格式
      • DEC的VAX/VMS上的COFF文件格式
    • 微软开发Windows NT时,成员来自于DEC公司的VAX/VMS小组
      • 就将原来系统上熟悉的工具和文件格式都搬过来,
      • 基础上做重新设计

    • “ Portable Executable”
    • 希望这个可执行文件格式能在不同版本的 Windows平台上用
    • 支持各种CPU
    • Windows NT、 Windows95到 Windows XP及 Windows Vista,还有 Windows CE都用PE可执行文件格式
    • Windows的PC版只支持x86的CPU,只关注PE在x86上的各种性质就行

    • VISUAL C++编译器产生的目标文件仍然用COFF格式
    • PE是COFF的一种扩展,结构在很大程度上相同,
      • 甚至跟ELF文件的基本结构也相同,都基于段的结构。
    • 下面讨论 Windows平台上的文件结构时
      • 目标文件默认为COFF格式
      • 而可执行文件为PE格式
    • 统称为PE/COFF文件
      • 也对比PE与COFF在结构方面的区别

    • 微软对64位 Windows上的PE文件结构稍改
      • 叫做PE32+
    • PE32+没添加任何结构,最大变化把那些原来32位字段变成64
      • 文件头中与地址相关的字段
    • 绝大部分情况下PE32+与PE的格式一致
      • 可将它看作是一般的PE文件

    • 与ELF文件相同, PE/COFF格式也用基于段的格式
    • 一个段可包含代码数据或其他信息
    • PE/COFF中,至少一个代码段
      • 叫“.code”,数据段叫“.data”。
    • 不同编译器产生的目标文件的段名不同,
      • VISUAL C++用“,code”和“,data”,
      • Borland编译器用“CODE”,“DATA”。
    • 跟ELF一样,段名只提示性作用,没实际意义
    • 如果用链接脚本来控制链接,段名可能会起到一定作用

    • 跟ELF一样,
    • PE也允许程序员将变量或函数放到自定义的段。
    • GCC中用

    attribute((section(“name”)))扩展属性,

    • VISUAL C++中用“#pragma”编译器指示。
    • 如下面这个语句:

    在这里插入图片描述

    • 把所有全局变量“global”放到“FOO”段去,
    • 用“pragram”将这个编译器指示换回来,恢复到“.data”,
    • 否则,任何全局变量和静态变量都会被放到“FOO”段

    5.2 PE的前身COFF

    展开全文
  • 这是Windows PE格式的文件加载器应用程序,提供OS内部可执行文件加载器类似的功能,但从用户模式运行。 它将可执行文件映射到内存,打补丁并初始化几种机制,然后将控制流传递给加载的映像。 该项目是为教育目的而...
  • 1. Windows的二进制文件格式PE/COFF 在32位Windows平台下,微软引入了一种叫PE...PE文件格式事实上ELF同根同源,它们都是由COFF(Common Object File Format)格式发展而来的,更加具体地讲是来源于当时著名的...

    1. Windows的二进制文件格式PE/COFF

    在32位Windows平台下,微软引入了一种叫PE(Portable Executable)的可执行格式。作为Win32平台的标准可执行文件格式,PE有着跟ELF一样良好的平台扩展性和灵活性。PE文件格式事实上与ELF同根同源,它们都是由COFF(Common Object File Format)格式发展而来的,更加具体地讲是来源于当时著名的DEC(Digital Equipment Corporation)的VAX/VMS上的COFF文件格式。微软将它的可执行文件格式命名为”Portable Executable”,从字面意义上讲是希望这个可执行文件格式能够在不同版本的Windows平台上使用,并且可以支持各种CPU。

    在Windows平台,VISUAL C++编译器产生的目标文件仍然使用COFF格式,而可执行文件为PE格式

    随着64位Windows的发布,微软对64位Windows平台上的PE文件结构稍微做了一些修改,这个新的文件格式叫做PE32+。新的PE32+并没有添加任何结构,最大的变化就是把那些原来32位的字段变成了64位。绝大部分情况下,PE32+与PE的格式一致,我们可以将它看作是一般的PE文件。

             与ELF文件相同,PE/COFF格式也是采用了那种基于段的格式。一个段可以包含代码、数据或其它信息,在PE/COFF文件中,至少包含一个代码段,这个代码段的名字往往叫做”.code”,数据段叫做”.data”。不同的编译器产生的目标文件的段名不同,VISUAL C++使用”.code”和”.data”,而Borland的编译器使用”CODE”, “DATA”。也就是说跟ELF一样,段名只有提示性作用,并没有实际意义。

    跟ELF一样,PE中也允许程序员将变量或函数放到自定义的段。在GCC中我们使用”__attribute__((section(“name”)))”扩展属性,在VISUAL C++中可以使用”#pragma”编译器指示,如”#pragma data_set(“name”)”。

    2. PE的前身----COFF

    SimpleSection.c内容如下:

    int printf(const char* format, ...);
    
    int global_init_var = 84;
    int global_uninit_var;
    
    void func1(int i)
    {
    	printf("%d\n", i);
    }
    
    int main(void)
    {
    	static int static_var = 85;
    	static int static_var2;
    
    	int a = 1;
    	int b;
    
    	func1(static_var + static_var2 + a + b);
    
    	return a;
    }

    以管理员身份打开cmd.exe,然后在C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin\amd64目录下,先执行vcvars64.bat,然后定位到SimpleSection.c所在的目录E:\test\下,执行”cl.exe /c /Za SimpleSection.c”,会生成目标文件SimpleSection.obj,执行结果如下图所示:

    “cl.exe”是VISUAL C++的编译器,即”Compiler”的缩写。”/c”参数表示只编译,不链接,即将.c文件编译成.obj文件,而不调用链接器生成.exe文件。如果不加这个参数,cl.exe会在编译”SimpleSection.c”文件以后,再调用link.exe链接器将该产生的SimpleSection.obj文件与默认的C运行库链接,产生可执行文件SimpleSection.exe。

    VISUAL C++有一些C和C++语言的专有扩展,这些扩展并没有定义ANSI C标准或ANSI C++标准。”/Za”参数禁用这些扩展,使得我们的程序跟标准的C/C++兼容。使用”/Za”参数时,编译器自动定义了__STDC__这个宏,我们可以在程序里通过判断这个宏是否被定义而确定编译器是否禁用了Microsoft C/C++语法扩展。

    跟GNU的工具链中的”objdump”一样,Visual C++也提供了一个用于查看目标文件和可执行文件的工具,就是”dumpbin.exe”。通过这个命令可以查看SimpleSection.obj的结构,”/ALL”参数是将打印输出目标文件的所有相关信息,包括文件头、每个段的属性和段的原始数据及符号表。也可以用”/SUMMARY”选项来查看整个文件的基本信息,它只输出所有段的段名和长度,执行结果如下图所示:

    COFF文件结构:几乎跟ELF文件一样,COFF也是由文件头及后面的若干个段组成,再加上文件末尾的符号表、调试信息的内容,就构成了COFF文件的基本结构。COFF文件的文件头部包括了两部分,一个是描述文件总体结构和属性的映像头(Image Header),另外一个是描述该文件中包含的段属性的段表(Section Table)。文件头后面紧跟着的就是文件的段,包括代码段、数据段等,最后还有符号表等。

    映像(Image):因为PE文件在装载时被直接映射到进程的虚拟空间中运行,它是进程的虚拟空间的映像。所以PE可执行文件很多时候被叫做映像文件(Image File)。

    文件头里描述COFF文件总体属性的映像头是一个”IMAGE_FILE_HEADER”的结构,它跟ELF中的”Elf64_Ehdr”结构的作用相同。这个结构及相关常数被定义在” C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Include”里面:

    //
    // File header format.
    //
    
    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;
    
    #define IMAGE_SIZEOF_FILE_HEADER             20

    对照前面”SimpleSection.txt”中的输出信息,我们可以看到输出的信息里面最开始一段”FILE HEADER VALUES”中的内容跟COFF映像头中的成员是一一对应的,如下图所示:

    可以看到这个目标文件的文件类型是”COFF OBJECT”,也就是COFF目标文件格式。文件头里面还包含了目标机器类型,例子里的类型是0x8664。按照微软的预想,PE/COFF结构的可执行文件应该可以在不同类型的硬件平台上使用,所以预留了该字段。在WinNT.h里面可以找到相应的以”IMAGE_FILE_MACHINE_”开头的目标机器类型的定义。文件头里面的”Number of Sections”是指该PE所包含的”段”的数量。”Time date stamp”是指PE文件的创建时间。“File pointer to symbol table”是符号表在PE中的位置。”Size of optional header”是指Optional Header的大小,这个结构只存在于PE可执行文件,COFF目标文件中该结构不存在,所以为0.

    映像头后面紧跟着的就是COFF文件的段表,它是一个类型为”IMAGE_SECTION_HEADER”结构的数组,数组里面每个元素代表一个段,这个结构跟ELF文件中的”Elf64_Shdr”很相似。这个数组元素的个数刚好是该COFF文件所包含的段的数量,也就是映像头里面的”number of sections”。这个结构是用来描述每个段的属性的,它也被定义在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 Name)、物理地址(Physical address)、虚拟地址(Virtual address)、原始数据大小(Size of raw data)、段在文件中的位置(File pointer ro raw data)、该段的重定位表在文件中的位置(File pointer to relocation table)、该段的行号表在文件中的位置(File pointer to line numbers)、标志位(Characteristics)等。VirtualSize:该段被加载至内存后的大小;VirtualAddress:该段被加载至内存后的虚拟地址;SizeOfRawData:该段在文件中的大小。注意:这个值有可能跟VirtualSize的值不一样,比如.bss段的SizeOfRawData是0,而VirtualSize值是.bss段的大小。另外涉及一些内存对齐等问题,这个值往往比VirtualSize小。Characteristics:段的属性,属性里包含的主要是段的类型(代码、数据、bss)、对齐方式及可读可写可执行等权限。段的属性是一些标志位的组合,这些标志位被定义在WinNT.h里,比如IMAGE_SCN_CNF_CODE(0x00000020)表示该段里面包含的是代码,等等。

    段表以后就是一个个的段的实际内容了。COFF中的代码段、数据段、BSS段的内容及它们的存储方式与ELF中几乎一样。

    3. 链接指示信息

    SimpleSection.txt中”.drectve”段相关的内容如下图所示:

    “.drectve”段实际上是”Directive”的缩写,它的内容是编译器传递给链接器的指令(Directive),即编译器希望告诉链接器应该怎样链接这个目标文件。段名后面就是段的属性,包括地址、长度、位置等与ELF中存在的相同的属性,最后一个属性是标志位”flags”,即IMAGE_SECTION_HEADERS里面的Characteristics成员。”.drectve”段的标志位为”0x100A00”,它是下表中标志位的组合:

    “dumpbin”已经为我们打印出了标志位的三个组合属性:Inof、Remove、1 byte align。即该段是信息段,并非程序数据;该段可以在最后链接成可执行文件的时候被抛弃;该段在文件中的对齐方式是1个字节对齐。

    输出信息中紧随其后的是该段在文件中的原始数据(RAW DATA #1,用十六进制显示的原始数据及相应的ASCII字符)。”dumpbin”知道该段是个”.drectve”段,并且对段的内容进行了解析,解析结果为一个”/DEFAULTLIB:’LIBCMT’”的链接指令(Linker Directives),实际上它就是”cl.exe”编译器希望传给”link.exe”链接器的参数。这个参数表示编译器希望告诉链接器,该目标文件需要LIBCMT这个默认库。LIBCMT的全称是Library C Multithread,它表示VC的静态链接的多线程C库,对应的文件在VC安装目录下的lib/libcmt.lib。我们可以在cl.exe编译器里面加入/Zl来关闭默认C库的链接指令。

    4. 调试信息

    COFF文件中所有以”.debug”开始的段都包含着调试信息。比如”.debug$S”表示包含的是符号(Symbol)相关的调试信息段;”.debug$P”表示包含预编译头文件(Precompiled Header Files)相关的调试信息段;”.debug$T”表示包含类型(Type)相关的调试信息段。在”SimpleSection.obj”中,我们只看到了”.debug$S”段,也就是只有调试时的相关信息。我们可以从该段的文本信息中看到目标文件的原始路径,编译器信息等。调试信息段的具体格式被定义在PE格式文件标准中。调试段相关信息在”SimpleSection.txt”中的内容如下:

    5. 大家都有符号表

     “SimpleSection.txt”的最后部分是COFF符号表(Symbol table),COFF文件的符号表包含的内容几乎跟ELF文件的符号表一样,主要就是符号名、符号的类型、所在的位置。”SimpleSection.txt”关于符号表的输出如下所示:

    在输出结果的最左列是符号的编号,也就是符号在符号表中的下标。接着是符号的大小,即符号所表示的对象所占用的空间。第三列是符号所在的位置,ABS(Absolute)表示符号是个绝对值,即一个常量,它不存在于任何段中;SECT1(Section #1)表示符号所表示的对象定义在本COFF文件的第一个段中,即本例中的”.drectve”段;UNDEF(Undefined)表示符号是未定义的,即这个符号被定义在其它目标文件中。第四列是符号类型,可以看到对于C语言的符号,COFF只区分了两种,一种是变量和其它符号,类型为notype,另外一种是函数,类型为notype (),这个符号类型值可以用于其它一些需要强符号类型的语言或系统中,可以给链接器更多的信息来识别符号的类型。第五列是符号的可见范围,Static表示符号是局部变量,只有目标文件内部是可见的;External表示符号是全局变量,可以被其它目标文件引用。最后一列是符号名,对于不需要修饰的符号名,”dumpbin”直接输出原始的符号名;对于那些经过修饰的符号名,它会把修饰前和修饰后的名字都打印出来,后面括号里面的就是未修饰的符号名。

    从符号表的dump输出信息中,我们可以看到”global_init_var”这个符号位于Section #3,即”.data”段。另外还有一个$SG1326的符号,其实它表示的是程序中的那个”%d\n”字符串常量。因为程序中要引用到这个字符串常量,而该字符串常量又没有名字,所以编译器自动为它生成了一个名字,并且作为符号放在符号表里面,可以看到这个符号对外都是不可见的。ELF文件中并没有为字符串常量自动生成的符号,另外所有的段名都是一个符号,”dumpbin”如果碰到某个符号是一个段的段名,那么它还会解析该符号所表示的段的基本属性,每个段名符号后面紧跟着一行就是段的基本属性,分别是段长度、重定位数、行号数和校验和。

     6. Windows下的ELF----PE

    PE文件是基于COFF的扩展,它比COFF文件多了几个结构。最主要的变化有两个:第一个是文件最开始的部分不是COFF文件头,而是DOS MZ可执行文件格式的文件头和桩代码(DOS MZ File Header and Stub);第二个变化是原来的COFF文件头中的”IMAGE_FILE_HEADER”部分扩展成了PE文件文件头结构”IMAGE_NT_HEADERS”,这个结构包括了原来的”Image Header”及新增的PE扩展头部结构(PE Optional Header)。PE文件的结构如下图所示:

    DOS下的可执行文件的扩展名与Windows下的可执行文件扩展名一样,都是”.exe”,但是DOS下的可执行文件格式是”MZ”格式,与Windows下的PE格式完全不同,虽然它们使用相同的扩展名。PE文件中的”Image DOS Header”和”DOS Stub”这两个结构就是为了兼容DOS系统而设计的,其中”IMAGE_DOS_HEADER”结构其实跟DOS的”MZ”可执行结构的头部完全一样,所以从某个角度看,PE文件其实也是一个”MZ”文件。”IMAGE_DOS_HEADER”的结构中有的前两个字节是”e_magic”结构,它是里面包含了”MZ”这两个字母的ASCII码;”e_cs”和”e_ip”两个成员指向程序的入口地址。

    当PE可执行映像在DOS下被加载的时候,DOS系统检测该文件,发现最开始两个字节是”MZ”,于是认为它是一个”MZ”可执行文件。然后DOS系统就将PE文件当作正常的”MZ”文件开始执行。DOS系统会读取”e_cs”和”e_ip”这两个成员的值,以跳转到程序的入口地址。然而PE文件中,”e_cs”和”e_ip”这两个成员并不指向程序真正的入口地址,而是指向文件中的”DOS Stub”。”DOS Stub”是一段可以在DOS下运行的一小段代码,这段代码的唯一作用是向终端输出一行字:”This program cannot be run in DOS”,然后退出程序,表示该程序不能在DOS下运行。所以我们如果在DOS系统下运行Windows的程序就可以看到上面这句话,这是因为PE文件结构兼容DOS “MZ”可执行文件结构的缘故。

     “IMAGE_DOS_HEADER”结构也被定义在WinNT.h里面,里面的”e_lfanew”成员表明了PE文件头(IMAGE_NT_HEADERS)在PE文件中的偏移,我们需要使用这个值来定位PE文件头。这个成员在DOS的”MZ”文件格式中它的值永远为0,所以当Windows开始执行一个后缀名为”.exe”的文件时,它会判断”e_lfanew”成员是否为0。如果为0,则该”.exe”文件是一个DOS  “MZ”可执行文件,Windows会启动DOS子系统来执行它;如果不为0,那么它就是一个Windows的PE可执行文件,”e_lfanew”的值表示”IMAGE_NT_HEADERS”在文件中的偏移。

    “IMAGE_NT_HEADERS”是PE真正的文件头,它包含了一个标记(Signature)和两个结构体。标记是一个常量。文件头包含的两个结构分别是映像头(Image Header)、PE扩展头部结构(Image Optional Header)。

    Windows中把32位的PE文件格式叫做PE32,把64位的PE文件格式叫做PE32+。这两种格式就是ELF32和ELF64一样,都大同小异,只不过关于地址和长度的一些成员从32位扩展成了64位,还增加了若干个额外的成员之外,没有其它区别。

    我们平时可以使用”IMAGE_OPTIONAL_HEADER”作为”Optional Image Header”的定义。它是一个宏,在64位的Windows下,Visual C++在编译时会定义”_WIN64”这个宏,那么”IMAGE_OPTIONAL_HEADER”就被定义成”IMAGE_OPTIONAL_HEADER64”;32位Windows下没有定义”_WIN64”这个宏,那么它就是”IMAGE_OPTIONAL_HEADER32”。

    PE数据目录:在Windows系统装载PE可执行文件时,往往需要很快地找到一些装载所需要的数据结构,比如导入表、导出表、资源、重定位表等。这些常用的数据的位置和长度都被保存在了一个叫做数据目录(Data Directory)的结构里面,其实它就是”IMAGE_OPTIONAL_HEADER”结构里面的”DataDirectory”成员。这个成员是一个”IMAGE_DATA_DIRECTORY”的结构数组,相关的定义如下:

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

    可以看到这个数组的大小为16,IMAGE_DATA_DIRECTORY结构有两个成员,分别是虚拟地址以及长度。DataDirectory数组里面每一个元素都对应一个包含一定含义的表。”WinNT.h”里面定义了一些以”IMAGE_DIRECTORY_ENTRY_”开头的宏,数值从0到14,它们实际上就是相关的表的宏定义在数组中的下标。比如”IMAGE_DIRECTORY_ENTRY_EXPORT”被定义为0,所以这个数组的第一个元素所包含的地址和长度就是导出表(Export Table)所在的地址和长度。这个数组中还包含其它的表,不如导入表、资源表、异常表、重定位表、调试信息表、线程私有存储(TLS)等的地址和长度。这些表多数跟装载和DLL动态链接有关,与静态链接没什么关系。

    GitHub: https://github.com/fengbingchun/Messy_Test 

    展开全文
  • 信息系统安全对抗实践 Windows PE文件格式及相关工具 内容提要 PE文件的概念 PE文件与其在内存中的对应 使用工具查看PE结构 2 PE文件 PE文件是Windows操作系统下使用的可执行文件格式它是微软在UNIX平 台的通用...
  • 第六章栈重定位表 本章主要介绍栈和代码重定位。站和重定位表两者并没有必然的联系,但都和代码有关。栈描述的是代码运行过程中,操作系统为调度程序之间相互调用关系,或临时存放操作数而设置的一种数据结构。...

    第六章 栈与重定位表

        本章主要介绍栈和代码重定位。站和重定位表两者并没有必然的联系,但都和代码有关。栈描述的是代码运行过程中,操作系统为调度程序之间相互调用关系,或临时存放操作数而设置的一种数据结构。重定位表则是在一个PE中的代码被加载到任意一个内存地址时,用来描述相关操作数地址变化规律的数据结构。通过重定位技术,代码运行在内存中的任意位置时,可以避免因操作数的定位错误而导致失败。

    6.1栈

        前面基本概念直接过...

        程序在运行的时候会为系统分配一块内存区域作为栈,由栈选择子SS和栈定指针(esp)来确定当前栈的大小,CPU则直接操作EBP来存取数据。

    内存中栈结构如下:

     

        压栈时根据压入的数据类型的字节大小,将ESP减少相应的字节数,如压入一个双子,则ESP-4。

        相反出栈的时候是esp增加相应的字节数,如弹出一个双字,则esp+4。

    6.1.1  栈的应用场合

    (1)保存临时的值

     Push eax

     ......

     Pop eax

     

    (2)保存程序现场

     CALL _subPrg

        当指令执行时,会将紧跟在CALL指令后面的下一条指令地址压入栈,以便于程序在调用完以后,能正确放回到主程序继续运行<shell code 常用>。

    (3)
        传递函数参数

     看下面的MessageBox调用反汇编

     

    下面是压栈以后的示意图。

        当子程序结束以后,会调用ret指令返回,eip随之被弹出。为了平衡栈,需要调用者使用如下语句将传入的参数一一弹出:

    Add esp,0010h  ;4个整型

    (4)存放过程中的局部变量

    进入一个过程后,会定义很多局部变量,而局部变量的存放处也是栈。为局部变量在栈中申请的内存区域成为缓冲区。当过程结束以后,局部变量将从栈中删除,恢复到进入过程最初状态。也就是说,局部变量在过程结束以后就自动被释放了,原因是CPU调整了栈的栈顶指针esp。

    6.1.3  栈溢出

        所谓栈溢出,是指由于程序没有考虑栈中定义的局部数据块的大小,而向该数据块写入了过多的数据,从而导致数据越界,覆盖了栈中的已存在的其他数据的技术。这里可以shellcode,细节不说了,之前单独总结过这里。后面都是基本定义,直接跳过,直接看重定位。

    6.2  代码重定位

        代码重定位是把可执行代码从内存的一个地方移动到另一个地方去,保证该部分代码还能正常执行的一种技术。用于补丁和病毒程序开发。


    6.2.1  重定位的提出

        可执行代码从内存的一个地方移动到另一个地方,所有的字节均保持不变;如果代码指令中的某些操作数不跟随着地址发生改变,势必会导致程序运行出错。这里的某些操作是指那些使用了绝对地址定位的程序指令中的操作数。如下:

        从上面可以看出,全局变量访问直接采用了绝对地址。如果直接把这部分机器码拷贝到另一个位置,直接执行会出问题的,因为需要我们重新给代码定位才可以。


    6.2.2  实现重定位的方法

    先看书上的姿势:

       是这样的,大体就是用相对偏移来算的,然后下面给了特长一段来解释这个,看了半天有点晕,我自己大体猜了下,然后用C++还原了这个场景。

    C++代码(就直接拿上面用过的那个例子):

    然后看下反汇编:

        注意被圈上的那一行,后面那个***ds:[00104F18h]是直接用的映地址写的,每次编译都是随机的,我看上面书上的意思是可以根据栈弹出来的位置,也就是函数里面的某个位置来偏移过去,于是我们可以验证下,直接还是看上面红色框的部分,注意这两个值:

     

    前面是代码地址,后面是全局变量地址,我在想,这两个差是不是固定的,于是就夺取了几组,发现差真的是固定的。

    00C815D4  mov         eax,dword ptr ds:[00C94F18h]  13944

    000515D4  mov         eax,dword ptr ds:[00064F18h]  13944

    000F15D4  mov         eax,dword ptr ds:[00104F18h]  13944

        so应该大体知道啥姿势了,于是模拟一发:

        先计算下偏移量:

        得到如下结果:

    pFunAddMark = 0x001a15c0 {TEST_CPP_.exe!wmain(int, wchar_t * *)}

    pnNumber = 0x001b4f18 {TEST_CPP_.exe!int g_nNumber} {1111}

        然后字节尝试测试一发:

        这样看来结果没啥问题,如果我没理解错书上的那一坨汇编的话,应该就是这么个意思,如果理解有误希望大家留言提醒我,一起学习。


    6.3  PE头文件中的重定位表

        重定位信息是在编译的时候,由编译器生成并被保留在可执行文件中。当程序执行前,操作系统会根据这些重定位信息对代码予以修正,复杂的操作由编译器和操作系统代替程序完成。程序被装入内存时,其基址是由字段IMAGE——OPTIONAL_HEADER32.imageBase决定的:

    但是,如果当装载时该位置已经被别的程序使用,那么操作系统就有权重新选择一个基地址。这时候就需要对所有的重定位信息进行修正,而修正的依据就是PE中的重定位表。

    6.3.1  重定位表定义

    重定位表为数据目录中注册的数据类型之一,其描述信息处于数据目录项的第6个目录项中:

    通过上面,得到信息:

    重定位表所在地址RVA=0x00018000

    重定位表数据大小    =0x000010C4

    结合这个:

    说明存在了.reloc段。

    然后根据RVA计算FOA:

    FOA = 0x12C00

    6.3.2  重定位表项IMAGE_BASE_RELOCATION

        与导入表类似,重定位表指针指向的位置是一个数组,而不像导出表一样只有一个结构。这个数组中的每一项都是如下结构:

    IMAGE_BASE_RELOCATION STRUCT

      VirtualAddress  dd  ?  ;重定位内存页的起始RVA

      SizeOfBlock    dd  ?  ;重定位块的长度

    IMAGE_BASE_RELOCATION ENDS

        解释下这两项:

        MAGE_BASE_RELOCATION.VirtualAddress

        +0000h,双字。重定位块RVA.由于直接寻址指令较多,所以在一些PE文件中,存在大量的需要修正的重定位地址。按照常规计算,每个地址占4字节,如果有n个重定位项,那么需要总的空间为4*n字节。重新审视直接寻址中的地址发现,在一页中的所有地址只需要12位(因为Win32页面大小为10000h,也就是4096字节,即2的12次方)。

        而这12位只需要用两个字就能表达出来。如果有n个重定位项,则只需要2*n个地址+4字节页面起始RVA+4字节的本业的重定位项长度。将以上两种情况的表达式:

    Sum0=4*n

    Sum1=2*n+4+4

        很明显,当有大量的重定位地址时,Sum0远大于Sum1。事实上,为了节约存储空间,重定位表的存储方式选择第二种方式。字段IMAGE_BASE_RELOCATION.VirtualAddress就是表达式Sum1中的第一个4,也就是页面起始RVA。

    IMAGE_BASE_RELOCATION.SizeOfBlock

    +0004h,双字。重定位块中重定位表项长度。该字段是表达式Sum1里的第二个4.

        数组和数组之间并不是相邻的。比如页面1的IMAGE_BASE_RELOCATION后并不是页面2的IMAGE_BASE_RELOCATION,而是页面1的所有重定位表项;每个项大小为一个字,每个字的高四位被用来说明此重定位的类型,剩下的十二位才是需要重定位的数据在页面中的地址。高四位含义如下:

       在实际的PE文件中,我们只能看到0和3这两种情况,也就是说要么是对其用的,要么是需要全部修正的。

    6.3.3  重定位表的结构

     

    展开全文
  • 使用SystemInternal工具内核调试器研究windows用户空间内核空间********************既然本篇的主角是PE文件,那么先对PE文件的结构作大致上的介绍,后文提到特定结构时还会补充说明.两个与PE相关的缩写经常容易...
  • (注:因为PE文件在装载时被直接映射到进程的虚拟空间中运行,它是进程的虚拟空间的映像。所以PE可执行文件很多时候被叫做映像文件) 段表Section Table: 描述该文件中包含的段属性; PE(Protable Executable...
  • 读书-程序员的自我修养-链接、封装库(12: 第五章:windows PE/COFF) windows PE/COFF1. windows的二进制文件格式PE/COFF2 PE的前身-COFF3. 链接指示信息4. 调试信息5. 大家都有符号表6. windows下的ELF-PE ...
  • Bart的PEBuilder相关的工具和插件
  • 深入浅出Windows PE(一) PE文件头  PE文件头记录了PE文件中的所有数据组织方式,它类似于一本书的目录,通过目录我们可以快速定位到某个具体的章节;通过PE文件头部分对某些数据结构的描述,我们也可以定位到...
  • windows PE Image 文件分析(5)--- .rsrc 节 resource table PE 文件所有使用的 resource table 非常复杂,一个典型的 windows GUI 应用程序普遍都使用到了 7 个左右的资源。   1. windows 中的资源 在...
  • 评估和部署工具包 (Windows ADK) 是用于自定义、评估以及向新计算机部署 Windows 操作系统的各种工具的集合。 Windows ADK 中可用的功能包括: • 应用程序兼容性工具包(ACT)  • 部署工具  • 用户状态迁移...
  • pe结构 chapter1 Windows PE开发环境 -HelloWorld.exe -chapter2 三个小工具的编写 -HelloWorld.exe -chapter3 PE文件头 -HelloWorld.exe -chapter4 导入表 -HelloWorld.exe -chapter5 导出表 -Hello...
  • 这篇文章将介绍Windows PE病毒, 包括PE病毒原理、分类及感染方式详解,并通过案例进行介绍。这些基础性知识不仅和系统安全相关,同样我们身边的APP、常用软件及操作系统紧密联系,希望这些知识对您有所帮助,更...
  • 首先了解与PE有关的基本概念: 1. 虚拟内存地址(VA) 2. 相对虚拟内存地址(RVA) 3. 文件偏移地址(FOA) 4. 特殊地址 虚拟内存地址:PE文件被操作系统加载进入内存,进程的基地址+相对虚拟内存地址相对...
  • Windows_PE权威指南光盘.rar

    热门讨论 2015-01-05 10:21:00
    内容全面,详尽地剖析了Windows PE文件格式的原理及其编程技术,涉及安全领域的各个方面和Windows系统的进程管理和底层机制:实战性强,以案例驱动的方式讲解了Windows PE文件格式在加密解密、软件汉化、逆向工程...
  • 5.1 Windows的二进制文件格式PE/COFF PE文件格式事实上ELF同根同源,它们都是由COFF格式发展而来。 5.2 PE前身——COFF 在win下,Command Prompt for vs 2017,cd命令进入源代码所在目录: 运行命令: ...
  • WindowsPE 第七章 资源表

    千次阅读 2017-01-15 16:01:06
    第七章 资源表 ...按照程序数据分离的设计思想,最理想的方案是单独为程序所需要的数据安排一节来存储-PE中的资源就是这么做的。 7.1资源分类  资源数据在PE里是最复杂的一种。其难度主要体现在对
  • 这是作者网络安全自学教程系列,主要是关于安全工具和实践操作的在线笔记,特分享出来...这篇文章将介绍Windows PE病毒, 包括PE病毒原理、分类及感染方式详解,并通过案例进行介绍。基础性文章,希望对您有所帮助~
  • windows平台下,可执行性文件采用PE文件格式,而visual C++编译器产生的目标文件仍然使用COFF格式。 ELF相同PE/COFF也是采用基于段的方式。 GCC中我们使用__attribute__((section("name")))指定段,visual C++中...
  • Windows PE 第八章 延迟加载导入表

    千次阅读 2017-02-09 23:46:03
     延迟加载导入表是PE中引入的专门用来描述动态链接库延迟加载相关的数据,因为这些数据所引起的作用和结构导入表数据基本一致,所以称为延迟加载导入表。  延迟加载导入表和导入表是相互分离的。一个PE文件中...
  • 菜鸟教程终极篇之Microsoft Windows Pre-installation Environment (Windows PE) 2.02007-04-11 17:39:58标签:Windows PE版权声明:原创作品,如需转载,请作者联系。否则将追究法律责任。 大家好啊.通过以前的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 874
精华内容 349
关键字:

windowspe与