2011-11-13 61 views
5

我想知道是否有人能夠幫助我解決我在學習時參加的入門彙編課程中的一個演講幻燈片時遇到的問題。我遇到的問題是不瞭解程序集,它是如何根據程序集確定C源代碼的順序。我將發佈我正在談論的片段,也許它會更清楚我所談論的內容。從程序集逆向工程C源代碼

C源給出:

int arith(int x, int y, int z) 
{ 
    int t1 = x+y; 
    int t2 = z+t1; 
    int t3 = x+4; 
    int t4 = y * 48; 
    int t5 = t3 + t4; 
    int rval = t2 * t5; 
    return rval; 
} 

大會授予:

arith: 
pushl %ebp 
movl %esp,%ebp 

movl 8(%ebp),%eax 
movl 12(%ebp),%edx 
leal (%edx,%eax),%ecx 
leal (%edx,%edx,2),%edx 
sall $4,%edx 
addl 16(%ebp),%ecx 
leal 4(%edx,%eax),%eax 
imull %ecx,%eax 

movl %ebp,%esp 
popl %ebp 
ret 

我只是困惑,我應該如何才能夠辨別例如,市場z + t1的增加(z + x + y)在彙編代碼中出現在第二行(源代碼中)時,它在彙編代碼中位於y * 48之後,或者例如x + 4是彙編中的第3行,它甚至不在其自身行中,與最後的leal聲明混在一起。當我有源代碼時,對我來說是有道理的,但是我應該能夠重現測試的源代碼,並且我明白,編譯器會優化事情,但是如果任何人有一種思考逆向工程的方法可以幫助我如果他們能夠引導我完成他們的思考過程,我將不勝感激。

謝謝。

+0

什麼優化你,當你正在編譯使用水平?如果您想要逐行轉換,請使用-O0,否則,您需要考慮優化。 – Maz

+1

...和逆轉優化代碼回到原來的C語句順序並不完全可能的。 –

+0

你確定這是一個天真的彙編?它看起來有點優化。寫下函數計算的代數表達式,看看你是否可以發現它。 –

回答

9

我已經分解了反彙編,以顯示如何從C源代碼生成程序集。

8(%ebp) = x12(%ebp) = y16(%ebp) = z

arith: 

創建堆棧幀:

pushl %ebp 
movl %esp,%ebp 


移動 xeaxyedx

movl 8(%ebp),%eax 
movl 12(%ebp),%edx 


t1 = x + yleal(加載有效地址)將添加 edxeax,和 t1將在 ecx

leal (%edx,%eax),%ecx 


int t4 = y * 48;在下面兩個步驟,乘以3,然後通過16 t4最終將 edx

乘以edx乘以2,並將edx加上結果,即。 edx = edx * 3

leal (%edx,%edx,2),%edx 

左移4位,即,由16乘:

sall $4,%edx 


int t2 = z+t1;ecx 最初保持 t1z是在 16(%ebp),在指令 ecx的端部將被保持 t2

addl 16(%ebp),%ecx 


int t5 = t3 + t4;t3只不過是 x + 4,而不是計算和存儲 t3t3的表達式放在一行。該指令至關重要,它與 t3 + t4相同。它增加了 edxt4)和 eaxx),並將4作爲 偏移量來實現該結果。

leal 4(%edx,%eax),%eax 

int rval = t2 * t5;相當直接的這一個; ecx代表t2eax代表t5。返回值通過eax傳回給調用者。

imull %ecx,%eax 


銷燬堆棧幀和恢復 espebp:從日常

movl %ebp,%esp 
popl %ebp 


返回:

ret 


從這個例子可以看出, resul噸是一樣的,但結構有點不同。最有可能的是,這些代碼是通過某種優化編譯的,或者有人自己寫了這些代碼來證明一個觀點。

正如其他人所說,你不能去準確地返回到從拆卸的來源。這取決於閱讀程序集的人的解釋以提供相應的C代碼。


爲了幫助學習組件和理解你的C程序的拆卸,你可以做在Linux上執行以下操作:

編譯與調試信息(-g),這將嵌入源:

gcc -c -g arith.c 

如果你是一個64位的機器上,你可以告訴編譯器創建與-m32標誌一個32位二進制(我這樣做了下面的例子)。


使用objdump的轉儲對象文件與它的源交織:

