2013-04-25 146 views
3

爲了調試目的(獲取調用堆棧),我正在努力將地址映射到它們的符號。 MS dbghelp.dll可以從地址中分辨符號(請參閱SymFromAddrMSDN)。但是,它不工作,我不知道這到底是怎麼過的工作,因爲地址似乎與程序的每次運行變化:爲什麼函數的地址會隨着每次運行而改變?

#include <iostream> 
void Foo() {} 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    const long unsigned int addr = reinterpret_cast<long unsigned int>(&Foo); 
    std::cout << "Address: " << std::hex << addr << std::endl; 
    return 0; 
} 

輸出:

D:\dev\Sandbox\Debug>Sandbox.exe 
Address: 901320 
D:\dev\Sandbox\Debug>Sandbox.exe 
Address: ce1320 
D:\dev\Sandbox\Debug>Sandbox.exe 
Address: 3a1320 
D:\dev\Sandbox\Debug>Sandbox.exe 
Address: 3f1320 

怎麼可能不同以往的程序從堆棧跟蹤中讀取地址並將其映射到函數?這聽起來對我來說很神奇。我沒有在鏈接的文檔中找到任何說我必須從地址或其他東西中減去某些東西的東西。

在我的理解中,由於我們克服了實模式,每一個進程都有一個虛擬內存空間,因此不需要再爲一個加載地址擲骰子。如果是DLL,我會理解絕對地址的不確定性,但不是主要的可執行文件。

使用VS2008試用Win7。

+0

這個隨機化的幾個答案,謝謝!我就像跆拳道!如何在這個超級MS「安全通過默默無聞」堆棧轉儲有用嗎? – Borph 2013-04-25 12:35:13

+0

因爲所有調試器都可以處理隨機加載的模塊。 DLL一直在移動。 – MSalters 2013-04-25 12:54:25

回答

3

因爲你的代碼被編譯爲使用地址空間佈局隨機化,這使得代碼更不容易受到攻擊,從「StackOverflows」。

如果你真的想改變這一點,那麼有一個linker option

2

這是ASLR在行動,如其他人已經提到。

看起來您需要做的是在調用SymLoadModuleEx()時爲可執行文件指定圖像庫。這是BaseOfDll參數。

我不知道確切位置,它保存在崩潰轉儲(如果在這個時候,其他程序與工作),但正在運行的程序可以獲取使用其自己的映像基址GetModuleHandle()(討論here)。

您可能想要保存加載到進程中的所有DLL的名稱和基地址,而不僅僅是EXE本身的名稱和基址。

+0

是的,謝謝!我正在減去正在運行的代碼中的基地址,因此日誌文件具有相對地址,並且工作正常。 GetModuleHandle()取得了訣竅。將來我可以處理所有DLL,但稍後會做。 – Borph 2013-04-26 07:54:07

相關問題