您的位置:首页 > 其它

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

2015-06-06 14:38 211 查看
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文件中寻找特定的数据时,我们就要通过这个数据目录表,查找指定的数据块,从中获取数据。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: