複製鏈接
請複製以下鏈接發送給好友

文件偏移地址

鎖定
文件偏移地址是指數據在PE文件中的地址,是文件在磁盤上存放時相對於文件開頭的偏移。文件偏移地址從pe文件的第一個字節開始計數,起始值為0。用十六進制工具(如WINHEX)打開文件所顯示的地址就是文件偏移地址。
中文名
文件偏移地址
外文名
WINHEX
起始值
0
文件基址
EXE為0x00400000

文件偏移地址名詞解釋

文件偏移:靜態反彙編工具看到的PE文件中某條指令的位置是相對於磁盤文件的。IDA Pro雖然是靜態反彙編工具,不過出來的是VA。
裝載基址(Image Base):PE文件裝入內存的 基地址。默認情況下,EXE文件的基址為0x00400000,DLL文件的基址為0x10000000。
虛擬內存地址(VA):PE文件中的指令被裝入內存後的地址,OllyDbg動態反彙編產生。
相對虛擬地址(RVA):內存地址相對與映射基址的偏移量。
VA = Image Base + RVA。
PE文件中的數據按照磁盤數據標準存放,以0x200字節為基本單位進行組織。 代碼裝入內存後,將按照內存數據標準存放,以0x1000字節為基本單位進行組織。
以下內容將十分有助於理解上述抽象名詞:

文件偏移地址文件組織

在Windows系統下,當一個PE應用程序運行時,這個PE文件在磁盤中的數據結構佈局和內存中的數據結構佈局是一致的。系統在載入一個可執行程序時,首先是Windows裝載器(又稱PE裝載器)把磁盤中的文件映射到進程的地址空間,它遍歷PE文件並決定文件的哪一部分被映射。其方式是將文件較高的偏移位置映射到較高的內存地址中。磁盤文件一旦被裝入內存中,其某項的偏移地址可能與原始的偏移地址有所不同,但所表現的是一種從磁盤文件偏移到內存偏移的轉換。
PE文件內存映射
當PE文件被加載到內存後,內存中的版本稱為模塊(Module),映射文件的起始地址稱為模塊句柄(hModule),可以通過模塊句柄訪問內存中的其他數據結構。這個初始內存地址也稱為文件映像基址(ImageBase)。載入一個PE程序的主要步驟如下:
(1)當PE文件被執行時,PE裝載器首先為進程分配一個4GB的虛擬地址空間,然後把程序所佔用的磁盤空間作為虛擬內存映射到這個4GB的虛擬地址空間中。一般情況下,會映射到虛擬地址空間中0x400000的位置。裝載一個應用程序的時間比一般人所設想的要少,因為裝載一個PE文件並不是把這個文件一次性地從磁盤讀到內存中,而是簡單地做一個內存映射,映射一個大文件和映射一個小文件所花費的時間相差無幾。當然,真正執行文件中的代碼時,操作系統還是要把存在於磁盤上的虛擬內存中的代碼交換到物理內存(RAM)中。但是,這種交換也不是把整個文件所佔用的虛擬地址空間一次性地全部從磁盤交換到物理內存中,操作系統會根據需要和內存佔用情況交換一頁或多頁。當然,這種交換是雙向的,即存在於物理內存中的一部分當前沒有被使用的頁,也可能被交換到磁盤中。
(2)PE裝載器在內核中創建進程對象和主線程對象以及其他內容。
(3)PE裝載器搜索PE文件中的Import Table(引入表),裝載應用程序所使用的動態鏈接庫。對動態鏈接庫的裝載與對應用程序的裝載方法完全類似。
(4)PE裝載器執行PE文件首部所指定地址處的代碼,開始執行應用程序主線程。
2.2.3 Big-endian和Little-endian
PE Header中IMAGE_FILE_HEADER的成員Machine 中的值,根據winnt.h中的定義,對於Intel CPU應該為0x014c。但是用十六進制編輯器打開PE文件時,看到這個WORD顯示的卻是4c 01。其實4c 01就是0x014c,只不過由於Intel CPU是Little-endian,所以顯示出來是這樣的。對於Big-endian和Little-endian,請看下面的例子。一個整型int變量,長度為4個字節。當這個整形變量的值為0x12345678時,對於Big-endian來説,顯示的是{12,34,45,78},而對於Little-endian來説,顯示的卻是{78,45,34,12}。注意Intel使用的是Little-endian。
2.2.4 3種不同的地址
PE文件的各種結構中,涉及到很多地址、偏移。有些是指在文件中的偏移,有些 是指在內存中的偏移。以下的第一種是指在文件中的地址,第二、三種是指在內存中的地址。
第一種,文件中的地址。比如用十六進制編輯器打開PE文件,看到的地址(偏移)就是文件中的地址,使用某個結構的文件地址,就可以在文件中找到該結構。
第二種,當文件被整個映射到內存時,例如某些PE分析軟件,把整個PE文件映射到內存中,這時是內存中的虛擬地址(VA)。如果知道在這個文件中某一個結構的內存地址的話,那麼它等於這個PE文件被映射到內存的地址加上該結構在文件中的地址。
第三種,當執行PE時,PE文件會被載入器載入內存,這時經常需要的是RVA。例如知道一個結構的RVA,那麼程序載入點加上RVA就可以得到該結構的內存地址。比如,如果PE文件裝入虛擬地址(VA)空間的0x400000處,某一結構的RVA 為0x1000,那麼其虛擬地址為0x401000。
PE文件格式要用到RVA,主要是為了減少PE裝載器的負擔。因為每個模塊都有可能被重載到任何虛擬地址空間,如果讓PE裝載器修正每個重定位項,這肯定是個夢魘。相反,如果所有重定位項都使用RVA,那麼PE裝載器就不必操心那些東西了,即它只要將整個模塊重定位到新的起始VA。這就像相對路徑和絕對路徑的概念:RVA類似相對路徑,VA就像絕對路徑。
注意,RVA和VA是指內存中,不是指文件中。是指相對於載入點的偏移而不是一個內存地址,只有RVA加上載入點的地址,才是一個實際的內存地址。