写在前面

  此系列是本人一个字一个字码出来的,包括代码实现和效果截图。 如有好的建议,欢迎反馈。码字不易,如果本篇文章有帮助你的,如有闲钱,可以打赏支持我的创作。如想转载,请把我的转载信息附在文章后面,并声明我的个人信息和本人博客地址即可,但必须事先通知我

你如果是从中间插过来看的,请仔细阅读 羽夏壳世界——序 ,方便学习本教程。

概述

  在学习PE结构之前,我们来大体看一下它的整体结构:

  初步学习PE文件,可能看的比较头大。如果你学习过编程语言的话,可以这么说:PE 文件是由一堆结构体和其他数据堆积起来的 。在学习本教程时,建议安装010 Editor可以更方便的学习PE结构,不过该软件是商用的。使用该软件主要是用了它的模板功能,如果是指定类型的文件,它也会主动匹配类型并提示使用相应的模板,如下所示是使用模板之后的效果:

  PE文件有两种状态,一个是在磁盘以文件的形式进行保存,另一个就是在内存中,如下图所示:

  为什么这么说呢?是因为有对齐这个概念,什么是对齐如果不会建议自己进行查阅,这个无论是编程语言还是操作系统基础中非常重要的概念,我就不在这里絮叨了。对于为什么有两种状态,之后的博文将会介绍。
  在PE结构中,有一个十分重要的概念就是RVAFOARVA英文全称为Relative Virtual Address,即相对虚拟地址;FOA英文全称为File Offset Address,即文件偏移地址。就是因为PE有两种状态,所以会有这两种偏移地址。当然还有一个VA,英文全称为Virtual Address,意为绝对的虚拟地址,也就是绝对值,是几就是几。而RVA需要基址才能准确定位到VA。有关RVAFOAVA之间的相互转化,将会到下一篇继续。

IMAGE_DOS_HEADER

  该结构体的结构如下:

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;

  这个结构体是历史遗留的产物,因为开始的时候是DOS系统,上面除了最后一个成员e_lfanew,其他的都是给16位DOS程序看的。不过第一个成员e_magic被作为合法PE文件的校验值,值为IMAGE_DOS_SIGNATURE/0x5A4D/"MZ"
  e_lfanew为文件偏移,指向了IMAGE_NT_HEADERS结构,这个就是我们真正可以跑在现在图形界面的Windows程序必须有的结构,我们来看一个程序与此部分相关的结构示意图如下:

DosStub

  接在IMAGE_DOS_HEADER结构体后面是被称之为DosStub的,我们能够看到一个字符串This program cannot be run in DOS mode,意为该程序不能够在Dos模式下运行。这里面其实不是垃圾数据,而是有意义的汇编代码,我们用16位反汇编器来看一下:

seg000:0000 seg000          segment byte public 'CODE' use16
seg000:0000 assume cs:seg000
seg000:0000 assume es:nothing, ss:seg000, ds:nothing, fs:nothing, gs:nothing
seg000:0000
seg000:0000 ; =============== S U B R O U T I N E =======================================
seg000:0000
seg000:0000 public start
seg000:0000 start proc near
seg000:0000 push cs
seg000:0001 pop ds
seg000:0002 assume ds:seg000
seg000:0002 mov dx, 0Eh
seg000:0005 mov ah, 9
seg000:0007 int 21h ; DOS - PRINT STRING
seg000:0007 ; DS:DX -> string terminated by "$"
seg000:0009 mov ax, 4C01h
seg000:000C int 21h ; DOS - 2+ - QUIT WITH EXIT CODE (EXIT)
seg000:000C start endp ; AL = exit code
seg000:000C
seg000:000C ; ---------------------------------------------------------------------------
seg000:000E aThisProgramCan db 'This program cannot be run in DOS mode.',0Dh,0Dh,0Ah
seg000:000E db '$',0
seg000:003A align 8
seg000:0040 db 0A9h, 2Ch, 93h, 71h, 0EDh, 4Dh, 0FDh, 22h, 0EDh, 4Dh
seg000:0040 db 0FDh, 22h, 0EDh, 4Dh, 0FDh, 22h, 8Fh, 35h, 0FCh, 23h
seg000:0040 db 0EEh, 4Dh, 0FDh, 22h, 8Fh, 35h, 0F8h, 23h, 0F5h, 4Dh
seg000:0040 db 0FDh, 22h, 8Fh, 35h, 0F9h, 23h, 0E7h, 4Dh, 0FDh, 22h
seg000:0040 db 8Fh, 35h, 0FEh, 23h, 0EEh, 4Dh, 0FDh, 22h, 3Eh, 3Fh
seg000:0040 db 0FCh, 23h, 0E9h, 4Dh, 0FDh, 22h, 0EDh, 4Dh, 0FCh, 22h
seg000:0040 db 0AAh, 4Dh, 0FDh, 22h, 6Dh, 34h, 0F9h, 23h, 0ECh, 4Dh
seg000:0040 db 0FDh, 22h, 6Dh, 34h, 2, 22h, 0ECh, 4Dh, 0FDh, 22h, 6Dh
seg000:0040 db 34h, 0FFh, 23h, 0ECh, 4Dh, 0FDh, 22h, 52h, 69h, 63h
seg000:0040 db 68h, 0EDh, 4Dh, 0FDh, 22h, 8 dup(0)
seg000:00A8 db 10h dup(?)
seg000:00A8 seg000 ends
seg000:00A8
seg000:00A8
seg000:00A8 end start

  注意一定要使用16位的反汇编器,否则无论是在32位是64位下,所有的代码都是错误的。
  上面的代码如果没有《微机原理》的基础可能有点难懂,这里就补充一下:int 21hDos下的中断,类似表示我要调用API了,不同的AH寄存器的值表示调用的函数是不一样的。如果是9,表示在屏幕上打印字符串,不过这个字符串不是用\0结尾的,而是$,和我们现代操作系统的\0的作用是一样的。如果AH的值为0x4C,则表示将AL作为返回值结束程序,和我们C语言编写main函数中的return 0;是一个道理。
  有关该部分就介绍到这里。

