《逆向工程核心原理》第13章——PE文件格式(1):PE头


介绍

PE是指32位可执行文件,也称PE32。64位可执行文件称为PE+或PE32+,是PE文件的一种扩展形式。


PE文件格式

PE文件种类如下:

种类主扩展名
可执行系列exe scr
库系列dll ocx cpl drv
驱动程序系列sys vxd
对象文件系列obj

严格来讲,obj文件之外的所有文件都是可执行的。ddl、sys文件虽然不能直接在shell执行,但可以使用其他方法(调试器、服务等)执行。

PE文件基本结构

从DOS头到节区头是PE头部分下面的节区合称为PE体。文件中使用偏移,内存中使用VA虚拟地址来表示位置。文件加载到内存后,节区的位置大小会发生变化。文件内容一般可分为代码、数据、资源节,分别保存。

各节区头分别定义各节区在文件或内存中的大小、位置、属性等

PE头和各节区尾部存在NULL填充区域,这是因为为了提高处理效率,计算机中使用“最小基本单位的概念”。

在这里插入图片描述

VA:进程虚拟内存的绝对地址。
RVA:从某一个基准位置(ImageBase)开始的相对地址

VA=RVA+ImageBase,两者都指的是装载进入内存后的地址

PE头内部信息大多以RVA形式存在:因为PE文件(主要是DLL)加载到进程虚拟内存的特定位置时,该位置可能已经加载了其他DLL,此时必须通过重定位将其加载到其他空白区域。发生重定位后,只要相对于基准位置的相对地址没有变化,就能正常访问。


PE头

包括

  • DOS头
  • DOS存根
  • NT头
  • 各节区头

DOS头

PE头最前面的40H字节是一个IMAGE_DOS_HEADER结构体——DOS头
在这里插入图片描述
两个重要成员:

  • e_magic:多有PE文件开始部分都有的DOS签名(‘MZ’,4D5A)
  • e_lfanew:指示NT头的偏移
    在这里插入图片描述

DOS存根

在DOS头下方,可选项且大小不固定由代码和数据混合而成
在这里插入图片描述
文件偏移40~4D区域为16位汇编指令:功能为输出偏移0E处字符串。在DOS调试器debug.exe中运行:
在这里插入图片描述
若使用得当,可以在一个可执行文件中创建另一个文件,在16位DOS和32位Windows中都能运行。

NT头

