2016-09-25 76 views
2

時,我在c內聯程序集中出現了段錯誤當我使用jmp時出現了段錯誤。當我調用jmp

在第一時間,我只是用jmp 0x30,和我有段故障。

我用gdb的debuged我的節目,我看到jmp被稱爲後,就跳轉到一個絕對地址。

(gdb) b main 
Breakpoint 1 at 0x80483b7: file f.c, line 3. 
(gdb) r 
Starting program: /root/work/f 

Breakpoint 1, main() at f.c:3 
3  __asm__("jmp 0x30\n" 
(gdb) n 
0x00000030 in ??() 
(gdb) 

我認爲它可能是一個相對地址,too.So我修改了PARAM爲jmp作爲calldisassemble main地址。 只是這樣的事情,

#include<stdio.h> 
int main(){ 
__asm__("jmp 0x080483e6\n" 
"popl %esi\n" 
"movl %esi,0x8(%esi)\n" 
"movb $0x0,0x7(%esi)\n" 
"movl $0x0,0xc(%esi)\n" 
"movl $0xb,%eax\n" 
"movl %esi,%ebx\n" 
"leal 0x8(%esi),%ecx\n" 
"leal 0xc(%esi),%edx\n" 
"int $0x80\n" 
"movl $0x1, %eax\n" 
"movl $0x0, %ebx\n" 
"int $0x80\n" 
"call 0x2a\n" 
".string \"/bin/sh\"\n"); 
return 0; 
} 

,但我得到這個

Breakpoint 1, main() at f.c:3 
3  __asm__("jmp 0x080483e6\n" 
(gdb) n 

Program received signal SIGSEGV, Segmentation fault. 
0x0000002a in ??() 
(gdb) 

我發現這個相關的問題confusing with JMP instruction,我修改了我這樣的代碼。

#include<stdio.h> 
int main(){ 
__asm__("jmp L\n" 
"sub:\n" 
"popl %esi\n" 
"movl %esi,0x8(%esi)\n" 
"movb $0x0,0x7(%esi)\n" 
"movl $0x0,0xc(%esi)\n" 
"movl $0xb,%eax\n" 
"movl %esi,%ebx\n" 
"leal 0x8(%esi),%ecx\n" 
"leal 0xc(%esi),%edx\n" 
"int $0x80\n" 
"movl $0x1, %eax\n" 
"movl $0x0, %ebx\n" 
"int $0x80\n" 
"jmp exit\n" 
"L:\n" 
"call sub\n" 
".string \"/bin/sh\"\n" 
"exit:\n"); 
return 0; 
} 

,但它不適合我,jmp被稱爲後,指令地址是仍然jmp

(gdb) b main 
Breakpoint 1 at 0x80483b7: file f.c, line 3. 
(gdb) r 
Starting program: /root/work/f 

Breakpoint 1, main() at f.c:3 
3  __asm__("jmp L\n" 
(gdb) n 

Program received signal SIGSEGV, Segmentation fault. 
0x080483ba in main() at f.c:3 
3  __asm__("jmp L\n" 
(gdb) n 

Program terminated with signal SIGSEGV, Segmentation fault. 
The program no longer exists. 
(gdb) 

行了,我不知道哪裏是問題,我真的很感激你的幫助!

+1

我不確定你要在這裏完成什麼。如果你的目標是學習c,這是一個不好的開始。如果目標是學習asm,這是關於最複雜的開始方式。也就是說,你正在修改(一個BUNCH)寄存器在asm中而不通知編譯器。當你的asm()退出時,這會造成一團糟。如果您必須這樣做,請考慮使用[extended asm](https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html),它允許您打開註冊表。 –

回答

1

我不認爲分割故障是由jmp L指令造成的。

看看我在這裏做:

(gdb) b main 
Breakpoint 1 at 0x80483be: file test.c, line 3. 
(gdb) run 
Starting program: /home/cad/a.out 

Breakpoint 1, main() at test.c:3 
3  __asm__("jmp L\n" 
(gdb) display/i $pc 
1: x/i $pc 
=> 0x80483be <main+3>: jmp 0x80483ec <main+49> 
(gdb) si 
0x080483ec  3  __asm__("jmp L\n" 
1: x/i $pc 
=> 0x80483ec <main+49>: call 0x80483c0 <main+5> 
(gdb) si 
0x080483c0  3  __asm__("jmp L\n" 
1: x/i $pc 
=> 0x80483c0 <main+5>: pop %esi 
(gdb) si 
0x080483c1  3  __asm__("jmp L\n" 
1: x/i $pc 
=> 0x80483c1 <main+6>: mov %esi,0x8(%esi) 
(gdb) si 

Program received signal SIGSEGV, Segmentation fault. 
0x080483c1 in main() at test.c:3 
3  __asm__("jmp L\n" 
1: x/i $pc 
=> 0x80483c1 <main+6>: mov %esi,0x8(%esi) 
(gdb) 

正如你看到的,我在main設置一個斷點,並啓用執行每臺機器指令(display/i $pc)的拆卸。然後我瀏覽了機器說明書(si)。事實證明,錯誤的指令是mov %esi,0x8(%esi)0x80483c1

據我所知,問題在於gdb只顯示它執行的下一個整體陳述。由於語句以分號結束,整個__asm__("...")東西算作一個語句和gdb只打印了它的第一線,即__asm__("jmp L\n",只要通過__asm__聲明調試步驟。


所以我們得到了清理,現在我們來弄清楚是什麼導致了分段錯誤。

當你已經躍升至Lcall sub執行。這將32位返回地址推入堆棧。在sub,pop %esi的第一條指令中,用返回地址填充%esi並將其從堆棧中移除。
當你mov %esi,0x8(%esi)現在,CPU試圖移動%esi0x8字節後面返回地址點,即,該代碼段內。而且,看起來,代碼在您的操作系統上是隻讀的,所以程序出錯。

0

有更多的時間來看看這個:

我認爲你試圖做一個SYS_WRITE但一切似乎通過其被「初始化」爲堆棧頂部值ESI寄存器進行初始化得到。我猜測程序員正在假定GNU調用標準,所以對於main(argc,argv):但你不需要這樣做;在32位系統上的esi會有argv的說法。但爲什麼流行?爲什麼不用參數明確聲明main。我認爲這是混淆進入的地方。