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