2012-09-16 44 views
2

當我運行以下C程序(在Ubuntu中使用gcc編譯)時,出現分段錯誤。字節編碼函數時發生分段錯誤?

#include <stdio.h> 

char f[] = "\x55\x48\x89\xe5\x48\x89\x7d\xf8\x48\x89\x75\xf0\x48\x8b\x45\xf8\x8b\x10\x48\x8b\x45\xf0\x8b\x00\x89\xd1\x29\xc1\x89\xc8\xc9\xc3"; 

int main() 
{ 
    int (*func)(); 
    func = (int (*)()) f; 

    int x=3,y=5; 
    printf("%d\n",(int)(*func)(&x,&y)); 
    return 0; 
} 

字符串f包含以下功能的機器代碼。

int f(int*a, int*b) 
{ 
    return *a-*b; 
} 

c.f:

f.o:  file format elf64-x86-64 

Disassembly of section .text: 

0000000000000000 <f>: 
    0: 55      push %rbp 
    1: 48 89 e5    mov %rsp,%rbp 
    4: 48 89 7d f8    mov %rdi,-0x8(%rbp) 
    8: 48 89 75 f0    mov %rsi,-0x10(%rbp) 
    c: 48 8b 45 f8    mov -0x8(%rbp),%rax 
    10: 8b 10     mov (%rax),%edx 
    12: 48 8b 45 f0    mov -0x10(%rbp),%rax 
    16: 8b 00     mov (%rax),%eax 
    18: 89 d1     mov %edx,%ecx 
    1a: 29 c1     sub %eax,%ecx 
    1c: 89 c8     mov %ecx,%eax 
    1e: c9      leaveq 
    1f: c3      retq 

這是使用編譯:

gcc test.c -Wall -Werror 
./a.out 
Segmentation fault 

預期輸出爲-2 - 我怎樣才能得到它的工作?

+0

哪裏是用於'F'函數的代碼? –

+0

更新的f.c內容 – Jo0o0

+1

運行這樣的代碼,你甚至不知道它是如何處理root用戶('sudo'等)是不負責任的。你值得擁有你自己的程序吃你的硬盤。 –

回答

4

有趣的是,鏈接器沒有抱怨你試圖鏈接char f[] = "...";作爲函數f()到你的應用程序。您嘗試調用功能f()。有一個符號f鏈接到可執行文件,但令人驚訝的是它根本沒有功能,但有一些變量。因此它無法執行它。這可能是由於堆棧執行保護機制。

爲了避免這種情況的出現,您只需將字符串獲取到進程內存的文本段。如果您聲明字符串爲const char f[],則可以實現此目的。

Smashing The Stack For Fun And Profit, by Aleph One

文本區域是由程序固定並且包括代碼(指令) 和只讀數據。該區域對應於 可執行文件的文本部分。

由於const char[]只讀的,編譯的代碼把它一起放入文本區域。由此防止執行機制被繞過,並且機器能夠在其中執行機器代碼。


實施例:

/* test.c */ 
#include <stdio.h> 

const char f[] = "\x55\x48\x89\xe5\x48\x89\x7d\xf8\x48\x89\x75\xf0\x48\x8b\x45\xf8\x8b\x10\x48\x8b\x45\xf0\x8b\x00\x89\xd1\x29\xc1\x89\xc8\xc9\xc3"; 

int main() 
{ 
    int (*func)(); 
    func = (int (*)()) f; 

    int x=3,y=5; 
    printf("%d\n",(int)(*func)(&x,&y)); 
    return 0; 
} 

收率:

$ gcc test.c -Wall && ./a.out 
-2 

(Fedora的16,GCC 4.6.3)

+0

我翻譯的書有錯誤,我把所有的test.c和錯誤是f不是一個函數 – Jo0o0

+0

我更新了牆上沒有錯誤的問題,但繼續分段錯誤 – Jo0o0

+0

f []不在堆棧上,但全球(和公共)。我不認爲.data部分是可執行的。 – wildplasser

0

如果我正確地理解了你,你試圖運行簡單的代碼,而不是在文本空間,而是在你初始化的靜態存儲?如果這是失敗的,那麼只有三個原因:你的代碼被初始化不正確(在這種簡單情況下不太可能),你的數據空間已經被踩到了(看起來不像這個簡單情況),或者你的系統是阻止它作爲一種安全措施(很可能因爲你試圖做的事非常不典型,主要用於緩衝區溢出利用)。

+0

我運行sudo ./a.out也得到了相同的錯誤 – Jo0o0

+0

代碼中沒有溢出,如何繞過安全措施 – Jo0o0

+1

以root身份運行並不能讓你繞過緩衝區溢出保護 - 事實上,最重要的是你在哪裏需要它。至於強制旁路 - 我不確定哪些系統調用允許您修改MMU保護位。 – mah