2012-09-02 232 views
4

我的問候&向所有人致意。我有一個C程序,基本上寫測試緩衝區溢出。這條指令是做什麼的?: - mov%gs:0x14,%eax

#include<stdio.h> 
    void display() 
    { 
      char buff[8]; 
      gets(buff); 
      puts(buff); 
    } 
    main() 
    { 
     display(); 
     return(0); 
    } 

現在我使用GDB反彙編它的顯示和主要部分。該代碼: - 彙編代碼的功能主要

轉儲:

0x080484ae <+0>: push %ebp  # saving ebp to stack 
    0x080484af <+1>: mov %esp,%ebp # saving esp in ebp 
    0x080484b1 <+3>: call 0x8048474 <display> # calling display function 
    0x080484b6 <+8>: mov $0x0,%eax # move 0 into eax , but WHY ???? 
    0x080484bb <+13>: pop %ebp  # remove ebp from stack 
    0x080484bc <+14>: ret    # return 

彙編轉儲結束。

轉儲的彙編代碼功能顯示:

0x08048474 <+0>: push %ebp   #saves ebp to stack   
    0x08048475 <+1>: mov %esp,%ebp  # saves esp to ebp 
    0x08048477 <+3>: sub $0x10,%esp # making 16 bytes space in stack 
    0x0804847a <+6>: mov %gs:0x14,%eax # what does it mean ???? 
    0x08048480 <+12>: mov %eax,-0x4(%ebp) # move eax contents to 4 bytes lower in stack 
    0x08048483 <+15>: xor %eax,%eax  # xor eax with itself (but WHY??) 
    0x08048485 <+17>: lea -0xc(%ebp),%eax #Load effective address of 12 bytes 
               lower placed value (WHY????) 

    0x08048488 <+20>: mov %eax,(%esp)  #make esp point to the address inside of eax 
    0x0804848b <+23>: call 0x8048374 <[email protected]> # calling get, what is "@plt" ???? 
    0x08048490 <+28>: lea -0xc(%ebp),%eax  # LEA of 12 bytes lower to eax 
    0x08048493 <+31>: mov %eax,(%esp)   # make esp point to eax contained address 
    0x08048496 <+34>: call 0x80483a4 <[email protected]> # again what is "@plt" ???? 
    0x0804849b <+39>: mov -0x4(%ebp),%eax # move (ebp - 4) location's contents to eax 
    0x0804849e <+42>: xor %gs:0x14,%eax   # # again what is this ???? 
    0x080484a5 <+49>: je  0x80484ac <display+56> # Not known to me 
    0x080484a7 <+51>: call 0x8048394 <[email protected]> # not known to me 
    0x080484ac <+56>: leave      # a new instruction, not known to me 
    0x080484ad <+57>: ret       # return to MAIN's next instruction 

彙編轉儲結束。

所以人們,你應該考慮我的功課。休息所有的代碼是我知道的,除了幾行。我已經包括一個大「爲什麼????」以及每行前面的評論中的更多問題。對我來說第一個障礙是「mov%gs:0x14,%eax」指令,我不能在這個指令之後做出流程圖。有人告訴我,這幾個指令是什麼意思,並在程序中做什麼?謝謝...

+2

主要返回0,這就是爲什麼'mov $ 0x0,%eax'。 – Qiau

+1

''xor%eax,%eax'是一種清除%eax的高效方法,因爲xor-ing相同的值總是會產生0. – Qiau

+5