NTIMAGE_NT_HEADERS结构体由3个成员组成:签名、文件头、可选头。其结构体大小为F8H起始位置由DOS头的e_lfanew确定(因为DOS存根大小不确定,这里为0000 00E0h
在这里插入图片描述
签名:50450000h(‘PE’00)
在这里插入图片描述

NT头:文件头

文件头是表现文件大致属性的IMAGE_FILE_HEADER结构体。
在这里插入图片描述
四个重要成员:

  • Machine:每个CPU唯一拥有的机器码,这里为Intel 386芯片14C。
  • NumberOfSections:节区数,此处为3。
  • SizeOfOptionalHeader:可选头大小,用来指出IMAGE_OPTIONAL_HEADER32/64的长度,此处是e0。
  • Characteristics表示文件属性,记住0002h与2000h。此处为010F,包含了重定向信息删除,可执行文件,行数移除,本地符号表移除以及系统文件等属性。
    在这里插入图片描述在这里插入图片描述

NT头:可选头

IMAGE_OPTIONAK_HEADER是PE头结构中最大的。其大小在IMAGE_FILE_HEADER的SizeOfOptionalHeader中标明,此处为00E0。
在这里插入图片描述
在这里插入图片描述
几个重要成员:

  • Magic:可选头是32结构体时,该值为10B。可选头是64位结构体时,该值为20B。
  • AddressOfEntryPointEP的RVA值,指出程序最先执行的代码起始地址
  • ImageBase:文件优先装入的虚拟内存地址。32位系统进程虚拟内存范围为0~FFFFFFFF。一般来说,EXE文件ImageBase值为00400000,DLL文件为10000000
    PE装载器先创建进程,再将文件载入内存,然后把EIP寄存器的值设为ImageBase+AddressOfEntryPoint。所以说EIP的初始值由可执行文件描述部分决定。
  • SectionAlignment、FileAligment:SectionAlignment指定了节区在内存中的最小单位,FileAligment指定了节区在磁盘文件中的最小单位。磁盘文件或内存的节区大小必定为对应最小单位的整数倍。
  • SizeOfImage:PE文件在虚拟内存中所占空间的大小,即加载后大小。
  • SizeOfHeadersPE头的大小,是FileAlignment的整数倍(磁盘文件中)。
  • Subsystem:区分系统驱动文件与普通可执行文件。
    在这里插入图片描述
  • NumberOfRvaAndSizes:指定最后一个成员DataDirectory数组的个数,以这个为准,而不是IMAGE_NUMBEROF_DIRECTERY_ENTRIES(16)。
  • DataDirectory:以IMAGE_DATA_DIRECTORY结构体数组,数组每一项都有被定义的值。DataDirectory[n]结构体中的每一个都有两个属性:一个是相对虚拟地址,一个是大小,其中每个结构体的大小为8字节。
    在这里插入图片描述
    在这里插入图片描述
    更正:程序EP的RVA应该是0000739D,上图框选应该向右移动两字节。

节区头

节区头中定义了各节区属性。PE文件中的code(代码)、data(数据)、resourse(资源)等按照属性分类存储在不同节区,这样可以保证程序的安全性。

节区头是由IMAGE_SECTION_HEADER结构体组成的数组,每个结构体对应一个节区。大小固定为40字节
在这里插入图片描述
几个重要成员:

  • VirtualSize内存中节区所占实际大小
  • VirtualAddress内存中节区起始地址(RVA),运行时会加上ImageBase值。按SectionAlignment对齐。
  • SizeofRawData:磁盘中节区所占大小,通常是VirtualSize按照FileAligment值对齐后得到的
  • PointerToRawData:磁盘中节区起始地址。按FileAligment对其。
  • Characteristics:节区属性,由bit OR组合而成。
    在这里插入图片描述
    下图显示notpad.exe的三个节区头数组:
    在这里插入图片描述在这里插入图片描述在这里插入图片描述

RVA与RAW

PE文件加载到内存时,每个节区都要准确完成内存地址与磁盘文件偏移之间的映射,这种映射称为RVA to RAW。方法为:(1)查找RVA所在节区(2)使用下方公式计算处文件偏移RAW。

RAW-PointerToRawData(磁盘中节区偏移)=RVA-VirtualAddress(内存中节区偏移)

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
PE文件格式逆向解析成汇编语言是一个非常复杂的任务,需要对PE文件格式有深入的了解,并且需要具备较强的反汇编技能。以下是一个简单的示例,演示如何将PE文件部信息逆向解析成汇编语言: ``` ; 定义IMAGE_DOS_HEADER结构体 IMAGE_DOS_HEADER struct e_magic dw ? e_cblp dw ? e_cp dw ? e_crlc dw ? e_cparhdr dw ? e_minalloc dw ? e_maxalloc dw ? e_ss dw ? e_sp dw ? e_csum dw ? e_ip dw ? e_cs dw ? e_lfarlc dw ? e_ovno dw ? e_res dw 4 dup(?) e_oemid dw ? e_oeminfo dw ? e_res2 dw 10 dup(?) e_lfanew dd ? IMAGE_DOS_HEADER ends ; 定义IMAGE_NT_HEADERS结构体 IMAGE_NT_HEADERS struct Signature dd ? FileHeader IMAGE_FILE_HEADER <> OptionalHeader IMAGE_OPTIONAL_HEADER32 <> IMAGE_NT_HEADERS ends ; 定义IMAGE_FILE_HEADER结构体 IMAGE_FILE_HEADER struct Machine dw ? NumberOfSections dw ? TimeDateStamp dd ? PointerToSymbolTable dd ? NumberOfSymbols dd ? SizeOfOptionalHeader dw ? Characteristics dw ? IMAGE_FILE_HEADER ends ; 定义IMAGE_OPTIONAL_HEADER32结构体 IMAGE_OPTIONAL_HEADER32 struct Magic dw ? MajorLinkerVersion db ? MinorLinkerVersion db ? SizeOfCode dd ? SizeOfInitializedData dd ? SizeOfUninitializedData dd ? AddressOfEntryPoint dd ? BaseOfCode dd ? BaseOfData dd ? ImageBase dd ? SectionAlignment dd ? FileAlignment dd ? MajorOperatingSystemVersion dw ? MinorOperatingSystemVersion dw ? MajorImageVersion dw ? MinorImageVersion dw ? MajorSubsystemVersion dw ? MinorSubsystemVersion dw ? Win32VersionValue dd ? SizeOfImage dd ? SizeOfHeaders dd ? CheckSum dd ? Subsystem dw ? DllCharacteristics dw ? SizeOfStackReserve dd ? SizeOfStackCommit dd ? SizeOfHeapReserve dd ? SizeOfHeapCommit dd ? LoaderFlags dd ? NumberOfRvaAndSizes dd ? DataDirectory dd 16 dup(?) IMAGE_OPTIONAL_HEADER32 ends ; 定义节表结构体 IMAGE_SECTION_HEADER struct Name db 8 dup(?) VirtualSize dd ? VirtualAddress dd ? SizeOfRawData dd ? PointerToRawData dd ? PointerToRelocations dd ? PointerToLinenumbers dd ? NumberOfRelocations dw ? NumberOfLinenumbers dw ? Characteristics dd ? IMAGE_SECTION_HEADER ends ; 定义变量 dos_header IMAGE_DOS_HEADER <> nt_headers IMAGE_NT_HEADERS <> section_headers IMAGE_SECTION_HEADER 16 dup(?) ; 读取PE文件 filename db 'test.exe', 0 handle dw ? buffer db 512 dup(?) bytes_read dw ? section_table_offset dd ? size_of_section_table dd ? ; 打开文件 mov ah, 3dh mov al, 0 ; 只读模式 mov dx, offset filename int 21h mov handle, ax ; 读取DOS部信息 mov ah, 3fh mov bx, handle mov cx, sizeof IMAGE_DOS_HEADER mov dx, offset dos_header int 21h ; 获取PE部偏移地址 mov ax, word ptr [dos_header+0x3c] mov bx, handle mov cx, sizeof IMAGE_NT_HEADERS mov dx, offset nt_headers add dx, ax int 21h ; 解析PE部信息 mov ax, word ptr [nt_headers.Signature] cmp ax, 'PE' jne exit_program ; 解析文件部信息 mov ax, word ptr [nt_headers.FileHeader.NumberOfSections] mov section_table_offset, dx mov size_of_section_table, ax * sizeof IMAGE_SECTION_HEADER add dx, sizeof IMAGE_FILE_HEADER mov cx, sizeof IMAGE_FILE_HEADER mov si, offset nt_headers.FileHeader mov di, dx rep movsb ; 解析可选部信息 mov ax, word ptr [nt_headers.OptionalHeader.Magic] cmp ax, IMAGE_NT_OPTIONAL_HDR32_MAGIC jne exit_program mov cx, sizeof IMAGE_OPTIONAL_HEADER32 mov si, offset nt_headers.OptionalHeader mov di, dx rep movsb ; 解析节表信息 mov ah, 3fh mov bx, handle mov cx, size_of_section_table mov dx, offset section_headers add dx, section_table_offset int 21h exit_program: ; 关闭文件 mov ah, 3eh mov bx, handle int 21h ``` 以上代码仅为示例,实际上解析PE文件格式的过程要比这个更加复杂,需要对不同的结构体进行不同的解析方式,并且需要处理一些特殊情况。同时,反汇编的过程还需要考虑一些优化问题,例如去除无用代码、还原函数调用等,以确保反汇编的代码正确、可读性强。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值