PE文件格式分析基础实战

举报
yd_281320545 发表于 2022/11/23 21:38:32 2022/11/23
【摘要】 本篇文章是在对PE文件格式有了一定了解的基础上,对最简单的PE文件进行分析,以此巩固和验证前面学到的知识。借助python的pefile包简化分析实验。其中分析的PE文件是由print(“hello world”);在Devcpp下编译生成的可执行文件。代码如下#include <stdio.h>int main(){ printf("hello world"); return 0;}首先放...

本篇文章是在对PE文件格式有了一定了解的基础上,对最简单的PE文件进行分析,以此巩固和验证前面学到的知识。借助python的pefile包简化分析实验。其中分析的PE文件是由print(“hello world”);在Devcpp下编译生成的可执行文件。代码如下

#include <stdio.h>
int main(){
	printf("hello world");
	return 0;
}

首先放上文章结尾处的PE文件结构结论图示
请添加图片描述

安装pefile包

pip install pefile

读取pe文件基本信息

import pefile
import os
import string
import shutil# 文件和文件集合的高级操作

pefile_path = "a.exe"
pe = pefile.PE(pefile_path)
print(pe)

DOS头

----------DOS_HEADER----------

[IMAGE_DOS_HEADER]
0x0        0x0   e_magic:                       0x5A4D    
0x2        0x2   e_cblp:                        0x90      
0x4        0x4   e_cp:                          0x3       
0x6        0x6   e_crlc:                        0x0       
0x8        0x8   e_cparhdr:                     0x4       
0xA        0xA   e_minalloc:                    0x0       
0xC        0xC   e_maxalloc:                    0xFFFF    
0xE        0xE   e_ss:                          0x0       
0x10       0x10  e_sp:                          0xB8      
0x12       0x12  e_csum:                        0x0       
0x14       0x14  e_ip:                          0x0       
0x16       0x16  e_cs:                          0x0       
0x18       0x18  e_lfarlc:                      0x40      
0x1A       0x1A  e_ovno:                        0x0       
0x1C       0x1C  e_res:                         
0x24       0x24  e_oemid:                       0x0       
0x26       0x26  e_oeminfo:                     0x0       
0x28       0x28  e_res2:                        
0x3C       0x3C  e_lfanew:                      0x80      

e_lfanew的值就是NT头(也叫PE头),指向0x80,所以NT头的文件偏移(Offset)就是0x80。从下面的NT头起始地址得以验证。

NT头

----------NT_HEADERS----------

[IMAGE_NT_HEADERS]
0x80       0x0   Signature:                     0x4550    

----------FILE_HEADER----------

[IMAGE_FILE_HEADER]
0x84       0x0   Machine:                       0x8664    
0x86       0x2   NumberOfSections:              0x11      
0x88       0x4   TimeDateStamp:                 0x61CD19BA [Thu Dec 30 02:30:18 2021 UTC]
0x8C       0x8   PointerToSymbolTable:          0x18000   
0x90       0xC   NumberOfSymbols:               0x5B8     
0x94       0x10  SizeOfOptionalHeader:          0xF0      
0x96       0x12  Characteristics:               0x27      
Flags: IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_LARGE_ADDRESS_AWARE, IMAGE_FILE_LINE_NUMS_STRIPPED, IMAGE_FILE_RELOCS_STRIPPED

----------OPTIONAL_HEADER----------

