[系统安全] 十六.PE文件逆向基础知识(PE解析、PE编辑工具和PE修改)

您可能之前看到过我写的类似文章,为什么还要重复撰写呢?只是想更好地帮助初学者了解病毒逆向分析和系统安全,更加成体系且不破坏之前的系列。因此,我重新开设了这个专栏,准备系统整理和深入学习系统安全、逆向分析和恶意代码检测,“系统安全”系列文章会更加聚焦,更加系统,更加深入,也是作者的慢慢成长史。换专业确实挺难的,逆向分析也是块硬骨头,但我也试试,看看自己未来四年究竟能将它学到什么程度,漫漫长征路,偏向虎山行。享受过程,一起加油~

作者前文介绍了三个漏洞,包括Chrome浏览器保存密码渗透解析、通过Chrome浏览器实现Win10蓝屏、音乐软件解密功能复现。这篇文章将介绍基础知识,详细讲解PE文件格式,熟悉各种PE编辑查看工具,针对目标EXE程序新增对话框等,这也为后续PE病毒和恶意代码的攻防打下扎实基础。这些基础性知识不仅和系统安全相关,同样与我们身边的APP、常用软件及系统紧密联系,希望这些知识对您有所帮助,更希望大家提高安全意识,安全保障任重道远。

使用工具包括:

  • PEView、Stud_PE
  • UltraEdit、010Editor
  • Ollydbg、x64dbg
  • exeScope
    待分析程序:
  • hello-2.5.exe

在这里插入图片描述

从2019年7月开始,我来到了一个陌生的专业——网络空间安全。初入安全领域,是非常痛苦和难受的,要学的东西太多、涉及面太广,但好在自己通过分享100篇“网络安全自学”系列文章,艰难前行着。感恩这一年相识、相知、相趣的安全大佬和朋友们,如果写得不好或不足之处,还请大家海涵!

接下来我将开启新的安全系列,叫“系统安全”,也是免费的100篇文章,作者将更加深入的去研究恶意样本分析、逆向分析、内网渗透、网络攻防实战等,也将通过在线笔记和实践操作的形式分享与博友们学习,希望能与您一起进步,加油~

作者的github资源:

前文分析:

声明:本人坚决反对利用教学方法进行犯罪的行为,一切犯罪行为必将受到严惩,绿色网络需要我们共同维护,更推荐大家了解它们背后的原理,更好地进行防护。该样本不会分享给大家,分析工具会分享。(参考文献见后)


一.PE文件基础

什么是PE文件?
PE文件的全称是Portable Executable,意为可移植的可执行的文件,常见的EXE、DLL、OCX、SYS、COM都是PE文件,PE文件是微软Windows操作系统上的程序文件(可能是间接被执行,如DLL)。

EXE文件格式:

  • DOS:MZ格式
  • WIndows 3.0/3.1:NE(New Executable)、16位Windows可执行文件格式

为什么要重点学习这种文件格式呢?

  • PE文件是可移植、可执行、跨Win32平台的文件格式
  • 所有Win32执行体(exe、dll、kernel mode drivers)
  • 知道PE文件本质后,能更好进行恶意样本分析、APT攻击分析、勒索病毒分析
  • 了解软件加密和加壳的思想,能够PJ相关的PE文件
  • 它是您熟悉Windows操作系统的第一步,包括EXE程序怎么映射到内存,DLL怎么导入等
  • 软件逆向工程的基本思想与PE文件格式息息相关
  • 如果您想成为一名黑客、系统安全工程师,那么精通PE文件是非常必要的

可执行程序是具有不同的形态的,比如用户眼中的QQ如下图所示。

在这里插入图片描述

在这里插入图片描述

本质上,QQ如下图所示。

在这里插入图片描述


PE文件格式总体结构
接着让我们来欣赏下PE文件格式总体结构图,包括:MZ头部、DOS stub、PE文件头、可选文件头、节表、节等。

在这里插入图片描述

本文的第二部分我们将对PE文件格式进行详细解析。比如,MZ头文件是定位PE文件头开始位置,用于PE文件合法性检测。DOS下运行该程序时,会提示用户“This Program cannot be run in DOS mode”。

