2013-06-30 53 views
3

我想了解有關unix/linux的更多信息,並將此問題彈入我的腦海 - 假設我創建了一個靜態/動態庫(.a或.so )並丟失了c/C++源代碼和頭文件。默認nm輸出給我的符號的名稱,但我需要知道返回類型和參數計數/類型來製作頭。是否有可能以某種方式獲得這些額外的信息來逆向設計給定庫的頭文件?假設 - 關於爲*現有*靜態/動態庫製作標題

回答

0

牢記主叫/被叫約定不同的處理器指令集有所不同,你已經知道名字的同時使用C和C++庫重整在一起,你可以試試下面的方法:

gdb <executable> 
.... 
disas <function name> 
.... 
Here you can make a wild guess about the type of return value and parameters using the bit size of those values written on stack making use of assembly code. 
3

您標記C和C++,兩者之間的答案略有不同。

對於C++,類的方法名稱中嵌入了符號名稱中的類型信息。你只需要弄清楚編譯該庫的編譯器如何改變名稱。

對於C來說,沒有真正乾淨的方法來做到這一點。您可以分解程序集並分析哪些寄存器和堆棧區在未寫入的情況下被讀取以找出函數需要多少個參數。這需要知道任何編譯器編譯庫所使用的調用約定。

同樣,你可以看看每個參數是如何在程序集中使用的。如果你看到它在加載指令中使用,它很可能是某種類型的指針,而如果你看到它在算術中使用,它可能是某種類型的整數。

對於返回類型,您可以檢查在返回指令之前是否有任何看似有意義的東西放入返回寄存器中。同樣,這需要知道您的平臺的調用約定。

下面是我如何在ARM程序集中做的事情的一個例子。

我知道ARM中的參數在寄存器r0到r3中傳遞,返回值存儲在寄存器r0中。考慮到這一點,我們可以開始逆向工程。讓我們來看看程序集中的兩個函數,並試圖找出函數原型是什麼。

00000000 <func1>: 
    0: e3510000 cmp r1, #0 
    4: 0a000007 beq 28 <func1+0x28> 
    8: e0801001 add r1, r0, r1 
    c: e1a03000 mov r3, r0 
    10: e3a00000 mov r0, #0 
    14: e4d32001 ldrb r2, [r3], #1 
    18: e1530001 cmp r3, r1 
    1c: e0800002 add r0, r0, r2 
    20: 1afffffb bne 14 <func1+0x14> 
    24: e12fff1e bx lr 
    28: e1a00001 mov r0, r1 
    2c: e12fff1e bx lr 

如果我們看看這裏,r0和r1在寫入任何內容之前都會被讀取。我們還可以看到r2和r3是在讀取之前寫入的。因此我們可以推斷func1最多有兩個參數。

我們也認識到,r0被移到r3,然後用作地址ldrb,這是一個從內存加載字節的指令。因此,我們推斷第一個參數是一個指針。由於指令只加載一個字節,我們也可以告訴它可能是指向某種單字節數據類型的指針。

r1中的第二個參數似乎永遠不會用於除比較和添加指令,因此它可能是一個整數。

在每個bx lr(返回調用者指令)之前,將某些內容放在r0中,因此我們推斷該函數返回某種類型的值。

如果此功能被提交給我,我猜的函數原型將是這個樣子:

int func1(unsigned char *, int); 

原文:

unsigned int func1(void *, unsigned int); 

這裏有一個其他功能

00000030 <func2>: 
    30: e0822001 add r2, r2, r1 
    34: e5c02000 strb r2, [r0] 
    38: e12fff1e bx lr 

這個很容易。

我們看到r0,r1和r2都是在寫入之前讀取的,所以我們可以猜測函數需要三個參數。 r0用作strb指令(存儲字節)的地址,所以它可能是一個指針。同樣,它只存儲一個字節,所以它可能是一個指向字節大小數據類型的指針。

另外兩個只用於add指令,所以可能是整數。

似乎沒有將任何內容放入r0中,因此該函數要麼返回第一個參數,要麼不返回值。

我猜原型將是以下

void func2(unsigned char *, int, int); 
unsigned char *func2(unsigned char *, int, int); 

原件之一:

void func2(char *, char, char); 
+0

哦,是的,沒錯我記得的地方閱讀信息前年齡被嵌入的符號名稱或某物C++,但當時我的頭腦已經超出了我的想法。我實際上使用C++而不是c,但是當我發現它時正在閱讀一本c書。 我用g ++重新編譯了我的測試代碼,並創建了一個.a文件,我可以看到這些符號帶有後綴,並且它們採用了整數,所以這就意味着什麼。 _Z4前綴是(4字節)int返回值也許?不管怎樣,謝謝!非常有趣的東西... 學習彙編程序是在我的待辦事項列表,但我還沒有在那裏。不過,我現在更有動力了! – Bevan

+0

我還會舉一個例子 – tangrs