一、关于重定位
1、直接寻址指令需要重定位。如:mov eax, dword ptr [4000c0h]
注意:call 401000h 是相对寻址,不需要重定位。
请问 call [401000h]需要重定位吗?
2、重定位需要的信息:重定位地址、实际装载地址、建议装载地址。
二、重定位数据结构
IMAGE_ BASE_RELOCATION struct
VirtualAddress dd ;重定位内存页首地址RVA
SizeOfBlock dd ;重定位块大小,包含本结构在内的大小
IMAGE_BASE_RELOCATION ends
1、该结构后面紧跟的是word型的重定位项。
2、重定位地址的 RVA = VirtualAddress + word型重定位项的低12位
3、word行重定位项的高4位表示重定位类型,一般常见的值为0和3
高4位值 | 常量表示 | 含义 |
0 | IMAGE_REL_BASED_ABSOLUTE | 使块按照32位对齐,位置为0 |
1 | IMAGE_REL_BASED_HIGH | 高16位必须应用于偏移量所指高字16位 |
2 | IMAGE_REL_BASED_LOW | 低16位必须应用于偏移量所指低字16位 |
3 | IMAGE_REL_BASED_HIGHLOW | 全部32位应用于所有32位 |
4 | IMAGE_REL_BASED_HIGHADJ | 需要32位,高16位位于偏移量,低16位位于下一个偏移量数组元素,组合为一个带符号数,加上32位的一个数,然后加上8000然后把高16位保存在偏移量的16位域内 |
5 | IMAGE_REL_BASED_MIPS_JMPADDR | 资料不详 |
6 | IMAGE_REL_BASED_SECTION | 资料不详 |
7 | IMAGE_REL_BASED_REL32 | 资料不详 |
4、重定位项数 = (SizeOfBlock - 4 - 4) / 2
5、重定位块结束,以IMAGE_BASE_RELOCATION结构的VirtualAddress值为0结束。因此若映像加载00400000h,则代码加载地址为00401000h
6、示例:
(1)运行界面
(2)代码processpefile_reloc.asm
;======================
;pe文件重定位表
;by 紫陌
;======================
;======================
;数据段
;======================
.data?
.const
szErrNon db '没有重定位信息', 0
szBaseReloc db '重定位首地址:%08X 重定位大小:%08X', 0dh, 0ah, 0
szTitleBlock db '================重定位块(%08X)(累计大小%08X)=============', 0dh, 0ah, 0
szBlock db '重定位内存页首地址(%08X):%08X', 0dh, 0ah
db '重定位块大小(%08X):%08X', 0dh, 0ah, 0
szEntry db '重定位项(%08X):%04X', 0dh, 0ah, 0
;======================
;代码段
;======================
.code
_ProcessPeFile_Reloc proc _lpImageBase
local @szBuf[512]:BYTE
local @dwRelocSize:DWORD
local @dwEntryNum:DWORD
local @dwTotalSize:DWORD
pushad
;********************
;从数据目录取重定位首地址和大小
;********************
mov edi, _lpImageBase
assume edi:ptr IMAGE_DOS_HEADER
add edi, [edi].e_lfanew
assume edi:ptr IMAGE_NT_HEADERS
mov ecx, [edi].OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC * sizeof IMAGE_DATA_DIRECTORY].isize
mov @dwRelocSize, ecx
mov edi, [edi].OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC * sizeof IMAGE_DATA_DIRECTORY].VirtualAddress
.if !edi
invoke lstrcpy, addr szShowMsg, addr szErrNon
invoke SetWindowText, hRichEdit, addr szShowMsg
jmp _overpos
.endif
;*******************
;将RVA转为文件偏移
;*******************
invoke _RvaToOffset, _lpImageBase, edi
add eax, _lpImageBase
mov edi, eax
assume edi:ptr IMAGE_BASE_RELOCATION
;*******************
;显示重定位首地址和大小
;*******************
invoke wsprintf, addr @szBuf, addr szBaseReloc, edi, @dwRelocSize
invoke lstrcpy, addr szShowMsg, addr @szBuf
invoke SetWindowText, hRichEdit, addr szShowMsg
;*******************
;循环显示重定位块
;*******************
mov @dwTotalSize, 0
.while TRUE
.break .if [edi].VirtualAddress == 0
;****************
;重定位块累计大小
;****************
mov ecx, @dwTotalSize
add ecx, [edi].SizeOfBlock
mov @dwTotalSize, ecx
invoke wsprintf, addr @szBuf, addr szTitleBlock, edi, @dwTotalSize
invoke lstrcat, addr szShowMsg, addr @szBuf
;****************
;重定位头
;****************
invoke wsprintf, addr @szBuf, addr szBlock, \
addr [edi].VirtualAddress, [edi].VirtualAddress, \
addr [edi].SizeOfBlock, [edi].SizeOfBlock
invoke lstrcat, addr szShowMsg, addr @szBuf
;****************
;重定位项
;****************
mov ecx, [edi].SizeOfBlock
sub ecx, 8
shr ecx, 1
mov @dwEntryNum, ecx
mov esi, edi
sub esi, 8
.while ecx
mov @dwEntryNum, ecx
lodsw
movzx eax, ax
invoke wsprintf, addr @szBuf, addr szEntry, esi, eax
invoke lstrcat, addr szShowMsg, addr @szBuf
mov ecx, @dwEntryNum
dec ecx
.endw
;*****************
;显示重定位块
;*****************
invoke SetWindowText, hRichEdit, addr szShowMsg
;*****************
;取下一个重定位块
;*****************
; mov ecx, @dwRelocSize
; sub ecx, [edi].SizeOfBlock
; mov @dwRelocSize, ecx
add edi, [edi].SizeOfBlock
.endw
_overpos:
assume edi:nothing
popad
ret
_ProcessPeFile_Reloc endp