PE文件格式各个头部结构

pe文件格式

Dos头

Dos头数据格式定义如下

typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header
    WORD   e_magic;                     // Magic number (固定标志,不会变的标志)4D5A MZ,用来判断是否是DOS程序的
    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;                    // DOS代码的执行位置,16位DOS下告知程序无法运行
    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 (PE文件头偏移,文件偏移值FA)
  } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

在32位程序下,有用的就是2个字段,一个是第一个字段标志和最后一个字段指向PE文件头格式的偏移值

NT头

NT头数据结构定义如下:包含文件头和选项头

typedef struct _IMAGE_NT_HEADERS {
    DWORD Signature;                           //固定值 PE文件标志4个字节
    IMAGE_FILE_HEADER FileHeader;              //文件头结构体
    IMAGE_OPTIONAL_HEADER32 OptionalHeader;    //选项头结构体(注意这个结构体是变长的)所以要偏移到下一个数据段的时候,跳过这个就不能写加sizeof IMAGE_OPTIONAL_HEADER32 (结构体大小为E0)不然读取PE文件格式就出错
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32; 

文件头数据结构定义如下

typedef struct _IMAGE_FILE_HEADER {
    WORD    Machine;                         //CPU类型        不可更改
    WORD    NumberOfSections;                //节数量         可以更改
    DWORD   TimeDateStamp;                   //文件创建时间   可以更改
    DWORD   PointerToSymbolTable;            //符号表偏移     可以更改
    DWORD   NumberOfSymbols;                 //符号数量       可以更改
    WORD    SizeOfOptionalHeader;            //指定选项头大小 可以更改
    WORD    Characteristics;                 //文件属性       不可更改
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

可以利用字段SizeOfOptionalHeader修改选项头大小实现反调试,因为调试器大部分解析PE文件的时候是固定用sizeof IMAGE_OPTIONAL_HEADER32(E0)去解析的选项头大小的,所以你修改后,文件格式变了,调试器解析就会出问题,记住只能增加选项头大小,而不能缩小,因为选项头缩小那原来的数据就破坏了,肯定会有问题

**注意点:**修改后比较麻烦的是文件内所有涉及文件偏移的位置都要减去增加部分的偏移,这样才能保证原来的偏移访问的位置是正确的

文件头最后一个字段Characteristics(文件属性)是按位查看的,如第14位为1则是0x2000,表示是一个dll文件,这个字段可以区分文件是dll还是exe

#define IMAGE_FILE_RELOCS_STRIPPED           0x0001  // Relocation info stripped from file.
#define IMAGE_FILE_EXECUTABLE_IMAGE          0x0002  // File is executable  (i.e. no unresolved external references).
#define IMAGE_FILE_LINE_NUMS_STRIPPED        0x0004  // Line nunbers stripped from file.
#define IMAGE_FILE_LOCAL_SYMS_STRIPPED       0x0008  // Local symbols stripped from file.
#define IMAGE_FILE_AGGRESIVE_WS_TRIM         0x0010  // Aggressively trim working set
#define IMAGE_FILE_LARGE_ADDRESS_AWARE       0x0020  // App can handle >2gb addresses
#define IMAGE_FILE_BYTES_REVERSED_LO         0x0080  // Bytes of machine word are reversed.
#define IMAGE_FILE_32BIT_MACHINE             0x0100  // 32 bit word machine.
#define IMAGE_FILE_DEBUG_STRIPPED            0x0200  // Debugging info stripped from file in .DBG file
#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP   0x0400  // If Image is on removable media, copy and run from the swap file.
#define IMAGE_FILE_NET_RUN_FROM_SWAP         0x0800  // If Image is on Net, copy and run from the swap file.
#define IMAGE_FILE_SYSTEM                    0x1000  // System File.
#define IMAGE_FILE_DLL                       0x2000  // File is a DLL.
#define IMAGE_FILE_UP_SYSTEM_ONLY            0x4000  // File should only be run on a UP machine
#define IMAGE_FILE_BYTES_REVERSED_HI         0x8000  // Bytes of machine word are reversed.

选项头数据结构如下

//YES:表示可以改  NO:表示不能改  RES:表示能改但是有限制

typedef struct _IMAGE_OPTIONAL_HEADER 
{
    WORD    Magic;               //NO 机器型号,判断是 PE是 32位还是 64位
    BYTE    MajorLinkerVersion;        //YES 链接器版本号高版本
    BYTE    MinorLinkerVersion;        //YES 链接器版本号低版本,组合起来就是 5.12 其中 5是高版本,C是低版本
    DWORD   SizeOfCode;            //YES 代码节的总大小(512为一个磁盘扇区)
    DWORD   SizeOfInitializedData;      //YES 初始化数据的节的总大小,也就是.data
    DWORD   SizeOfUninitializedData;     //YES 未初始化数据的节的大小,也就是.data?
    DWORD   AddressOfEntryPoint;       //NO 程序执行入口地址(OEP) RVA(相对虚拟偏移地址)
    DWORD   BaseOfCode;            //YES 代码的节的起始 RVA(相对偏移)也就是代码区的偏移,偏移+模块首地址定位代码区
    DWORD   BaseOfData;            //YES 数据结的起始偏移(RVA),同上
    DWORD   ImageBase;             //YES 程序的建议模块基址(意思就是说作参考用的,模块建议基址如果被使用了就会使用别的地址)
    DWORD   SectionAlignment;        //RES 内存中的节对齐 一般是0x1000 
    DWORD   FileAlignment;          //RES 文件中的节对齐 一般是0x200
    WORD    MajorOperatingSystemVersion;  //YES 操作系统版本号高位
    WORD    MinorOperatingSystemVersion;  //YES 操作系统版本号低位
    WORD    MajorImageVersion;        //YES PE版本号高位
    WORD    MinorImageVersion;        //YES PE版本号低位
    WORD    MajorSubsystemVersion;      //NO 子系统版本号高位
    WORD    MinorSubsystemVersion;      //YES 子系统版本号低位
    DWORD   Win32VersionValue;        //YES 32位系统版本号值,注意只能修改为4 5 6表示操作系统支持nt4.0 以上,5的话依次类推
    DWORD   SizeOfImage;            //RES 整个程序也就是整PE文件在内存中占用的空间(包含PE映射尺寸)
    DWORD   SizeOfHeaders;           //RES 所有头大小(头的结构体大小)+节表结构体大小,记得值一定是文件对齐值的倍数,也就是到第一节区实际位置的偏移
    DWORD   CheckSum;              //YES 校验和,对于驱动程序,可能会使用
    WORD    Subsystem;             //NO 文件的子系统 :0x02表示窗口程序
    WORD    DllCharacteristics;        //NO DLL文件属性,也可以成为特性,可能DLL文件可以当做驱动程序使用
    DWORD   SizeOfStackReserve;        //RES 预留的栈的大小
    DWORD   SizeOfStackCommit;         //RES 立即申请的栈的大小(分页为单位)
    DWORD   SizeOfHeapReserve;         //RES 预留的堆空间大小
    DWORD   SizeOfHeapCommit;         //RES 立即申请的堆的空间的大小
    DWORD   LoaderFlags;            //YES 与调试有关
    DWORD   NumberOfRvaAndSizes;        //RES 下面数据目录的数量:0x10表示有16个
    IMAGE_DATA_DIRECTORY DataDirectory[16]; //RES 数据目录,默认16个,可以查看宏*/
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

数据目录项IMAGE_DATA_DIRECTORY 定义如下

typedef struct _IMAGE_DATA_DIRECTORY 
{
    DWORD   VirtualAddress;                //相对虚拟地址RVA 
    DWORD   Size;                          //大小
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

重点关注的数据目录项有几个

	   IMAGE_DIRECTORY_ENTRY_EXPORT          0   // 导出表
       IMAGE_DIRECTORY_ENTRY_IMPORT          1   // 导入表
       IMAGE_DIRECTORY_ENTRY_RESOURCE        2   // 资源表
       IMAGE_DIRECTORY_ENTRY_BASERELOC       5   // Base Relocation Table
       IMAGE_DIRECTORY_ENTRY_TLS             9   // TLS Directory
       IMAGE_DIRECTORY_ENTRY_IAT            12   // 导入表地址

节表头

节表头的数据结构定义如下

typedef struct _IMAGE_SECTION_HEADER
{
    BYTE    Name[IMAGE_SIZEOF_SHORT_NAME];  //YES 节区的名字 8个字节
    union
    {
            DWORD   PhysicalAddress;          
            DWORD   VirtualSize;        //YES 节区在内存的大小,实际值是按内存对齐算
    } Misc;
    DWORD   VirtualAddress;          //虚拟地址 节区的 RVA地址(拷到内存中哪个位置)
    DWORD   SizeOfRawData;           //在文件中对齐的尺寸(拷多大)
    DWORD   PointerToRawData;         //在文件中的偏移FA(从文件哪里开始拷)
    DWORD   PointerToRelocations;       //在 OBJ文件中使用
    DWORD   PointerToLinenumbers;      //行号表位置,调试使用
    WORD    NumberOfRelocations;       //在 OBJ文件中使用
    WORD    NumberOfLinenumbers;        //行号表的数量
    DWORD   Characteristics;         //节的属性
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

添加节表操作
1修改_IMAGE_FILE_HEADER中的节数量
2修改_IMAGE_OPTIONAL_HEADER中的程序占用空间大小
3结表末尾增加一个节表结构体
4按实际文件偏移填写结构体各成员值

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值