'gs:0x14'的操作看起來像[stack canary](http:///en.wikipedia.org/wiki/Stack_buffer_overflow#Stack_canaries)。 'xor%eax,%eax'只是將'eax'設置爲'0'的一種方法。 'lea -0xc(%ebp),%eax'將'buff'的地址加載到'eax'中,所以它可以傳入'gets/puts'。 – DCoder

回答

6
0x0804849e <+42>: xor %gs:0x14,%eax   # # again what is this ???? 
0x080484a5 <+49>: je  0x80484ac <display+56> # Not known to me 
0x080484a7 <+51>: call 0x8048394 <[email protected]> # not known to me 
0x080484ac <+56>: leave      # a new instruction, not known to me 
0x080484ad <+57>: ret       # return to MAIN's next instruction 

了GS segment可用於thread local storage。例如。它用於errno,所以多線程程序中的每個線程都有自己的errno變量。

上面的函數名是一個很大的線索。這必須是stack canary

leave是一些CISC指令,可以完成您在實際ret之前需要做的所有事情,但我不知道詳細信息)。

+0

感謝朋友們,對於我來說謝謝大家的回覆。我是初學者。所以我在Google上搜索你答案中使用的新術語。 – kriss

+0

「堆棧金絲雀」一詞以及其他解釋。很好的信息,謝謝 –

1

stack_check_fail是gcc緩衝區溢出檢查的一部分。它使用libssp(stack-smash-protection),並且你在開始時的移動爲堆棧設置了一個守護進程,並且xor%gs:0x14 ...是一個檢查,看看守衛是否仍然可以。當它沒問題時,它跳轉到離開(檢查彙編程序doc,它是堆棧處理的幫助程序指令)並跳過跳轉到stack_chk_fail,這會中止程序併發出錯誤消息。

您可以使用gcc選項-fno-stack-protector禁用發出此溢出檢查。

正如已經在評論中提到的那樣,xor x,x只是一個清除x的快速命令,而最終的mov 0,%eax是用於main的返回值。

3

其他已經解釋了GS的事情(與線程做)..

0x08048483 <+15>: xor %eax,%eax  # xor eax with itself (but WHY??) 

對此作出解釋需要的X86架構的一些歷史:

的XOR EAX,EAX指令清除所有位在寄存器eax中(加載一個零),但是正如你已經發現的那樣,這似乎是不必要的,因爲寄存器在下一條指令中加載了一個新值。

但是,xor eax,eax在x86上也做了其他事情。你可能知道你可以通過使用al,ah和ax來訪問寄存器eax的一部分。自386年以來,它就一直如此,當時eax真的是一個單一的寄存器,那時情況還好。

但是,這是沒有更多。您在代碼中看到並使用的寄存器只是佔位符。 CPU內部使用更多的內部寄存器和完全不同的指令集。你寫的指令被翻譯成這個內部指令集。

如果您使用AL,AH和EAX,例如您從CPU的角度使用三個不同的寄存器。

現在,如果您在使用AL或AH後訪問EAX,則CPU必須合併這些不同的寄存器才能生成有效的EAX值。

行:

0x08048483 <+15>: xor %eax,%eax  # xor eax with itself (but WHY??) 

不僅清除eax寄存器。它還告訴CPU所有重命名的子寄存器:AL,AH和AX現在可以認爲是無效的(設爲零),並且CPU不必做任何子寄存器合併。

爲什麼編譯器會發出這條指令?

因爲編譯器不知道將在哪個上下文中調用display()。你可以從一段使用AL和AH進行大量字節算術的代碼中調用它。如果它不能通過XOR清除EAX寄存器,那麼CPU將不得不進行昂貴的寄存器合併,這會花費很多週期。

因此,在函數啓動時做這些額外的工作可以提高性能。在你的情況下是沒有必要的,但是因爲編譯器不知道發出的指令是肯定的。

10
0x080484b6 <+8>: mov $0x0,%eax # move 0 into eax , but WHY ???? 

不要你有這個?:

return(0); 

他們可能有關。 :)

0x0804847a <+6>: mov %gs:0x14,%eax # what does it mean ???? 

這意味着從地址爲gs:0x14的內存中讀取4個字節到eax中。 gs是一個段寄存器。最可能的線程本地存儲(AKA TLS)通過此寄存器引用。

0x08048483 <+15>: xor %eax,%eax  # xor eax with itself (but WHY??) 

