计算机系统引导过程

graph LR
a(主板BIOS<br>系统进行<br>自检) ==> b("硬盘主<br>引导程序<br>(MBR)")
b ==> c("活动分区<br>引导程序<br>(DBR)")
c ==> d("操作系统<br>引导<br>(如NTLDR)")
d ==> e(操作系统<br>内核启动)
e ==> f(驱动程序<br>及服务)
f ==> g(系统<br>自启动程序)

PE文件:可移植的可执行程序

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

  • 文件感染:

    使目标PE文件具备[或启动]病毒功能[或目标程序]

    但不破坏目标PE文件原有功能和外在形态(如团标)等

  • 病毒代码如何与目标PE文件融为一体

    代码植入、控制权获取、及图标更改等

PE文件总体结构

1.DOS MZ header
2.DOS Stub
3.PE header
4.Section table
5-1 Section 1
5-2 Section 2
Section …
5-n Section n

MZ-DOS:MZ文件头(0x40+),定位PE文件头开始位置,也可用于PE文件合法检测。
3C处的值(末4位):指向PE文件头开始位置。

DOS Stub:小型DOS程序,在DOS下运行会提示“This is program cannot be run in DOS mode”。

PE header:由三部分组成

  1. 字串 “PE\0\0” (Signature) (0x04):本域为PE标记,可以此识别给定文件是否为有效PE文件

  2. 映像文件头(FileHeader)(0x14):包含了关于PE文件物理分布的信息,比如节数目、后续可选文件头大小机器类型等。

    顺序名字大小(字节)描述
    1Machine *2机器类型,x86为14CH
    2NumberOfSection **2文件中节的个数
    3TimeDataStamp4生成该文件的时间
    4PointerToSymbleTable4COFF符号表的偏移
    5NumberOfSymbols4符号数目
    6SizeOFOptionalHeader*2可选头的大小
    7Characteristics *2关于文件信息的标记,比如文件是exe还是dll
  3. 可选映像头(OptionalHeader): 定义了PE文件许多关键信息

    • 内存镜像加载地址(ImagaBase)
    • 程序入口点(代码从哪里开始执行)
    • 节在文件和内存中的对齐粒度
    • 本程序在内存中的镜像大小、文件头大小等
    • 目录Directory (16项 * 8字节) : 每一项对应后面重要的数据结构的开始位置、大小
    名字描述
    AddressOfEntryPoint*
    (位置: D8H,4字节)
    PE装载器准备运行的PE文件的第一条指令的RVA。
    (病毒感染中通用关键字段)
    ImagaBase
    (位置: E4H,4字节)
    PE文件的优先转载地址。如:如果该值是400000h,
    PE装载器将尝试把文件虚拟地址空间的400000h处
    SectionAlignment
    (位置: E8H,4字节)
    内存中节对齐的粒度
    FileAlignment
    (位置: ECH,4字节)
    文件中节对齐的粒度

节表:紧挨着 PE header 的一个结构数组。

每一个节表对应一个节表项:

  • 节名;
  • 节在文件和内存中的开始地址;
  • 长度;
  • 节属性等。

:可执行文件的核心部分。

  • 代码节
  • 数据节
  • 引入函数节
  • 资源节(如图标)
  • 引出函数节(DLL文件中常见)
  • 重定位节(DLL文件中常见)

概念解析

ImagaBase: PE文件在内存中的优先装载地址(大部分为400000H)

RVA地址: Relative Virtual Address,相对虚拟地址,它是相对内存中ImagaBase的偏移

对齐粒度: 按照内存对齐粒度读取到内存,不足的用0填充。
例如:桶的容量为100L,现有367L水,则需要4个桶
文件中节对齐粒度:0x200; 内存中节对齐粒度:0x1000字节。

​ 因此在PE文件中有很多“00”字节,恶意程序可以利用这些填充字节。


代码节

  • 紧接着节表之后,一般名为 .text或CODE,该节含有程序的可执行代码
  • 每个PE都有代码节

已初始化的数据节

  • 一般名为 .data或DATA
  • 已初始化的数据节中放的是在编译时刻就已经确定的数据

未初始化的数据节

  • 一般名为 .bbs
  • 节内放油未初始化的全局变量和静态变量

引入函数节

  • 节名一般为 .rdata

  • 是被程序调用但起执行代码又不在程序中的函数

    1. 这些函数位于一个或者多个DLL中,在调用这程序中只保留了函数信息,包括函数民及其驻留的DLL名等
    2. 动态链接库: 例如kernel32.dll、user32.dll、gdi32.dll等
  • 该节含有四个表

    名字解释
    IMPORT Address Table引入地址表
    IMPORT Directory Table引入目录表
    IMPORT Name Table引入名称表
    IMPORT Hints/Names & DLL Names引入提示/名称和DLL名称
    • IMPORT Address Table(IAT):引入地址表,DWORD数组[可通过可选文件头中的DataDirectory的第13项定位]

      • 在文件中时,其内容与Import Name Table完全一样
      • 在内存中时,每个双字中存放着对应引入函数的地址
    • IMPORT Directory Table由一系列的IMAGE_IMPORT_DESCEIPTOR结构(5字段*4字节)组成

      • 结构的数量取决于程序要使用DLL文件的数量,每一个结构对应一个DLL文件
      • 在所以这些结构的最后,由一个内容全为0的IMAGE_IMPORT_DESCRIPTOR结果作为结束
    • IMPORT Name Table,DATA最高位:

      • 为0时:表示通过函数名引入,指向 IMPORT Hints/Names
      • 为1时:表示通过序号引入函数
    • IMPORT Hints/Names & DLL Names 分解说明

      • IMAGE_IMPORT_BY_NAME结构
        • 80 00 为Hints,ExitProcess为引入函数名
        • 62 02 为Hints,wsprintfA为引入函数名
        • 9D 01 为Hints,MessageBoxA为引入函数名
      • DLL names字符串
        • kernel32.dll 为dll文件名
        • user32.dll 为dll文件名

引出函数节

  • 节名一般为 .edata,有时和 .text节合在一起。这是本文件向其他程序提供调用函数的列表、函数所在的地址具体代码实现

  • 关键结构:引出目录表(导出表、输出表)

    ​ 结构解析:

    序号位置名称大小解释
    100HCharacteristics4一般为0
    204HTimeDataStamp4文件生成时间
    308HMajorVersion2主版本号
    40AHMinorVersion2次版本号
    50CHName4指向DLL的名字
    610HBase4开始的序列号
    714HNumberOfFunctions4AddressOfFunctions 数组的项数
    818HNumberOfNames4AddressOfNames 数组的项数
    91CHAddressOfFunctions4指向“函数地址”数组—导出地址表
    1020HAddressOfNames4指向“函数名所在地址”数组—函数名地址表
    1124HAddressOfNameOrdinals4指向“函数索引序列号”数组—函数序列表
  • 导出地址表 — EXPORT ADDRESS Table,Dword的两种可能含义

    • dwExportRVA,指向导出地址(一般情况)
    • dwForwarderRVA,指向另外一个DLL中的某个API函数名
  • 导出名字表 — EXPORT Name Table,保存指向名字的指针

  • 导出序号表 — EXPORT Ordinal Table,保存的是各导出函数的函数地址在导出地址表的序号

    • 为何需要导出地址表?
      导出函数名字和导出地址表中的地址不是一一对应关系 (Why?)
      1.一个函数实现可能有多个名字
      2.某些函数没有名字,仅通过序号导出

程序调试

用户态调试:Ollydbg

内核代码调试:Windbg