PE文件格式学习总结

来源:互联网 发布:算法时代 编辑:程序博客网 时间:2024/05/21 11:08

PE文件被称为可移植的执行体是Portable Execute的全称,常见的EXE、DLL、OCX、SYS、COM都是PE文件,PE文件是微软Windows操作系统上的程序文件(可能是间接被执行,如DLL),继承自unix的COFF文件格式.在微软的NT C编译器出来后微软就使用PE文件格式了。

************首先定位到+0h处
struct _IMAGE_DOS_HEADER_STRUCT
************************ 中间相隔若干
************************(以下首地址由_IMAGE_DOS_HEADER_STRUCT.e_lfanew确************************ 定)
struct _IMAGE_NT_HEADERS{
       DWORD Signature;
       _IMAGE_FILE_HEADERS  FileHeader;
_IMAGE_OPTIONAL_HEADER ;
}
************************紧跟无需定位
struct _IMAGE_SECTION_HEADER(数组);
//数组数组的数目由_IMAGE_NT_HEADERS.FileHeader.NumberOfSections决定

******************************中间间隔若干
*****************************以下首地址由_IMAGE_OPTIONAL_HEADER. *****************************IMAGE_DATA_DIRECTORY.[2].VirtualAddress
*****************************确定。

IMAGE_IMPORT_DESCRIPTOR数组若干,由最后一个数组内容全0结束

******************************中间间隔若干
*****************************以下首地址由_IMAGE_OPTIONAL_HEADER. *****************************IMAGE_DATA_DIRECTORY.[1].VirtualAddress
*****************************确定。

IMAGE_EXPORT_DIRECTORY

                                           
1、可以通过_IMAGE_DOS_HEADER_STRUCT的e_magic==”MZ”和_IMAGE_NT_HEADERS的Signature==”PE/0/0”共同判断是否PE文件。

然后_IMAGE_DOS_HEADER_STRUCT得e_lfanew的地址指向_IMAGE_NT_HEADERS所在地址,定位_IMAGE_NT_HEADERS后可以读取_IMAGE_NT_HEADERS。

2、_IMAGE_OPTIONAL_HEADER的最后一项是IMAGE_DATA_DIRECTORY数组里面有16项,分别为Export Table,Import Table,Resources Table,Exception Table,Security Table,Base Relocation Table,Debug ,Copyright,Global Ptr,Thread Local Storage,Load configuration,Bound Import,Import Address Table,Delay Import,Com Discriptor,保留。

3、_IMAGE_FILE_HEADERS 的_IMAGE_NT_HEADERS.FileHeader.NumberOfSections表明文件区块数目。通过文件区块数目判断_IMAGE_SECTION_HEADER的数目。读完_IMAGE_SECTION_HEADER后可以直接读若干个_IMAGE_SECTION_HEADER。读出各区块的数据描述。

4、通过_IMAGE_OPTIONAL_HEADER. IMAGE_DATA_DIRECTORY.[1].VirtualAddress指向地址定位到输入表,然后通过FirstThunk定位IMAGE_THUNK_DATA,通过IMAGE_THUNK_DATA.AddressOfData判断是否为按名索引。如果AddressOfData最高位为0,低31位指向IMAGE_IMPORT_BY_NAME,可以读取函数名了。如果最高位为1则低31为为输入表的函数编号。

5、最后通过_IMAGE_OPTIONAL_HEADER. IMAGE_DATA_DIRECTORY.[0].VirtualAddress指向地址定位到输出表  IMAGE_EXPORT_DIRECTORY.AddressOfNames指向输出函数数组地址,数组内存储的是指向函数名的地址。函数名的数目由NumberOfNames决定。

