2011-06-24 18 views
3

這裏的東西不那麼重要了,我最近一直在沉思一下:Discover程序在內存中的圖像

我知道,我的程序的虛擬地址空間包含(每個線程)的棧和堆和一些靜態分配內存等等。但是它是否包含程序的所有圖像?是否有可能以某種方式(無論平臺如何依賴這個技巧)找出我自己的圖像的地址範圍?內存是隻讀的嗎?

總之:我可以製作一個打印自己的程序嗎?

如果無法完成,問題會更少,我可以打印自己的堆棧嗎?我想是這樣的:

const char * BASE; 

void print_stack(); 

int main(int argc, char * argv[]) { 
    BASE = &argc; 
    /* do stuff */ 
    print_stack(); 
    return 0; 
} 

void print_stack() { 
    int sentinel; 
    const char * bottom = &sentinel; 
    while (bottom < BASE) 
    printf("%02X ", *bottom++); 
} 
+0

@Joe:謝謝,我從來不知道''! –

回答

1

要回答你的第一個問題,當然也包含了你的程序的說明:你只能執行您可以訪問什麼。要查看說明的地址,您可以獲取功能的地址並從那裏開始打印。然後你可以使用像udis86這樣的庫來拆卸它們。但請注意,編譯器不需要以任何特定方式對函數進行排序,因此從main開始並從中讀取並不能保證獲得所有內容,可能會對未分配的內存進行踐踏。要在整個指令內存範圍內(您正在尋找.text段),可以從操作系統中查找地址+大小(在Linux中,該信息將在/proc/[pid]/maps,在OS X中爲可以使用vmmap或通過mach_vm_region()內核陷阱詢問內核),然後直接讀取內存。您也可以使用nm轉儲程序的符號,將所有指向0123'段(它們應標記爲T,nm輸出)並將其轉儲。這不是一個好的方法,因爲你必須拆卸所有的東西,以確定它們之間有填充的情況下它們結束的位置。

所有映射的內存都可以訪問,但並非全部都是可寫的(.text段不會)。有一點要記住,如果你的操作系統實現ASLR,這些地址可能不會穩定地調用調用。

要解決您的第二個問題,是的,您可以打印自己的堆棧並在第三方庫的幫助下對其進行打印,但不是您嘗試這樣做的方式。作爲讀者的練習,可以通過gdb或其他反彙編器反彙編你的一個函數,並查看在你的函數序言期間堆棧中的內存是如何分配的) ,因此您的for-loop將永遠不會運行,因爲BASE可能總是大於sentinel的地址。

+0

感謝您的所有提示!我會看'/ proc/[pid]/maps',非常有趣。我不想'nm',我只是想在執行過程中在實時內存中徘徊。當然,堆棧會下降,哦。我會解決這個問題! –

1

是的,代碼字節(通常在此上下文中稱爲程序「文本」)是虛擬地址空間的一部分。

您可以確定函數的地址,例如, main(),並用它來確定一系列文本頁面中的單個有效地址。您將不得不調用虛擬內存特定的API來確定該地址映射的範圍。

共享庫(.so文件)將其文本映射到不連續的VM區域。

+0

我的所有功能都是隱約連續的,即,如果我從'&main'開始打印直到出現segfault,我會看到所有內容嗎? –

+0

通常,所有鏈接在一起的.o文件都放置在一個連續的範圍內。這不受任何標準的保證。在.o文件中,代碼字節幾乎總是連續的。主要不一定會在這個記憶範圍的開始處。如果你從一個地址開始讀取並從那裏移動任何一個方向,你可能會不知不覺地進入堆棧,堆棧或數據存儲器。 –

+0

好玩。我可以問操作系統一個給定的地址是否已分配給我?這樣我就可以在兩個方向走路,並在我跳出界限時停下來。 –

相關問題