pe结构分析

为什么要手工打造PE文件?        
我们知道,往往从一个系统可执行文件结构上,就可以看整个操作系统的一些特性。也就是说PE里有Windows操作系统结构与运行机理的影子。由此可见,PE文件必然是一个非常庞杂且逻辑复杂的结构,那么为什么我们还要“自取其辱”来手工制造一个PE文件呢?这就要从PE文件的重要性说起了。

         我们现今组成Windows大家庭的主要成员就是PE文件了,里面包括EXE、DLL、OCX、SYS等一切最有价值的文件都是PE文件格式,易语言包括了EXE、DLL。
        特别是对于想学习加壳、解壳、编译、预处理、汇编、搞虚拟机的朋友们来说,熟知PE文件结构更是必不可少的基本功!
        但也正是由于PE文件的复杂性,我们才要采取一些特别的办法来攻克它,其中手工打造PE文件就是一条捷径。
        你可以想像一下,如果你都可以手工打造PE文件的话,那么对于PE文件的了解更是可见一斑了。我们可以利用所得的知识结合易语言让开发更有趣。
今天在这里运用所得的知识详细的写出了PE的生产过程,可以很好的了解PE。
一、整体性息
    这部分以图表的形式表示PE文件的整体结构。
————-*————————————————-*
                 | DOS Header(IMAGE_DOS_HEADER) | –>64 Byte
DOS头部  ————————————————–
                 | DOS Stub                                                   | –>112 Byte
————-*————————————————-*
                 | “PE”00 (Signature)                                   | –>4 Byte
                  ————————————————-
                 | IMAGE_FILE_HEADER                          | –>20 Byte
PE文件头 ————————————————–
                 | IMAGE_OPTIONAL_HEADER32          | –>96 Byte
                 —————————————————
                 | 数据目录表                                                | –>128 Byte
————-*————————————————–*
                 | IMAGE_SECTION_HEADER                 | –>40 Byte
                 —————————————————
   块表      | IMAGE_SECTION_HEADER                 | –>40 Byte
                  ————————————————–
                 | IMAGE_SECTION_HEADER                 | –>40 Byte  
————-*————————————————–*
                 |.text                                                              | –>512 Byte
                 —————————————————
    块         |.rdata                                                           | –>512 Byte
                 —————————————————
                 |.data                                                            | –>512 Byte
————-*————————————————-*
                 | COFF行号                                                 | –>NULL
                 —————————————————
调试信息 | COFF符号表                                             | –>NULL
                 —————————————————
                 | Code View 调试信息                               | –>NULL
————-*————————————————–*
1、对于PE文件有一个整体的认识。
2、方便审查自己的构造进度。
       这里我们重点介绍怎样用其审查自己的构造进度,首先希望各位读者明白我们将要手工构造的一个体积为2560字节的这个小家伙,对于初次上手的读者们来说并不是一件小的工程,因此有必要知道自己现在正做什么,以及做到哪里了。


       那好,我们先搞明白第一个问题“我们的文件体积是怎么计算出来的呢”。
       首先我们要知道,PE文件自始至终都是以一种节的思想来构造的,那么我们就要从节开始。
       对于本文所讲述的PE文件来讲总共有三个区块(节),他们分别用来存放可执行代码、输入表信息以及全局变量,接触过PE文件的朋友对于区块的概念应该不陌生,我们知道Windows下的很多应用程序的文件对齐粒度,也就是大名鼎鼎的FileAlignment字段的值多为200h Byte,也就是十进制的512 Byte。我们同样应该知道,对于不足512字节的区段,余下部分要用00h填充到512字节大小,对与超过部分(例如513字节的区段)我们就要在多分配给他512字节个空间。
       当然,这些基础知识我想有一部分读者应该比较熟悉,那么对于PE文件头部分呢?也是如此吗?例如本例中的PE头就占用了544个字节,但是很显然这要使其填充到1024(400h)字节处才能开始第一个区段.text段。
       正是如此,我们整个文件的体积就是PE头+3个区段的体积之和,也就是PE头(512*2)+3个区段(512*3)=2560,这也就是我们所构造的PE文件的最终大小了。
       其次我们提前搞清楚一些字段与区段的偏移量也是比较重要的,这里对于计算方式不再多说,请大家直接看下面的表:
1、PE头开始处 000000B0h
2、IMAGE_OPTIONAL_HEADER32开始处 000000C8h
3、数据目录表开始处 00000128h
4、块表开始处 000001A8h
5、.text块开始处 00000400h
6、.rdata块开始处 00000600h
7、.data块开始处 00000800h

二、重点字段
这里只对需手工构造的字段进行着重介绍,详细的PE文件结构字段请见第三部分。
1、DOS头部
1-1  DOS Header
1-1-1   e_magic  [WORD]  –>4D 5A (* DOS可执行文件头标记)
注释:此处值总是为MZ的16进制码。
1-1-19  e_lfanew  [DWORD]  –>B0 00 00 00 (* 指向PE文件头的偏移量。0xB0=64+112)
注释:此处的值正好为为DOS头部的大小,因为DOS头部后面就是PE文件头部分了。
2  PE文件头
2-1  “PE”00
2-1-1  Signature  [DWORD] –>50450000h (* PE文件头标记)
注释:此处的值总是为PE的16进制值加0000h。
2-2  IMAGE_FILE_HEADER
2-2-1  Machine  [WORD]  –>4C 01 (* 可执行文件的目标CPU类型)
注释:此PE文件可以运行于哪个CPU下,其标志就为相应的值。
*——————————*
|     机器            |  标志   |
——————————-
| Intel i386         | 14Ch   |
——————————-
| MIPS R3000    | 162h   |
——————————-
| MIPS R4000    | 166h   |
——————————-
| Alpha AXP       | 184h   |
——————————-
| Power PC        | 1F0h   |
*—————————–*
2-2-2  NumberOfSections  [WORD]  –>03 00 (* 区块数目)
注释:此值决定此PE文件的区块数目,本文件为3个区块。
2-2-6  SizeOfOptionalHeadr  [WORD]  –>E0 00 (* PE头(IMAGE_OPTIONAL_HEADER32)大小)
注释:此值表示PE文件头的大小。
2-2-7  Characteristics  [WORD]  –>0F 01 (* 文件属性)
注释:此值为文件的执行属性。EXE文件此值一般为010Fh,DLL文件此值一般为0210h。
2-3  IMAGE_OPTIONAL_HEADER32
2-3-1   Magic  [WORD]  –>0B 01 (* 标记字)
注释:此处是一个标记字,用于描述次PE文件的映像类型。ROM映像为0107h;普通可执行映像010Bh;PE32+则是020Bh。
2-3-7   AddressOfEntryPoint  [DWORD] –>00 10 00 00 (* 程序执行入口RAV)
注释:通俗的说就是指向可执行代码区块(例如.text)的首地址。
2-3-10  ImageBase  [DWORD] –>00 00 40 00 (* 程序默认装入基地址)
注释:是指文件在内存中首选的装入地址。
2-3-11  SectionAlignment  [DWORD] –>00 10 00 00 (* 内存中区块对齐值)
注释:PE文件被装入内存中时的块对齐大小,也叫做块粒度。其默认的对其尺寸是CPU的页尺寸。
2-3-12  FileAlignment  [DWORD] –>00 02 00 00 (* 文件中区块对齐值)
注释:磁盘上PE文件的区块对齐大小。这个值必须是2的幂,并且最小为200h。
2-3-17  MajorSubsystemVersion  [WORD]  –>04 00 (* 运行所需最低子系统主版本号)
注释:要求最低的子系统主版本号,一般情况下都为4。
2-3-18  MinorSubsystemVersion  [WORD]  –>00 00 (* 运行所需最低子系统次版本号)
注释:要求最低的子系统次版本号,一般情况下都为0。
2-3-20  SizeOfImage  [DWORD] –>00 40 00 00 (* 映像装入内存后的总尺寸)
注释:指的是装入文件从Image Base到最后一个区块的总大小。
2-3-21  SizeOfHeaders  [DWORD] –>00 04 00 00 (* DOS头、PE头、区块表的总大小)
注释:指的是DOS头、PE头与区块表的总大小,并且所有这些项目都出现在PE文件中任何代码或数据块之前。此值遵守文件对齐粒度。
2-3-23  Subsystem [WORD]  –>03 00 (* 文件子系统)
注释:标明可执行文件所期望的子系统(用户界面类型)。
*—-*————————————-*
| 值 |          子系统                          |
*—-*————————————-*
| 0  | 未知                                        |
——————————————–
| 1  | 不需要子系统(如驱动程序) |
———————————————
| 2  | 图形接口子系统(GUI)          |
———————————————
| 3  | 字符子系统(CUI)                 |
———————————————
| 5  | OS/2字符子系统                      |
———————————————
| 7  | POSIX字符子系统                    |
———————————————
| 8  | 保留                                         |
———————————————
| 9  | Windows CE图形界面              |
*—-*————————————–*
2-3-30  NumberOfRvaAndSizes  [DWORD] –>10 00 00 00 (* 数据目录标的项数,默认总为16)
注释:数据目录的项数。这个字段字NT系统发布以来就一直是16。
  2-4  数据目录表
