• 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中重定位表中的内容重新定位;

      ④ 完成对接。

  • 相关阅读:
    项目延期原因及应对之道
    我只是来刷屏的
    php学习1留言板的创建
    位运算
    hnu 12264 collisions
    数组和指针的区别
    hnu12263 Gluttonous robot
    解决Mac上安装Zookeeper问题:FAILED TO WRITE PID
    Dubbo问题记录:No provider available for the service xxx from registry localhost:9090
    SqlServer和mysql的日期函数备忘
  • 原文地址:https://www.cnblogs.com/onetrainee/p/12642510.html
Copyright © 2020-2023  润新知