(好像这个格式现在有一点改变,好像后来对对输入表,输出表格式有了改变。比如用VC6.0生成的文件用,这种方法分析就不行。但是用Windows DDK 3790.1830生成的sys文件用这种格式还是能分析出来的。有点怪。
附上文中提到的文件结构。(大部分MSDN能查到,不能查到的其实也有定义,不需要自己再定义一遍),他们中的数据说明了该文件的很多很多信息。

源代码放到CSDN资源了:      http://download.csdn.net/source/2127232
一下是对某应用程序分析的结果。可以分析比如WAR3,CS的PE文件,毕竟它们出来的时间比较早,输入输出表格式还没有改变。
1 ------------检查MA-DOS文件头.
    PE文件头位置0x     130.
2 ------------检查PE文件头.
    Runs on Intel i386
    文件区块数目 4.
    文件创建日期 Thu Jun 06 00:53:20 2002
    COFF符号表文件偏移位置 0.
    COFF符号表符号个数 0.
    IMAGE_OPTIONAL_HEADER32结构大小 e0.
    文件中不存在重定位信息.
    文件可执行。如果为0,一般是链接时出了问题了.
    行号信息被移去.
    符号信息被移去.
    目标平台为32位处理机.
3 ------------检查可选文件头.
    普通可执行镜像文件
    链接程序的主版本号:6.
    链接程序的次版本号:0.
    所有含代码区块的总大小:0x   ab000.
    所有初始化数据块总大小:0x 3b7c000.
    所有未初始化数据块总大小:0x       0.
    程序执行入口:0x   84812.
    代码区起始RVA:0x    1000.
    数据区起始RVA:0x   ac000.
    程序默认装入基地址:0x  400000.
    内存区块中的对齐值:0x    1000.
    文件区块中的对齐值:0x    1000.
    操作系统主版本号:4.
    操作系统次版本号:0.
    用户自定义主版本号:0.
    用户自定义次版本号:0.
    所需要子系统主版本号:4.
    所需要子系统次版本号:0.
    保留通常被设置为0.===0.
    映像装入内存总尺寸0x 3c28000.
    DOS头、PE头部、区块表总大小0x    1000.
    映像校验和0x       0.
    界面子系统含义:图形接口子系统.
    DllMain()函数何时被调用,默认为0.===0.
    初始化线程堆栈大小0x  100000
    一开始被委派给堆栈的内存数量0x    1000
    为进程默认堆保留的内存0x  100000
    EXE中委派给堆的内存大小0x    1000
    LoaderFlags与调试有关默认为0.===0.
    数据目录的项数:16.
    Export Table        :
     数据块起始RVA:0x   c70d0.
     数据块长度:   0x    45bb.
    …………………………
4 ------------检查区块表.
    区块名:.text.
     数据块长度:             0x   aaa5e.
     区块RVA地址:            0x    1000.
     文件对齐后的尺寸:       0x   ab000.
     在文件中的偏移:         0x    1000.
     重定位的偏移:           0x       0.
     行号表的偏移:           0x       0.
     OBJ中使用重定位项数目:  0x       0.
     行号表中行号的数目:     0x       0.
     包含代码.
     该块可以执行.
     该块可读.
    …………………………..
5 ------------检查输入表.
    包含指向输入表的RVA:             0x   c3c80.
    一个32位时间标志:                0x       0.
    第一个被转向的API索引一般为0.===:0x       0.
    输入DLL名的地址:                 0x   c3f22.
    转向的DLL名字:                   WONAuth.dll
    包含指向输入表的RVA             :0x   ac6dc.
     输入函数:
      ?GetCommunityId@WON_AuthCertificate1@@QB
      …………………………..
             包含指向输入表的RVA:             0x   c3d10.
    一个32位时间标志:                0x       0.
    第一个被转向的API索引一般为0.===:0x       0.
    输入DLL名的地址:                 0x   c68d0.
    转向的DLL名字:                   WSOCK32.dll
    包含指向输入表的RVA             :0x   ac76c.
     输入函数:
低31位可以看成函数序号52
低31位可以看成函数序号101
……………………………
6 ------------检查输出表.
    未使用总是为0.===0
    输出表创建时间 Thu Jun 06 00:53:20 2002
    主版本号,一般为0.===0
    次版本号,一般为0.===0
    模块的真实名称:cstrike.exe
    基数:用于这个可执行文件输出表的起始序数值一般为1.===1.
    AddressOfFunctions阵列中的元素个数:276.
    AddressOfNames阵列中的元素个数:276.
    指向函数地址数组:              0x   c70f8.
    函数名字的指针地址:            0x   c7548.
    指向输出序列号数组:            0x   c7998.
     输出函数名:
             ??0?$Dar@D@vgui@@QAE.
             ??0?$Dar@D@vgui@@QAE.
                         …………………………………..