zoukankan      html  css  js  c++  java
  • PE文件

     Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html

    PE文件

    1. DOS头文件

    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;

    2. NT头

    NT头包括三类:PE指纹、NT文件头、NT可选头

    typedef struct _IMAGE_NT_HEADERS {
        DWORD Signature;
        IMAGE_FILE_HEADER FileHeader;
        IMAGE_OPTIONAL_HEADER32 OptionalHeader;
    } IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

      1)NT文件头

      typedef struct _IMAGE_FILE_HEADER {
        WORD    Machine;  // 可以运行在什么CPU上
        WORD    NumberOfSections;  // 表示节的数量
        DWORD   TimeDateStamp;  // 编译时间
        DWORD   PointerToSymbolTable; // 调试相关
        DWORD   NumberOfSymbols; // 调试相关
        WORD    SizeOfOptionalHeader; // 可选头PE的大小
        WORD    Characteristics; // 文件属性(动态机制可以被修改)
      } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

      2)NT文件头

      typedef struct _IMAGE_OPTIONAL_HEADER {
          WORD    Magic; // 32位 或 64位
          BYTE    MajorLinkerVersion; // 链接器主版本号
          BYTE    MinorLinkerVersion; // 链接器次版本号
          DWORD   SizeOfCode;  // 代码节数据总和
          DWORD   SizeOfInitializedData; // 初始化的数据总和
          DWORD   SizeOfUninitializedData; // 未初始化的数据总和
          DWORD   AddressOfEntryPoint; // 代码执行入口
          DWORD   BaseOfCode; //  代码开始的基址 编译器填写 没有
          DWORD   BaseOfData; //  数据开始的基址 编译器填写 没有
          DWORD   ImageBase; // 内存镜像基址
          DWORD   SectionAlignment; // 内存对齐
          DWORD   FileAlignment; // 文件对齐
          WORD    MajorOperatingSystemVersion; // 操作系统主版本号
          WORD    MinorOperatingSystemVersion; // 操作系统次版本号
          WORD    MajorImageVersion; // PE文件自身主版本号
          WORD    MinorImageVersion; // PE文件自身次版本号
          WORD    MajorSubsystemVersion; // 运行时所需子系统版本号
          WORD    MinorSubsystemVersion; // 运行时所需子系统版本号
          DWORD   Win32VersionValue; // 子系统版本的值 必须为0
          DWORD   SizeOfImage;  // 内存中整个PE文件的映射的尺寸
          DWORD   SizeOfHeaders; // 所有头+节表对齐后的大小,否则加载会出错
          DWORD   CheckSum; // 校验和 一些系统文件有要求,用来判断文件是否被修改
          WORD    Subsystem; // 子系统 驱动(1) 图形(2) 控制台、DLL(3)
          WORD    DllCharacteristics; // 文件特性(不是针对DLL)
          DWORD   SizeOfStackReserve; // 初始化时保留的栈大小
          DWORD   SizeOfStackCommit; // 初始化时实际提交的栈大小
          DWORD   SizeOfHeapReserve; // 初始化时保留的堆大小
          DWORD   SizeOfHeapCommit; // 初始化时实际提交的大小
          DWORD   LoaderFlags; // 调试目录
          DWORD   NumberOfRvaAndSizes; // 目录项数据
          IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
      } IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

    3.PE节表

      NT可选头最后部分有一个 IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]

      typedef struct _IMAGE_SECTION_HEADER {
          BYTE    Name[IMAGE_SIZEOF_SHORT_NAME]; // 节区名称,可自定义,只截取前8个
          union {              // 该节没有对齐前的真实尺寸,该值可以不准确
                  DWORD   PhysicalAddress;
                  DWORD   VirtualSize;
          } Misc;
          DWORD   VirtualAddress;     // 在内存中的偏移地址,加上ImageBase才是真正的内存地址
          DWORD   SizeOfRawData;    // 节在文件中对齐后的尺寸
          DWORD   PointerToRawData;    // 节在文件中对齐后的尺寸
          DWORD   PointerToRelocations;    // 节区在文件中的偏移
          DWORD   PointerToLinenumbers;   
          WORD    NumberOfRelocations;
          WORD    NumberOfLinenumbers;
          DWORD   Characteristics;              // 节的属性
      } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

      1)没有初始值的全局变量,在文件中没有位置,但一旦加载到内存其会存在位置。

     

    4. RVA 与 FOA 的转换

      RVA 相对虚拟地址 FOA 文件偏移地址

      

    5. 导出表

      typedef struct _IMAGE_EXPORT_DIRECTORY {
          DWORD   Characteristics;
          DWORD   TimeDateStamp;
          WORD    MajorVersion;
          WORD    MinorVersion;
          DWORD   Name;        //
          DWORD   Base;        // 基数
          DWORD   NumberOfFunctions;
          DWORD   NumberOfNames;
          DWORD   AddressOfFunctions;     // 函数地址表
          DWORD   AddressOfNames;         // 名称地址表
          DWORD   AddressOfNameOrdinals;  // 名称序号表
      } IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;

      其操作如下图所示:

      

      ① 如果直接用序号来找函数,直接搜索函数地址表即可,因为其是按照函数索引来进行排序的。

      ② 函数名称表,其是按照字母顺序排序的,其结合函数序号表来进行找到其地址。

        比如找Plus函数,其通过名字对比其在函数表中的第2个位置,其查表Table[2] = 0,则说明其在函数地址表中第0号位置,很轻松能定位到函数。

    6. 函数地址表

      

      ① 导入表是一串连续的_IMAGE_IMPORT_DESCRIPTOR导出数组,一个DLL存在一个这种数组,直到0为止。

      ② _IMAGE_THUNK_DATA 看最高位,如果是1则表示序号,并且将最高位清0,如果最高位不是1,则其指向如下数据结构

        typedef struct _IMAGE_IMPORT_BY_NAME {
             WORD    Hint;
             CHAR   Name[1];
        } IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;

        其中连续的名字是以零结尾。

      ③ 注意,我们从函数导出表中并没法看到其对应的函数地址,这是当然的,既然导入表,我们没有DLL,其通过名字和序号完成创建的。

    7. 重定位表

      注意,全局变量直接计算一个伪地址写入到硬编码中的,因此其必须要重定位。

      重定位的结构为 _IMAGE_BASE_RELOCATION

      typedef struct _IMAGE_BASE_RELOCATION {

        DWORD   VirtualAddress;
        DWORD   SizeOfBlock;
      } IMAGE_BASE_RELOCATION;

      其并不是这么简单,其实质是重定位块,SizeOfBlock表示重定位块的大小,当下一个重定位块为0时则表示重定位表的结束。

      

    8. DLL文件的加载过程

      ① 扫描母进程的输入表,查看需要加载进入母进程地址空间的DLL和数量;

      ② 扫描循环加载所有的DLL文件,当DLL被加载完成后,从导入表中查找所需要的函数,

        在DLL文件的输出表中搜索,定位后,将得到的地址放入母函数的IAT表中,依次循环,直到将所有的DLL函数定位;

      ③ 将DLL中重定位表中的内容重新定位;

      ④ 完成对接。

  • 相关阅读:
    Windows Server 2003 SP2(32位) 中文版 下载地址 光盘整合方法
    用Recycle()方法对Java对象的重要性
    Lotus中千奇百怪的 $$
    Developing a simple application using steps "User Decision" and "Mail"(1) 沧海
    沟通中的情绪管理(演讲稿) 沧海
    人只有在压力之下,才可能成功,没做一件事,都必须成功,不许言败 沧海
    什么是IDOC,以及IDOC的步骤 沧海
    VS2008 Professional Edition CHS中的deffactory.dat读取错误 沧海
    Including custom text in the step "User Decision" 沧海
    SAP Upgrade Strategy 沧海
  • 原文地址:https://www.cnblogs.com/onetrainee/p/12642510.html
Copyright © 2011-2022 走看看