2-4-2   Import Table
注释:输入表
2-4-2-1  VirtualAddress [DWORD] –>10 20 00 00 (* 数据块的起始RAV)
注释:输入表的起始地址,要去除IAT所占空间,直接从第一个IID开始。
2-4-2-2  Size  [DWORD] –>3C 00 00 00 (* 数据块的长度)
注释:从第一个IID到最后一个IMAGE_IMPORT_BY_NAME的总长度。
3  块表
3-1  IMAGE_SECTION_HEADER (1 .text)
3-1-1   Name  [BYTE]  –>2E 74 65 78 74 00 00 00 (* 8个字节的块名)
注释:此区块的名称,限制在8字节以内。
3-1-2   VirtualSize  [DWORD] –>26 00 00 00 (* 被实际使用的区块大小)
注释:此区块包含数据的大小。
3-1-10  Characteristics  [DWORD] –>20 00 00 60 (* 该区块的读写、执行属性)
注释:
*—————————————————————-*
|  字段值   |              用 途                                         |
—————————————————————–
| 00000020h | 包含代码,常与10000000h一起设置 |
—————————————————————–
| 00000040h | 包含已初始化数据                              |
—————————————————————–
| 00000080h | 包含未初始化数据                              |
—————————————————————–
| 02000000h | 可以被丢弃                                         |
—————————————————————–
| 10000000h | 共享块                                                |
—————————————————————–
| 20000000h | 可执行                                                |
—————————————————————–
| 40000000h | 可读                                                   |
—————————————————————–
| 80000000h | 可写                                                   |
—————————————————————–
4  块
4-1  .text (* 此区段是一段汇编代码的16进制形式,功能是弹出一个MessageBox提示框)
–>HEX
6A 00 68 00 30 40 00 68  07 30 40 00 6A 00 E8 07
00 00 00 6A 00 E8 06 00  00 00 FF 25 08 20 40 00
FF 25 00 20 40 00
注释:这是下面汇编指令的16进制模式。
–>ASM
00401000  6A 00         PUSH 0
00401002  68 00304000   PUSH first_PE.00403000
00401007  68 07304000   PUSH first_PE.00403007
0040100C  6A 00         PUSH 0
0040100E  E8 07000000   CALL <JMP.&user32.MessageBoxA>
00401013  6A 00         PUSH 0
00401015  E8 06000000   CALL <JMP.&kernel32.ExitProcess>
0040101A  FF25 08204000 JMP DWORD PTR DS:[<&user32.MessageBoxA>]
00401020  FF25 00204000 JMP DWORD PTR DS:[<&kernel32.ExitProcess>]
4-2  .rdata (* 该区块包含输入表)
4-2-1  IMAGE_THUNK_DATA32 (IAT 1)
注释:这里有很多人都搞不明白,其实IMAGE_THUNK_DATA32是一个联合体,可以同时代表IAT与INT。
4-2-1-1 AddressOfData [DWORD] –>76 20 00 00 (* 指向IMAGE_IMPORT_BY_NAME的RVA)
注释:作为IAT时我们就会使用他的AddressOfData成员,用来存放指向IMAGE_IMPORT_BY_NAME的RVA,当程序装入内存后,只与IAT交换信息,输入表的其他部分就不再需要了。
由于本例子两个API函数引自与两个不同的DLL文件,所以要补00000000h结束。
注释:这里同样有很多人不明白,每当属于某一个DLL文件的API罗列完毕后,就要输入00加以结束。
4-2-3  IMAGE_IMPORT_DESCRIPTOR (IID 1)
注释:这里稍微复杂些,它的作用就是使用INT指定某个DLL文件中的API函数,并配合IAT指向相关API的地址。
4-2-3-1 OriginalFirstThunk [DWORD] –>4C 20 00 00 (* 指向输入名称表INT的RVA)
注释:这里指定某个系统DLL文件中的API函数。
4-2-3-4 Name  [DWORD] –>6A 20 00 00 (* 指向DLL名字的RVA与指针)
注释:这里指定某个系统DLL文件。
4-2-3-5 FirstThunk  [DWORD] –>08 20 00 00 (* 指向输入地址表IAT的RVA)
注释:这里指定相关的IAT,并由IAT在IMAGE_IMPORT_BY_NAME中获得相应API的地址。
4-2-4  IMAGE_IMPORT_DESCRIPTOR (IID 2)
4-2-4-1 OriginalFirstThunk [DWORD] –>54 20 00 00 (* 指向输入名称表INT的RVA)
4-2-4-4 Name               [DWORD] –>84 20 00 00 (* 指向DLL名字的RVA与指针)
4-2-4-5 FirstThunk         [DWORD] –>00 20 00 00 (* 指向输入地址表IAT的RVA)
填充20个00h空字节做结尾标记
注释:关于填充20个字节作为IID的结尾标记只是一个规律,还没找到相关资料证实。
4-2-5  IMAGE_THUNK_DATA32 (INT 1)
4-2-5-1  ForwarderString [DWORD] –>5C 20 00 00 (* 指向一个转向字符的RVA)
注释:直接指向相关API函数。
由于本例子两个API函数引自与两个不同的DLL文件,所以要补00000000h结束。
注释:与上面的IAT原理一样,就是这样的一个格式。
4-2-7  IMAGE_IMPORT_BY_NAME ( 1 )
4-2-7-2  Name [BYTE] –>4D 65 73 73 61 67 65 42 6F 78 41 (* MessageBoxA的16进制码)
注释:相关API函数的16进制代码。
后跟输出此函数的DLL名称16进制码00 75 73 65 72 33 32 2E 64 6C 6C 00 00 user32.dll
注释:相关系统的API函数罗列完毕后,通常都在最后一个API后空00h,并跟着这个DLL名称的16进制数据。
总结:这里罗列了一些需要手工构建的部分结构,如果想看更加详细的请关注下面的内容。