[IMAGE_OPTIONAL_HEADER64]
0x98       0x0   Magic:                         0x20B     
0x9A       0x2   MajorLinkerVersion:            0x2       
0x9B       0x3   MinorLinkerVersion:            0x18      
0x9C       0x4   SizeOfCode:                    0x1E00    
0xA0       0x8   SizeOfInitializedData:         0x1C00    
0xA4       0xC   SizeOfUninitializedData:       0xC00     
0xA8       0x10  AddressOfEntryPoint:           0x1500    
0xAC       0x14  BaseOfCode:                    0x1000    
0xB0       0x18  ImageBase:                     0x400000  
0xB8       0x20  SectionAlignment:              0x1000    
0xBC       0x24  FileAlignment:                 0x200     
0xC0       0x28  MajorOperatingSystemVersion:   0x4       
0xC2       0x2A  MinorOperatingSystemVersion:   0x0       
0xC4       0x2C  MajorImageVersion:             0x0       
0xC6       0x2E  MinorImageVersion:             0x0       
0xC8       0x30  MajorSubsystemVersion:         0x5       
0xCA       0x32  MinorSubsystemVersion:         0x2       
0xCC       0x34  Reserved1:                     0x0       
0xD0       0x38  SizeOfImage:                   0x22000   
0xD4       0x3C  SizeOfHeaders:                 0x600     
0xD8       0x40  CheckSum:                      0x2C948   
0xDC       0x44  Subsystem:                     0x3       
0xDE       0x46  DllCharacteristics:            0x0       
0xE0       0x48  SizeOfStackReserve:            0x200000  
0xE8       0x50  SizeOfStackCommit:             0x1000    
0xF0       0x58  SizeOfHeapReserve:             0x100000  
0xF8       0x60  SizeOfHeapCommit:              0x1000    
0x100      0x68  LoaderFlags:                   0x0       
0x104      0x6C  NumberOfRvaAndSizes:           0x10      
DllCharacteristics: 

IMAGE_FILE_HEADER.NumberOfSections=0x11
区段(节)数量为17个,后面一定会有17个节头表项(区段表项)

pefile包解析出来的结果是在IMAGE_OPTIONAL_HEADER64之后没有体现IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];内容,而是直接跟着17个PE Sections的区段表项。

但是从偏移地址可以看出其中空缺了一部分0x104~0x188,如下所示
请添加图片描述
从01edit中查看这部分内容,如下所示,就是数据目录表项的内容(16个表项,最后一个为全0).
请添加图片描述
在python输出的内容后面也能看到

----------Directories----------

[IMAGE_DIRECTORY_ENTRY_EXPORT]
0x108      0x0   VirtualAddress:                0x0       
0x10C      0x4   Size:                          0x0       
[IMAGE_DIRECTORY_ENTRY_IMPORT]
0x110      0x0   VirtualAddress:                0x8000    
0x114      0x4   Size:                          0x7C8     
[IMAGE_DIRECTORY_ENTRY_RESOURCE]
0x118      0x0   VirtualAddress:                0x0       
0x11C      0x4   Size:                          0x0       
[IMAGE_DIRECTORY_ENTRY_EXCEPTION]
0x120      0x0   VirtualAddress:                0x5000    
0x124      0x4   Size:                          0x234     
[IMAGE_DIRECTORY_ENTRY_SECURITY]
0x128      0x0   VirtualAddress:                0x0       
0x12C      0x4   Size:                          0x0       
[IMAGE_DIRECTORY_ENTRY_BASERELOC]
0x130      0x0   VirtualAddress:                0x0       
0x134      0x4   Size:                          0x0       
[IMAGE_DIRECTORY_ENTRY_DEBUG]
0x138      0x0   VirtualAddress:                0x0       
0x13C      0x4   Size:                          0x0       
[IMAGE_DIRECTORY_ENTRY_COPYRIGHT]
0x140      0x0   VirtualAddress:                0x0       
0x144      0x4   Size:                          0x0       
[IMAGE_DIRECTORY_ENTRY_GLOBALPTR]
0x148      0x0   VirtualAddress:                0x0       
0x14C      0x4   Size:                          0x0       
[IMAGE_DIRECTORY_ENTRY_TLS]
0x150      0x0   VirtualAddress:                0xA020    
0x154      0x4   Size:                          0x28      
[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG]
0x158      0x0   VirtualAddress:                0x0       
0x15C      0x4   Size:                          0x0       
[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT]
0x160      0x0   VirtualAddress:                0x0       
0x164      0x4   Size:                          0x0       
[IMAGE_DIRECTORY_ENTRY_IAT]
0x168      0x0   VirtualAddress:                0x81EC    
0x16C      0x4   Size:                          0x1B0     
[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT]
0x170      0x0   VirtualAddress:                0x0       
0x174      0x4   Size:                          0x0       
[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR]
0x178      0x0   VirtualAddress:                0x0       
0x17C      0x4   Size:                          0x0       
[IMAGE_DIRECTORY_ENTRY_RESERVED]
0x180      0x0   VirtualAddress:                0x0       
0x184      0x4   Size:                          0x0 

