第七講,重定位表


一丶何為重定位(注意,不是重定位表格)

首先,我們先看一段代碼,比如調用Printf函數,使用OD查看.

那么大家有沒有想過這么一個問題,函數的字符串偏移是00407030位置,函數Call的地址是00401020的位置

但是如果模塊首地址申請不到了,變為了00100000的位置,那么此時的偏移是不是都是錯的了?

首先說下,一般重定位表格都是DLL中的,因為滿足不了模塊首地址的需求,所以會遇到函數的重定位問題.

那么如果磨壞地址變為了00100000的位置,那么對應的字符串位置是不是也要變為00107030的位置,而Call的地址,是不是也要變為00101020的位置

那么這個就叫做重定位,我們要把偏移,以及各種需要修正的位置,變為正確的.

 

二丶重定位表格如何設計?

首先我們自己先想一下,重定位的表格要如何設計?

我猜想,你要保存模塊的地址  ,修改地址,偏移, 以及大小.

新的模塊 ImageBase

舊的模塊 iMageBase

修改的地址 

偏移

修改的大小

那么如果這樣設計會不會出現問題?

會出現很多問題,比如占得字節太多了,如果是Kerner32.dll里面都是這樣設計,那么得要多少內存.

那么進一步的優化

可不可以一個分頁,保存修改的偏移,以及長度

分頁: page  (DWORD) 占4個字節

大小: size (DWORD)     偏移:offset(DWORD)

表格設計為上面的,

感覺這樣可以了.但是感覺還可以進一步的優化,大小,以及偏移都占4個字節,是不是浪費了

而且如果記錄一個分頁中的重定位的數據,那么偏移是不會超過12位的(二進制12位,轉為10進制是1024),  那么如果一個DWORD存儲文件偏移,那么高4位是沒有用的.

而且我們發現,大小也是很占位置的.大小一個字節就可以表示了,比如0 做對齊使用,1修改高16位的偏移,2修改低16位的偏移,3修改4個字節大小

那么是不是可以合並了

page  (DWORD)

sizeofoffset

0x3005    代表的意思就是看高位,3代表我要修改4個字節,005代表修改的當前頁的偏移位置.

 

三丶真正的重定位表格

看下重定位表格的真正的結構體吧.

代碼:

typedef struct _IMAGE_BASE_RELOCATION {
    DWORD   VirtualAddress;            頁存儲的RVA
    DWORD   SizeOfBlock;              word類型數組的個數,也就是下面注釋的
//  WORD    TypeOffset[1];
} IMAGE_BASE_RELOCATION;
typedef IMAGE_BASE_RELOCATION UNALIGNED * PIMAGE_BASE_RELOCATION;

那么看看是不是和我們猜想的一樣,我們隨便找個DLL,在數據目錄中定位重定位表格

1.尋找數據目錄RVA偏移

我們首先要找到數據目錄中重定位表格的RVA偏移然后判斷屬於哪個節,通過公式轉化,得到在文件中的實際偏移位置.

 

得出RVA = 6000h

2.判斷屬於哪個節

我們發現,新增加了一個節,這個節就是重定位的節然后虛擬地址是6000位置,而且在文件偏移的位置也是6000h

那么我們就得出 FA = RVA了,那么就不用算了,可以確定,文件偏移位置就是6000就是重定位表的位置

 

3.定位文件偏移處,查看排列

然后可以看出 前八個字節分別保存頁的RVA偏移,以及大小,.我們使用計算器計算一下,看看有多大

計算的出 160h,這個大小,保存的是數組大小+上我們八個字節的總大小,也就是說160 - 8 = 數組的大小了.  

 

可以看出確實是怎么大,然后就到記錄下一個分頁了.

 

 

四丶數組解析查看

 那么按照我們的想法看上面重定位表中的數組的第一個,按照小尾方式讀取則是

0x3005  那么高位是3那么就是要修改大小是4個字節,005則是代表偏移.

至於高位怎么查看,VC++6.0中的宏已經定義了.

代碼:

#define IMAGE_REL_I386_ABSOLUTE         0x0000  // Reference is absolute, no relocation is necessary
#define IMAGE_REL_I386_DIR16            0x0001  // Direct 16-bit reference to the symbols virtual address
#define IMAGE_REL_I386_REL16            0x0002  // PC-relative 16-bit reference to the symbols virtual address
#define IMAGE_REL_I386_DIR32            0x0006  // Direct 32-bit reference to the symbols virtual address
#define IMAGE_REL_I386_DIR32NB          0x0007  // Direct 32-bit reference to the symbols virtual address, base not included
#define IMAGE_REL_I386_SEG12            0x0009  // Direct 16-bit reference to the segment-selector bits of a 32-bit virtual address
#define IMAGE_REL_I386_SECTION          0x000A
#define IMAGE_REL_I386_SECREL           0x000B
#define IMAGE_REL_I386_REL32            0x0014  // PC-relative 32-bit reference to the symbols virtual address

