在前邊我們探討過RVA 這個詞,但對於初次接觸可攜式執行檔的朋友來說,顯得尤其陌生和無奈。中國人不喜歡老外的縮寫,但總要**著接受……不過,在有了前邊知識的鋪墊之後,現在來談這個概念大傢伙應該能夠得心應手了。起碼不用顯得那麼的費解和無奈~
RVA 是相對虛擬位址(Relative Virtual Address)的縮寫,顧名思義,它是一個“相對位址”。可攜式執行檔中的各種資料結構中涉及地址的欄位大部分都是以 RVA 表示的,有木有??
更為準確的說,RVA 是當可攜式執行檔被裝載到記憶體中後,某個資料位元置相對於檔案頭的位移量。舉個例子,如果 Windows 裝載器將一個可攜式執行檔裝入到 00400000h 處的記憶體中,而某個區塊中的某個資料被裝入 0040**xh 處,那麼這個資料的 RVA 就是(0040**xh - 00400000h )= **xh,反過來說,將 RVA 的值加上檔案被裝載的基地址,就可以找到資料在記憶體中的實際地址。
DOS 檔案頭、可攜式執行檔頭和區塊表的位移位置與大小均沒有變化。而各個區區塊對應到記憶體後,其位移位置就發生了變化。
RVA 使得檔案裝入記憶體後的資料定位變得方便,然而卻給我們要定位位於磁碟上的靜態可攜式執行檔帶來了麻煩。舉個例子說話:……由於例子在視頻中,這裡爭取時間我就不寫啦,大夥看參考視頻示範吧。
如何換算 RVA 和檔案位移呢?
當處理可攜式執行檔時候,任何的 RVA 必須經過到檔案位移的換算,才能用來定位並訪問檔案中的資料,但換算卻無法用一個簡單的公式來完成,事實上,唯一可用的方法就是最土最笨的方法:
步驟一:迴圈掃描區塊表得出每個區塊在記憶體中的起始 RVA(根據IMAGE_SECTION_HEADER 中的VirtualAddress 欄位),並根據區塊的大小(根據IMAGE_SECTION_HEADER 中的SizeOfRawData 欄位)算出區塊的結束 RVA(兩者相加即可),最後判斷目標 RVA 是否落在該區塊內。
步驟二:通過步驟一定位了目標 RVA 處於具體的某個區塊中後,那麼用目標 RVA 減去該區塊的起始 RVA ,這樣就能得到目標 RVA 相對於起始地址的位移量 RVA2.
步驟三:在區塊表中擷取該區塊在檔案中所處的位移地址(根據IMAGE_SECTION_HEADER 中的PointerToRawData 欄位), 將這個位移值加上步驟二得到的 RVA2 值,就得到了真正的檔案位移地址。