zoukankan      html  css  js  c++  java
  • 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;                    //* NT头指针
      } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
    
    NT头:
    
    typedef struct _IMAGE_NT_HEADERS {
      DWORD                 Signature;       //*pe签名
      IMAGE_FILE_HEADER     FileHeader;      //*PE标准
      IMAGE_OPTIONAL_HEADER OptionalHeader;  //*PE可选头
    } IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS;        
    
    NT::标准PE头:
    
    typedef struct _IMAGE_FILE_HEADER {
        WORD    Machine;                     //*cpu识别
        WORD    NumberOfSections;            //*文件的节数目 (节表与节的数目一样)
        DWORD   TimeDateStamp;               //*文件创建日期和时间
        DWORD   PointerToSymbolTable;        //用于调试
        DWORD   NumberOfSymbols;             //用于调试
        WORD    SizeOfOptionalHeader;        //*PE可选头的大小,32位PE文件默认为E0h,64位PE文件默认大小为F0h 大小可以自定
        WORD    Characteristics;             //*关于文件信息的标记,比如文件是exe还是dll
    } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
    
    NT::可选PE头(32位下大小为E0 64位的为F0)
    
    typedef struct _IMAGE_OPTIONAL_HEADER
    
    {
            WORD Magic;                       //*说明文件类型:10B 32位下的PE文件        20B 64位下的PE文件
            BYTE MajorLinkerVersion;          //链接程序的主版本号
            BYTE MinorLinkerVersion;          //链接程序的次版本号
            DWORD SizeOfCode;                 //*所有含代码的节的总大小,必须是FileAlignment的整数倍 编译器填的 没用
            DWORD SizeOfInitializedData;      //*已初始化数据的大小 必须是FileAlignment的整数倍 编译器填的 没用
            DWORD SizeOfUninitializedData;    //*未初始化数据的大小 必须是FileAlignment的整数倍 编译器填的 没用
            DWORD AddressOfEntryPoint;        //*****程序执行入口RVA
            DWORD BaseOfCode;                 //*代码开始的基址, 编译器填的 没用
            DWORD BaseOfData;                 //*数据开始的基址, 编译器填的 没用
            DWORD ImageBase;                  //*****内存镜像基址
            DWORD SectionAlignment;           //*内存中的区块的对齐大小
            DWORD FileAlignment;              //*文件中的区块的对齐大小
            WORD MajorOperatingSystemVersion; //要求操作系统最低版本号的主版本号
            WORD MinorOperatingSystemVersion; //要求操作系统最低版本号的副版本号
            WORD MajorImageVersion;           //可运行于操作系统的主版本号
            WORD MinorImageVersion;           //可运行于操作系统的次版本号
            WORD MajorSubsystemVersion;       //要求最低子系统版本的主版本号,
            WORD MinorSubsystemVersion;       //要求最低子系统版本的次版本号
            DWORD Win32VersionValue;          //莫须有字段,不被病毒利用的话一般为0
            DWORD SizeOfImage;                //*内存中整个PE文件的映射尺寸,可以比实际值大,但必须是SectionAlignment的整数倍
            DWORD SizeOfHeaders;              //*所有头+节表按照文件对齐后的大小,否则加载会出错
            DWORD CheckSum;                   //*校验和,一些系统文件有要求,用来判断文件是否被修改
            WORD Subsystem;                   //可执行文件期望的子系统
            WORD DllCharacteristics;          //DllMain()函数何时被调用,默认为 0
            DWORD SizeOfStackReserve;         //*初始化时的栈大小
            DWORD SizeOfStackCommit;          //*初始化时实际提交的栈大小
            DWORD SizeOfHeapReserve;          //*初始化时保留的堆大小
            DWORD SizeOfHeapCommit;           //*初始化时实际提交的堆大小
            DWORD LoaderFlags;                //与调试有关,默认为 0
            DWORD NumberOfRvaAndSizes;        //下边数据目录的项数,这个字段自Windows NT 发布以来 一直是16
            IMAGE_DATA_DIRECTORY DataDirectory
                        [IMAGE_NUMBEROF_DIRECTORY_ENTRIES];// 数据目录表
    } IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
    
    节表:
    IMAGE_SIZEOF_SHORT_NAME组成,每个结构体代表一个节区
    
    #define IMAGE_SIZEOF_SHORT_NAME              
     
    typedef struct _IMAGE_SECTION_HEADER {
        BYTE    Name[IMAGE_SIZEOF_SHORT_NAME];   //8个字节 一般情况下是以“”结尾的ASCII码字符串来标识的名称 内容可以自定义 可能由于字母太多编译器不添加""需要注意
        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;
    
    注意:
                VirtualAddress 和 PointerToRawData 不带有任何值,分别由_IMAGE_OPTIONAL_HEADER中的SectionAlignment和FileAlignment确定
                VirtualSize和SizeOfRawData一般具有不同的值,即磁盘节区的大小与加载到内存的大小是不一样的。
                
    导入表(IAT)/ 导出表():
    
    typedef struct _IMAGE_IMPORT_DESCRIPTOR {
        _ANONYMOUS_UNION union {
            DWORD Characteristics;
    
            DWORD OriginalFirstThunk;            // INT的地址(Import Name Table)(RVA)
        } DUMMYUNIONNAME;                        //
        DWORD TimeDateStamp;                     //
        DWORD ForwarderChain;                    //
        DWORD Name;                              //库名称字符串的地址    (RVA)
        DWORD FirstThunk;                        // IAT的地址(Import Address Table)(RVA)
    } IMAGE_IMPORT_DESCRIPTOR,*PIMAGE_IMPORT_DESCRIPTOR;
    
    typedef struct _IMAGE_EXPORT_DIRECTORY {
        DWORD   Characteristics;
        DWORD   TimeDateStamp; // 时间戳
        WORD    MajorVersion;
        WORD    MinorVersion;
        DWORD   Name; // *指向该导出表文件名字符串
        DWORD   Base; // *导出函数起始序号
        DWORD   NumberOfFunctions; // *所有导出函数的个数
        DWORD   NumberOfNames; // *以函数名字导出的函数个数
        DWORD   AddressOfFunctions;     // *导出函数地址表RVA
        DWORD   AddressOfNames;         // *导出函数名称表RVA
        DWORD   AddressOfNameOrdinals;  // *导出涵数序号表RVA
    } IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
    
    
     
     
    注意: INT与IAT是长整型(4个字节数据类型)数组,以NULL结束 INT中各元素的值为IMAGE_IMPORT_BY_NAME结构体指针(有时IAT也拥有相同的值) INT与IAT的大小应相同 INT输入顺序: 1.读取IID的Name成员,获取库名称字符串("kernel32.dll") 2.装载相应库——————> LoadLibrary("kernel32.dll") 3.读取IID的OriginalFirstThunk成员,获取INT地址 4.逐一读取INT中数组的值,获取相应IMAGE_IMPORT_BY_NAME地址(RVA) 5.使用IMAGE_IMPORT_BY_NAME的Hint(ordinal) 或Name项,获取相应函数的起始地址。 GetProcAddress("GetCurrentThreadId") 6.读取IID的FirstThunk(IAT)成员,获得IAT地址 7.将上面获得的函数地址输入相应IAT数组值。 8.重复以上补助4~7,直到INT结束(遇到NULL时) RVA与RAW转换:     RAW = RAV - VirtualAddress + PointerToRawData     物理地址 = 内存相对地址 - 内存节区的起始地址 + 物理节区的起始位置
  • 相关阅读:
    Inline Hook 钩子编写技巧
    FPS 游戏实现D3D透视 (API Hook)
    FPS 游戏实现GDI透视 (三角函数)
    X86驱动:恢复SSDT内核钩子
    X86驱动:挂接SSDT内核钩子
    VS2013+WDK8.1 驱动开发环境配置
    C/C++ 语言之反汇编揭秘:目录
    WinRAR 去广告的姿势
    C/C++ 实现反调试的手段
    springboot项目部署到独立tomcat的爬坑集锦
  • 原文地址:https://www.cnblogs.com/zheh/p/4143889.html
Copyright © 2011-2022 走看看