在这里插入图片描述

PE文件格式与恶意软件的关系

  • 何为文件感染或控制权获取?
    使目标PE文件具备或启动病毒功能(或目标程序)
    不破坏目标PE文件原有功能和外在形态(如图标)等
  • 病毒代码如何与目标PE文件融为一体呢?
    代码植入
    控制权获取
    图标更改
    Hook

PE文件解析常用工具包括:

  • PEView:可按照PE文件格式对目标文件的各字段进行详细解析。
  • Stud_PE:可按照PE文件格式对目标文件的各字段进行详细解析。
  • Ollydbg:可跟踪目标程序的执行过程,属于用户态调试工具。
  • UltraEdit \ 010Editor:可对目标文件进行16进制查看和修改。


二.PE文件格式解析

该部分实验内容:

  • 使用010Editor观察PE文件例子程序hello-2.5.exe的16进制数据
  • 使用Ollydbg对该程序进行初步调试,了解该程序功能结构,在内存中观察该程序的完整结构
  • 使用010Editor修改该程序,使得该程序仅弹出第二个对话框

1.010Editor解析PE文件

PE文件结构如下图所示,我推荐大家使用010Editor工具及其模板来进行PE文件分析。
MZ头部+DOS stub+PE文件头+可选文件头+节表+节

在这里插入图片描述


(1) 使用010Editor工具打开PE文件,并运行模板
该PE文件可分为若干结构,如下图所示。

在这里插入图片描述


(2) MZ文件头(000h-03fh)
下图为hello-2.5.exe的MZ文件头,该部分固定大小为40H个字节。偏移3cH处字段Offset to New EXE Header,指示“NT映象头的偏移地址”,其中000000B0是NT映象头的文件偏移地址,定位PE文件头开始位置,用于PE文件合法性检验。

在这里插入图片描述

000000B0指向PE文件头开始位置。

在这里插入图片描述


(3) DOS插桩程序(040h-0afh)
DOS Stub部分大小不固定,位于MZ文件头和NT映象头之间,可由MZ文件头中的Offset to New EXE Header字段确定。下图为hello-2.5.exe中的该部分内容。

在这里插入图片描述


(4) PE文件头(0b0h-1a7h)
该部分包括PE标识、映像文件头、可选文件头。

  • Signature:字串“PE\0\0”,4个字节(0b0H~0b4H)
  • 映象文件头File Header:14H个字节(0b5H~0c7H)
    偏移2H处,字段Number of Section 给出节的个数(2个字节):0003
    偏移10H处,字段Size of Optional Header 给出可选映象头的大小(2个字节):00E0
  • 可选映象头Optional Header:0c8H~1a7H

在这里插入图片描述

对应解析如下图所示,包括PE标识、X86架构、3个节、文件生成时间、COFF便宜、可选头大小、文件信息标记等。

在这里插入图片描述

010Editor使用模板定位PE文件各节点信息。

在这里插入图片描述

PE文件可选文件头224字节,其对应的字段信息如下所示:

typedef struct _IMAGE_OPTIONAL_HEADER {

    WORD    Magic;                  /*机器型号,判断是PE是32位还是64位*/
    BYTE    MajorLinkerVersion;          /*连接器版本号高版本*/
    BYTE    MinorLinkerVersion;          /*连接器版本号低版本,组合起来就是 5.12 其中5是高版本,C是低版本*/
    DWORD   SizeOfCode;               /*代码节的总大小(512为一个磁盘扇区)*/
    DWORD   SizeOfInitializedData;        /*初始化数据的节的总大小,也就是.data*/
    DWORD   SizeOfUninitializedData;       /*未初始化数据的节的大小,也就是 .data ? */
    DWORD   AddressOfEntryPoint;          /*程序执行入口(OEP) RVA(相对偏移)*/
    DWORD   BaseOfCode;               /*代码的节的起始RVA(相对偏移)也就是代码区的偏移,偏移+模块首地址定位代码区*/
    DWORD   BaseOfData;               /*数据结的起始偏移(RVA),同上*/
    DWORD   ImageBase;               /*程序的建议模块基址(意思就是说作参考用的,模块地址在哪里)*/

    DWORD   SectionAlignment;           /*内存中的节对齐*/
    DWORD   FileAlignment;             /*文件中的节对齐*/
    WORD    MajorOperatingSystemVersion;    /*操作系统版本号高位*/
    WORD    MinorOperatingSystemVersion;    /*操作系统版本号低位*/
    WORD    MajorImageVersion;          /*PE版本号高位*/
    WORD    MinorImageVersion;          /*PE版本号低位*/
    WORD    MajorSubsystemVersion;        /*子系统版本号高位*/
    WORD    MinorSubsystemVersion;        /*子系统版本号低位*/
    DWORD   Win32VersionValue;          /*32位系统版本号值,注意只能修改为4 5 6表示操作系统支持nt4.0 以上,5的话依次类推*/
    DWORD   SizeOfImage;               /*整个程序在内存中占用的空间(PE映尺寸)*/
    DWORD   SizeOfHeaders;            /*所有头(头的结构体大小)+节表的大小*/
    DWORD   CheckSum;               /*校验和,对于驱动程序,可能会使用*/
    WORD    Subsystem;              /*文件的子系统 :重要*/
    WORD    DllCharacteristics;         /*DLL文件属性,也可以成为特性,可能DLL文件可以当做驱动程序使用*/
    DWORD   SizeOfStackReserve;         /*预留的栈的大小*/
    DWORD   SizeOfStackCommit;          /*立即申请的栈的大小(分页为单位)*/
    DWORD   SizeOfHeapReserve;          /*预留的堆空间大小*/
    DWORD   SizeOfHeapCommit;           /*立即申请的堆的空间的大小*/
    DWORD   LoaderFlags;             /*与调试有关*/
    DWORD   NumberOfRvaAndSizes;         /*下面的成员,数据目录结构的项目数量*/
    IMAGE_DATA_DIRECTORY DataDirectory[16];  /*数据目录,默认16个,16是宏,这里方便直接写成16*/
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

(5) 节表(1a8h-21fh)

  • 表项大小固定,28H个字节;表项个数由映象文件头的字段Number of Section 给出。
  • 每个表项的起始位置起(8个字节),字段Name给出对应节的名称。
  • 每个表项的偏移14H处(4个字节),字段Offset to Raw Data给出对应节的起始文件偏移。

在这里插入图片描述

该结构包括3个节,对应上图的3个struct IMAGE_SECTION_HEADER,即“.test”、“.rdata”、“.data”节,其偏移地址对应下图紫色区域,分别是400、600、800的位置。

在这里插入图片描述


(6) 3个节

  • 400H-5ffH:代码节
  • 600H-7ffH:引入函数节
  • 800H-9ffH:数据节

在这里插入图片描述

注意,代码节“.text”前46H为数据,后面全是0位填充值,为了实现文件的200H对齐,所以代码节是400H到5ffH。

在这里插入图片描述


(7) 引入函数节
⽤来从其他DLL中引⼊函数,引入了kernel32.dll和user32.dll,这个节一般名为“.rdata”。引入函数是被某模块调用的但又不在调用者模块中的函数,用来从其他(系统或第三方写的)DLL中引入函数,例如kernel32.dll、gdi32.dll等。

在这里插入图片描述

010Editor打开如下图所示:

在这里插入图片描述

详细标注信息如下图所示:(图引自HYQ同学,再此感谢)

在这里插入图片描述


(8) 数据节
数据节实际大小58h,对齐后大小200h,地址为800h-9ffh,包括对话框弹出的具体内容。

在这里插入图片描述



2.Ollydbg动态调试程序

使用Ollydbg对该程序进行初步调试,了解该程序功能结构,在内存中观察该程序的完整结构。注意,内存对齐单位和文件对齐单位的不同,内容和文件中IAT表内容的不同。我们以hello-2.5.exe程序作为示例进行调试。

第一步,打开OD加载PE文件。
OD是一款PE文件动态调试器,此时程序断点自动停止在程序入口点00401000H位置。

在这里插入图片描述

在010Editor中,我们可以看到,该PE程序基地址是400000h,程序入口地址是1000h,两个相加为加载至内存中的地址,即401000h。

在这里插入图片描述


第二步,动态调试程序。
当我们双击地址位置,则可以下断点且变红,比如0040100Fh。

在这里插入图片描述

接着查看对应调试快捷键,F7是单步步入,F8是单步步过。

在这里插入图片描述

我们直接按F8单步步过,此时的位置会CALL一个MessageBoxA函数。

在这里插入图片描述

直接单步步过,此时会弹出第一个对话框,点击“确定”按钮。

在这里插入图片描述


第三步,动态调试程序之数据跟随。
接着我们看左下角部分的内存数据,在该区域按下“Ctrl+G”在数据窗口中跟随,输入基地址400000。

在这里插入图片描述

此时可以看到加载到内存中的数据,可以看到该数据与010Editor打开的PE文件数据一致的。

在这里插入图片描述

接着继续按F8单步步过弹出第二个窗口。

在这里插入图片描述

右上角是它寄存器的值,包括各个寄存器中的数据,我们实验中主要使用的寄存器包括EAX、ECX、EDX、EBX等。

在这里插入图片描述

接着步过0040102E,它是退出进程ExitProcess的位置,此时进程已经终止,如下图所示。

在这里插入图片描述

实验讲到这里,使用OD动态调试的PE文件的基础流程就讲解完毕,后续随着实验深入,我们还会使用该工具。



3.仅弹出第二个窗口

使用010Editor修改该程序,使得该程序仅弹出第二个对话框。思路为:修改程序的入口点地址。

第一步,确定程序入口点地址。
前面我们用010Editor(或PEView)确定了可选文件头中Adress od Entry Point这一项,里面的值是1000h,这个是RVA相对便宜地址,偏移在D8处大小为4字节。装载到内存后,程序入口点应该是401000h。

在这里插入图片描述

第二步,确定第二个对话框的偏移地址。
然后看到OD里,为第二个call做传入参数的push语句从401016开始,故我们将1000改为1016即可弹出第二个窗口。

在这里插入图片描述

第三步,利用PE编辑工具修改程序入口地址。
注意,可以在PE模板中修改该值,将AddressOfEntryPoint修改为1016h

在这里插入图片描述

第四步,双击运行仅弹出第二个对话框。

在这里插入图片描述



三.熟悉并分析PE文件的引出表

实验内容如下:

  • 熟悉各类PE文件格式查看和编辑工具,如PEView、Stud_PE等
  • 结合hello-2.5.exe熟悉PE文件头部、引入表的结构,熟悉函数导入的基本原理
  • 找到系统System32目录下的user32.dll文件,用010Editor打开并分析该文件引出表,找出函数MessageBoxA的地址,并验证该地址是否正确

在文件中的引入表结构:IMAGE_IMPORT_DESCRIPTOR

在这里插入图片描述

在内存中的引入表结构:IMAGE_IMPORT_DESCRIPTOR

在这里插入图片描述



1.PEView和Stud_PE查看文件

(1) 使用PEView查看文件属性
PEview.exe工具是一款可以进行PE文件解析的强大PE文件解析工具,通过PEview软件可以分析PE文件的详细格式。如下图所示,左边是相应结构,右边是对应的数据。PEView虽然能读写PE文件的数字化模板,但作者更推荐使用010Editor编辑。

ImageBase: PE文件在内存中的优先装载地址。
RVA地址:Relative Virtual Address,相对虚拟地址,它是相对内存中ImageBase的偏移位置。

在这里插入图片描述

比如PE文件头(IMAGE_NT_HEADERS)中,AddressOfEntryPoint为1000h,基地址为400000h。

在这里插入图片描述

下面是导入表信息:

在这里插入图片描述

第一条指令在内存中的地址计算方法如下图所示:

在这里插入图片描述


(2) 使用stud_PE查看文件属性
该软件用于显示头部、DOs、区段、函数等信息,包括导入表、导出表等。

在这里插入图片描述

在这里插入图片描述

显示对应的3个节信息。

在这里插入图片描述

显示该EXE程序加载的两个DLL文件及函数。

在这里插入图片描述



2.寻找函数MessageBoxA的地址

user32.dll是Windows用户界面相关应用程序接口,用于包括Windows处理、基本用户界面等特性。这里采用PEview+STUD_PE方法分析,找到系统System32目录下的user32.dll文件,用010Editor打开并分析该文件引出表,找出函数MessageBoxA的地址,并验证该地址是否正确。

第一步,使用PEView打开user32.dll,查找MessageBoxA的RVA。
找到系统System32目录下的user32.dll文件并打开,在AddressOfNames数组(Name Pointer Table)中找到MessageBoxA字符串,其数组序号为01DD

在这里插入图片描述

在Ordinal Table找到序号(Value)01DD项,Data为01DC;而由于Ordinal Table中Data从0开始,故在Address Table中找到第01DC+1,即01DD项。

在这里插入图片描述

Address Table中01DD项的Data为407EA,也即MessageBoxA的RVA(相对虚拟地址)。

在这里插入图片描述

第二步,得到RVA为38D9后,用Stud_PE打开user32.dll,使用Raw与RVA转换功能,得其VA为77D507EA

在这里插入图片描述

第三步,用OD打开hello-2.5.exe,查看MessageBoxA,两个值并不一致。
用OD调试程序的时候发现其VA地址其实是74DA0F40,与计算出的77D507EA位置有所偏差,然后查找资料发现这应该是操作系统处于安全原因改变了真实地址。

在这里插入图片描述

之后我在虚拟机的XP环境下进行了相同的实验,其值为77D507EA,完全一致。注意,user32.dll来自XP操作系统。

在这里插入图片描述

最终得出结论:XP之后的操作系统对真实地址做了相关的保护。



四.PE文件新增对话框

实验内容是手工修改hello-2.5.exe程序,使得其可以弹出第三个对话框(提示框标题为“武汉大学信安病毒实验”,内容为:你的姓名+日期)。基本思路为:

  • 修改.text段:添加MessageBoxA的函数调用
  • 修改.data段:添加MessageBoxA的参数信息
  • 修改.text和.data的节表信息

第一步,使用OD打开目标PE文件。
如下图所示,包括第一个对话框、第二个对话框和退出进程。

在这里插入图片描述


第二步,修改数据区“.data”。

  • Title:RVA是0040 3059
  • Text:RVA是0040 306A

注意,从下图所示的位置开始修改,地址为0040 3059,需要留一个00字符,表示截断符。同样,title和text之间也要用00隔开。

在这里插入图片描述

右键选择“二进制”->“编辑”,其快捷键为Ctrl+E。

在这里插入图片描述

输入标题“武汉大学信安病毒实验”。

在这里插入图片描述

此时标题已经成功写入,接着空一个00,从下图所示位置接着写入正文内容,地址为0040 306A。

在这里插入图片描述

接着写入内容,如下图所示。

在这里插入图片描述

增加内容如下图所示:

在这里插入图片描述

注意,现在我们只是写入内存,而没有写入PE文件中。


第三步,选中新增内容,右键点击“复制到可执行文件”。

在这里插入图片描述

此时显示如下图所示,成功复制到PE文件中。

在这里插入图片描述


第四步,修改代码段。
我们需要在代码段第二个对话框之后插入新的数据,从而弹出第三个对话框。需要将下图阴影部分整体后移。

在这里插入图片描述

首先,在0040101B位置进行数据跟随。

在这里插入图片描述

数据跟随显示如下图所示,代码段中每个弹框是22字节,从“68 40”开始,共计两个弹框。

在这里插入图片描述

接着我们将退出函数的所有字节复制出来,为了整体后移。
6A 00 E8 01 00 00 00 CC FF 25 00 20 40 00 FF 25 0C 20 40 00 FF 25 08 20 40

在这里插入图片描述

接着空22字节用于填写第三个对话框信息,将复制的二进制数据粘贴出来(Ctrl+E),如下图所示。

在这里插入图片描述

将第一个对话框22字节代码复制至第三个对话框,如下图所示:

在这里插入图片描述


第五步,修改.text段。
第二个栈的参数是它的Title,需要将偏移地址设置为对应的位置。

在这里插入图片描述

右键“数据窗口中跟随”->“立即数”。

在这里插入图片描述

第三个窗口标题的地址修改为“00403059”。

在这里插入图片描述

Ctrl+E修改为59。

在这里插入图片描述

修改第三个窗口Text地址为“0040306A”。

在这里插入图片描述


第六步,修改CALL对应的地址。
注意,三个对话框CALL对应的E8值需要以00401056(user32.MessageBoxA)为基址。

  • 第一个对话框E8:00401056-00401016=40
  • 第二个对话框E8:00401056-0040102C=2A
  • 第三个对话框E8:00401056-00401042=14

在这里插入图片描述

修改如下图所示:

在这里插入图片描述


第七步,保存文件。
选择“复制到可执行文件”->“所有修改”按钮。

在这里插入图片描述

点击“全部复制”。
在这里插入图片描述

最终保存修改的PE文件。

在这里插入图片描述

运行PE文件,成功弹出第三个框。

在这里插入图片描述

新增的内容如下图所示:

在这里插入图片描述

注意:

  • 检查在OD中所做的全部修改,是否保存到可执行文件中。
  • .text和.data节表中,表示节实际大小的字段“Virtual Size”应该做出修改,但不修改文件依然能正常运行。


五.总结

文章写到这里,就介绍完毕,本文主要讲解PE文件解析、PE编辑工具使用和PE结构修改,属于系统安全和PE逆向相关知识,希望对您有所帮助。内容包括:

  • PE文件基础
  • PE文件格式解析
    – 010Editor解析PE文件
    – Ollydbg动态调试程序
    – 仅弹出第二个窗口
  • 熟悉并分析PE文件的引出表
    – PEView和Stud_PE查看文件
    – 寻找函数MessageBoxA的地址
  • PE文件新增对话框

后续将学习PE文件图标修改、对话框分析、EXE解析、加壳解密等。希望这系列文章对您有所帮助,同时真的感觉自己技术好菜,要学的知识好多。未知攻焉知防,人生漫漫其路远兮,作为初学者,自己真是爬着前行,感谢很多人的帮助,继续爬着,继续加油!

欢迎大家讨论,是否觉得这系列文章帮助到您!如果存在不足之处,还请海涵。任何建议都可以评论告知读者,共勉~

学安全一年,认识了很多安全大佬和朋友,希望大家一起进步。这篇文章中如果存在一些不足,还请海涵。作者作为网络安全和系统安全初学者的慢慢成长路吧!希望未来能更透彻撰写相关文章。同时非常感谢参考文献中的安全大佬们的文章分享,深知自己很菜,得努力前行。编程没有捷径,逆向也没有捷径,它们都是搬砖活,少琢磨技巧,干就对了。什么时候你把攻击对手按在地上摩擦,你就赢了,也会慢慢形成了自己的安全经验和技巧。加油吧,少年希望这个路线对你有所帮助,共勉。

2020年8月18新开的“娜璋AI安全之家”,主要围绕Python大数据分析、网络空间安全、人工智能、Web渗透及攻防技术进行讲解,同时分享CCF、SCI、南核北核论文的算法实现。娜璋之家会更加系统,并重构作者的所有文章,从零讲解Python和安全,写了近十年文章,真心想把自己所学所感所做分享出来,还请各位多多指教,真诚邀请您的关注!谢谢。

(By:Eastmount 2021-01-25 星期一 夜于武汉 http://blog.csdn.net/eastmount/ )


参考文献:
[1] 武大《软件安全》课程
[2] 师姐PPT、师弟师妹PPT及视频
[3] PE文件格式分析 - Erio
[4] PE文件学习系列一为什么是PE - Egojit
[5] 第二章PE文件结构解析 - 百度文库

猜你喜欢

转载自blog.csdn.net/Eastmount/article/details/113141466
PE