此文檔主要講解導出表,重定位信息:
使用例子爲: 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
第四部:
第五步:計算:
Offset‘s AddressOfFunctions: 00BC2D68-1000+400 = BC2168
Offset‘s AddressOfName:00BC2DA0-1000+400 = BC21A0
Offset‘s 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