逆向工程——PE(一)

 本章参考书《逆向工程核心原理》

什么是PE?

PE(Protable Executable),是Windows操作系统下使用的可执行文件,因为Windows分32位操作系统和64位操作系统,因此与之相对应有PE(或称为PE32)PE+(或称为PE32+)。这里主要分析PE32。

 

 

PE的分类

 

其中我们遇见的比较多的是exe可执行文件、sys驱动程序文件、dll动态链接库文件以及obj对象文件。

在这些文件中,除了obj对象文件,其他的文件都能够被直接或者间接地执行(例如驱动程序和库文件,就要使用相应的调试器,加载器或者是服务等来执行)。

 

 

PE文件的基本结构

 


 

    • DOS头

    DOS头的主要作用是使PE文件对DOS文件具有兼容性,表现为IMAGE_DOS_HEADER结构体(大小为64字节)。    

 1 typedef struct _IMAGE_DOS_HEADER{
 2         WORD    e_magic     ;
 3         WORD    e_cblp        ;
 4         WORD    e_cp          ;
 5         WORD    e_crlc         ;
 6         WORD    e_cparhdr    ;
 7         WORD    e_minalloc    ;
 8         WORD    e_maxalloc    ;
 9         WORD    e_ss            ;
10         WORD    e_sp            ;
11         WORD    e_csum        ;
12         WORD    e_ip            ;
13         WORD    e_cs            ;
14         WORD    e_lfarlc        ;
15         WORD    e_ovno        ;
16         WORD    e_res[4]        ;
17         WORD    e_oemid        ;
18         WORD    e_oeminfo    ;
19         WORD    e_res2[10]    ;
20         WORD    e_lfanew        ;
21 } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

            其中比较重要的是  e_magic (DOS签名)  , e_lfanew(NT头的偏移)

      其中“5A4D”(橘色标记)为e_magic(一般的PE文件的DOS头都是“5A4D”),而000000F8(红色标记)则是e_lfanew,NT头开始的位置,注意,此处为小端序表记法。

 

    • DOS存根

    DOS存根在DOS头的下方,是个可选项,大小不固定。DOS存根由代码和数据混合组成。

        

 

      深色区域即为DOS存根,而用红框框出来的则是DOS系统下16位汇编指令,因此32位Windows不会识别,此16位汇编指令为:

  

1 0E            PUSH         CS
2 1F            POP          DS
3 BA0E00        MOV          DX,000E     ; DX = 0E  : "This program cannot be run in DOS mode"  
4 B409          MOV          AH,09       ;WriteString()
5 CD21          INT          21
6 B8014C        MOV          AX,4C01     ;Exit()
7 CD21          INT          21

 

    • NT头

    NT头是PE头中的核心部分,在整个PE头中也占据很大的空间。

1 typedef struct _IMAGE_NT_HEADERS{
2         DWORD                      Signature     ;
3         IMAGE_FILE_HEADER          FileHeader    ;
4         IMAGE_OPTIONAL_HEADER32    OptionalHeader;
5 }IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

 

        

      IMAGE_NT_HEADERS结构体主要由以上3个成员组成。

 

      

      根据DOS头中的e_lfanew值(000000F8),我们找到了NT头中的第一个变量Signture(50450000h)一般ASCLL码都是"PE"

      

      •  NT头:文件头(IMAGE_FILE_HEADER)

      

1 typedef    struct    _IMAGE_FILE_HEADER{
2         WORD     Machine                 ;
3         WORD     NumberOfSections        ;
4         DWORD    TimeDateStamp           ;
5         DWORD    PointerToSymbolTable    ;
6         DWORD    NumberOfSymbols         ;
7         WORD     SizeOfOptionalHeader    ;
8         WORD     Characteristics         ;
9 }IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

 

#1.Machine

  每个cpu都有唯一的Machine码。兼容32位Intel的Machine码为0x014c。

 1 #define IMAGE_FILE_MACHINE_UNKNOWN           0
 2 #define IMAGE_FILE_MACHINE_I386              0x014c  // Intel 386.
 3 #define IMAGE_FILE_MACHINE_R3000             0x0162  // MIPS little-endian, 0x160 big-endian
 4 #define IMAGE_FILE_MACHINE_R4000             0x0166  // MIPS little-endian
 5 #define IMAGE_FILE_MACHINE_R10000            0x0168  // MIPS little-endian
 6 #define IMAGE_FILE_MACHINE_WCEMIPSV2         0x0169  // MIPS little-endian WCE v2
 7 #define IMAGE_FILE_MACHINE_ALPHA             0x0184  // Alpha_AXP
 8 #define IMAGE_FILE_MACHINE_POWERPC           0x01F0  // IBM PowerPC Little-Endian
 9 #define IMAGE_FILE_MACHINE_SH3               0x01a2  // SH3 little-endian
10 #define IMAGE_FILE_MACHINE_SH3E              0x01a4  // SH3E little-endian
11 #define IMAGE_FILE_MACHINE_SH4               0x01a6  // SH4 little-endian
12 #define IMAGE_FILE_MACHINE_ARM               0x01c0  // ARM Little-Endian
13 #define IMAGE_FILE_MACHINE_THUMB             0x01c2
14 #define IMAGE_FILE_MACHINE_IA64              0x0200  // Intel 64
15 #define IMAGE_FILE_MACHINE_MIPS16            0x0266  // MIPS
16 #define IMAGE_FILE_MACHINE_MIPSFPU           0x0366  // MIPS
17 #define IMAGE_FILE_MACHINE_MIPSFPU16         0x0466  // MIPS
18 #define IMAGE_FILE_MACHINE_ALPHA64           0x0284  // ALPHA64
19 #define IMAGE_FILE_MACHINE_AXP64             IMAGE_FILE_MACHINE_ALPHA64

#2.NumberOfSections

  NumberOfSections用来指出此文件中存在的节区个数。

#3.SizeOfOptionalHeader

  用来指出IMAGE_OPTIONAL_HEADER32的长度。尽管说,IMAGE_OPTIONAL_HEADER32结构体大小已经确定,但是为了和PE32+区分(在PE32+中,可选头为IMAGE_OPTIONAL_HEADER64,大小与PE中的可选头不同),因此需要SizeOfOptionalHeader来明确结构体大小。

#4.Characteristics

  用来标识文件属性,来表示文件是否可运行,是否为DLL等信息。

 

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

 #5.TimeDateStamp

   记录编译器创造此文件的时间。

 

 

以下是notepad.exe的IMAGE_FILE_HEADER结构体:

014C             machine
0005             number of sections
144CAAC5         TimeDateStamp
00000000         PointerToSymbolTable
00000000         NumberOfSymbols
00E0             SiezOfOptionalHeader
0102             Characteristics:
                       IMAGE_FILE_32BIT_MACHINE
                       IMAGE_FILE_EXECUTABLE_IMAGE

 

      • NT头:可选头(IMAGE_OPTIONAL_HEADER32)

 

 

 1 typedef struct _IMAGE_DATA_DIRECTORY {
 2     DWORD   VirtualAddress;
 3     DWORD   Size;
 4 } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
 5 
 6 #define IMAGE_NUMBEROF_DIRECTORY_ENTRIES    16
 7 
 8 //
 9 // Optional header format.
10 //
11 
12 typedef struct _IMAGE_OPTIONAL_HEADER {
13     //
14     // Standard fields.
15     //
16 
17     WORD    Magic;
18     BYTE    MajorLinkerVersion;
19     BYTE    MinorLinkerVersion;
20     DWORD   SizeOfCode;
21     DWORD   SizeOfInitializedData;
22     DWORD   SizeOfUninitializedData;
23     DWORD   AddressOfEntryPoint;
24     DWORD   BaseOfCode;
25     DWORD   BaseOfData;
26 
27     //
28     // NT additional fields.
29     //
30 
31     DWORD   ImageBase;
32     DWORD   SectionAlignment;
33     DWORD   FileAlignment;
34     WORD    MajorOperatingSystemVersion;
35     WORD    MinorOperatingSystemVersion;
36     WORD    MajorImageVersion;
37     WORD    MinorImageVersion;
38     WORD    MajorSubsystemVersion;
39     WORD    MinorSubsystemVersion;
40     DWORD   Win32VersionValue;
41     DWORD   SizeOfImage;
42     DWORD   SizeOfHeaders;
43     DWORD   CheckSum;
44     WORD    Subsystem;
45     WORD    DllCharacteristics;
46     DWORD   SizeOfStackReserve;
47     DWORD   SizeOfStackCommit;
48     DWORD   SizeOfHeapReserve;
49     DWORD   SizeOfHeapCommit;
50     DWORD   LoaderFlags;
51     DWORD   NumberOfRvaAndSizes;
52     IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
53 } IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

其中红字标识的是可选头中比较重要的变量,以下我来对它们一一介绍。

#1.Magic

  当文件为PE时,可选头为IMAGE_OPTIONAL_HEADER32,Magic = 10B

  当文件为PE+时,可选头为IMAGE_OPTIONAL_HEADER64,Magic = 20B

#2.AddressOfEntryPoint

   程序最先被执行的代码起始地址。相当重要。

 #3.ImageBase

        当PE文件被装载到内存空间中去时,ImageBase指出文件的优先装入地址。执行PE文件时,PE装载器先创建进程,再将文件载入内存,然后把EIP寄存器的值设置为ImageBase + AddressOfEntryPoint 。

 #4.SectionAlignment,FileAlignment

  SectionAlignment指定了节区在内存中的最小单位

  FileAlignment指定了节区在磁盘中的最小单位

  一个文件的SectionAlignment和FileAlignment可能相同,也有可能不同。

  磁盘文件或内存中的节区大小必定为FileAlignment或SectionAlignment值的整数倍。