這里只需要知道0 1 2 代表的意思即可,因為0x3005的高位是 用位運算 | 上去的,所以3代表的是1 和 2的組合

0  對齊使用

1.修改高16位  

2.修改低16位

1和2 使用位運算|起來就是修改4個字節.

1.定位修改位置

那么怎么定位要修改的位置那?

 公式:

現在的ImageBase(模塊地址) +  當前分頁大小的虛擬地址 +5的位置等於要修改的位置:

比如假設我們的現在的模塊地址是00400000位置,而DLL以前的位置是10000000  而它以前的字符串的偏移是   10003045

首先定位修改地址:

 

00400000 + 1000 + 005 = 401005  那么在401005的位置就是你要修改的位置

比如我們在寫一個

0x3096 =  400000 + 1000 + 96 = 401096  那么定位的位置就是401096是你要修改的偏移,大小是4個字節,高位為3  為什么是4個字節,一會看下內部存儲

2.修改的偏移計算

比如我們調用一個printf 

push 10003096    "HelloWorld"

call    10004086  

那么我們要修正他的偏移

我們現在得知,以前的DLL偏移是  10000000    以前的字符串偏移是  10003096 ,不過因為DLL的模塊地址沒有滿足,那么現在的模塊地址變為了00400000的位置

那么我們要修正偏移

公式:

現在的ImageBase (00400000) - 以前的ImageBase(10000000) + 以前的偏移(10003096)

這樣寫匯編代碼好寫,如果便於理解的話,可以寫成下面那樣,只不過你需要知道的是匯編代碼就是上面這種寫法就行

以前的偏移(10003096)  - 以前的ImageBase(10000000) + 現在的ImageBase(00400000)  

= 3096 + 400000

= 403096  (計算出來的偏移)

那么push的位置就成了 403096了,已經重定位了.

 

五丶實戰演練查看

 因為DLL中的重定位表中的項太多,所以這里使用一個EXE(沒有導出函數的EXE),然后注入這個DLL,那么這個EXE就有重定位表格了.  

首先我們先看DLL, 3005的位置要重定位

按照公式我們得出,要修改的位置是

現在模塊地址 + 當前表中記錄分頁 + 數組中后三位的偏移(上面說過,如果按照分頁存儲,那么3位就可以表達一個分頁需要記錄的了)

那么現在  我們的EXE的模塊地址是00500000 + 1000(重定位表中第一項成員) + 005  (這是一個數組,第一個成員是0x3005  取出后三位則是005)

得出修改的位置是  00501005的位置,我們OD中CTRL+ G看看這個位置是不是要修正.

代碼亂了,那么我們可能斷掉指令了,那么此時CTRL + A重新分析一下.

 

可以看出,我們修正的位置是501005的位置,不過匯編代碼在501004才能顯示出來,501005后面正好是要修正的地址,那么只需要計算偏移填進去就可以了,大小是按照高4個字節, 現在0x3005 高位是3那么代表了要修正4個字節的偏移.

算出偏移位置:

偏移位置我們要進行反推了

因為OD已經幫我們重定位好了.

503000 = 現在的ImageBase - 以前的ImageBase + 以前的偏移 = 現在的偏移(503000)

那么現在計算以前的偏移

以前的偏移 = 現在的偏移 - 現在的ImageBase + 以前的ImageBase 

=  503000 - 50000 + 60000000 

= 3000 + 60000000

= 60003000 (以前的偏移)

那么算出了以前的偏移,我們就計算這4個字節要填寫的偏移,也就是503000怎么得出來的

公式上面說了:

 Cur (縮寫,代表當前的意思)  Old(代表舊的意思)  offset(代表偏移的意思)

CurImageBase - OldImageBase + OldOffset = 要填入的偏移

代入公式:

00500000  -  60000000  + 60030000 = 00503000 (要填寫的文件偏移)

看下我們當前的模塊地址:

Inject是我們當前的EXE的名稱,模塊地址在00500000的位置

DLL的模塊地址是60000000  這個地址是我們通過修改DLL中的選項頭中的ImageBase得到的.

 

 

六丶總結

 上面講的很細致

今天主要就是結構體會看,偏移會算即可.

總結一下公式

1.定位重定位的地址  (也就是在哪里修改)

首先從數組取出一項,(2個字節大小)

比如0x3005

公式:

定位修改地址  = 現在模塊 + 當前結構記錄分頁的RVA  + 取出數組的2個字節的低3位

例子: 00401000 + 1000 + 005 = 世紀你要修改的地址,修改大小和取出word自己的第一位有關

2.計算出偏移地址,填寫到定位地址的位置,使其偏移正確

現在的模塊地址  - DLL模塊地址 + 以前的偏移 = 實際修改的偏移

便於理解的公式:

以前的偏移 - DLL模塊地址 + 現在模塊地址 

3.計算出以前偏移

要計算出以前的偏移,你首先要得出現在的偏移,好在OD已經寫好了,其實文件中也有存儲的.(自己找吧)

以前的偏移 = 現在的偏移 - 現在模塊地址 + DLL模塊地址


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM