zoukankan      html  css  js  c++  java
  • PE知识复习之PE的各种头属性解析

                    PE知识复习之PE的各种头属性解析

    一丶DOS头结构体

    typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header
        WORD   e_magic;                     // Magic number
        WORD   e_cblp;                      // Bytes on last page of file
        WORD   e_cp;                        // Pages in file
        WORD   e_crlc;                      // Relocations
        WORD   e_cparhdr;                   // Size of header in paragraphs
        WORD   e_minalloc;                  // Minimum extra paragraphs needed
        WORD   e_maxalloc;                  // Maximum extra paragraphs needed
        WORD   e_ss;                        // Initial (relative) SS value
        WORD   e_sp;                        // Initial SP value
        WORD   e_csum;                      // Checksum
        WORD   e_ip;                        // Initial IP value
        WORD   e_cs;                        // Initial (relative) CS value
        WORD   e_lfarlc;                    // File address of relocation table
        WORD   e_ovno;                      // Overlay number
        WORD   e_res[4];                    // Reserved words
        WORD   e_oemid;                     // OEM identifier (for e_oeminfo)
        WORD   e_oeminfo;                   // OEM information; e_oemid specific
        WORD   e_res2[10];                  // Reserved words
        LONG   e_lfanew;                    // File address of new exe header
      } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

    DOS头是在16位程序下使用的.所以不用全部关心.只需要关心第一个跟最后一个成员记住即可.

    DOS头大小是64个字节,十六进制是0x40 总结一下就是说. 4行只有第一行的前两个字节.以及最后一行的4个字节有用.

     WORD   e_magic  这个成员是操作系统检查的MZ头.
     LONG   e_lfanew 这个成员指向PE头.也很重要.
    如果上面两个成员更改了.那么文件就不能运行了.

    二丶NT头解析

      NT头也是我们所指的PE头. 其中NT头包括了文件头跟扩展头.

    typedef struct _IMAGE_NT_HEADERS {
        DWORD Signature;                      PE标识
        IMAGE_FILE_HEADER FileHeader;         文件头
        IMAGE_OPTIONAL_HEADER32 OptionalHeader;扩展头
    } IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

    NT头的第一个成员也很重要.是PE标识.占4个字节. DOS头的最后一个成员的偏移.就是NT头.(PE)

    例如:

    操作系统会检查PE头.以及MZ头.检查是否是正确的值.

    而NT头中有两个子结构体.一个是文件头.一个是扩展头.这两个头比较重要.

    三丶文件头解析

      文件头挺重要的.里面存储了我们的节表个数.等等一些列信息.跟扩展头息息相关.

    文件头大小是20个字节. 十六进制 是0x14大小.如果按照16一行分组.那么就是一行零4个字节.是文件头总大小.

    typedef struct _IMAGE_FILE_HEADER {
        WORD    Machine;                        机器型号.表名了我们CPU执行的这个PE文件是x86的还是x64的.有一系列宏标识.
        WORD    NumberOfSections;                   节表个数. 此成员很重要.标识着我们的节表有多少个.如果节个数小于节的总数那么程序就不能运行.
        DWORD   TimeDateStamp;                     文件时间.不重要.与文件属性里面的创建事件修改时间无关.编译器填写的
     DWORD PointerToSymbolTable; 调试器相关 DWORD NumberOfSymbols; 调试器相关. WORD SizeOfOptionalHeader; 扩展PE头大小,此成员很重要.表明了我们的扩展头总体大小. WORD Characteristics; 文件属性 } IMAGE_FILE_HEADER,
    *PIMAGE_FILE_HEADER;

    machine 标识 #define IMAGE_FILE_MACHINE_IA64              0x0200  // Intel 64 代表是x64运行的程序. 其中 0x14c则带便是86运行的程序.具体可以查看宏

    文件头中标红的都很重要. 一个是操作系统判断是什么系统运行的文件.一个是当前PE的节个数.一个表明了扩展头的大小.一个表明了文件属性

    总结: 一行零4个字节.其中前4个字节很重要.分别表示机器型号.以及节个数. 一行零2个字节表明了扩展头大小.也很重要.

    关于最后一个成员 是按位来做的.具体成员如下.

    四丶扩展头解析

      扩展头的大小.在我们的文件头中标识着. 一般是E0大小.扩展头是可以更改的. E0十进制大小是224个字节.

    我们看一下扩展头结构.

    x86跟x64的扩展头是不一样的.我们直说一下x86

    typedef struct _IMAGE_OPTIONAL_HEADER {
        //
        // Standard fields.
        //
    
        WORD    Magic;              //标志.表名了我们的PE是x86还是x64
        BYTE    MajorLinkerVersion;          //连接器主要版本号
        BYTE    MinorLinkerVersion;          //连接器次要版本号 例如 3.54 主要版本就是3.次要就是54
        DWORD   SizeOfCode;                  //代码段大小,以字节为单位.
        DWORD   SizeOfInitializedData;       //初始化数据部分的大小.
        DWORD   SizeOfUninitializedData;     //未知初始化数据的大小
        DWORD   AddressOfEntryPoint;         //OEP 程序入口点,驱动程序也是入口点.对于DLL而言.是可选的.没有入口则为0
        DWORD   BaseOfCode;                  //指向代码部分的指针              
        DWORD   BaseOfData;                  //指向数据部分开头的指针
    
        //
        // NT additional fields.
        //
    
        DWORD   ImageBase;                  //基址.PE文件加载到内存中的基址.这个值是64k的倍数.DLL默认值是0x100000000,应用程序默认是0x00400000
    windows CE除外.他是0x00010000 DWORD SectionAlignment; //PE文件加载到内存中.的内存对齐.按照这个成员进行对齐 DWORD FileAlignment; //文件对齐,PE存数据存放在文件中.按照文件对其值对其 WORD MajorOperatingSystemVersion;//所需要操作系统的主要版本号. WORD MinorOperatingSystemVersion;//所需要操作系统的次要版本号. WORD MajorImageVersion; //PE主版本号 WORD MinorImageVersion; //PE次版本号 WORD MajorSubsystemVersion; //子系统主要版本号. WORD MinorSubsystemVersion; //子系统次要版本号. DWORD Win32VersionValue; //保留成员,必须为0 DWORD SizeOfImage; //PE镜像大小.必须是内存对齐的倍数. sizeofImage/SectionAllignment == 0 才可以 DWORD SizeOfHeaders; // DOS头+NT头+节表的总大小.按照文件对齐存放 sizeofHeaders / FileAlignment == 0
       DWORD SubSystem           //表名PE文件是什么程序. 1驱动程序2窗口程序3控制台程序(DLL) DWORD CheckSum; WORD DllCharacteristics; //P的文件属性 DWORD SizeOfStackReserve; //堆栈保留字节数.我们的程序使用的栈空间多大靠这个成员.不过操作系统只作为参考 DWORD SizeOfStackCommit; //要为堆栈提交的字节数.不做参考 DWORD SizeOfHeapReserve; //堆保留字节数. DWORD SizeOfHeapCommit; //本地堆提交的字节数. PS: 栈堆保留数值.斗鱼自己的sizeof(Head/stack)Commit成员有关. DWORD LoaderFlags; //成员已经过时 DWORD NumberOfRvaAndSizes; //数据目录数组的大小 IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];//数据目录 } IMAGE_OPTIONAL_HEADER32,
    *PIMAGE_OPTIONAL_HEADER32;

     总结来说.上面的成员挺多的.也很重要. 

    OEP  AddressOfEntryPoint 指明了PE入口点.在扩展头的0x10字节位置.也就是扩展头往下数一行就是OEP. OEP所在位置是一行零4个字节.
    ImageBase 基址. 指明了PE加载时候的基址.基址+ OEP就能确定代码在哪里开始运行. 0x1c位置处.也就是扩展头下数一行零12个字节,下面4个字节就是Image. Image所在位置是2行位置.
    SectionAlignment 内存对齐,PE加载到内存中所需要的对齐值. 在扩展头两行位置处.往下数4个字节就是. 所在位置两行零4个字节
    FileAlignment 文件对齐,PE存放在文件中的数据的对齐值.扩展头两行零4个字节位置. 所在位置是两行零八个字节.也就是两行半.
     SizeOfImage PE的镜像大小. 扩展头 三行半位置往下数4个字节 所在位置.三行零12字节位置处.
    SizeOfHeaders DOS头+NT头+节表的大小.按照文件对齐放在文件中的成员. 三行零12字节位置处往下数4个字节. 所在位置是4行位置.
    
    
    NumberOfRvaAndSizes 数据目录大小.所在位置六行位置处 下面都是数据目录了.数据目录指明了导入表导出表等等一些列的表格位置

    关于扩展头.重要成员就这么多. 主要就是熟悉各成员之间的关系.

    sizeofImage 跟 内存对齐成员有关 sizeofImage / sectionAlignment == 0
    sizeofHeaders 头大小.跟文件对齐有关 SizeofHeaders / FileAlignment == 0

    五丶数据目录

      数据目录在我们的扩展头中.作为一个子结构体存放

    typedef struct _IMAGE_DATA_DIRECTORY {
        DWORD   VirtualAddress;
        DWORD   Size;
    } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

    数据目录的作用就是指明了PE文件的导入表.导出表等等一些列表格在哪里存放. 有两个成员.一个是虚拟地址.一个是大小.



     
     
     
     
  • 相关阅读:
    android studio 提示翻译
    mysql-You can’t specify target table for update in FROM clause错误
    echarts-案例
    maven-过滤不打入包的文件
    neo4j关闭和开启密码访问权限
    linux-crontab定时任务
    neo4j-备份、恢复
    windows和linux执行class
    mvn-打jar运行包(含环境变量配置)
    mysql-netstat
  • 原文地址:https://www.cnblogs.com/iBinary/p/9714965.html
Copyright © 2011-2022 走看看