美高梅网站是多少PE结构分析,PE结构学习02
分类:美高梅-操作

重定位表是一个数组,这个数组的大小记载在 _IMAGE_OPTIONAL_HEADER 的

数据目录表也是一个结构体数组------>每一个结构体里面记录的是每个表所对应的RVA以及大小

(扩展:

  • 区段头表(它是一个结构体数组)是由多个IMAGE_SECTION_HEADER这样的结构体组成,以一个全是0的结构体结尾;
  • 导入表也是一个结构体数组(后面会重点讲),以一个全0元素结尾,导入表中的IMAGE_THUNK_DATA(文件没有加载的时候,OrignalFirstThunk与FirstThunk指向IMAGE_THUNK_DATA)也是一个结构体数组;
  • 重定位表:它也是一个结构体数组,以全0元素结尾
  • 资源表:它里面也包含结构体数组(更为详细的可以查阅相关文献)
    )
  • 今天我们学习导出表:

偏移类型的含义如下:

美高梅网站是多少 1

 PIMAGE_NT_HEADERS Pnt = (PIMAGE_NT_HEADERS)((int)Pdos->e_lfanew + (int)Pdos);

 IMAGE_OPTIONAL_HEADER32 Popt = Pnt->OptionalHeader;

 IMAGE_EXPORT_DIRECTORY * Export;
 Export = (IMAGE_EXPORT_DIRECTORY*)(Popt.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + (ULONG_PTR)Pdos);

 DWORD * AllAddress;
 DWORD * AllName;
 USHORT * AllOrg;

 AllAddress = (DWORD*)((int)Export->AddressOfFunctions + (int)Pdos);//函数地址数组
 AllName = (DWORD*)((int)Export->AddressOfNames + (int)Pdos);//函数名称数组
 AllOrg = (USHORT *)((int)Export->AddressOfNameOrdinals + (int)Pdos);//序号数组


 int OneAddress;
 char * OneName;
 USHORT OneOrg;
 char * Buf = new char[500];
 int ListId = NULL;

 for (int i = 0; i < (int)Export->NumberOfNames; i++)
 {

 OneName = (char*)((BYTE*)Pdos + AllName[i]);
 OneOrg = (USHORT)AllOrg[i];
 OneAddress = (int)((int)Pdos + AllAddress[OneOrg]);

 printf("Name: %s, Org :%d,Address :%xn", OneName, OneOrg, OneAddress);
 }

 return 0;
}

每个元素的大小都记载在 SizeOfBlock 中,这个元素是由 一个 _IMAGE_美高梅4858官方网站 ,BASE_RELOCATION 结构体和一个TypeOffset 数组组成的。TypeOffset 数组的每个元素占2个字节,其中,高4位是偏移类型(type),低12位表示需要重定位的地址(Offset),即,它与 VirtualAddress 相加即是指向 PE 映像中需要修改的那个代码的RVA。

文件头

美高梅网站是多少 2

image.png

  • 文件头大小0x14个字节(由图可知:它是Nt头的第二个元素)

  • 扩展头的大小就在里面

  • 节的数量也在里面

  • 文件头里面保存了PE文件的一些属性(这里只列举了部分):
    1.是否是dll(0x0210),exe(0x010F)
    2.是否可执行

typedef struct _IMAGE_BASE_RELOCATION {
    DWORD   VirtualAddress;
    DWORD   SizeOfBlock;
//  WORD    TypeOffset[1];
} IMAGE_BASE_RELOCATION;
typedef IMAGE_BASE_RELOCATION UNALIGNED * PIMAGE_BASE_RELOCATION;

美高梅网站是多少 ,image.png

美高梅网站是多少 3

其他中文翻译:

再小结一波:

ImageBase(映像基址,装载基址,它是一个VA值):如果没有加载到这个地址则会重定位(就是PE文件加载进内存之后,就相当于知道了Dos头的位置,然后就可以知道其他的位置了),就是PE装入内存的基地址,默认情况下,EXE文件在内存中的基地址是0X0040 0000,DLL文件为0x0100 0000,由编译器决定!
程序入口点(OEP)
映像大小(SizeOfImage)------------>把文件加载进内存,所需要的内存大小(注意是进行了块对齐之后)
代码大小(SizeOfCode)------>所有区段的总大小
代码基址(BaseOfCode)起始代码的 RVA---->.text的RVA
数据基址(BaseOfData)起始数据的RVA----->.data的RVA
头大小(SizeOfHeaders)------------>所有头部大小,就是文件主体相对文件起始的偏移
内存对齐(SectionAlignment)----------->为0x1000(4KB)
文件对齐(FileAlignment)---------------->200h(0x200)
DLL标记(DllCharacteristics)-------->指示Dll特征的标志

  • AddressOfFunctions 指向所有函数的地址。
  • AddressOfNames 指向名字的地址。
  • AddressOfNameOrdinals 指向一个序号。