#5.SizeOfImage

  SizeOfImage指定了PE在加载入内存中所占空间的大小,在一般情况下,文件的大小与加载到内存中的大小是不同的。

#6.SizeOfHeaders

  整个PE头的大小,值为FileAlignment的整数倍。第一节区所在位置与SizeOfHeaders距文件偏移量相同。

#7.Subsystem

  用来区分不同的文件。

        

 

#8.NumberOfRvaAndSizes

  指定DataDirectory(IMAGE_OPTIONAL_HEADER32结构体中最后一个成员)数组的个数。

#9.DataDirectory

  DataDirectory是由IMAGE_DATA_DIRECTORY结构体组成的数组,数组的每项都有被定义的值。

 

DataDirectory[0] = EXPORT  Directory
DataDirectory[1] = IMPORT  Directory
DataDirectory[2] = RESOURCE  Directory
DataDirectory[3] = EXCEPTION  Directory
DataDirectory[4] = SECURITY  Directory
DataDirectory[5] = BASERELOC  Directory
DataDirectory[6] = DEBUG  Directory
DataDirectory[7] = COPYRIGHT  Directory
DataDirectory[8] = GLOBALPTR  Directory
DataDirectory[9] = TLS  Directory
DataDirectory[A] = LOAD_CONFIG  Directory
DataDirectory[B] = BOUND_IMPORT  Directory
DataDirectory[C] = IAT  Directory
DataDirectory[D] = DELAY_IMPORT  Directory
DataDirectory[E] = COM_DESCRIPTOR  Directory
DataDirectory[F] = Reserved  Directory

 

 

 

 

介绍完了可选头里的每个成员,再带大家实际分析一下notepad.exe

地址           十六进制         备注
000110 010B magic 000120 0001B2B0 AdressOfEntryPoint 000130 00001000 SectionAlignment 000134 00000200 FileAlignment 00014C 00000400 SizeOfHeaders 000154 0002 Subsystem 000170 00000000 DataDirectory[0].VirtualAdress(RVA of EXPORT Directory) 000178 0001F4AC DataDirectory[1].VirtualAdress(RVA of IMPORT Directory) 00017C 00000230 DataDirectory[1].Size(size of IMPORT Directory)

这里只列出来了一些比较重要的成员,各位朋友们可以自己练习,把剩下的成员都标识出来哦!~

 

至此,NT头已经讲完了,在进入下一内容前,我建议各位读者把NT头再回顾一下。

 

 

    • 节区头

    节区头由IMAGE_SECTION_HEADER结构体组成的数组,有多少个节区就有多少个结构体。并且在节区中有这样的规定:把代码(code),数据(data)和资源(resourse)分类存储在不同的节区里。

    

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

 

VirtualSize  :内存中节区所占大小。

VirtualAddress  :内存中节区起始地址(RVA)。

SizeOfRawData:磁盘文件中节区所占大小。

PointerToRawData:磁盘文件中节区起始位置。

characteristics:节区属性。

 1 //
 2 // Section characteristics.
 3 //
 4 //      IMAGE_SCN_TYPE_REG                   0x00000000  // Reserved.
 5 //      IMAGE_SCN_TYPE_DSECT                 0x00000001  // Reserved.
 6 //      IMAGE_SCN_TYPE_NOLOAD                0x00000002  // Reserved.
 7 //      IMAGE_SCN_TYPE_GROUP                 0x00000004  // Reserved.
 8 #define IMAGE_SCN_TYPE_NO_PAD                0x00000008  // Reserved.
 9 //      IMAGE_SCN_TYPE_COPY                  0x00000010  // Reserved.
