PE知识学习(二,三)

PE知识学习(二)


上一贴我们了解了pe头部的dos部首部分,我们知道在这个结构里e_magic和e_lfanew这两个域对我们来说很重要.同时我们也提到了e_lfanew域指向IMAGE_NT_HEADERS32结构在pe文件的偏移.
补充声明一下:这里的知识是适用于32位字的机器上的.

下面我们接着看IMAGE_NT_HEADERS32结构,这个部分在pe文件的学习里至关重要.

IMAGE_NT_HEADERS32的结构定义如下:

typedef struct _IMAGE_NT_HEADERS {
DWORD Signature;             **PE文件标识 "PE",0,0
IMAGE_FILE_HEADER FileHeader;      **映像文件头
IMAGE_OPTIONAL_HEADER32 OptionalHeader; **映像可选头
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

这其中又包含了两个结构.我们一点一点的往下看.
IMAGE_FILE_HEADER这个结构的定义如下:
typedef struct _IMAGE_FILE_HEADER {
00h  WORD  Machine;          **运行平台
02h  WORD  NumberOfSections;     **区块数目
06h  DWORD  TimeDateStamp;       **文件日期时间戳
0Ah  DWORD  PointerToSymbolTable;   **指向符号表
0Eh  DWORD  NumberOfSymbols;      **符号表中的符号数量
12h  WORD  SizeOfOptionalHeader;   **映像可选头结构的大小
14h  WORD  Characteristics;      **文件特征值
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

我们看一下这几个域:

1) Machine域说明这个pe文件在什么CPU上运行,具体如下:
#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

2) NumberOfSections
pe文件中区块的数量,关于区块下面还要讲到,这里先有个印象就可以了.

3)TimeDateStamp
文件日期时间戳,指这个pe文件生成的时间,它的值是从1969年12月31日16:00:00以来的秒数.

4)PointerToSymbolTable
Coff调试符号表的偏移地址.

5)NumberOfSymbols
Coff符号表中符号的个数. 这个域和前个域在release版本的程序里是0.

6)SizeOfOptionalHeader
IMAGE_OPTIONAL_HEADER32结构的大小(即多少字节).我们接着就要提到这个结构了.事实上,pe文件的大部分重要的域都在IMAGE_OPTIONAL_HEADER结构里.

7)Characteristics
这个域描述pe文件的一些属性信息,比如是否可执行,是否是一个动态连接库等.具体定义如下:
#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.
一个pe文件的特征值就是这些属性值加在一起的.

希望这些没有让你头晕,其实内容不多,只是一个IMAGE_FILE_HEADER结构,而这个结构包含7个域而已.
让我们先熟悉这个结构,我们编个程序来显示这些信息.

#include "stdafx.h"
#include "windows.h"
#include "stdio.h"
#include "conio.h"

int main(int argc, char* argv[])
{
FILE *p;
LONG e_lfanew; //指向IMAGE_NT_HEADERS32结构在文件中的偏移
IMAGE_FILE_HEADER myfileheader;

p = fopen("test1.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结构的偏移
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;
}

此程序在win98 + vc6.0 环境下编译通过.


pe知识学习(三)



前两个贴子我们已经介绍了pe文件的两个结构,希望还没有让你看晕.下面我把pe文件的结构列出来,让我们有个全局的印象.
_______________________________
|  IMAGE_DOS_HEADER     |    <-- Dos部首
-------------------------------
|  PE,0,0         |    <-- PE文件标志
-------------------------------
|  IMAGE_FILE_HEADER     |    <-- 映像文件头
-------------------------------
|  IMAGE_OPTIONAL_HEADER32  |    <-- 映像可选头
-------------------------------
|  Section Table       |    <-- 节表
-------------------------------
|  .text           |    <-- 代码区段
-------------------------------
|  .data           |    <-- 数据区段
-------------------------------
|  .idata          |    <-- 输入表
-------------------------------
|  .edata          |    <-- 输出表
-------------------------------
|  .reloc          |    <-- 重定位表区段
-------------------------------
|  ....           |
-------------------------------
|  调试信息         |
-------------------------------

好了,我们接着看看IMAGE_OPTIONAL_HEADER32结构.这个结构的域比较多,但是和后面要讲到的节表一样,非常重要.希望你能够用心体会,并动手实践一下.
IMAGE_OPTIONAL_HEADER32的结构定义如下:

typedef struct _IMAGE_OPTIONAL_HEADER {
//
// Standard fields.
//

00h WORD  Magic;          //幻数,32位pe文件总为010bh
02h BYTE  MajorLinkerVersion;   //连接器主版本号
03h BYTE  MinorLinkerVersion;   //连接器副版本号
04h DWORD  SizeOfCode;       //代码段总大小
08h DWORD  SizeOfInitializedData;  //已初始化数据段总大小
0ch DWORD  SizeOfUninitializedData; //未初始化数据段总大小
10h DWORD  AddressOfEntryPoint;   //程序执行入口地址(RVA)
14h DWORD  BaseOfCode;       //代码段起始地址(RVA)
18h DWORD  BaseOfData;       //数据段起始地址(RVA)

//
// NT additional fields.
//

1ch DWORD  ImageBase;        //程序默认的装入起始地址
20h DWORD  SectionAlignment;    //内存中区块的对齐单位
24h DWORD  FileAlignment;      //文件中区块的对齐单位
28h WORD  MajorOperatingSystemVersion; //所需操作系统主版本号
2ah WORD  MinorOperatingSystemVersion; //所需操作系统副版本号
2ch WORD  MajorImageVersion;    //自定义主版本号
2eh WORD  MinorImageVersion;    //自定义副版本号
30h WORD  MajorSubsystemVersion;  //所需子系统主版本号
32h WORD  MinorSubsystemVersion;  //所需子系统副版本号
34h DWORD  Win32VersionValue;    //总是0
38h DWORD  SizeOfImage;       //pe文件在内存中的映像总大小
3ch DWORD  SizeOfHeaders;      //从pe文件开始到节表(包含节表)的总大小
40h DWORD  CheckSum;        //pe文件CRC校验和
44h WORD  Subsystem;        //用户界面使用的子系统类型
46h WORD  DllCharacteristics;   //为0
48h DWORD  SizeOfStackReserve;   //为线程的栈初始保留的虚拟内存的默认值
4ch DWORD  SizeOfStackCommit;    //为线程的栈初始提交的虚拟内存的大小
50h DWORD  SizeOfHeapReserve;    //为进程的堆保留的虚拟内存的大小
54h DWORD  SizeOfHeapCommit;    //为进程的堆初始提交的虚拟内存的大小
58h DWORD  LoaderFlags;       //为0
5ch DWORD  NumberOfRvaAndSizes;   //数据目录结构数组的项数,总为 00000010h
60h IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
//数据目录结构数组
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;


下面再具体解释一下各个域的含义.不要闲罗嗦,后面这些知识实在是太重要了.
1)Magic 幻数,32位pe文件总为010bh
这个常数的定义如下:
#define IMAGE_NT_OPTIONAL_HDR32_MAGIC   0x10b
#define IMAGE_NT_OPTIONAL_HDR64_MAGIC   0x20b
#define IMAGE_ROM_OPTIONAL_HDR_MAGIC    0x107

2)MajorLinkerVersion 连接程序的主版本号 如vc6.0的为06h

