解密系列(系统篇_PE结构详解笔记3)

来源:互联网 发布:布雷克.格里芬数据 编辑:程序博客网 时间:2024/06/12 01:49
     IMAGE_OPTIONAL_HEADER32 叫可选映象头结构,定义在IMAGE_FILE_HEADER结构里面的第三个字段。虽然名字上说是可选的,但是它要与IMAGE_OPTONAL_HEADER结合起来,才是一个完整的“PE文件结构”。
    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;

    
AddressOfEntryPoint字段:文件被执行时的入口地址,这是一个RVA(相对虚拟地址)。如果在一个可执行文件上想附加一段代码让它先被执行,就只需将入口地址指向附加的代码即可。
    
ImageBase字段:当我们文件被执行的时候,如果可能的话,系统由优先将文件装入到由ImageBase字段指定的地址中,只有指定的地址已经被其他模块使用时,文件才被装到其他地址中。对于EXE来说,每个文件总是使用独立的虚拟地址空间,优先装入地址不可能被其他模块占据,也就意味着EXE文件不在需要重定位信息。但对于DLL来说,多个DLL文件全部使用宿主EXE文件的地址空间,不能保证优先装入地址没有被其他的DLL使用,所以DLL文件必须包含重定位信息以防万一。
    
SectionAlignment字段和FileAlignment字段前一个字段指定节被装入内存后的对齐单位,也就是说,每个节被装入的地址必须是本子段指定数值的整数倍。而后一个字段指定节存储在磁盘文件中的对齐单元。
    Subsystem字段:这个程序需要的是哪种子系统,是图形界面的还是控制台界面等。
    DataDirectory字段:这是最重要的字段之一,是我们的数据目录表。我们的整个程序要么就是代码要么就是数据,这个字段事实上是一个数组,有十六个元素,在这个字段前面有NumberOfRvaAndSizes字段,定义的是数据目录的项数。这十六个元素到底是干嘛的呢?先看这个IMAGE_DATA_DIRECTORY结构:
    
typedef struct _IMAGE_DATA_DIRECTORY
    {
        DWORD VirtualAddress;    //数据起始的RVA
        DWORD Size;        //数据块的长度
    } IMAGE_DATA_DIRECTORY,*PIMAGE_DATA_DIRECTORY;

    
    十六个成员分别如上,我们主要需要了解的是导出表和导入表、资源表、重定位表, 当我们的程序要需要用到什么DLL的某个函数时,就需要将这个DLL装入内存,然后将相应的函数地址放到导出表和导入表中,资源表存放的东西很多,例如说鼠标的类型、图片的类型等等,重定位后面再说。
    当我们写一个病毒的时候,病毒需要用到的一些函数,可能就存在导出表和导入表中,我们需要窃取这些函数,然后使用,神不知鬼不觉。总之, 
在PE文件中寻找特定的数据时,我们就要通过这个数据目录表,查找指定的数据块,从中获取数据。
0 0
原创粉丝点击