pe文件中的3处Characteristics

首先:pe文件结构

1、DOS头,对应结构体IMAGE_DOS_HEADER。

2、DOS存根,大小不定,由编译器决定,没有对应的结构体。

3、NT头,对应结构体IMAGE_NT_HEADER,包括3部分定义如下:

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

4、节区头,对应结构体IMAGE_SECTION_HEADER,有多少个节区就有多少个连续的IMAGE_SECTION_HEADER结构体。

5、各个节区。

3处Characteristics分别位于IMAGE_FILE_HEADER、IMAGE_OPTIONAL_HEADER、IMAGE_SECTION_HEADER结构体中

1、IMAGE_FILE_HEADER结构体定义:

typedef struct _IMAGE_FILE_HEADER {
  WORD  Machine;                   // 定义该pe文件运行在那种cpu上
  WORD  NumberOfSections;          // 定义节区头有多少个连续IMAGE_SECTION_HEADER结构体     
  DWORD TimeDateStamp;             // 编译器生成该pe文件的时间  
  DWORD PointerToSymbolTable;
  DWORD NumberOfSymbols;
  WORD  SizeOfOptionalHeader;      // IMAGE_OPTIONAL_HEADER32或者IMAGE_OPTIONAL_HEADER64大小,常用来定位节区头位置
  WORD  Characteristics;           // 用于表示该pe文件属性
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

在WinNT.h中有定义(只列举部分):

#define IMAGE_FILE_EXECUTABLE_IMAGE          0x0002  // File is executable
#define IMAGE_FILE_SYSTEM                    0x1000  // System File.
#define IMAGE_FILE_DLL                       0x2000  // File is a DLL.
#define IMAGE_FILE_BYTES_REVERSED_HI         0x8000  // Bytes of machine word are reversed.
                                                     // 处理机的高位字节是相反的

有样本中专门检测0x8000,如果没有就申请可读写内存空间,有就申请可执行读写的内存空间,如图:

2、IMAGE_OPTIONAL_HEADER结构体定义

typedef struct _IMAGE_OPTIONAL_HEADER {
  WORD                 Magic;                         // 32位pe文件为0x010B,64位pe文件为0x020B
  BYTE                 MajorLinkerVersion;
  BYTE                 MinorLinkerVersion;
  DWORD                SizeOfCode;
  DWORD                SizeOfInitializedData;
  DWORD                SizeOfUninitializedData;
  DWORD                AddressOfEntryPoint;          // 该pe文件入口点RVA
  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;                  // 该pe文件对应镜像在内存中总大小,pe加载器根据此处值决定申请连续内存空间大小 
  DWORD                SizeOfHeaders;                // 该pe文件所有头的总长度,dos头+dos存根+NT头+节区表头,用来把"头"从文件到拷贝到镜像长度
  DWORD                CheckSum;                     // 该pe文件校验和 
  WORD                 Subsystem;
  WORD                 DllCharacteristics;           // ?????????????  
  DWORD                SizeOfStackReserve;
  DWORD                SizeOfStackCommit;
  DWORD                SizeOfHeapReserve;
  DWORD                SizeOfHeapCommit;
  DWORD                LoaderFlags;
  DWORD                NumberOfRvaAndSizes;         // 指明DataDirectory数组元素个数,一直是0x00000010
  IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

这里DllCharacteristics,好多书上翻译成DLL何时被调用,这个理解感觉…………

找到宏定义:

#define IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE 0x0040     // DLL can move.

用od调试样本时发现,这里有0x0040标志时,每次重新调试,镜像基址都会变化(ASLR),把40修改成00,即使有重定位节区,也不会重定位行为,od调试就方便了许多。

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
#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
                                                  // 最后一个保留,未使用

3、IMAGE_SECTION_HEADER结构体定义:

typedef struct _IMAGE_SECTION_HEADER {
  BYTE  Name[IMAGE_SIZEOF_SHORT_NAME];  // 节区名,最大长度8个字节
  union {
    DWORD PhysicalAddress;
    DWORD VirtualSize;            // 该节区在镜像(内存)中的大小
  } Misc;
  DWORD VirtualAddress;           // 该节区在镜像(内存)中的RVA
  DWORD SizeOfRawData;            // 该节区在文件中的大小
  DWORD PointerToRawData;         // 该节区在文件中的偏移
  DWORD PointerToRelocations;
  DWORD PointerToLinenumbers;
  WORD  NumberOfRelocations;
  WORD  NumberOfLinenumbers;
  DWORD Characteristics;          // 该节区属性
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

根据在文件和镜像中的大小和偏移完成从文件到镜像的加载,根据在镜像中位置和大小结合Characteristics值,使用VirtualProtect修改该节区在镜像中的内存属性。

注意:pe文件的节区是多个。

猜你喜欢

转载自blog.csdn.net/singleyellow/article/details/86819574