10 
11 #define IMAGE_SCN_CNT_CODE                   0x00000020  // Section contains code.
12 #define IMAGE_SCN_CNT_INITIALIZED_DATA       0x00000040  // Section contains initialized data.
13 #define IMAGE_SCN_CNT_UNINITIALIZED_DATA     0x00000080  // Section contains uninitialized data.
14 
15 #define IMAGE_SCN_LNK_OTHER                  0x00000100  // Reserved.
16 #define IMAGE_SCN_LNK_INFO                   0x00000200  // Section contains comments or some other type of information.
17 //      IMAGE_SCN_TYPE_OVER                  0x00000400  // Reserved.
18 #define IMAGE_SCN_LNK_REMOVE                 0x00000800  // Section contents will not become part of image.
19 #define IMAGE_SCN_LNK_COMDAT                 0x00001000  // Section contents comdat.
20 //                                           0x00002000  // Reserved.
21 //      IMAGE_SCN_MEM_PROTECTED - Obsolete   0x00004000
22 #define IMAGE_SCN_NO_DEFER_SPEC_EXC          0x00004000  // Reset speculative exceptions handling bits in the TLB entries for this section.
23 #define IMAGE_SCN_GPREL                      0x00008000  // Section content can be accessed relative to GP
24 #define IMAGE_SCN_MEM_FARDATA                0x00008000
25 //      IMAGE_SCN_MEM_SYSHEAP  - Obsolete    0x00010000
26 #define IMAGE_SCN_MEM_PURGEABLE              0x00020000
27 #define IMAGE_SCN_MEM_16BIT                  0x00020000
28 #define IMAGE_SCN_MEM_LOCKED                 0x00040000
29 #define IMAGE_SCN_MEM_PRELOAD                0x00080000
30 
31 #define IMAGE_SCN_ALIGN_1BYTES               0x00100000  //
32 #define IMAGE_SCN_ALIGN_2BYTES               0x00200000  //
33 #define IMAGE_SCN_ALIGN_4BYTES               0x00300000  //
34 #define IMAGE_SCN_ALIGN_8BYTES               0x00400000  //
35 #define IMAGE_SCN_ALIGN_16BYTES              0x00500000  // Default alignment if no others are specified.
36 #define IMAGE_SCN_ALIGN_32BYTES              0x00600000  //
37 #define IMAGE_SCN_ALIGN_64BYTES              0x00700000  //
38 #define IMAGE_SCN_ALIGN_128BYTES             0x00800000  //
39 #define IMAGE_SCN_ALIGN_256BYTES             0x00900000  //
40 #define IMAGE_SCN_ALIGN_512BYTES             0x00A00000  //
41 #define IMAGE_SCN_ALIGN_1024BYTES            0x00B00000  //
42 #define IMAGE_SCN_ALIGN_2048BYTES            0x00C00000  //
43 #define IMAGE_SCN_ALIGN_4096BYTES            0x00D00000  //
44 #define IMAGE_SCN_ALIGN_8192BYTES            0x00E00000  //
45 // Unused                                    0x00F00000
46 
47 #define IMAGE_SCN_LNK_NRELOC_OVFL            0x01000000  // Section contains extended relocations.
48 #define IMAGE_SCN_MEM_DISCARDABLE            0x02000000  // Section can be discarded.
49 #define IMAGE_SCN_MEM_NOT_CACHED             0x04000000  // Section is not cachable.
50 #define IMAGE_SCN_MEM_NOT_PAGED              0x08000000  // Section is not pageable.
51 #define IMAGE_SCN_MEM_SHARED                 0x10000000  // Section is shareable.
52 #define IMAGE_SCN_MEM_EXECUTE                0x20000000  // Section is executable.
53 #define IMAGE_SCN_MEM_READ                   0x40000000  // Section is readable.
54 #define IMAGE_SCN_MEM_WRITE                  0x80000000  // Section is writeable.

 

接下来以notepad.exe的节区为例做分析:

1 0001F0        2E746578 74000000    Name(.text)
2 0001F8        0001AE2C           Misc.VirtualSize
3 0001FC        00001000           VirtualAddress
4 000200        0001B000            SizeOfRawData
5 000204        00000400           PointerToRawData
6 000214        60000020           Characteristics:
                                     IMAGE_SCN_MEM_EXECUTE
                                     IMAGE_SCN_MEM_READ
                                     IMAGE_SCN_CNT_CODE

由于.text是第一块节区,因此VirtualAddress和PointerToRawData是不带任何值的(是由IMAGE_OPTIONAL_HEADER32中)SectionAlignment和FileAlignment确定的。

 

 

因为文件从磁盘中载入到内存中,因为载入点不同,会引起地址的变化,在磁盘中的相对位置称为RAW,在内存中的相对地址是RVA,在内存中的绝对地址是VA。这三者的对应转换关系如下:

    VA  =  ImageBase  +  RVA

   RAW  =  RVA -  VirtualAddress  +  PointerToRawData

比如说,现在有一段数据,RVA = 7000 ,查节区,发现第一节区为1B000(SizeOfRawData可知)> 7000 ,说明这个数据段在第一节区,再将7000减去1000(内存中节区的起始地址),加上400(文件中节区的起始地址),就得到该数据段在文件中的位置。

以上的地址转换称为:RVA to RAW,极为重要!!

 

 

好了,本篇文章的内容主要是讲解PE文件和其重要的PE头结构,以及重要的地址转换公式,在(二)中将继续讲解PE头的核心内容IAT(Import Address Table)。

欢迎读者讨论,批评与指正!

 

转载于:https://www.cnblogs.com/re-and-er/p/PE1.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值