三、PE文件结构字段列表
1  DOS头部
1-1  DOS Header
1-1-1   e_magic     [WORD]            –>4D 5A (* DOS可执行文件头标记)
1-1-2   e_cblp        [WORD]              ->00 00 (文件最后页的字节数)
1-1-3   e_cp           [WORD]              ->00 00 (文件页数)
1-1-4   e_crlc         [WORD]               ->00 00 (重定位元素个数)
1-1-5   e_cparhdr  [WORD]               ->00 00 (以段落为单位的头部大小)
1-1-6   e_minalloc  [WORD]              ->00 00 (所需的最小附加段)
1-1-7   e_maxalloc [WORD]               ->00 00 (所需的最大附加段)
1-1-8   e_ss           [WORD]              ->00 00 (初始的堆栈段(SS)相对偏移量值)
1-1-9   e_sp           [WORD]              ->00 00 (初始的堆栈指针(SP)值)
1-1-10  e_csum     [WORD]               ->00 00 (校验和)
1-1-11  e_ip           [WORD]               ->00 00 (初始的指令指针(IP)值)
1-1-12  e_cs          [WORD]               ->00 00 (初始的代码段(CS)相对偏移量值)
1-1-13  e_lfarlc      [WORD]               ->00 00 (重定位表在文件中的偏移地址)
1-1-14  e_ovno      [WORD]               ->00 00 (覆盖号)
1-1-15  e_res         [WORD] 4 dup     ->00 00 (保留字,一般都是为确保对齐而预留)
1-1-16  e_oemid     [WORD]              ->00 00 (OEM 标识符,相对于 e_oeminfo)
1-1-17  e_oeminfo  [WORD]              ->00 00 (OEM 信息,即 e_oemid 的细节)
1-1-18  e_res2       [WORD] 10 dup  ->00 00 (保留字,一般都是为确保对齐而预留)
1-1-19  e_lfanew    [DWORD]          –>B0 00 00 00 (* 指向PE文件头的偏移量。0xB0=64+112)
1-2  DOS Stub
全部填00h
2  PE文件头
2-1  “PE”00
2-1-1  Signature [DWORD] –>50450000h (* PE文件头标记)
2-2  IMAGE_FILE_HEADER
2-2-1  Machine                        [WORD]    –>4C 01 (* 可执行文件的目标CPU类型)
2-2-2  NumberOfSections        [WORD]    –>03 00 (* 区块数目)
2-2-3  TimeDateStamp            [DWORD]   ->00 00 00 00 (文件创建的时间与日期)
2-2-4  PointerToSymbolTable [DWORD]   ->00 00 00 00 (指向符号表,用于调试)
2-2-5  NumberOfSymbols        [DWORD]   ->00 00 00 00 (符号表中的符号个数,用于调试)
2-2-6  SizeOfOptionalHeadr    [WORD]    –>E0 00 (* PE头(IMAGE_OPTIONAL_HEADER32)大小)
2-2-7  Characteristics              [WORD]    –>0F 01 (* 文件属性)
2-3  IMAGE_OPTIONAL_HEADER32
2-3-1   Magic                                       [WORD]     –>0B 01 (* 标记字)
2-3-2   MajorLinkerVersion                  [BYTE]        ->00 (连接程序主版本号)
2-3-3   MinorLinkerVersion                  [BYTE]        ->00 (连接程序次版本号)
2-3-4   SizeOfCode                              [DWORD]   ->00 00 00 00 (所有含代码区块的总大小)
2-3-5   SizeOfInitializedData                 [DWORD]   ->00 00 00 00 (所有初始化数据区块大总大小)
2-3-6   SizeOfUninitializedData             [DWORD]   ->00 00 00 00 (所有未初始化数据区块大总大小)
2-3-7   AddressOfEntryPoint                [DWORD]  –>00 10 00 00 (* 程序执行入口RAV)
2-3-8   BaseOfCode                             [DWORD]   ->00 00 00 00 (代码区块起始RAV)
2-3-9   BaseOfData                              [DWORD]   ->00 00 00 00 (数据区块起始RAV)
2-3-10  ImageBase                               [DWORD]  –>00 00 40 00 (* 程序默认装入基地址)
2-3-11  SectionAlignment                      [DWORD]  –>00 10 00 00 (* 内存中区块对齐值)
2-3-12  FileAlignment                            [DWORD]  –>00 02 00 00 (* 文件中区块对齐值)
2-3-13  MajorOperatingSystemVersion [WORD]      ->00 00 (操作系统主版本号)
2-3-14  MinorOperatingSystemVersion [WORD]      ->00 00 (操作系统次版本号)
2-3-15  MajorImageVersion                   [WORD]      ->00 00 (用户自定义主版本号)
2-3-16  MinorImageVersion                   [WORD]      ->00 00 (用户自定义次版本号)
2-3-17  MajorSubsystemVersion           [WORD]     –>04 00 (* 运行所需最低子系统主版本号)
2-3-18  MinorSubsystemVersion           [WORD]     –>00 00 (* 运行所需最低子系统次版本号)
2-3-19  Win32VersionValue                  [DWORD]    ->00 00 00 00 (保留值,通常为0)
2-3-20  SizeOfImage                             [DWORD]   –>00 40 00 00 (* 映像装入内存后的总尺寸)
2-3-21  SizeOfHeaders                         [DWORD]   –>00 04 00 00 (* DOS头  PE头  区块表的总大小)
2-3-22  CheckSum                                [DWORD]    ->00 00 00 00 (映像效验和)
2-3-23  Subsystem                                [WORD]     –>03 00 (* 文件子系统)
2-3-24  DllCharacteristics                      [WORD]      ->00 00 (显示DLL特性的旗标)
2-3-25  SizeOfStackReserve                 [DWORD]    ->00 00 00 00 (初始化堆栈总大小)
2-3-26  SizeOfStackCommit                   [DWORD]   ->00 00 00 00 (初始化实际提交堆栈大小)
2-3-27  SizeOfHeapReserve                  [DWORD]   ->00 00 00 00 (初始化保留堆栈大小)
2-3-28  SizeOfHeapCommit                   [DWORD]   ->00 00 00 00 (初始化实际保留堆栈大小)
2-3-29  LoaderFlags                              [DWORD]  ->00 00 00 00 (与调试相关,默认值为0)
2-3-30  NumberOfRvaAndSizes             [DWORD] –>10 00 00 00 (* 数据目录标的项数,默认总为16)
  2-4  数据目录表