objdump -d -S arith.o 

-d =拆卸,-S =顯示源。您可以添加-M intel-mnemonic,如果你喜歡,在過& T語法,你的例子使用使用英特爾ASM語法。

輸出:

arith.o:  file format elf32-i386 


Disassembly of section .text: 

00000000 <arith>: 
int arith(int x, int y, int z) 
{ 
    0: 55      push %ebp 
    1: 89 e5     mov %esp,%ebp 
    3: 83 ec 20    sub $0x20,%esp 
    int t1 = x+y; 
    6: 8b 45 0c    mov 0xc(%ebp),%eax 
    9: 8b 55 08    mov 0x8(%ebp),%edx 
    c: 01 d0     add %edx,%eax 
    e: 89 45 fc    mov %eax,-0x4(%ebp) 
    int t2 = z+t1; 
    11: 8b 45 fc    mov -0x4(%ebp),%eax 
    14: 8b 55 10    mov 0x10(%ebp),%edx 
    17: 01 d0     add %edx,%eax 
    19: 89 45 f8    mov %eax,-0x8(%ebp) 
    int t3 = x+4; 
    1c: 8b 45 08    mov 0x8(%ebp),%eax 
    1f: 83 c0 04    add $0x4,%eax 
    22: 89 45 f4    mov %eax,-0xc(%ebp) 
    int t4 = y * 48; 
    25: 8b 55 0c    mov 0xc(%ebp),%edx 
    28: 89 d0     mov %edx,%eax 
    2a: 01 c0     add %eax,%eax 
    2c: 01 d0     add %edx,%eax 
    2e: c1 e0 04    shl $0x4,%eax 
    31: 89 45 f0    mov %eax,-0x10(%ebp) 
    int t5 = t3 + t4; 
    34: 8b 45 f0    mov -0x10(%ebp),%eax 
    37: 8b 55 f4    mov -0xc(%ebp),%edx 
    3a: 01 d0     add %edx,%eax 
    3c: 89 45 ec    mov %eax,-0x14(%ebp) 
    int rval = t2 * t5; 
    3f: 8b 45 f8    mov -0x8(%ebp),%eax 
    42: 0f af 45 ec    imul -0x14(%ebp),%eax 
    46: 89 45 e8    mov %eax,-0x18(%ebp) 
    return rval; 
    49: 8b 45 e8    mov -0x18(%ebp),%eax 
} 
    4c: c9      leave 
    4d: c3      ret 

正如你可以看到,沒有優化編譯器產生比你有例如通過更大的二進制。你可以玩的是和編譯時添加一個編譯器優化標誌(即-O1-O2-O3)。優化級別越高,反彙編看起來就越抽象。

例如,只有1級優化(gcc -c -g -O1 -m32 arith.c1),產生的彙編代碼是短了很多:

00000000 <arith>: 
int arith(int x, int y, int z) 
{ 
    0: 8b 4c 24 04    mov 0x4(%esp),%ecx 
    4: 8b 54 24 08    mov 0x8(%esp),%edx 
    int t1 = x+y; 
    8: 8d 04 11    lea (%ecx,%edx,1),%eax 
    int t2 = z+t1; 
    b: 03 44 24 0c    add 0xc(%esp),%eax 
    int t3 = x+4; 
    int t4 = y * 48; 
    f: 8d 14 52    lea (%edx,%edx,2),%edx 
    12: c1 e2 04    shl $0x4,%edx 
    int t5 = t3 + t4; 
    15: 8d 54 11 04    lea 0x4(%ecx,%edx,1),%edx 
    int rval = t2 * t5; 
    19: 0f af c2    imul %edx,%eax 
    return rval; 
} 
    1c: c3      ret 
6

您無法複製原始來源,只能複製等效來源。

在你的情況下,t2的計算可以出現在t1之後和retval之前的任何地方。

源甚至可能是一個單一的表達式:

return (x+y+z) * ((x+4) + (y * 48)); 
1

Decompilation不完全實現的:有一些知識損失的源代碼(其中評論&名字給你原來的線索去時程序員的意圖)二進制機器代碼(其中指令將由處理器執行)。

5

逆向工程時,您並不關心原始源代碼,而是關心它的功能。副作用是你看到了代碼的作用,而不是程序員想要代碼做什麼。