PE导出表、重定位详解

来源:互联网 发布:csgom4a1皮肤知乎 编辑:程序博客网 时间:2024/05/17 06:47

此文档主要讲解导出表,重定位信息:

使用例子为: Windows.UI.Xaml.dll、010editor

1、导出表,重定位表的地址存放在哪里

DOS头-àPE头文件(_IMAGE_NT_HEADERS)-à扩展头(IMAGE_OPTIONAL_HEADER32)-à数据目录表

数据目录表中的内容:

structIMAGE_DATA_DIRECTORY  Export                   (1)

……

StructIMAGE_DATA_DIRECTORY BaseRelocationTable (6)

 

Typedef  struct IMAGE_DATA_DIRECTORY {

DWORDVirtualAddress ; //此处地址为在内存中的地址

DWORD  size ;

}

如下图信息:


2、这里是VirtualAddress,如何转变成相对文件地址:

根据pe文件的区段表进行转换:

去段表的结构:

Typedefstruct  _IMAGE_SECTION_HEADER{

BYTEName[0x8];

Union{

DWORDPhysicalAddress;

DWORDVirtualSize ;

}

DWORDVirualAddress ;

DWORDSzieOfRawData;

DWORDPointerToRawData;

DWORDPointerToRelocations;

DWORDPointerToLinenumbers;

WORDNumberOfRelocations;

WORDNumberOfLinenumbers;

DWORDCharacteristics;

}

查看需要转换的RVA在哪一个区段中。比如:VirualAddress (比如:此地址为第一个模块地址)<RVA <VirualAddres(第二个模块地址),那么RVA应该依据第一个模块进行转换:RVA-VirualAddress+PointerToRawData=offset(相对文件偏移)


1、   导出表地址指向一个数据结构,该结构为:

Typedef struct _IMAGE_EXPROT_DIRECTORY{

DWORD Characteristics;              //0x0

DWORD TimeDataStamp;                     //0x4

WORD MajorVersion;                              //0x8

WORD MinorVersion;               //0xA

DWORD Name;                        //0xC

DWORD Base;                          //0x10

DWORD NumberOfFuncions;            //0x14

DWORD NumberOfName;                //0x18

DWORD  AddressOfFunctions;        //0x1c  导出地址表

DWORD AddressOfName;                //0x20   导出名称表

DWORD AddressOfNameOrdinals;   //0x24    指向导出序列号数组

}

如何利用导出名称表中的名称找到函数导出的地址:

导出名称表与导出序列号数组是相互对应的,序号与导出地址表的数组索引对应。

 

AddressOfName 找出你需要的函数名,从AddressOfNameOrdinals;中找出与之对应的序列号,根据序列号找到导出地址。比如:序列号为5,那么就找导出地址表中的第六个数据(导出地址表从0开始)。

实战:

根据PEID我们可以看到我们看到到处函数信息:(依据此信息验证手工寻找)


第一步:


第二步:


第三步:

计算offset: BC2D40-1000+400 = BC2140


第四部:


第五步:计算:

Offsets   AddressOfFunctions 00BC2D68-1000+400 = BC2168

Offsets  AddressOfName:00BC2DA0-1000+400 = BC21A0

Offsets  AddressOfNameOrdinals:00BC2DD8-1000+400 = BC21D8

第六步寻找createString RVA地址:

寻找字符串:


00BC2E08-1000+400 = BC2208


寻找Oridinal:


寻找0号索引地址:

 

地址:00864ac0

 

 

2、   重定位表的信息。

根据扩展表找到重定位表的RVA,通过段表将RVA转换成offset.

Offset指向的位置为一个数据结构:

typedef struct _IMAGE_BASE_RELOCATION{

DWORD     VirtualAddress;     //0x0    重定位页的起始地址

DWORD      SizeOfBlock;  //0x4    本结构+重定位数组

}

此数据结构之后是:

Struct {

WORD Offset:12;  //重定位偏移

WORD  Type:4;       //重定位类型

}

Type  == 0x3 (大部分重定位都是该值):重定位偏移指向的整个4字节大小的地址都需要修正。

 

如何计算重定位位置:

VirtualAddress +offset+ImageBase(PE结构中的数据)-ImageBase(实际装入的地址) = 需要重定位的RVA

下一步:

DWORD PTR [需要重定位的RVA] = DWORD PTR(需要重定位的RVA) -ImageBase(PE结构中的数据)+ImageBase(实际装入的地址)

 

循环多少次此分页重定位结束:

N = (SizeOfBlock-Sizeof(_IMAGE_BASE_RELOCATION))/sizeof(struct{WORD Offset:12,WORD Type:4})

 

N次之后,开启下一个分页的重定位信息。

实战:

第一步:


第二步:


第三步计算:

BFA000-BFA000+BF5000 = BF5000

第四步:

 

VirtualAddress = 00001000;

SizeOfBlock = 00000808

重定位的个数:

N = (00000808-8)/2 =0x400;

第五步:

00 30 的意思是:

imagebase+重定位00001000+0地址处的四个字节。

 

 

Windows.UI.Xaml加载基址默认为10000000,第一个需要重定位的数据为:10B377A0.

我们手动改变dll的加载基址,变成707A0000.需要重定位的位置为:707A0000+1000.

原来数据为:10B377A0,重定位后的数据:


10B377A0-10000000+707A0000  =  712D77A0

0 0
原创粉丝点击