1.代码重定位提出

可执行代码在PE文件中移动到另一个位置时,内容并不变,但如果全局数据位置变了但是某些使用绝对地址定位的操作数的代码将不会改变,这时

仍然引用目标将会出错.

例如: 

0040103B >/$ B8 00304000 mov eax,parseRel.00403000 ; ASCII "test"

 操作数是个绝对地址,如果重定位后这条代码不修改,那么引用的是重定位后的parseRel.00403000 地址.将可能出错

 

2.PE文件重定位表原理

PE文件的默认加载基址被其他文件占用时,如加载dll时,2个dll默认加载到同一个地方,但是后一个如果要加载成功就需要重定位表.

因此重定位表常常用于dll中

对于一个地址,它是4B大小,正常来说如果有n个地址需要重定位将需要n*4个字节大小的缓冲来存储这些地址. 但是Windows采用了另一种方式

存储这些地址: 以一个需要重定位的地址所在的页为单位,且知道该页基址,那么在这个页(4096个字节)中需要重定位的地址只需记录低16bit即可,因为

这些地址中高16bit都是一样的(其实在这个页中高20bit都是一样的).

因此保存一个页的重定位信息所需4(页基址RVA)+4(需要重定位的地址个数)+2*n个字节即可.

 

重定位表信息存储在OptionHeader的数据目录的第6个字段中: 例如ntdll的重定位位置 :

在图中该表显示了重定位表的表项IMAGE_BASE_RELOCATION:

typedef struct _IMAGE_BASE_RELOCATION {
    DWORD   VirtualAddress;  //该页起始RVA
    DWORD   SizeOfBlock;    //该页需要重定位的地址个数
} IMAGE_BASE_RELOCATION;

重定位表结构:重定位项结构, 接着是该页的重定位地址信息(2字节),接着是下一个页的重定位项结构,接着是该页的重定位地址信息(2字节).......依次类推如图:

 

其中2字节的重定位地址信息的高4bit是重定位类型, 有多种,但只用到了2种:

0 = IMAGE_REL_ALPHA_ABSOLUTE  无意义,用作对齐

3=IMAGE_REL_ALPHA_GPREL32    表示双字32bit都需要修正

于是当高4bit是3时,需要重定位的代码的地址=页基址+映像基址+低12bit

根据这个地址找到该处代码后即可将其取4字节大小的操作数进行修正.

 

 

3.解析重定位表

 根据以上分析不难写出解析代码:

  1 .386
  2 .model flat,stdcall
  3 option casemap:none
  4 include        windows.inc
  5 include        kernel32.inc
  6 include        msvcrt.inc
  7 includelib    kernel32.lib
  8 includelib    msvcrt.lib
  9 
 10 
 11 .data
 12 addrinfo        db        '重定位基址: 0x%x',0dh,0ah,0
 13 numinfo            db        '重定位地址数量:0x%x',0dh,0ah,0
 14 addrlist        db        '地址列表:',0dh,0ah,0
 15 
 16 tip                db        '请输入文件路径',0dh,0ah,0
 17 errorinfo        db        '错误代码:%d',0dh,0ah,0
 18 noRel            db        '无重定位表',0dh,0ah,0
 19 addritem        db        '0x%x',09h,0
 20 scanfs            db        '%s',0
 21 entercode        db        0dh,0ah,0
 22 .data?
 23 filePath        db        MAX_PATH dup(?)
 24 .code
 25 _RVAToOffset proc _lpFileHead,_dwRVA
 26   local @dwReturn
 27   
 28   pushad
 29   mov esi,_lpFileHead
 30   assume esi:ptr IMAGE_DOS_HEADER
 31   add esi,[esi].e_lfanew
 32   assume esi:ptr IMAGE_NT_HEADERS
 33   mov edi,_dwRVA
 34   mov edx,esi
 35   add edx,sizeof IMAGE_NT_HEADERS
 36   assume edx:ptr IMAGE_SECTION_HEADER
 37   movzx ecx,[esi].FileHeader.NumberOfSections
 38   ;遍历节表
 39   .repeat
 40     mov eax,[edx].VirtualAddress
 41     add eax,[edx].SizeOfRawData        ;计算该节结束RVA,不用Misc的主要原因是有些段的Misc值是错误的!
 42     .if (edi>=[edx].VirtualAddress)&&(edi<eax)
 43       mov eax,[edx].VirtualAddress
 44       sub edi,eax                ;计算RVA在节中的偏移
 45       mov eax,[edx].PointerToRawData
 46       add eax,edi                ;加上节在文件中的的起始位置
 47       jmp @F
 48     .endif
 49     add edx,sizeof IMAGE_SECTION_HEADER
 50   .untilcxz
 51   assume edx:nothing
 52   assume esi:nothing
 53   mov eax,-1
 54 @@:
 55   mov @dwReturn,eax
 56   popad
 57   mov eax,@dwReturn
 58   ret
 59 _RVAToOffset endp
 60 
 61 
 62 LoadPe    proc filename:dword
 63     
 64     LOCAL    hFile:dword
 65     LOCAL    hMap:dword
 66     LOCAL    imageBase:dword
 67     pushad
 68     invoke    CreateFile, filename,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0
 69     .if eax==INVALID_HANDLE_VALUE
 70         invoke GetLastError
 71         invoke crt_printf,offset errorinfo,eax
 72         mov eax,0
 73         ret
 74     .endif
 75     mov     hFile ,eax
 76     invoke    CreateFileMapping, hFile,0,PAGE_READONLY,0,0,0
 77     .if eax==INVALID_HANDLE_VALUE||eax==0
 78         invoke CloseHandle,hFile
 79         invoke GetLastError
 80         invoke crt_printf,offset errorinfo,eax
 81         mov eax,0
 82         ret
 83     .endif
 84     mov hMap,eax
 85     invoke    MapViewOfFile,hMap,FILE_MAP_READ,0,0,0
 86     .if eax==0
 87         invoke CloseHandle,hFile
 88         invoke CloseHandle,hMap
 89         invoke GetLastError
 90         invoke crt_printf,offset errorinfo,eax
 91         mov eax,0
 92         ret
 93     .endif
 94     mov imageBase,eax
 95     invoke CloseHandle,hFile
 96     invoke CloseHandle,hMap
 97     popad
 98     mov eax,imageBase
 99     ret