到此得出结论PE文件部分结构
DOS头(其中包括DOS头的MZ标识部分和DOS Stub加载模块部分)后面紧跟着NT头,NT头包含Signature字段、IMAGE_FILE_HEADER结构体、IMAGE_OPTIONAL_HEADER32结构体。
在IMAGE_OPTIONAL_HEADER32结构体中的最后一个元素就是数据目录表(一个结构体数组),每个结构体中描述了数据块起始RVA地址和大小。可以用公式把RVA转成Offset(文件偏移地址)来找到这些数据目录表项中指向的数据块的文件偏移地址,在稍后会进行分析。

下面接着看从0x188处开始的IMAGE_SECTION_HEADER
以第一个区段表项为例

[IMAGE_SECTION_HEADER]
0x188      0x0   Name:                          .text
0x190      0x8   Misc:                          0x1C60    
0x190      0x8   Misc_PhysicalAddress:          0x1C60    
0x190      0x8   Misc_VirtualSize:              0x1C60    
0x194      0xC   VirtualAddress:                0x1000    
0x198      0x10  SizeOfRawData:                 0x1E00    
0x19C      0x14  PointerToRawData:              0x600     
0x1A0      0x18  PointerToRelocations:          0x0       
0x1A4      0x1C  PointerToLinenumbers:          0x0       
0x1A8      0x20  NumberOfRelocations:           0x0       
0x1AA      0x22  NumberOfLinenumbers:           0x0       
0x1AC      0x24  Characteristics:               0x60500020
Flags: IMAGE_SCN_ALIGN_1024BYTES, IMAGE_SCN_ALIGN_16BYTES, IMAGE_SCN_ALIGN_1BYTES, IMAGE_SCN_ALIGN_2048BYTES, IMAGE_SCN_ALIGN_256BYTES, IMAGE_SCN_ALIGN_32BYTES, IMAGE_SCN_ALIGN_4096BYTES, IMAGE_SCN_ALIGN_4BYTES, IMAGE_SCN_ALIGN_64BYTES, IMAGE_SCN_ALIGN_8192BYTES, IMAGE_SCN_ALIGN_8BYTES, IMAGE_SCN_ALIGN_MASK, IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ
Entropy: 5.812202 (Min=0.0, Max=8.0)
MD5     hash: 0f72c726b7b38f1ecc59860cf2bb3590
SHA-1   hash: 4f880ea203a0e93c736ed5a381fe99ab1f23c7e7
SHA-256 hash: e1daded1b379cb1595af17e00cdee8b1ee9daad1ced4d866cc776f02d7aeafff
SHA-512 hash: 098c76066bd5f70bba7a897aad1e7c913b5f923c73602575f30ca9b3b30575fa3aca47455b418291550c4092b25fd3090fd62107ee9f935c4502b0ca86e80deb

PointerToRawData=0x600,SizeOfRawData=0x1E00
.text节的文件偏移地址为0x600,大小为0x1E00

最后一个区段表项内容如下