2-4-1   Export Table
2-4-1-1   VirtualAddress [DWORD]  ->00 00 00 00 (数据块的起始RAV)
2-4-1-2   Size                  [DWORD]  ->00 00 00 00 (数据块的长度)
2-4-2   Import Table
2-4-2-1   VirtualAddress [DWORD] –>10 20 00 00 (* 数据块的起始RAV)
2-4-2-2   Size                 [DWORD] –>3C 00 00 00 (* 数据块的长度)
2-4-3   Resources Table
2-4-3-1   VirtualAddress [DWORD]  ->00 00 00 00 (数据块的起始RAV)
2-4-3-2   Size                 [DWORD]  ->00 00 00 00 (数据块的长度)
2-4-4   Exception Table
2-4-4-1   VirtualAddress [DWORD]  ->00 00 00 00 (数据块的起始RAV)
2-4-4-2   Size                  [DWORD]  ->00 00 00 00 (数据块的长度)
2-4-5   Security Table
2-4-5-1   VirtualAddress [DWORD]  ->00 00 00 00 (数据块的起始RAV)
2-4-5-2   Size                  [DWORD]  ->00 00 00 00 (数据块的长度)
2-4-6   Base relocation Table
2-4-6-1   VirtualAddress [DWORD]  ->00 00 00 00 (数据块的起始RAV)
2-4-6-2   Size                 [DWORD]  ->00 00 00 00 (数据块的长度)
2-4-7   Debug
2-4-7-1   VirtualAddress [DWORD]  ->00 00 00 00 (数据块的起始RAV)
2-4-7-2   Size                  [DWORD]  ->00 00 00 00 (数据块的长度)
2-4-8   Copyright
2-4-8-1   VirtualAddress [DWORD]  ->00 00 00 00 (数据块的起始RAV)
2-4-8-2   Size                  [DWORD]  ->00 00 00 00 (数据块的长度)
2-4-9   Global ptr
2-4-9-1   VirtualAddress [DWORD]  ->00 00 00 00 (数据块的起始RAV)
2-4-9-2   Size                  [DWORD]  ->00 00 00 00 (数据块的长度)
2-4-10  Threda local storage(TLS)
2-4-10-1  VirtualAddress [DWORD]  ->00 00 00 00 (数据块的起始RAV)
2-4-10-2  Size                  [DWORD]  ->00 00 00 00 (数据块的长度)
2-4-11  Load configuration
2-4-11-1  VirtualAddress [DWORD]  ->00 00 00 00 (数据块的起始RAV)
2-4-11-2  Size                  [DWORD]  ->00 00 00 00 (数据块的长度)
2-4-12  Bound import
2-4-12-1  VirtualAddress [DWORD]  ->00 00 00 00 (数据块的起始RAV)
2-4-12-2  Size                  [DWORD]  ->00 00 00 00 (数据块的长度)
2-4-13  Import Address Table(IAT)
2-4-13-1  VirtualAddress [DWORD]  ->00 00 00 00 (数据块的起始RAV)
2-4-13-2  Size                  [DWORD]  ->00 00 00 00 (数据块的长度)
2-4-14  Delay import
2-4-14-1  VirtualAddress [DWORD]  ->00 00 00 00 (数据块的起始RAV)
2-4-14-2  Size                  [DWORD]  ->00 00 00 00 (数据块的长度)
2-4-15  COM descriptor
2-4-15-1  VirtualAddress [DWORD]  ->00 00 00 00 (数据块的起始RAV)
2-4-15-2  Size                 [DWORD]  ->00 00 00 00 (数据块的长度)
2-4-16  保留
2-4-16-1  VirtualAddress [DWORD]  ->00 00 00 00 (数据块的起始RAV)
2-4-16-2  Size                  [DWORD]  ->00 00 00 00 (数据块的长度)
3  块表
3-1  IMAGE_SECTION_HEADER (1 .text)
3-1-1   Name                            [BYTE]       –>2E 74 65 78 74 00 00 00 (* 8个字节的块名)
3-1-2   VirtualSize                     [DWORD]  –>26 00 00 00 (* 被实际使用的区块大小)
3-1-3   VirtualAddress              [DWORD]  –>00 10 00 00 (* 区块的RAV地址)
3-1-4   SizeOfRawData             [DWORD]  –>00 02 00 00 (* 该块在磁盘中所占的大小)
3-1-5   PointerToRawData        [DWORD]  –>00 04 00 00 (* 该块在磁盘文件中的偏移)
3-1-6   PointerToRelocations    [DWORD]   ->00 00 00 00 (在OBJ文件中使用,重定位偏移)
3-1-7   PointerToLinenumbers  [DWORD]   ->00 00 00 00 (行号表的偏移,调试中使用)
3-1-8   NumberOfRelocations    [WORD]     ->00 00 (在OBJ文件中使用,重定位项数目)
3-1-9   NumberOfLinenumbers  [WORD]     ->00 00 (行号表中行号的数目)
3-1-10  Characteristics              [DWORD] –>20 00 00 60 (* 该区块的读写  执行属性)
3-2  IMAGE_SECTION_HEADER (2 .rdata)
3-2-1   Name                            [BYTE]     –>2E 72 64 61 74 61 00 00 (* 8个字节的块名)
3-2-2   VirtualSize                    [DWORD] –>92 00 00 00 (* 被实际使用的区块大小)
3-2-3   VirtualAddress              [DWORD] –>00 20 00 00 (* 区块的RAV地址)
3-2-4   SizeOfRawData             [DWORD] –>00 02 00 00 (* 该块在磁盘中所占的大小)
3-2-5   PointerToRawData        [DWORD] –>00 06 00 00 (* 该块在磁盘文件中的偏移)
3-2-6   PointerToRelocations   [DWORD]   ->00 00 00 00 (在OBJ文件中使用,重定位偏移)
3-2-7   PointerToLinenumbers  [DWORD]  ->00 00 00 00 (行号表的偏移,调试中使用)
3-2-8   NumberOfRelocations    [WORD]    ->00 00 (在OBJ文件中使用,重定位项数目)
3-2-9   NumberOfLinenumbers  [WORD]    ->00 00 (行号表中行号的数目)
3-2-10  Characteristics              [DWORD] –>40 00 00 40 (* 该区块的读写  执行属性)
3-3  IMAGE_SECTION_HEADER (3 .data)
3-3-1   Name                             [BYTE]      –>2E 64 61 74 61 00 00 00 (* 8个字节的块名)
3-3-2   VirtualSize                     [DWORD]  –>3E 00 00 00 (* 被实际使用的区块大小)
3-3-3   VirtualAddress               [DWORD]  –>00 30 00 00 (* 区块的RAV地址)
3-3-4   SizeOfRawData             [DWORD]  –>00 02 00 00 (* 该块在磁盘中所占的大小)
3-3-5   PointerToRawData        [DWORD]  –>00 08 00 00 (* 该块在磁盘文件中的偏移)
3-3-6   PointerToRelocations    [DWORD]   ->00 00 00 00 (在OBJ文件中使用,重定位偏移)
3-3-7   PointerToLinenumbers  [DWORD]   ->00 00 00 00 (行号表的偏移,调试中使用)
3-3-8   NumberOfRelocations    [WORD]     ->00 00 (在OBJ文件中使用,重定位项数目)
3-3-9   NumberOfLinenumbers  [WORD]     ->00 00 (行号表中行号的数目)
3-3-10  Characteristics              [DWORD] –>40 00 00 C0 (* 该区块的读写、执行属性)
由于FileAlignment为0x200大小,而此时整个PE头已经超过200,所以要填0到0x400处
4  块
4-1  .text (* 此区段是一段汇编代码的16进制形式,功能是弹出一个MessageBox提示框)
–>HEX
6A 00 68 00 30 40 00 68  07 30 40 00 6A 00 E8 07
00 00 00 6A 00 E8 06 00  00 00 FF 25 08 20 40 00
FF 25 00 20 40 00
–>ASM
00401000  6A 00         PUSH 0
00401002  68 00304000   PUSH first_PE.00403000
00401007  68 07304000   PUSH first_PE.00403007
0040100C  6A 00         PUSH 0
0040100E  E8 07000000   CALL <JMP.&user32.MessageBoxA>
00401013  6A 00         PUSH 0
00401015  E8 06000000   CALL <JMP.&kernel32.ExitProcess>
0040101A  FF25 08204000 JMP DWORD PTR DS:[<&user32.MessageBoxA>]
00401020  FF25 00204000 JMP DWORD PTR DS:[<&kernel32.ExitProcess>]
由于FileAlignment为0x200大小,而此时整个PE头未超过200,所以要填0到0x600处
4-2  .rdata (* 该区块包含输入表)
4-2-1  IMAGE_THUNK_DATA32 (IAT 1)
4-2-1-1 AddressOfData [DWORD] –>76 20 00 00 (* 指向IMAGE_IMPORT_BY_NAME的RVA)
由于本例子两个API函数引自与两个不同的DLL文件,所以要补00000000h结束。
4-2-2  IMAGE_THUNK_DATA32 (IAT 2)
4-2-1-2 AddressOfData [DWORD] –>5C 20 00 00 (* 指向IMAGE_IMPORT_BY_NAME的RVA)
由于本例子两个API函数引自与两个不同的DLL文件,所以要补00000000h结束。
4-2-3  IMAGE_IMPORT_DESCRIPTOR (IID 1)
4-2-3-1 OriginalFirstThunk  [DWORD] –>4C 20 00 00 (* 指向输入名称表INT的RVA)
4-2-3-2 TimeDateStamp      [DWORD]  ->00 00 00 00 (32位的时间标志)
4-2-3-3 ForwarderChain      [DWORD]  ->00 00 00 00 (被转向API的索引)
4-2-3-4 Name                      [DWORD] –>6A 20 00 00 (* 指向DLL名字的RVA与指针)
4-2-3-5 FirstThunk              [DWORD] –>08 20 00 00 (* 指向输入地址表IAT的RVA)
4-2-4  IMAGE_IMPORT_DESCRIPTOR (IID 2)
4-2-4-1 OriginalFirstThunk  [DWORD] –>54 20 00 00 (* 指向输入名称表INT的RVA)
4-2-4-2 TimeDateStamp      [DWORD]  ->00 00 00 00 (32位的时间标志)
4-2-4-3 ForwarderChain      [DWORD]  ->00 00 00 00 (被转向API的索引)
4-2-4-4 Name                      [DWORD] –>84 20 00 00 (* 指向DLL名字的RVA与指针)
4-2-4-5 FirstThunk              [DWORD] –>00 20 00 00 (* 指向输入地址表IAT的RVA)
填充20个00h空字节做结尾标记
4-2-5  IMAGE_THUNK_DATA32 (INT 1)
4-2-5-1  ForwarderString [DWORD] –>5C 20 00 00 (* 指向一个转向字符的RVA)
由于本例子两个API函数引自与两个不同的DLL文件,所以要补00000000h结束。
4-2-6  IMAGE_THUNK_DATA32 (INT 2)
4-2-6-1  ForwarderString [DWORD] –>76 20 00 00 (* 指向一个转向字符的RVA)
由于本例子两个API函数引自与两个不同的DLL文件,所以要补00000000h结束。
4-2-7  IMAGE_IMPORT_BY_NAME ( 1 )
4-2-7-1  Hint    [WORD] –>00 00 (* 此函数所驻留DLL的输出表序号)
4-2-7-2  Name [BYTE]   –>4D 65 73 73 61 67 65 42 6F 78 41 (* MessageBoxA的16进制码)
后跟输出此函数的DLL名称16进制码00 75 73 65 72 33 32 2E 64 6C 6C 00 00 user32.dll
4-2-8  IMAGE_IMPORT_BY_NAME ( 2 )
4-2-8-1  Hint    [WORD] –>00 00h  (* 此函数所驻留DLL的输出表序号)
4-2-8-2  Name [BYTE]   –>45 78 69 74 50 72 6F 63 65 73 73 (* ExitProcess的16进制码)
后跟输出此函数的DLL名称16进制码00 6B 65 72 6E 65 6C 33 32 2E 64 6C 6C 00 00 kernel32.dll
由于FileAlignment为0x200大小,而此时整个PE头未超过200,所以要填0到0x800处
4-3  .data       填充数据(字符串) NULL结尾

点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据