zoukankan      html  css  js  c++  java
  • 学破解 <二> PE格式之IMAGE_NT_HEADERS

    这个IMAGE_NT_HEADERS其实就是PE相关结构的映像头,NT据我揣测应该是New Technology的缩写,区分于DOS WIN9X的新技术,您老要是非觉得是NTR什么的也没关系。
    IMAGE_NT_HEADERS的结构是这个样子的
     
    IMAGE_NT_HEADERS STRUCT  
    {  
    +0h     DWORD    Signature 
    +4h         IMAGE_FILE_HEADER    FileHeader 
    +18h        IMAGE_OPTIONAL_HEADER32    OptionalHeader 
    } IMAGE_NT_HEADERS ENDS 
    其中包含两个子结构体,和一个标志。
    其中Signature字段被设置成00004550h ,ASCII码为PE00 ,标志着PE头文件的开始。上一篇中DOS头结构体中的e_lfanew正是指向这里。
     
    IMAGE_FILE_HEADER这个结构是这样的
     
    typedef     struct _IMAGE_FILE_HEADER  

    +04h    WORD        Machine;                                // 运行平台 
    +06h    WORD        NumberOfSections;       // 文件的区块数目 
    +08h    DWORD   TimeDateStamp;          // 文件创建日期和时间 
    +0Ch    DWORD   PointerToSymbolTable;       // 指向符号表(主要用于调试) 
    +10h    DWORD   NumberOfSymbols;        // 符号表中符号个数(同上) 
    +14h    WORD        SizeOfOptionalHeader;       // IMAGE_OPTIONAL_HEADER32 结构大小 
    +16h    WORD        Characteristics;            // 文件属性 
    } IMAGE_FILE_HEADER,  *PIMAGE_FILE_HEADER; 
     
    Machine 代表了CPU的类型 ,定义在windows.h中
     
      #define IMAGE_FILE_MACHINE_UNKNOWN  0 
    #define IMAGE_FILE_MACHINE_I386    0x014c // Intel 386. 
    #define IMAGE_FILE_MACHINE_R3000   0x0162 // MIPS little-endian, 0x160 big-endian 
    #define IMAGE_FILE_MACHINE_R4000   0x0166 // MIPS little-endian 
    #define IMAGE_FILE_MACHINE_R10000   0x0168 // MIPS little-endian 
    #define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169 // MIPS little-endian WCE v2 
    #define IMAGE_FILE_MACHINE_ALPHA   0x0184 // Alpha_AXP 
    #define IMAGE_FILE_MACHINE_POWERPC  0x01F0 // IBM PowerPC Little-Endian 
    #define IMAGE_FILE_MACHINE_SH3    0x01a2 // SH3 little-endian 
    #define IMAGE_FILE_MACHINE_SH3E    0x01a4 // SH3E little-endian 
    #define IMAGE_FILE_MACHINE_SH4    0x01a6 // SH4 little-endian 
    #define IMAGE_FILE_MACHINE_ARM    0x01c0 // ARM Little-Endian 
    #define IMAGE_FILE_MACHINE_THUMB   0x01c2 
    #define IMAGE_FILE_MACHINE_IA64    0x0200 // Intel 64 
    #define IMAGE_FILE_MACHINE_MIPS16   0x0266 // MIPS 
    #define IMAGE_FILE_MACHINE_MIPSFPU  0x0366 // MIPS 
    #define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466 // MIPS 
    #define IMAGE_FILE_MACHINE_ALPHA64  0x0284 // ALPHA64 
    #define IMAGE_FILE_MACHINE_AXP64   IMAGE_FILE_MACHINE_ALPHA64 
     
    NumberOfSection 代表区块的数目,区块表紧跟在IMAGE_NT_HEADERS后面,区块表大概是一个链表结构,链表长度由NumberOfSection的数值决定。
    TimeDataStamp 表明文件的创建时间
    SizeOfOptionalHeader 是IMAGE_NT_HEADERS的另一个子结构IMAGE_OPTIONAL_HEADER的大小,32位的PE文件这个值一般是00E0,64位的PE文件一般是00F0
    Characteristics 代表文件的属性EXE文件一般是0100h DLL文件一般是210Eh,多种属性可以用或运算同时拥有。
     
    #define IMAGE_FILE_RELOCS_STRIPPED     0x0001 // 重定位信息被移除 
    #define IMAGE_FILE_EXECUTABLE_IMAGE     0x0002 // 文件可执行 
    #define IMAGE_FILE_LINE_NUMS_STRIPPED    0x0004 // 行号被移除 
    #define IMAGE_FILE_LOCAL_SYMS_STRIPPED   0x0008 // 符号被移除 
    #define IMAGE_FILE_AGGRESIVE_WS_TRIM    0x0010 // Agressively trim working set 
    #define IMAGE_FILE_LARGE_ADDRESS_AWARE   0x0020 // 程序能处理大于2G的地址 
    #define IMAGE_FILE_BYTES_REVERSED_LO    0x0080 // Bytes of machine word are reversed. 
    #define IMAGE_FILE_32BIT_MACHINE      0x0100 // 32位机器 
    #define IMAGE_FILE_DEBUG_STRIPPED      0x0200 // .dbg文件的调试信息被移除 
    #define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400 // 如果在移动介质中,拷到交换文件中运行 
    #define IMAGE_FILE_NET_RUN_FROM_SWAP    0x0800 // 如果在网络中,拷到交换文件中运行 
    #define IMAGE_FILE_SYSTEM          0x1000 // 系统文件 
    #define IMAGE_FILE_DLL           0x2000 // 文件是一个dll 
    #define IMAGE_FILE_UP_SYSTEM_ONLY      0x4000 // 文件只能运行在单处理器上 
    #define IMAGE_FILE_BYTES_REVERSED_HI     0x8000 // Bytes of machine word are reversed. 
     
    下面来编写一个程序来显示一下这个结构体
     
    #include "windows.h"                //PE的那一套结构体大多都是定义在这个头文件里的 
    #include "stdio.h" 
     
    int main(int argc, char* argv[]) 

        FILE *p; 
        LONG e_lfanew; //指向IMAGE_NT_HEADERS32结构在文件中的偏移 
        IMAGE_FILE_HEADER myfileheader; 
         
        p = fopen("test.exe","r+b"); 
        if(p == NULL)return -1; 
     
        fseek(p,0x3c,SEEK_SET); 
        fread(&e_lfanew,4,1,p); 
        fseek(p,e_lfanew+4,SEEK_SET); //指向IMAGE_FILE_HEADER结构的偏移PE的标志位是DWORD占4字节 
        fread(&myfileheader,sizeof(myfileheader),1,p); 
     
        printf("IMAGE_FILE_HEADER结构:\n"); 
        printf("Machine       : %04X\n",myfileheader.Machine); 
        printf("NumberOfSections  : %04X\n",myfileheader.NumberOfSections); 
        printf("TimeDateStamp    : %08X\n",myfileheader.TimeDateStamp); 
        printf("PointerToSymbolTable : %08X\n",myfileheader.PointerToSymbolTable); 
        printf("NumberOfSymbols   : %08X\n",myfileheader.NumberOfSymbols); 
        printf("SizeOfOptionalHeader : %04X\n",myfileheader.SizeOfOptionalHeader); 
        printf("Characteristics   : %04X\n",myfileheader.Characteristics); 
        getch(); 
        return 0; 

    总的来说IMAGE_FILE_HEADER是记录文件的各种信息的
     
    下面说一下IMAGE_OPTIONAL_HEADER结构,他是一个可选结构,是对IMAGE_FILE_HEADER的一个补充,当然很多情况下它是必须的。
     
    typedef struct _IMAGE_OPTIONAL_HEADER  

        // 
        // Standard fields.   
        // 
    +18h    WORD    Magic;         // 标志字, ROM 映像(0107h),普通可执行文件(010Bh) 
    +1Ah    BYTE      MajorLinkerVersion;     // 链接程序的主版本号 
    +1Bh    BYTE      MinorLinkerVersion;     // 链接程序的次版本号 
    +1Ch    DWORD   SizeOfCode;     // 所有含代码的节的总大小 
    +20h    DWORD   SizeOfInitializedData;    // 所有含已初始化数据的节的总大小 
    +24h    DWORD   SizeOfUninitializedData; // 所有含未初始化数据的节的大小 
    +28h    DWORD   AddressOfEntryPoint;    // 程序执行入口RVA 
    +2Ch    DWORD   BaseOfCode;      // 代码的区块的起始RVA 
    +30h    DWORD   BaseOfData;      // 数据的区块的起始RVA 
        // 
        // NT additional fields.    以下是属于NT结构增加的领域。 
        // 
    +34h    DWORD   ImageBase;      // 程序的首选装载地址 
    +38h    DWORD   SectionAlignment;      // 内存中的区块的对齐大小 
    +3Ch    DWORD   FileAlignment;      // 文件中的区块的对齐大小 
    +40h    WORD    MajorOperatingSystemVersion;  // 要求操作系统最低版本号的主版本号 
    +42h    WORD    MinorOperatingSystemVersion;  // 要求操作系统最低版本号的副版本号 
    +44h    WORD    MajorImageVersion;       // 可运行于操作系统的主版本号 
    +46h    WORD    MinorImageVersion;       // 可运行于操作系统的次版本号 
    +48h    WORD    MajorSubsystemVersion;  // 要求最低子系统版本的主版本号 
    +4Ah    WORD    MinorSubsystemVersion;  // 要求最低子系统版本的次版本号 
    +4Ch    DWORD   Win32VersionValue;       // 莫须有字段,不被病毒利用的话一般为0 
    +50h    DWORD   SizeOfImage;       // 映像装入内存后的总尺寸 
    +54h    DWORD   SizeOfHeaders;       // 所有头+ 区块表的尺寸大小 
    +58h    DWORD   CheckSum;       // 映像的校检和 
    +5Ch    WORD    Subsystem;       // 可执行文件期望的子系统 
    +5Eh    WORD    DllCharacteristics;       // DllMain()函数何时被调用,默认为0 
    +60h    DWORD   SizeOfStackReserve;       // 初始化时的栈大小 
    +64h    DWORD   SizeOfStackCommit;       // 初始化时实际提交的栈大小 
    +68h    DWORD   SizeOfHeapReserve;        // 初始化时保留的堆大小 
    +6Ch    DWORD   SizeOfHeapCommit;        // 初始化时实际提交的堆大小 
    +70h    DWORD   LoaderFlags;        // 与调试有关,默认为0  
    +74h    DWORD   NumberOfRvaAndSizes;  // 下边数据目录的项数,这个字段自Windows NT 发布以来        // 一直是16 
    +78h    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; 
           // 数据目录表 
    } IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32; 
     
    这个结构东西各种多啊···非常蛋疼,不过很多都是optional的,可以不用管他们,重要的就那么几个。
    AddressOfEntryPoint 指出文件执行时的入口地址,是一个RVA地址,就是大家常说的OEP,常常各种寻找的OEP,如果你有什么代码要先于程序主体执行,只需要将这个入口指向这段代码就行啦~
    ImageBase 指向文件的优先装入地址,一般情况EXE文件不需要重定位,DLL文件可能需要重定位。
    SectionAlignment 和FileAlignment 确定了内存中的节对齐单位和在磁盘中的节对齐单位。
    DataDirectory 成员是一个比较牛逼的成员,它由16个IMAGE_DATA_DIRCTORY结构组成,用来定义多种不通用处的数据块。
    这个结构体的内容很简单
     
    typedef struct _IMAGE_DATA_DIRECTORY { 
      DWORD VirtualAddress; 相对虚拟地址 
      DWORD Size;      大小 
    } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; 
    只有相对虚拟地址和大小两个成员。
     
    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; 
    IMAGE_NUMBEROF_DIRECTORY_ENTRIES 的值代表了数据块的用途
     
    #define IMAGE_DIRECTORY_ENTRY_EXPORT     0 // Export Directory 
    #define IMAGE_DIRECTORY_ENTRY_IMPORT     1 // Import Directory 
    #define IMAGE_DIRECTORY_ENTRY_RESOURCE    2 // Resource Directory 
    #define IMAGE_DIRECTORY_ENTRY_EXCEPTION   3 // Exception Directory 
    #define IMAGE_DIRECTORY_ENTRY_SECURITY    4 // Security Directory 
    #define IMAGE_DIRECTORY_ENTRY_BASERELOC   5 // Base Relocation Table 
    #define IMAGE_DIRECTORY_ENTRY_DEBUG     6 // Debug Directory 
    //   IMAGE_DIRECTORY_ENTRY_COPYRIGHT   7 // (X86 usage) 
    #define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE  7 // Architecture Specific Data 
    #define IMAGE_DIRECTORY_ENTRY_GLOBALPTR   8 // RVA of GP 
    #define IMAGE_DIRECTORY_ENTRY_TLS      9 // TLS Directory 
    #define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG  10 // Load Configuration Directory 
    #define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 // Bound Import Directory in headers 
    #define IMAGE_DIRECTORY_ENTRY_IAT      12 // Import Address Table 
    #define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 // Delay Load Import Descriptors 
    #define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 // COM Runtime descriptor 
     
    最后把这些结构·读出来看一看。
     
    #include "windows.h" 
    #include "stdio.h" 
     
    int main(int argc, char* argv[]) 

        FILE *p; 
        unsigned long Signature; 
        IMAGE_FILE_HEADER myfileheader; 
        IMAGE_DOS_HEADER mydosheader; 
        IMAGE_OPTIONAL_HEADER myoptionalheader; 
     
        p = fopen("test.exe","r+b"); 
        if(p == NULL)return -1; 
     
        fread(&mydosheader,sizeof(mydosheader),1,p); 
        fseek(p,mydosheader.e_lfanew,SEEK_SET); 
        fread(&Signature,sizeof(Signature),1,p); 
     
        fseek(p,mydosheader.e_lfanew+sizeof(Signature),SEEK_SET);//指向IMAGE_FILE_HEADER结构的偏移 
        fread(&myfileheader,sizeof(myfileheader),1,p); 
     
        fseek(p,mydosheader.e_lfanew+sizeof(Signature)+sizeof(myfileheader),SEEK_SET); 
        fread(&myoptionalheader,sizeof(myoptionalheader),1,p); 
     
        printf("%X\n",mydosheader.e_lfanew); 
     
        printf("Signature          : %04X\n",Signature); 
        printf("IMAGE_FILE_HEADER结构:\n"); 
        printf("Machine            : %04X\n",myfileheader.Machine); 
     
        printf("IMAGE_OPTIONALHEADER_HEADER结构:\n"); 
        printf("Magic       : %04X\n",myoptionalheader.Magic); 
     
    由于这个IMAGE_OPENTIONAL_HEADER结构成员太多,我就不都打出来了,Magic的值一般为010bH,由此可以判顿读取出的结构是否正确。

  • 相关阅读:
    很有意思的“老黄历”网站
    ubuntu
    getopt在Python中的使用
    系统变量TERM不知是用来干什么的?它的值有vt100,vt220等,这些值代表什么意思?
    >/dev/null 2>&1
    linux下常用的ftp服务器软件
    Windows环境下访问NFS
    linux iSCSI target配置全过程
    iSCSI target在安全方面相关设定
    folly学习心得
  • 原文地址:https://www.cnblogs.com/tk091/p/2456174.html
Copyright © 2011-2022 走看看