[IMAGE_SECTION_HEADER]
0x408      0x0   Name:                          /92
0x410      0x8   Misc:                          0x520     
0x410      0x8   Misc_PhysicalAddress:          0x520     
0x410      0x8   Misc_VirtualSize:              0x520     
0x414      0xC   VirtualAddress:                0x21000   
0x418      0x10  SizeOfRawData:                 0x600     
0x41C      0x14  PointerToRawData:              0x17A00   
0x420      0x18  PointerToRelocations:          0x0       
0x424      0x1C  PointerToLinenumbers:          0x0       
0x428      0x20  NumberOfRelocations:           0x0       
0x42A      0x22  NumberOfLinenumbers:           0x0       
0x42C      0x24  Characteristics:               0x42100040
Flags: IMAGE_SCN_ALIGN_1024BYTES, IMAGE_SCN_ALIGN_16BYTES, IMAGE_SCN_ALIGN_1BYTES, IMAGE_SCN_ALIGN_256BYTES, IMAGE_SCN_ALIGN_4096BYTES, IMAGE_SCN_ALIGN_4BYTES, IMAGE_SCN_ALIGN_64BYTES, IMAGE_SCN_ALIGN_MASK, IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ
Entropy: 1.384952 (Min=0.0, Max=8.0)
MD5     hash: c792483200c7bd47e0810b5db34918c1
SHA-1   hash: 60c426bd47d1e32908dec26c7f3e584e9108e784
SHA-256 hash: 079531fc13743c7eaeed23f8af25731b120eeab425dcea38573d3316aa7ab3ed
SHA-512 hash: 5c290766cef7422600372eb50f6b82d2b58a8ca0aab90767e0dc4140e70ea5c1b063a30624864cdc6544c2f7316bff69db686cfb118111733b5c85db2ec722c8

起始地址为0x408,一个[IMAGE_SECTION_HEADER]占40个字节,得到区段头表(节头表)结束位置在0x430-0x1的地方,0x430开始就是其他的内容。

但是0x430~0x600地址范围内的内容全0,如下所示
请添加图片描述
观察IMAGE_OPTIONAL_HEADER64中FileAlignment=0x200,即对齐为0x200,所以这里是因为对齐方式的原因才会出现全0,并且从0x600开始就是第一个区段表项中指向的数据在文件中的偏移地址。

到此得出结论节头表(区段头表)后面紧跟着的就是节的具体信息,但是会遵从对齐规则

并且第一个区段从0x600开始,占大小为0x1e00,结束位置在0x2400-0x01处,从0x2400开始正好就是第二个区段表项中指向的文件偏移地址。

而最后一个区段表项结束位置在0x17A00+0x600-0x1处。从0x18000再往后就是其他的内容。

下面再看一下上面提到过的数据目录表,如下所示
请添加图片描述
没有从文件向外导出任何内容,所以导出表内容全空。有导入内容,虚拟地址为0x8000,下面先转换成文件偏移地址。
用LordPE打开查看这个PE文件的区段信息,如下所示
请添加图片描述
得到导入表的文件偏移地址为0x3400,并且可以看到它是.idata节(区段)。
那就再回到刚才的17个区段表项去寻找,果然找到相关信息,如下所示

请添加图片描述
这个节的起始地址正好也是0x3400,这就证实了这个导入表的数据被当作了一个节(区段)。

再回去看0x18000开始的位置是什么
请添加图片描述
PointerToSymbolTable指向COFF符号表偏移指针,可以看到这是符号表的开始位置。

COFF符号表是一个由记录组成的数组,每个记录长18个字节。定义如下

typedef struct _IMAGE_SYMBOL
{
    union
    {
        BYTE ShortName[8];  //8字节名称
        struct
        {
            DWORD Short;   //过长时为0
            DWORD Long;    //偏移量
        }Name;    
        PBYTE LongName[2]; //两个指针,其中第二个是指向过长的节名称的,第一个为0(union)
    }N;
    DWORD Value;           //与符号相关的值
    SHORT SectionNumber;   //节表的索引,以标识定义这个符号的节
    WORD Type;             //一个表示类型的数字
    BYTE StorageClass;     //一个标识储存类别的枚举类型值
    BYTE NumberOfAuxSymbol;//在最后一个记录后的辅助符号表数量
}IMAGE_SYMBOL;

那么COFF符号表位置为0x18000~0x1e6f0。
再往后就是很多可打印的字符串组成的内容,如下所示

请添加图片描述

根据PE文件格式,猜测后面的内容都是附加的一些数据了。

最后根据以上实验结果,结合网上查询到的PE文件格式,画出一个更精细的PE文件格式图示,
如下所示
请添加图片描述

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。