2011-09-03 74 views
3

今天我有一個想法,試圖手動加載編譯後的代碼。我腦海裏想的是讀取一個編譯後的目標文件並將其存儲到一個緩衝區中,獲取緩衝區中的位置什麼是入口點,獲取該元素的地址,並將其轉換爲函數指針並通過指針調用該函數。但是,我發現了一個障礙:如何從包含編譯代碼的字節數組中獲取主函數(或任意函數)的地址?手動加載已編譯的代碼

謝謝

P.我知道我可以使用API​​動態加載,但我想手動執行它...如果這不是一項壓倒性的努力。這只是一個概念驗證項目,所以我沒有問題保持簡單! 再次感謝!

+2

您是否明確想要與'dlopen()'不同的東西,它在運行時加載共享庫? –

+0

你正在尋找的是所討論的.o文件的文件格式,這取決於它們被編譯的內容以及可能的編譯時選項。 nm實用程序可能是您的朋友。 – JustJeff

+2

此外,無論您是在編譯「手動加載」代碼,都需要有一個調用約定,與編譯到正在加載的.o中的內容兼容。好事,這只是概念驗證。 – JustJeff

回答

0

如果你使用目標文件或鏈接庫來做這件事,那基本上是手動映射,你可以在這裏得到一個相當不錯的閱讀/參考(但是對於windows):http://pastebin.com/HbWNAV99代碼執行存儲的緩衝區,這是JIT會做的事情,因此需要預先計算入口點並將緩衝區內存設置爲可執行。

1

您可以在二進制文件中搜索函數序言,它會給你所有的函數,但是你將無法判斷哪個函數是入口點。假設你也可以搜索函數調用,然後假設在整個目標文件中未被調用的函數調用是你的入口點。看起來有點受虐狂,但再一次,手動加載和調用一個對象文件,而不是一個exe或加載一個DLL,在這種情況下,不需要知道入口點。下面是這兩個函數我說的是:

/* 
prologue: 
    push ebp ; 55 
    mov ebp esp ; 8B EC 

functionCall: 
    call foo ; E8 &foo 
*/ 
const unsigned char prologueBin[] = {0x55, 0x8B, 0xEC}; 
const unsigned char callOpcode = 0xE8; 


inline bool isThisAfunction(unsigned char* pBin) { 
    return (pBin[0] == prologueBin[0] && pBin[1] == prologueBin[1] && pBin[2] == prologueBin[2]); 
}; 
inline bool isThisCall(unsigned char* pBin) { 
    return *pBin == callOpcode; 
}; 

isThisCall()可以打開了大量的誤報,但因爲你會用它來宰殺你的函數列表止跌回升通過isThisAfunction(),它是不可能消除一個並不真正被調用的函數。

基本上,我只推薦這個,如果你真的需要加載一塊你完全不知道的東西並稱之爲函數。