計算邏輯地址

    不知道有木有騷年和我一樣曾經疑惑過,我們說的分段機制轉換最開始的邏輯地址哪裏來的,比如程序的指令地址?要明白這個,我們首先需要知道代碼編譯成二進制後在磁盤上是怎麼組織的(以windows下的exe文件爲例)

    舉個栗子:

.386
.model flat,stdcall
Option Casemap:none

include			windows.inc
include			user32.inc
includelib		user32.lib
include			kernel32.inc
includelib		kernel32.lib

.data
	szText db 'fwddsg',0

.code
Start:
	invoke MessageBoxA,NULL,offset szText,offset szText,MB_OK
	invoke ExitProcess,0
end Start
    這段彙編使用MASMPlus編譯後會生成一個exe文件,功能很簡單,就是彈出個提示框。這段代碼啓動後第一條指令的地址是多少?


    這邊是OD加載程序後的截圖,這邊可以看到,Start處的地址爲0x401000,’fwddsg’字符串的地址是0x403000,這些邏輯地址怎麼來的呢?我們隨便用款PE文件解析器打開程序:
PE頭信息:


    這邊很容易看出,加載基址是0x400000,入口地址是0x1000,按這麼算第一條指令的地址恰好是0x401000,我們再看下代碼段和數據段在磁盤上的內容(想看文件在磁盤的內容,用UE打開exe文件即可)
代碼段:

    這邊RVA虛地址0x1000在磁盤0x400(節數據地址)上對應的內容和OD上的內容一模一樣,也就是說此節保存的就是代碼編譯後的指令(當然.text不一定保存的全是指令,只要節屬性相同的內容,數據也可以放這邊),所以第一條指令的起始地址就是0x40000+0x1000=0x401000,這邊由於程序的main地址就是代碼節起始地址,所以可以這樣計算

數據段:


    這邊的RVA虛地址0x3000在磁盤0x800(節數據地址)上對應的內容是’fwddsg’,加上起始地址0x400000=0x403000,這下知道常量字符串的地址怎麼算出來的嗎?(這邊要說下,dsg的含義據說語文好的認爲是大帥哥,語文不好的就認爲是大騷狗,很奇怪的是我身邊的人的語文好像都不怎麼好~)

    上面PE文件的相關信息是在程序編譯連接的時候由編譯器和連接器完成的(注意這個時候保存的是RVA),所以最初的邏輯地址在程序編譯連接完成後基本就可以計算出來了,細心的同學會發現大部分程序的加載基址都是0x400000(高10位爲1),這個表示使用頁目錄的第一項,所有程序都用這一個基址沒問題嗎?別忘了,程序每次啓動,操作系統都會爲其分配一個獨一無二的頁目錄基址,所以程序線性地址的索引相同也無所謂
(這邊所有描述基本基於EXE文件,其他格式的PE文件可能有點不同,PE文件結構和加載詳細過程可參考《琢石成器》相關章節)

發佈了32 篇原創文章 · 獲贊 13 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章