3)MinorLinkerVersion 连接程序的次版本号 如vc6.0的为00h

4)SizeOfCode pe文件代码段的大小.是FileAlignment的整数倍.

5)SizeOfInitializedData 所有含已初始化数据的块的大小,一般在.data段中.

6)SizeOfUninitializedData 所有含未初始化数据的块的大小,一般在.bss段中.

7)AddressOfEntryPoint 程序开始执行的地址,这是一个RVA(相对虚拟地址).对于exe文件,这里是启动代码;对于dll文件,这里是libMain()的地址.
脱壳时第一件事就是找入口点,指的就是这个值.

8)BaseOfCode 代码段基地址,微软的连接程序生成的程序一般把这个值置为1000h,  

9)BaseOfData 数据段基地址

10)ImageBase pe文件默认的装入地址.windows9x中exe文件为400000h,dll文件为10000000h.

11)SectionAlignment 内存中区块的对齐单位.区块总是对齐到这个值的整数倍.x86的32位系统上默认值位1000h

12)FileAlignment pe文件中区块的对齐单位.pe文件中默认值为 200h.

13)MajorOperatingSystemVersion
14)MinorOperatingSystemVersion
上面两个域是指运行这个pe文件所需的操作系统的最低版本号.windows95/98和windows nt 4.0 的内部版本号都是 4.0 ,而windows2000的内部版本号是5.0

15)MajorImageVersion
16)MinorImageVersion
上面两个域是指用户自定义的pe文件的版本号.可以通过连接程序来设置,如: LINK /VERSION:2.0 MyApp.obj一般在升级时使用.

17)MajorSubsystemVersion  
18)MinorSubsystemVersion
上面两个域是指运行这个pe文件所要求的子系统的版本号. 

19)Win32VersionValue 总是0

20)SizeOfImage pe文件装入内存后映像的总大小.如果SectionAlignment域和FileAlignment域相等,那么这个值也是pe文件在硬盘上的大小.

21)SizeOfHeaders 从文件开始到节表(包含节表)的总大小.其后是各个区段的数据.        

22)CheckSum pe文件的CRC校验和.

23)Subsystem pe文件的用户界面使用的子系统类型.定义如下:

#define IMAGE_SUBSYSTEM_UNKNOWN       0  // Unknown subsystem.
#define IMAGE_SUBSYSTEM_NATIVE        1  // Image doesnt require a subsystem.
#define IMAGE_SUBSYSTEM_WINDOWS_GUI     2  // Image runs in the Windows GUI subsystem.
#define IMAGE_SUBSYSTEM_WINDOWS_CUI     3  // Image runs in the Windows character subsystem.
#define IMAGE_SUBSYSTEM_OS2_CUI       5  // image runs in the OS/2 character subsystem.
#define IMAGE_SUBSYSTEM_POSIX_CUI      7  // image runs in the Posix character subsystem.
#define IMAGE_SUBSYSTEM_NATIVE_WINDOWS    8  // image is a native Win9x driver.
#define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI    9  // Image runs in the Windows CE subsystem.

24)DllCharacteristics 总为0

25)SizeOfStackReserve 为线程的栈初始保留的虚拟内存的大小,默认为00100000h.如果在调用CreateThread函数时指定堆栈的大小为0,被创建的线程的堆栈的初始大小就与这个值相同.

26)SizeOfStackCommit 为线程的栈初始提交的虚拟内存的大小.微软的连接程序把这个值置为 1000h.

27)SizeOfHeapReserve 为进程的堆保留的虚拟内存的大小.默认值为 00100000h.

28)SizeOfHeapCommit 为进程的堆初始提交的虚拟内存的大小.微软的连接程序把这个值置为1000h.

29)LoaderFlags 通常为0

30)NumberOfRvaAndSizes 数据目录结构数组的项数,总为 00000010h
这个值定义如下:
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES  16

31)IMAGE_DATA_DIRECTORY DataDirectory[0x10] 数据目录结构数组
IMAGE_DATA_DIRECTORY结构定义如下:

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

这个结构包含了pe文件中重要部分的RVA地址和大小.这个数组使操作系统的加载程序能够快速定位特定的区段.具体定义如下:
#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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值