2012-11-06 50 views
3

我有一個功能,看起來像這樣:C函數棧佈局

int bof(char *str) 
{ 
    char buffer[12]; 

    strcpy(buffer, str); 

    return 1; 
} 

我試圖改寫其返回地址。我發現我可以這樣做,例如使用memcpy(buffer+24, "\x15\xf1\xff\xbf", 4)。我不明白的是爲什麼我需要訪問buffer + 24。我對C內存模型的理解告訴我,當執行此功能的堆棧看起來應該像

bottom of               top of 
memory                memory 
      buffer(12)  sfp(4) ret(4) str(4) 
<------ [   ][  ][  ][  ] ---> 

top of               bottom of 
stack                 stack 

這表明,我應該在RET地址應在緩衝區+ 16開始。額外的8個字節在哪裏?

順便說一句,我在32位系統上運行這個。

+2

這個問題可能是一個很好的參考:[緩衝區溢出攻擊](http://stackoverflow.com/questions/7344226/buffer-overflow-attack) – Mysticial

+1

只需使用調試器,並回答自己的問題。這幾乎肯定取決於(至少部分)你的操作系統,編譯器和編譯器版本:) – paulsm4

+2

編譯器可以自由添加任何填充 – texasbruce

回答

3

檢查ISO C 99和更早的標準,你會發現沒有C內存模型這樣的東西。每個編譯器都可以自由使用它喜歡的任何模型來滿足功能規範。一個簡單的例子是編譯器可以使用或省略幀指針。它也可以爲返回值分配空間或使用寄存器。

當我編譯我的機器上的代碼,我得到

_bof: 
    pushl %ebp 
    movl %esp, %ebp 
    subl $40, %esp 
    movl 8(%ebp), %eax 
    movl %eax, 4(%esp) 
    leal -20(%ebp), %eax 
    movl %eax, (%esp) 
    call _strcpy 
    movl $1, %eax 
    leave 
    ret 

leal指令在bp-20計算緩衝區起始位置。在序幕之後,堆棧框架看起來像:

[ bp+8: str ] [bp+4: rtn address ] [bp: saved bp] [ bp-20: buf ] ... 

因此,看起來您必須編寫28個字節來更改返回地址。我的猜測是,編譯器正試圖對齊段落邊界上的堆棧幀。這裏包括strcpy arg setup的全幀是48個字節,這是3段。段落對齊有助於總線和緩存性能。

2

這不是C內存模型或C函數調用堆棧佈局。這只是您瞭解特定編譯器和硬件體系結構的實現。在ARM 32位CPU中,函數調用參數1〜4不會推入堆棧,它使用r0〜r3傳遞參數,然後將其他參數推送到堆棧,如果參數超過4的話。函數返回地址可能也不需要推入堆棧,因爲有一個特殊的寄存器LR來保存返回地址。