不知道。可能與優化有關。

0x08048485 <+17>: lea -0xc(%ebp),%eax #Load effective address of 12 bytes 
              lower placed value (WHY????) 

它使eax指向一個位於堆棧上的局部變量。 sub $0x10,%esp爲他們分配了一些空間。

0x08048488 <+20>: mov %eax,(%esp)  #make esp point to the address inside of eax 

錯了。它將eax寫入堆棧頂部。它將作爲堆棧參數傳遞給被調用函數:

0x0804848b <+23>: call 0x8048374 <[email protected]> # calling get, what is "@plt" ???? 

我不知道。可能是一些名字搗毀。

現在你應該已經猜到了什麼是局部變量。 buff,它還能是什麼?

0x080484ac <+56>: leave      # a new instruction, not known to me 

爲什麼不在CPU手冊中查找它?

現在,我大概可以解釋你的GS/TLS的事情......

0x08048474 <+0>: push %ebp   #saves ebp to stack   
0x08048475 <+1>: mov %esp,%ebp  # saves esp to ebp 
0x08048477 <+3>: sub $0x10,%esp # making 16 bytes space in stack 
0x0804847a <+6>: mov %gs:0x14,%eax # what does it mean ???? 
0x08048480 <+12>: mov %eax,-0x4(%ebp) # move eax contents to 4 bytes lower in stack 
... 
0x0804849b <+39>: mov -0x4(%ebp),%eax # move (ebp - 4) location's contents to eax 
0x0804849e <+42>: xor %gs:0x14,%eax   # # again what is this ???? 
0x080484a5 <+49>: je  0x80484ac <display+56> # Not known to me 
0x080484a7 <+51>: call 0x8048394 <[email protected]> # not known to me 
0x080484ac <+56> 

所以,這段代碼需要從TLS的值(在GS:0×14),並將其存儲正下方的保存EBP價值(在ebp-4)。然後有你的東西get()put()。然後這段代碼檢查來自TLS的值的副本是否保持不變。 xor %gs:0x14,%eax做比較。

如果異或值相同,則XOR的結果是0,並且flags.zf是1。否則,結果不爲0和flags.zf是0

je 0x80484ac <display+56>檢查flags.zf和如果flags.zf = 1,則跳過call 0x8048394 <[email protected]>。IOW,如果來自TLS的值的副本保持不變,則跳過此調用。

這是什麼意思?這是一種嘗試捕獲緩衝區溢出的方法。如果超出緩衝區的末尾寫入,則會覆蓋從TLS複製到堆棧的值。

爲什麼我們從TLS中獲取這個值,爲什麼不只是一個恆定的硬編碼值?我們可能希望使用不同的非硬編碼值來更頻繁地捕獲溢出(因此TLS中的值將從運行改變爲另一個程序運行,並且在程序的不同線程中它們會有所不同)。如果每次程序運行時隨機選擇值,那麼也會降低攻擊者成功利用緩衝區溢出的機率。

最後,如果發現由於緩衝區溢出而覆蓋了該值的副本,則call 0x8048394 <[email protected]>將調用一個專用於執行必要操作的特殊功能,例如,報告問題並終止程序。

+0

謝謝阿列克謝,我希望我能給你多個「有用的職位」。非常感謝這麼好的解釋。 – kriss

+0

Alexy!我有個疑問。在說明中: - 致電0x8048374 <[email protected]> ;; lea -0xc(%ebp),%eax ;; mov%eax,(%esp),爲什麼這樣做?我的意思是INPUTed值已經在堆棧中。那麼爲什麼程序將LEA加載到eax,然後將eax值移到堆棧。輸入已經存在,那麼爲什麼再次這個過程? – kriss

+0

作爲參數傳遞給'gets()'和'puts()'的數組指針可以通過'gets()'以任意方式更改。調用代碼確保'puts()'的參數是正確的。 –

相關問題