100 
101 LoadPe endp
102 
103 getRelocInfo proc imageBase:dword
104     
105     LOCAL    relocRva:dword
106     LOCAL    nums:dword
107     LOCAL    index:dword
108     LOCAL    sizeofreloc:dword
109     LOCAL    sizeofall
110     pushad
111     mov relocRva,0
112     mov nums,0
113     mov index,0
114     mov esi,imageBase
115     assume esi: ptr IMAGE_DOS_HEADER 
116     
117     mov eax,[esi].e_lfanew
118     add eax,esi
119     assume eax: ptr IMAGE_NT_HEADERS
120     lea ebx,dword ptr [eax].OptionalHeader.DataDirectory[8*5]
121     mov ebx,dword ptr [ebx+4] ;获取重定位表总大小
122     mov sizeofall,ebx
123     mov eax,[eax].OptionalHeader.DataDirectory[8*5].VirtualAddress
124 
125     .if eax==0
126         invoke crt_printf,noRel
127         mov eax,0
128         ret
129     .endif
130     invoke _RVAToOffset,imageBase,eax
131     add esi,eax
132     mov relocRva,esi
133     invoke crt_printf,offset addrlist
134     ;至此esi指向重定位表
135 parse:    
136     mov edx,dword ptr [esi] ;地址
137     mov ebx,dword ptr [esi+4] ;大小
138     
139     mov sizeofreloc,ebx
140     mov ecx,sizeofreloc
141     sub ecx,08h
142     shr ecx,1
143     mov nums,ecx    ;获取重定位表项个数
144 
145     invoke    crt_printf,offset addrinfo,edx
146     invoke crt_printf,offset numinfo,nums
147 
148     xor edi,edi  
149     ;output是输出某个重定位表项
150 output:
151     
152     mov edx,index
153     cmp edx,nums
154     jnl outputend
155 
156     invoke crt_printf ,offset addritem,word ptr [esi+edx*2+8]
157     inc edi
158     .if edi == 5
159         xor edi,edi
160         invoke crt_printf,offset entercode
161     .endif    
162     
163     lea edx,dword ptr [index]
164     inc dword ptr [edx]
165     jmp output
166     
167 outputend:    
168 ;输出完后继续定位到下一个重定位表项,如果超过了总大小则说明没有了
169     invoke crt_printf,offset entercode
170     mov index,0    ;将index归0
171     add esi,sizeofreloc
172     mov eax,esi
173     sub eax,relocRva
174     cmp eax,sizeofall
175     jnz parse
176 
177     
178     ret
179 
180 getRelocInfo endp
181 start:
182     invoke    crt_printf,offset tip
183     invoke    crt_scanf,offset scanfs,offset filePath
184     invoke LoadPe,offset filePath
185     .if eax>0
186         invoke    getRelocInfo,eax
187     .endif
188     
189     
190     invoke    ExitProcess,0
191 
192 end start