美高梅网站是多少 4

扩展头

美高梅网站是多少 5

image.png

美高梅网站是多少 6

image.png

美高梅网站是多少 7

常量 描述
IMAGE_REL_BASED_ABSOLUTE       0x0 使块按照32位对齐,位置为0。
IMAGE_REL_BASED_HIGH 0x1 高16位必须应用于偏移量所指高字16位。
IMAGE_REL_BASED_LOW 0x2 低16位必须应用于偏移量所指低字16位。
IMAGE_REL_BASED_HIGHLOW 0x3 全部32位应用于所有32位。
IMAGE_REL_BASED_HIGHADJ 0x4 需要32位,高16位位于偏移量,低16位位于下一个偏移量数组元素,组合为一个带符号数,加上32位的一个数,然后加上8000然后把高16位保存在偏移量的16位域内。
PE头部包含了Dos头,一直到节表的结束位置,.text区段开始之前
  • 数据目录表
![](https://upload-images.jianshu.io/upload_images/5676193-cfbc56c21cd7568f.png)

image.png
  • 我们知道OptionalHeader指向的DataDirectory[]数组一共有16个,每个都是一样的结构:

首先找到重定位表,这里使用工具:

扩展头详解:
typedef struct _IMAGE_OPTIONAL_HEADER {
    //
    // Standard fields.
    //

    WORD    Magic;                          //表示这是一个什么类型的PE文件,32位一般是0x010B,64位的文件一般是0x020B
    BYTE    MajorLinkerVersion;
    BYTE    MinorLinkerVersion;
    DWORD   SizeOfCode;                  //所有代码区段(节)的总大小(基于文件对齐后的大小)
    DWORD   SizeOfInitializedData;            //已经初始化的数据的总大小
    DWORD   SizeOfUninitializedData;        //未初始化的数据的大小
    DWORD   AddressOfEntryPoint;            //程序开始执行的相对虚拟地址,即OEP,这是一个RVA,要想得到VA,则必须要加上ImageBase(下面有介绍!!!!!)
    DWORD   BaseOfCode;              //起始代码的相对虚拟地址(RVA),就是.text段的RVA
    DWORD   BaseOfData;              //  其实数据的相对虚拟地址(RVA),就是.data段的RVA

    //
    // NT additional fields.
    //

    DWORD   ImageBase;                //默认加载地址(如果没有这个基址会发生重定位)
    DWORD   SectionAlignment;          //块对齐数,一般是0x1000
    DWORD   FileAlignment;                    //文件对齐数,一般是0x200
    WORD    MajorOperatingSystemVersion;
    WORD    MinorOperatingSystemVersion;
    WORD    MajorImageVersion;
    WORD    MinorImageVersion;
    WORD    MajorSubsystemVersion;
    WORD    MinorSubsystemVersion;
    DWORD   Win32VersionValue;
    DWORD   SizeOfImage;                      //把文件加载进内存,所需要的内存大小,是进行了内存对齐之后的大小
    DWORD   SizeOfHeaders;                //所有头部大小(这是按照文件对齐后的大小),也是文件主体相对文件起始的偏移,是所有头+节表的大小
    DWORD   CheckSum;
    WORD    Subsystem;
    WORD    DllCharacteristics;                    //文件(包括exe和dll文件)特征标志(见下面一张图)
    DWORD   SizeOfStackReserve;                   //表示进程中栈可以增长到的最大值,一般1M
    DWORD   SizeOfStackCommit;                    //进程中栈的初始值,据说也是栈每次分配增长的值,一般4KB
    DWORD   SizeOfHeapReserve;                      //表示进程中堆可以增长到的最大值,一般1M
    DWORD   SizeOfHeapCommit;                        //进程堆的初始值
    DWORD   LoaderFlags;
    DWORD   NumberOfRvaAndSizes;      //数据目录的个数,也就是下面那个数组中元素的个数
    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];//数据目录表,比较重要!
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

美高梅网站是多少 8

image.png

扩展头里面比较重要的在上面已经做出注释

源代码如下:

Dos头:
  • Dos头的前两个字节恒为4D5A(只是作为判断PE文件的第一个标志,并不能通过它就能判断是否是PE文件)

  • Dos头的最后四个字节是指向NT头的偏移量
    只有前两个字节和后面四个字节关系到PE文件是否正常运行

  • NT头:

![](https://upload-images.jianshu.io/upload_images/5676193-1017ee68ff187eb6.png)

image.png
  • 前面四个字节恒为0x4550,用于判断是否为PE文件的第二个标志

  • Nt头后面就是各个区段信息

导出表:

美高梅网站是多少 9

PE中有结构体数组的结构的总结:

数录节入重!

  • 节表(区段头表)

美高梅网站是多少 10

image.png

.text 段:代码段
.data段:数据段
.bss段:表示未初始化的数据,比如Static变量
.rdata 段:表示只读的数据,比如字符串
……
.relcoc段:存储重定位信息的区段
各变量存放于哪个区:
常量 ------------------>.rdata区
静态变量------------->.bss区
全局变量-------------->.data 区
节表里面的几个重要数据:
VirtualAddress:这个区段的相对虚拟地址
SizeofRawData:这个区段在磁盘中的大小,进行了文件对齐
PointerToRawData:区段的文件偏移,就是这个区段在磁盘文件中的起始位置
一个重要的公式:
offset(转)=RVA(需要转换的RVA)-RVA(所在区段的RVA)+offset(就是PointerToRawData)

  • 上篇文章,我们学习了各种头,Dos,NT,节表头,我们知道,OptionalHeader指向的DataDirectory[]数组一共有16个:

结构图如下,图片中 0 和 000 都表示16进制数,转换到二进制是  0000 和 0000 0000 0000:

美高梅网站是多少 11

分析常见的dll:在QQ中的 zlib.dll 文件 (在QQ安装目录下的bin文件夹中):

typedef struct _IMAGE_EXPORT_DIRECTORY 
 {
 DWORD Characteristics;//未使用,总是定义为0 
 DWORD TimeDateStamp;//文件生成时间 
 WORD MajorVersion;//未使用,总是定义为0 
 WORD MinorVersion;//未使用,总是定义为0 
 DWORD Name; //模块的真实名称的RVA 
 DWORD Base; //基数,加上序数就是函数地址数组的索引值 
 DWORD NumberOfFunctions;//导出函数的总数 
 DWORD NumberOfNames; //以名称方式导出的函数的总数 
 DWORD AddressOfFunctions; // RVA from base of image指向输出函数地址的RVA 
 DWORD AddressOfNames; // RVA from base of image指向输出函数名字的RVA 
 DWORD AddressOfNameOrdinals; // RVA from base of image向输出函数序号的RVA 

 } IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY

Constant

Value

Description

IMAGE_REL_BASED_ABSOLUTE

  0

The base relocation is skipped. This type can be used to pad a block.

IMAGE_REL_BASED_HIGH

  1

The base relocation adds the high 16 bits of the difference to the 16bit field at offset. The 16-bit field represents the high value of a 32-bit word.

IMAGE_REL_BASED_LOW

  2

The base relocation adds the low 16 bits of the difference to the 16-bit field at offset. The 16-bit field represents the low half of a 32-bit word.

IMAGE_REL_BASED_HIGHLOW

  3

The base relocation applies all 32 bits of the difference to the 32-bit field at offset.

IMAGE_REL_BASED_HIGHADJ

  4

The base relocation adds the high 16 bits of the difference to the 16-bit field at offset. The 16-bit field represents the high value of a 32-bit word. The low 16 bits of the 32-bit value are stored in the 16-bit word that follows this base relocation. This means that this base relocation occupies two slots.

IMAGE_REL_BASED_MIPS_JMPADDR

  5

The relocation interpretation is dependent on the machine type.

When the machine type is MIPS, the base relocation applies to a MIPS jump instruction.

IMAGE_REL_BASED_ARM_MOV32

  5

This relocation is meaningfull only when the machine type is ARM or Thumb. The base relocation applies the 32-bit address of a symbol across a consecutive MOVW/MOVT instruction pair.

IMAGE_REL_BASED_RISCV_HIGH20

  5

This relocation is only meaningful when the machine type is RISC-V. The base relocation applies to the high 20 bits of a 32-bit absolute address.

 

  6

Reserved, must be zero.

IMAGE_REL_BASED_THUMB_MOV32

  7

This relocation is meaningful only when the machine type is Thumb. The base relocation applies the 32-bit address of a symbol to a consecutive MOVW/MOVT instruction pair.

IMAGE_REL_BASED_RISCV_LOW12I

  7

This relocation is only meaningful when the machine type is RISC-V. The base relocation applies to the low 12 bits of a 32-bit absolute address formed in RISC-V I-type instruction format.

IMAGE_REL_BASED_RISCV_LOW12S

  8

This relocation is only meaningful when the machine type is RISC-V. The base relocation applies to the low 12 bits of a 32-bit absolute address formed in RISC-V S-type instruction format.

IMAGE_REL_BASED_MIPS_JMPADDR16

  9

The relocation is only meaningful when the machine type is MIPS. The base relocation applies to a MIPS16 jump instruction.

IMAGE_REL_BASED_DIR64

10

The base relocation applies the difference to the 64-bit field at offset.

美高梅网站是多少 12

例子:

  1. VirtualAddress  虚拟偏移地址
  2. size  大小

找到数据:

typedef struct _IMAGE_IMPORT_BY_NAME 
{
 WORD Hint;
 CHAR Name[1];
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;

.DataDirect‌​ory[IMAGE_DIRECTORY_E‌​NTRY_BASERELOC].Size 成员中

  1. Characteristics:现在没有用到,一般为0。
  2. TimeDateStamp:导出表生成的时间戳,由连接器生成。
  3. MajorVersion,MinorVersion:看名字是版本,实际貌似没有用,都是0。
  4. Name:模块的名字,就是dll的名称。
  5. Base:序号的基数,按序号导出函数的序号值从Base开始递增。
  6. NumberOfFunctions:所有导出函数的数量。
  7. NumberOfNames:按名字导出函数的数量。
  8. AddressOfFunctions:一个RVA,指向一个DWORD数组,数组中的每一项是一个导出函数的RVA,顺序与导出序号相同。
  9. AddressOfNames:一个RVA,依然指向一个DWORD数组,数组中的每一项仍然是一个RVA,指向一个表示函数名字。
  10. AddressOfNameOrdinals:一个RVA,还是指向一个WORD数组,数组中的每一项与AddressOfNames中的每一项对应,表示该名字的函数在AddressOfFunctions中的序号。

VirtualAddress 为 0x1000,SizeOfBlock 为 0x64。第一个条目为 0x338C,高四位为 0x3,offset为 0x38C,即偏移地址为 0x138C (由 0x1000 + 0x38C得来)应用于此地址上全部32位。打开C32Asm反汇编查看:

美高梅网站是多少 13

  • NtHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT ],这个数据目录表VirtualAddress指向的是导出表的地址:

美高梅网站是多少 14

  1. IMAGE_DIRECTORY_ENTRY_IMPORT 导入表
  2. IMAGE_DIRECTORY_ENTRY_BASERELOC 基址重定位表
  3. IMAGE_DIRECTORY_ENTRY_EXPORT 导出表
  4. IMAGE_DIRECTORY_ENTRY_RESOURCE 资源表
  • 我们接下来要学习的有:
  1. 我们知道dll文件,是动态链接库,里面有许多函数给别人调用,但是别人怎么知道里面有什么函数呢?就需要导出表清单给人家看,就如同你去餐厅点餐,却不知道餐厅有什么菜,这时服务生会拿出菜单来,这个菜单就如同导出表。
  2. 所有PE文件都可以有导出表,只是大部分情况下,exe不提供导出表而已。
  • 查找导出表代码(c/c++):

    int main(int argc, char *argv[]) { PIMAGE_DOS_HEADER Pdos = (PIMAGE_DOS_HEADER)GetModuleHandle(L"user32.dll");

 

本文由美高梅网站是多少发布于美高梅-操作,转载请注明出处:美高梅网站是多少PE结构分析,PE结构学习02

上一篇:没有了 下一篇:PE结构分析,学习笔记
猜你喜欢
热门排行
精彩图文