逆向工程核心原理5:PE文件

PE : portable execute (windows下的可执行文件)
VA : 进程虚拟内存的绝对地址,方位是 0x00000000 ~ 0xFFFFFFFF (进程的虚拟内存是4G)
RVA : 相对的虚拟地址,从某个基准位置(images)开始的相对地址

PE分为如下部分 :
    PE头 :  从DOS头(DOS Header) 到节区头(section header)
                dos头、dos存根、NT头
    PE体 :  代码(.text) 数据(.data) 资源(.rsrc)


关键结构体 :
*********************************      PE头相关       *********************************
 DOS头, 40字节 
typedef struct _IMAE_DOS_HEADER {       //DOS .EXE header                                    位置  
    WORD e_magic;                       //Magic number;                                                 0x00          AD5A
    WORD e_cblp;                          //Bytes on last page of file                                 0x02  
    WORD e_cp;                             //Pages in file                                                      0x04  
    WORD e_crlc;                           //Relocations                                                       0x06  
    WORD e_cparhdr;                    //Size of header in paragraphs                           0x08  
    WORD e_minalloc;                   //Minimum extra paragraphs needed                0x0A  
    WORD e_maxalloc;                  //Maximum extra paragraphs needed                0x0C  
    WORD e_ss;                             //Initial (relative) SS value                                   0x0E  
    WORD e_sp;                            //Initial SP value                                                  0x10  
    WORD e_csum;                       //Checksum                                                         0x12  
    WORD e_ip;                            //Initial IP value                                                    0x14  
    WORD e_cs;                            //Initial (relative) CS value                                    0x16  
    WORD e_lfarlc;                       //File address of relocation table                         0x18  
    WORD e_ovno;                       //Overlay number                                                0x1A  
    WORD e_res[4];                      //Reserved words                                                 0x1C  
    WORD e_oemid;                     //OEM identifier (for e_oeminfo)                         0x24  
    WORD e_oeminfo;                  //OEM information; e_oemid specific                 0x26   
    WORD e_res2[10];                   //Reserved words                                                0x28  
    LONG e_lfanew;                      /File address of new exe header                          0x3C      如下图可知, 值为0x000000F8
} IMAGE_DOS-HEADER, *PIMAGE_DOS_HEADER;

使用Hex Edit工具可以查看 :  https://pan.baidu.com/s/1zaP2Hl5h7IrWMGGdG7HFMQ

DOS存根 :
    在dos头的下方,可有可无,由代码和数据混合组成, 没有也可以正常运行。
    从下图可知,e_lfanew的位置为0x3四个字节, 值为0x000000F8, 所有dos存根的内容为 0x00000040 ~ 0x000000F8 (.. this is program cannot be run in DOS mode ....)
    备注 : 后续部分小截图直接从这里截图的
    


NT头
typedef struct _IMAGE_NT_HEADERS {         
    DWORD Signature;                                                      //位置在e_lfanew上   PE signature : 5045  
    IMAGE_FILE_HEADER FileHeader;                                //e_lfanew + 0x4         文件头结构体  
    IMAGE_OPTIONAL_HEADER32 OptionalHeader;        //e_lfanew + 0x18        可选头结构体  
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;  


NT头 : 文件头
typedef struct _IMAGE_FILE_HEADER {  
    WORD Machine;                               //位置为 e_lfanew + 0x4   //该字段表示可执行文件的目标CPU类型  014c  intel
    WORD NumberOfSections;              //e_lfanew + 0x6               //该字段表示PE文件的节区的个数  0004
    DWORD TimeDateStamp;                //e_lfanew + 0x8                //该字段表明文件时何时被创建的,这个值是自1970年1月1日以来用格林  
                                                             //威治时间计算的秒数  
    DWORD PointerToSymbolTable;     //e_lfanew + 0xC                //  
    DWORD NumberOfSymbols;           //e_lfanew + 0x10             //  
    WORD SizeOfOptionalHeader;        //e_lfanew + 0x12             //该字段指定IMAGE_OPTIONAL_HEADER结构的大小  
    WORD Characteristics;                    //e_lfanew + 0x14              //该字段指定文件的类型  
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;   //大小20字节  
  
                                                Machine字段取值  
                        宏定义                                     值                   意义  
#define IMAGE_FILE_MACHINE_I386           0x014c           Intel  
#define IMAGE_FILE_MACHINE_ALPHA       0x0184          DEC Alpha  
#define IMAGE_FILE_MACHINE_IA64           0x0200          Intel(64 - bit)  
#define IMAGE_FILE_MACHINE_AXP64       0x0284           DEC Alpha(64 - bit)  

                                            Characteristics字段取值  
                    宏定义                                                    值                意义  
#define IMAGE_FILE_RELOCS_STRIPPED                  0x0001     文件中不存在重定位信息  
#define IMAGE_FILE_EXECUTABLE_IMAGE               0x0002     文件可执行  
#define IMAGE_FILE_LINE_NUMS_STRIPPED            0x0004     行号信息已从文件中移除  
#define IMAGE_FILE_LOCAL_SYMS_STRIPPED         0x0008     符号信息已从文件中移除  
#define IMAGE_FILE_DLL                                          0x2000     DLL文件  
#define IMAGE_FILE_SYSTEM                                   0x1000     系统文件  
#define IMAGE_FILE_32BIT_MACHINE                     0x0100     目标平台为32位平台  

NT头 : 可选头
typedef struct _IMAGE_OPTIONAL_HEADER {  
     WORD Magic ;                                             //位置为 e_lfanew + 0x18                       //文件的状态类型   10B(32位)  20B(64位)
    BYTE MajorLinkerVersion;                          //e_lfanew + 0x1A                               //主链接版本号  
    BYTE MinorLinkerVersion;                          //e_lfanew + 0x1B                               //次链接版本号  
    DWORD SizeOfCode;                                 //e_lfanew + 0x1C                               //代码节的大小  
    DWORD SizeOfInitializedData;                  //e_lfanew + 0x20                               //已初始化数据块的大小  
    DWORD SizeOfUninitializedData;              //e_lfanew + 0x24                               //未初始化数据块的大小  
      DWORD AddressOfEntryPoint ;                  //e_lfanew + 0x28                               //程序执行的入口,相对虚拟地址,简称EP  
    DWORD BaseOfCode;                               //e_lfanew + 0x2C                               //代码段的起始相对虚拟地址  
    DWORD BaseOfData;                                //e_lfanew + 0x30                               //数据段的起始相对虚拟地址  
     DWORD ImageBase;                                 //e_lfanew + 0x34                               //内存首选装载地址  
    DWORD SectionAlignment                      //e_lfanew + 0x38                               //节在内存中的对齐值  
    DWORD FileAlignment                             //e_lfanew + 0x3C                               //节在文件中的对齐值  
    WORD MajorOperatingSystemVersion;   //e_lfanew + 0x40                               //要求最低操作系统的主版本号  
    WORD MinorOperatingSystemVersion;   //e_lfanew + 0x42                               //要求最低操作系统的次版本号  
    WORD MajorImageVersion;                     //e_lfanew + 0x44                               //可执行文件的主版本号      
    WORD MinorImageVersion;                     //e_lfanew + 0x46                               //可执行文件的次版本号  
    WORD MajorSubsystemVersion;             //e_lfanew + 0x48                               //要求最低子系统的主版本号  
    WORD MinorSubsystemVersion;             //e_lfanew + 0x4A                               //要求最低子系统的次版本号  
    DWORD Win32VersionValue;                  //e_lfanew + 0x4C                               //该成员变量是被保留的  
     DWORD SizeOfImage;                             //e_lfanew + 0x50                               //可执行文件装入内存后的总大小  
    DWORD SizeOfHeader;                           //e_lfanew + 0x54                               //PE头的大小,包括DOS头、PE头、节表的总和大小  
    DWORD CheckSum;                                //e_lfanew + 0x58                               //校验和  
     WORD Subsystem;                                  //e_lfanew + 0x5C                               //可执行文件的子系统类型  
    WORD DllCharacteristics;                       //e_lfanew + 0x5E                               //指定DLL文件的属性,该值大部分时候为0  
    DWORD SizeOfStackReserve;                //e_lfanew + 0x60                               //为线程保留的栈大小  
    DWORD SizeOfStackCommit;                //e_lfanew + 0x64                               //为线程已经提交的栈大小  
    DWORD SizeOfHeapReserve;                //e_lfanew + 0x68                               //为线程保留的堆大小  
    DWORD SizeOfHeapCommit;                //e_lfanew + 0x6C                               //为线程已经提交的堆大小  
    DWORD LoaderFlags;                            //e_lfanew + 0x70                               //被废弃的成员值  
     DWORD NumberOfRvaandSizes;          //e_lfanew + 0x74                               //数据目录项的个数  
    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];   //e_lfanew + 0x78   //数据目录表  
    //#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16            
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;      //大小224字节  

                                                            Magic取值  
                  宏定义                                                    值                意义  
#define IMAGE_NT_OPTIONAL_HDR_MAGIC       0x10b          可执行文件  
#define IMAGE_ROM_OPTIONAL_HDR_MAGIC    0x107          ROM文件  
 
                                                    Subsystem取值  
                          宏定义                                           值                意义  
#define IMAGE_SUBSYSTEM_UNKNOWN              0             未知子系统  
#define IMAGE_SUBSYSTEM_NATIVE                     1            不需要子系统  
#define IMAGE_SUBSYSTEM_WINDOWS_GUI        2            图形子系统  
#define IMAGE_SUBSYSTEM_WINDOWS_CUI        3            控制台子系统  
  
  
//IMAGE_DATA_DIRECTORY  
typedef struct _IMAGE_DATA_DIRECTORY {  
    DWORD VirtualAddress;  
    DWORD Size;  
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;  
  
                                    DataDirectory
索引                        宏定义                                     意义  
0    IMAGE_DIRECTORY_ENTRY_EXPORT            导出表
1    IMAGE_DIRECTORY_ENTRY_IMPORT            导入表
2    IMAGE_DIRECTORY_ENTRY_RESOURCE        资源
3    IMAGE_DIRECTORY_ENTRY_EXCEPTION       异常(具体资料不详)
4    IMAGE_DIRECTORY_ENTRY_SECURITY          安全(具体资料不详)
5    IMAGE_DIRECTORY_ENTRY_BASERELOC       重定位表
6    IMAGE_DIRECTORY_ENTRY_DEBUG              调试信息
7    IMAGE_DIRECTORY_ENTRY_ARCHITECTURE  版权信息

8    IMAGE_DIRECTORY_ENTRY_GLOBALPTR               具体资料不详
9    IMAGE_DIRECTORY_ENTRY_TLS                             Thread Local Storage
10    IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG         具体资料不详
11    IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT      具体资料不详
12    IMAGE_DIRECTORY_ENTRY_IAT                            导入函数地址表
13    IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT        具体资料不详
14    IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR   具体资料不详
15    未使用


节区头 :
typedef struct _IMAGE_SECTION_HEADER {                  //第一个节区,每个节区依次往后推40字节即可  
    BYTE Name[IMAGE_SIZEOF_SHORT_NAME];             //位置为 e_lfanew + 0xF8                   //保存节的名称  
    union {                                       
        DWORD PhysicalAddress;                                    //e_lfanew + 0x100                          //  
        DWORD VirtualSize;                                             //e_lfanew + 0x104                          //数据实际的节区大小  
    } Misc;  
    DWORD VirtualAddress;                                          //e_lfanew + 0x108                          //该节区载入到内存后的相对虚拟地址  
    DWORD SizeOfRawData;                                         //e_lfanew + 0x10C                          //该节区在磁盘上的大小  
    DWORD PointerToRawData;                                    //e_lfanew + 0x110                          //该节区在磁盘文件上的偏移值  
    DWORD PointerToRelocations;                               //e_lfanew + 0x114  
    DWORD PointerToLinenumbers;                             //e_lfanew + 0x118  
    WORD NumberOfRelocations;                                //e_lfanew + 0x11C  
    WORD NumberOfLinenumbers;                              //e_lfanew + 0x11E  
     DWORD Characteristics;                                          //e_lfanew + 0x120                          //节区属性  
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;   //该数据结构大小为40字节  
      
                                                Characteristics(节区属性)
                      宏定义                                         值                    意义  
#define IMAGE_SCN_CNT_CODE              0x00000020       该节区含代码  
#define IMAGE_SCN_MEM_SHARED        0x10000000       该节区为可共享  
#define IMAGE_SCN_MEM_EXECUTE       0x20000000       该节区为可执行  
#define IMAGE_SCN_MEM_READ            0x40000000       该节区为可读  
#define IMAGE_SCN_MEM_WRITE           0x80000000       该节区为可写  


上面是为了更加熟悉PE文件。
最后,介绍一块PE工具PEView :  https://pan.baidu.com/s/1L2dGaawb_qoRF7px5X3oiw
可以直观的看到PE各个结构体的值

















猜你喜欢

转载自blog.csdn.net/dengshengli123/article/details/80819752