PE文件学习(一)

         PE是Portable executable(可移植的可执行文件)的简写,在Windows系统中PE文件是一种重要的文件格式,其中COM、PIF、SCR、EXE、dll等都是PE文件。所以学习PE文件是了解操作系统工作方式的一种很好的方法。   

        学习PE,首先要对PE有个大体的轮廓,所以本人在网上找到了两张PE文件结构图。基于这两张图更进一步的了解PE文件结构:

        

         从图中不难看出,DOS头和PE头是由一个个的结构体构成的。不同的结构体中保存着不同的信息,一个结构体又包含着另一个结构体。通过这两张图,我们能对PE有个大概的轮廓了。

         今天主要是对PE有个大概的了解,所以只是将其中的一部分结构体列出。

         首先是MS—DOS头:

typedef  struct _IMAGE_DOS_HEADER{
WORD  e_magic;
WORD  e_cblp;
WORD  e_cp;
WORD  e_crlc;
WORD  e_cparhdr;
WORD  e_minalloc;
WORD  e_maxalloc;
WORD  e_ss;
WORD  e_sp;
WORD  e_csum;
WORD  e_ip;
WORD  e_cs;
WORD  e_lfarlc;
WORD  e_ovno;
WORD  e_res[4];
WORD  e_oemid;
WORD  e_oeminfo;
WORD  e_res2[10];
WORD  e_lfanew;
}IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

    第一个成员则e_magic是帮助我们确定这是否是MS—DOS系统下的可执行文件

    其中最后一个成员e_lfanew能帮我们找到PE文件头。e_lfanew的偏移地址一般都是0x3C。这里用到的工具是010Editor

   

F0的地址即是PE文件头的开始地址:



            PE文件头结构体:

typedef struct  _IMAGE_NT_HEADERS{
DWORD  Signature;      // PE标志
IMAGE_FILE_HEADER FileHeader;   //文件头
IMAGE_OPTIONAL_HEADER32  OptionalHeader;  //扩展头
}IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
           其中的Signature是PE文件头的标识内容总是0x50450000,ASCII码也就是PE00.

           IMAGE_FILE_HEADER结构体:

typedef  struct  _IMAGE_FILE_HEADER{
WORD  Machine;                 //运行平台
WORD  NumberOfSections;        //区段数量
DWORD  TimeDateStamp;          //文件的创建时间
DWORD  PointerToSymbolTable;   //符号表指针
DWORD  NumberOfSymbols;        //符号的数量
WORD   SizeOfOptionalHeader;   //扩展头的大小
WORD   Characteristics;        //文件属性
}IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

    其中的NumberOfSections和SizeOfOptionalHeader相对来说更需要关注,一个是区段的数量,一个是扩展头的大小。


          IMAGE_OPTIONAL_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;


 

其中的AddressOfEntryPoint和ImageBase是更需要关注的 一个是程序执行入口的RVA,一个是程序的首选装载基址。

         _IMAGE_SECTION_HEADER 区块结构体

typedef  struct  _IMAGE_SECTION_HEADER{
   BYTE  Name[IMAGE_SIZEOF_SHORT_NAME];
 union{
             DWORD  PhysicalAddress;
             DWORD  VirtualSize;
           }Misc;
DWORD  VirtualAddress;
DWORD  SizeOfRavData;
DWORD  PointerToRawData;
DWORD  PointerToRelocations;
DWORD  PointerToLinenumbers;
WORD    NumberOfRelocations;
WORD    NumberOfLinenumbers;
DWORD  Characteristics;
}  IMAGE_SECTION_HEADER,  *PIMAGE_SECTION_HEADER;
其中的VirtualAddress、SizeOfRavData、PointerToRelocations和Characteristics更需要关注。

      区段映射到内存地址将会改变。这就是区段对齐,也是遵循页对齐机制使得区段在内存中地址发生改变。

      虚拟内存地址 = 装载基址 + 相对虚拟地址(RVA)

      这些结构体是其中的一部分结构体,其余的结构体均在 IMAGE_OPTIONAL_HEADER结构体 的资源目录表中。资源目录表中的结构体也将是第二篇笔记要记录的内容了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值