IMAGE_NT_HEADERS

  该结构体在32位和64位程序是有所不同的,只不过是结构体的成员大小的区别,如下所示:

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

  Signature是一个十分重要的成员。PE指纹的第二部分,值为IMAGE_NT_SIGNATURE/0x00004550/"PE"。如果值是错误的,同样被判定为非法PE文件。
  FileHeader是标准PE头,大小为20个字节,可以通过IMAGE_SIZEOF_FILE_HEADER宏获取,具体细节后面将会介绍。
  OptionalHeader是扩展PE头,虽然名字带着可选,但它是必需结构。
  我们再来看看它在二进制文件下的位置:

IMAGE_FILE_HEADER

  该结构体在32位和64位的程序是一样的,如下所示:

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;

  Machine指示可以运行在什么样的CPU上,它的值如下:

  • 任意CPUIMAGE_FILE_MACHINE_UNKNOWN/0x0000
  • Intel 386以及后续CPU: IMAGE_FILE_MACHINE_I386/0x014C
  • x64:IMAGE_FILE_MACHINE_AMD64/0x8664

下面是其中的所有成员:

#define IMAGE_FILE_MACHINE_UNKNOWN           0
#define IMAGE_FILE_MACHINE_TARGET_HOST 0x0001 // Useful for indicating we want to interact with the host and not a WoW guest.
#define IMAGE_FILE_MACHINE_I386 0x014c // Intel 386.
#define IMAGE_FILE_MACHINE_R3000 0x0162 // MIPS little-endian, 0x160 big-endian
#define IMAGE_FILE_MACHINE_R4000 0x0166 // MIPS little-endian
#define IMAGE_FILE_MACHINE_R10000 0x0168 // MIPS little-endian
#define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169 // MIPS little-endian WCE v2
#define IMAGE_FILE_MACHINE_ALPHA 0x0184 // Alpha_AXP
#define IMAGE_FILE_MACHINE_SH3 0x01a2 // SH3 little-endian
#define IMAGE_FILE_MACHINE_SH3DSP 0x01a3
#define IMAGE_FILE_MACHINE_SH3E 0x01a4 // SH3E little-endian
#define IMAGE_FILE_MACHINE_SH4 0x01a6 // SH4 little-endian
#define IMAGE_FILE_MACHINE_SH5 0x01a8 // SH5
#define IMAGE_FILE_MACHINE_ARM 0x01c0 // ARM Little-Endian
#define IMAGE_FILE_MACHINE_THUMB 0x01c2 // ARM Thumb/Thumb-2 Little-Endian
#define IMAGE_FILE_MACHINE_ARMNT 0x01c4 // ARM Thumb-2 Little-Endian
#define IMAGE_FILE_MACHINE_AM33 0x01d3
#define IMAGE_FILE_MACHINE_POWERPC 0x01F0 // IBM PowerPC Little-Endian
#define IMAGE_FILE_MACHINE_POWERPCFP 0x01f1
#define IMAGE_FILE_MACHINE_IA64 0x0200 // Intel 64
#define IMAGE_FILE_MACHINE_MIPS16 0x0266 // MIPS
#define IMAGE_FILE_MACHINE_ALPHA64 0x0284 // ALPHA64
#define IMAGE_FILE_MACHINE_MIPSFPU 0x0366 // MIPS
#define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466 // MIPS
#define IMAGE_FILE_MACHINE_AXP64 IMAGE_FILE_MACHINE_ALPHA64
#define IMAGE_FILE_MACHINE_TRICORE 0x0520 // Infineon
#define IMAGE_FILE_MACHINE_CEF 0x0CEF
#define IMAGE_FILE_MACHINE_EBC 0x0EBC // EFI Byte Code
#define IMAGE_FILE_MACHINE_AMD64 0x8664 // AMD64 (K8)
#define IMAGE_FILE_MACHINE_M32R 0x9041 // M32R little-endian
#define IMAGE_FILE_MACHINE_ARM64 0xAA64 // ARM64 Little-Endian
#define IMAGE_FILE_MACHINE_CEE 0xC0EE

  NumberOfSections指示节的数量,它十分重要。
  TimeDateStamp指示编译器填写的时间戳与文件属性里面创建时间/修改时间无关,计算的是当前时间与1970年0时0点0分差的秒数。
  PointerToSymbolTable/NumberOfSymbols与调试相关,不做关注。
  SizeOfOptionalHeader表示扩展PE头的大小,可以修改合适的数值。在默认情况下,32位PE文件:0xE0,64位PE文件:0xF0
  Characteristics指示了文件属性,它的值有如下:

#define IMAGE_FILE_RELOCS_STRIPPED           0x0001  // Relocation info stripped from file.
#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 // File is executable (i.e. no unresolved external 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 // Aggressively 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.

  我们再来看看它在二进制文件下的位置:

IMAGE_OPTIONAL_HEADER

  这个结构体在32位和64位是有区别的,是某些成员的大小区别,它们的结构如下:

typedef struct _IMAGE_OPTIONAL_HEADER {
WORD Magic;
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;
DWORD SizeOfInitializedData;
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint;
DWORD BaseOfCode;
DWORD BaseOfData;
DWORD ImageBase;
DWORD SectionAlignment;
DWORD FileAlignment;
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion;
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage;
DWORD SizeOfHeaders;
DWORD CheckSum;
WORD Subsystem;
WORD DllCharacteristics;
DWORD SizeOfStackReserve;
DWORD SizeOfStackCommit;
DWORD SizeOfHeapReserve;
DWORD SizeOfHeapCommit;
DWORD LoaderFlags; //调试相关
DWORD NumberOfRvaAndSizes; //目录表的个数(决定DataDirectory数组长度)
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

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; #define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16

  Magic标识程序的位数。32位程序为值为IMAGE_NT_OPTIONAL_HDR32_MAGIC/0x10b,64位程序为值为IMAGE_NT_OPTIONAL_HDR64_MAGIC/0x20b。它是判断程序位数的关键属性。
  AddressOfEntryPoint的值表示程序入口RVA,十分重要。
  ImageBase表示该PE比较倾向的内存镜像加载基址,比较重要。对于DLL这个值通常并不被操作系统采纳,如果开启了随机基址的EXE也是如此。
  SectionAlignment表示内存对齐值,十分重要。
  FileAlignment表示文件对齐值,十分重要。
  SizeOfImage表示内存中整个PE文件的映射的尺寸,可比实际的值大,必须是SectionAlignment的整数倍,十分重要。
  SizeOfHeaders所有头和节表按照文件对齐后的大小,否则加载会出错,这十分重要。
  CheckSum表示校验和,一些系统文件有要求用来判断文件是否被修改。
  Subsystem意为子系统,驱动程序值为1,图形界面值为2,控制台、DLL值为3。下面是其枚举:

#define IMAGE_SUBSYSTEM_UNKNOWN              0   // Unknown subsystem.
#define IMAGE_SUBSYSTEM_NATIVE 1 // Image doesn't require a subsystem.
#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2 // Image runs in the Windows GUI subsystem.
#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3 // Image runs in the Windows character subsystem.
#define IMAGE_SUBSYSTEM_OS2_CUI 5 // image runs in the OS/2 character subsystem.
#define IMAGE_SUBSYSTEM_POSIX_CUI 7 // image runs in the Posix character subsystem.
#define IMAGE_SUBSYSTEM_NATIVE_WINDOWS 8 // image is a native Win9x driver.
#define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI 9 // Image runs in the Windows CE subsystem.
#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10 //
#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 //
#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12 //
#define IMAGE_SUBSYSTEM_EFI_ROM 13
#define IMAGE_SUBSYSTEM_XBOX 14
#define IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION 16
#define IMAGE_SUBSYSTEM_XBOX_CODE_CATALOG 17

  DllCharacteristics是文件特性,不是针对DLL文件的,该成员是比较重要的,基址重定位就是从这个成员进行设置的。下面是其枚举:

//      IMAGE_LIBRARY_PROCESS_INIT            0x0001     // Reserved.
// IMAGE_LIBRARY_PROCESS_TERM 0x0002 // Reserved.
// IMAGE_LIBRARY_THREAD_INIT 0x0004 // Reserved.
// IMAGE_LIBRARY_THREAD_TERM 0x0008 // Reserved.
#define IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA 0x0020 // Image can handle a high entropy 64-bit virtual address space.
#define IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE 0x0040 // DLL can move.
#define IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY 0x0080 // Code Integrity Image
#define IMAGE_DLLCHARACTERISTICS_NX_COMPAT 0x0100 // Image is NX compatible
#define IMAGE_DLLCHARACTERISTICS_NO_ISOLATION 0x0200 // Image understands isolation and doesn't want it
#define IMAGE_DLLCHARACTERISTICS_NO_SEH 0x0400 // Image does not use SEH. No SE handler may reside in this image
#define IMAGE_DLLCHARACTERISTICS_NO_BIND 0x0800 // Do not bind this image.
#define IMAGE_DLLCHARACTERISTICS_APPCONTAINER 0x1000 // Image should execute in an AppContainer
#define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER 0x2000 // Driver uses WDM model
#define IMAGE_DLLCHARACTERISTICS_GUARD_CF 0x4000 // Image supports Control Flow Guard.
#define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE

  DataDirectory是存储表位置大小的数组。不同的索引代表不同的表的数据,下面是其枚举:

#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

  我们再来看看它在二进制文件下的位置:

IMAGE_SECTION_HEADER

  IMAGE_SECTION_HEADER是节区头,是重要的结构体,在32位和64位下的程序没有区别。大小可通过IMAGE_SIZEOF_SECTION_HEADER获取,在内存的展开大小 = Max(Misc,SizeOfRawData)。如果此节为已初始化的变量,则 Misc > SizeOfRawData;若节为未初始化的变量则 Misc < SizeOfRawData。如下是结构体成员:

#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;

  Name表示节区名称,ASCII字符串,可自定义,只截取8个。
  Misc表示该节在没有对齐前的真实尺寸,该值可以不准确。
  VirtualAddress是在内存中的偏移地址,加上lmageBase才是在内存中的真正地址,十分重要。
  PointerToRawData是节区在文件中的偏移,十分重要。
  PointerToRelocations/PointerToRelocations/NumberOfRelocations/PointerToLinenumbers与调试相关,不关注。
  Characteristics是节的属性。下面是其枚举:

//      IMAGE_SCN_TYPE_REG                   0x00000000  // Reserved.
// IMAGE_SCN_TYPE_DSECT 0x00000001 // Reserved.
// IMAGE_SCN_TYPE_NOLOAD 0x00000002 // Reserved.
// IMAGE_SCN_TYPE_GROUP 0x00000004 // Reserved.
#define IMAGE_SCN_TYPE_NO_PAD 0x00000008 // Reserved.
// IMAGE_SCN_TYPE_COPY 0x00000010 // Reserved.
#define IMAGE_SCN_CNT_CODE 0x00000020 // Section contains code.
#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 // Section contains initialized data.
#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 // Section contains uninitialized data.
#define IMAGE_SCN_LNK_OTHER 0x00000100 // Reserved.
#define IMAGE_SCN_LNK_INFO 0x00000200 // Section contains comments or some other type of information.
// IMAGE_SCN_TYPE_OVER 0x00000400 // Reserved.
#define IMAGE_SCN_LNK_REMOVE 0x00000800 // Section contents will not become part of image.
#define IMAGE_SCN_LNK_COMDAT 0x00001000 // Section contents comdat.
// 0x00002000 // Reserved.
// IMAGE_SCN_MEM_PROTECTED - Obsolete 0x00004000
#define IMAGE_SCN_NO_DEFER_SPEC_EXC 0x00004000 // Reset speculative exceptions handling bits in the TLB entries for this section.
#define IMAGE_SCN_GPREL 0x00008000 // Section content can be accessed relative to GP
#define IMAGE_SCN_MEM_FARDATA 0x00008000
// IMAGE_SCN_MEM_SYSHEAP - Obsolete 0x00010000
#define IMAGE_SCN_MEM_PURGEABLE 0x00020000
#define IMAGE_SCN_MEM_16BIT 0x00020000
#define IMAGE_SCN_MEM_LOCKED 0x00040000
#define IMAGE_SCN_MEM_PRELOAD 0x00080000
#define IMAGE_SCN_ALIGN_1BYTES 0x00100000 //
#define IMAGE_SCN_ALIGN_2BYTES 0x00200000 //
#define IMAGE_SCN_ALIGN_4BYTES 0x00300000 //
#define IMAGE_SCN_ALIGN_8BYTES 0x00400000 //
#define IMAGE_SCN_ALIGN_16BYTES 0x00500000 // Default alignment if no others are specified.
#define IMAGE_SCN_ALIGN_32BYTES 0x00600000 //
#define IMAGE_SCN_ALIGN_64BYTES 0x00700000 //
#define IMAGE_SCN_ALIGN_128BYTES 0x00800000 //
#define IMAGE_SCN_ALIGN_256BYTES 0x00900000 //
#define IMAGE_SCN_ALIGN_512BYTES 0x00A00000 //
#define IMAGE_SCN_ALIGN_1024BYTES 0x00B00000 //
#define IMAGE_SCN_ALIGN_2048BYTES 0x00C00000 //
#define IMAGE_SCN_ALIGN_4096BYTES 0x00D00000 //
#define IMAGE_SCN_ALIGN_8192BYTES 0x00E00000 //
// Unused 0x00F00000
#define IMAGE_SCN_ALIGN_MASK 0x00F00000
#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 // Section contains extended relocations.
#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 // Section can be discarded.
#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 // Section is not cachable.
#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 // Section is not pageable.
#define IMAGE_SCN_MEM_SHARED 0x10000000 // Section is shareable.
#define IMAGE_SCN_MEM_EXECUTE 0x20000000 // Section is executable.
#define IMAGE_SCN_MEM_READ 0x40000000 // Section is readable.
#define IMAGE_SCN_MEM_WRITE 0x80000000 // Section is writeable.

  我们再来看看它在二进制文件下的位置:

IMAGE_DATA_DIRECTORY

  IMAGE_DATA_DIRECTORY是十分重要的结构体,具体重要性的体现已经在IMAGE_OPTIONAL_HEADER介绍过了,如下是其结构:

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

  VirtualAddress是指表在内存的RVA,十分重要。
  Size是指IMAGE_DATA_DIRECTORY结构体和其使用的所有数据之和,该值不会影响程序的运行。

  我们再来看看它在二进制文件下的位置:

小结

  本篇我们只介绍了基本结构体,对于后面比较复杂的几个表和地址转化,考虑到比较复杂,挪到下一篇进行。
  看完本篇文章一定要把在16进制下看明白结构,最好用自己熟悉的编程语言写一个解析上面所述结构体的解析器,以巩固自己的学习成果。

下一篇

  羽夏壳世界—— PE 结构(下)

羽夏壳世界—— PE 结构(上)的更多相关文章

  1. (五)羽夏看C语言——结构体与类

    写在前面   由于此系列是本人一个字一个字码出来的,包括示例和实验截图.本人非计算机专业,可能对本教程涉及的事物没有了解的足够深入,如有错误,欢迎批评指正. 如有好的建议,欢迎反馈.码字不易,如果本篇 ...

  2. 羽夏 Bash 简明教程(上)

    写在前面   该文章根据 the unix workbench 中的 Bash Programming 进行汉化处理并作出自己的整理,并参考 Bash 脚本教程 和 BashPitfalls 相关内容 ...

  3. (四)羽夏看C语言——循环与跳转

    写在前面   由于此系列是本人一个字一个字码出来的,包括示例和实验截图.本人非计算机专业,可能对本教程涉及的事物没有了解的足够深入,如有错误,欢迎批评指正. 如有好的建议,欢迎反馈.码字不易,如果本篇 ...

  4. 羽夏笔记——PE结构(不包含.Net)

    写在前面   本笔记是由本人独自整理出来的,图片来源于网络.本人非计算机专业,可能对本教程涉及的事物没有了解的足够深入,如有错误,欢迎批评指正. 如有好的建议,欢迎反馈.码字不易,如果本篇文章有帮助你 ...

  5. 羽夏看Linux内核——引导启动(上)

    写在前面   此系列是本人一个字一个字码出来的,包括示例和实验截图.如有好的建议,欢迎反馈.码字不易,如果本篇文章有帮助你的,如有闲钱,可以打赏支持我的创作.如想转载,请把我的转载信息附在文章后面,并 ...

  6. 羽夏逆向指引—— Hook

    写在前面   此系列是本人一个字一个字码出来的,包括示例和实验截图.可能有错误或者不全面的地方,如有错误,欢迎批评指正,本教程将会长期更新. 如有好的建议,欢迎反馈.码字不易,如果本篇文章有帮助你的, ...

  7. 羽夏看Linux内核——中断与分页相关入门知识

    写在前面   此系列是本人一个字一个字码出来的,包括示例和实验截图.如有好的建议,欢迎反馈.码字不易,如果本篇文章有帮助你的,如有闲钱,可以打赏支持我的创作.如想转载,请把我的转载信息附在文章后面,并 ...

  8. 跟羽夏学 Ghidra ——窗口

    写在前面   此系列是本人一个字一个字码出来的,包括示例和实验截图.本人非计算机专业,可能对本教程涉及的事物没有了解的足够深入,如有错误,欢迎批评指正. 如有好的建议,欢迎反馈.码字不易,如果本篇文章 ...

  9. (三)羽夏看C语言——进制

    写在前面   由于此系列是本人一个字一个字码出来的,包括示例和实验截图.本人非计算机专业,可能对本教程涉及的事物没有了解的足够深入,如有错误,欢迎批评指正. 如有好的建议,欢迎反馈.码字不易,如果本篇 ...

随机推荐

  1. 使用阿里云镜像站NTP服务搭建NTP服务器(基于CentOS 7系统)

    镜像下载.域名解析.时间同步请点击 阿里云开源镜像站 一.NTP服务器介绍 网络时间协议(Network Time Protocol,NTP)服务器,也就是日常所说的NTP服务器,用来提供同步时间服务 ...

  2. 6月15日 python学习总结 Django模板语言相关内容

    Django模板语言相关内容   Django模板系统 官方文档 常用语法 只需要记两种特殊符号: {{  }}和 {% %} 变量相关的用{{}},逻辑相关的用{%%}. 变量 {{ 变量名 }} ...

  3. Nebula Graph 在网易游戏业务中的实践

    本文首发于 Nebula Graph Community 公众号 当游戏上知识图谱,网易游戏是如何应对大规模图数据的管理问题,Nebula Graph 又是如何帮助网易游戏落地游戏内复杂的图的业务呢? ...

  4. linux下的shell脚本

    先说明以下内容来自: http://c.biancheng.net/cpp/shell/ ,C语言中文网,请大家支持原作,点击链接查看. 我写下来只是作为笔记,如果侵权,请留言,立马删除. Shell ...

  5. Dubbo 服务降级,失败重试怎么做?

    可以通过 dubbo:reference 中设置 mock="return null".mock 的值也可以修 改为 true,然后再跟接口同一个路径下实现一个 Mock 类,命名 ...

  6. yarn上运行flink环境搭建

    主要完成hadoop集群搭建和yarn上运行flink 1.搭建hadoop伪集群 主要是搭建hadoop MapReduce(yarn)和HDFS 1.1 下载&配置环境变量 这里下载的ha ...

  7. 转:C++11常用新特性快速一览

    转载至:https://blog.csdn.net/jiange_zh/article/details/79356417 1.nullptr nullptr 出现的目的是为了替代 NULL. 在某种意 ...

  8. @Qualifier 注解?

    当有多个相同类型的 bean 却只有一个需要自动装配时,将@Qualifier 注解和 @Autowire 注解结合使用以消除这种混淆,指定需要装配的确切的 bean.

  9. 学习zabbix(三)

    前言: 学习zabbix之前,不得不了解的是SNMP协议 SNMP:简单网络管理协议(Simple Network Protocol) Snmp由两部分组成,监控端和被监控端 监控模式: 主动模式:N ...

  10. 学习saltstack (三)

    salt是一个新的基础平台管理工具,2011-02-20诞生,创造者Thoms SHatch,起名salt原因生活中常见.易记,使用saltstack.com原因这个域名没有被注册,Because s ...