I got an segmentation fault when I use jmp
.
At the first time,I just used jmp 0x30
, and I got segmentation fault.
I debuged my program by using gdb, and i saw that after jmp
was called, it jump to a absolute address.
(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)
I thought that it may be an relative address,too.So I modified the param for jmp
as the address of call
from disassemble main
.
just something like this,
#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;
}
but I got this
Breakpoint 1, main () at f.c:3
3 __asm__("jmp 0x080483e6\n"
(gdb) n
Program received signal SIGSEGV, Segmentation fault.
0x0000002a in ?? ()
(gdb)
I found this relevant question confusing with JMP instruction,and i modified my code like this.
#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;
}
but it not suitable for me, after jmp
was called, the instruction address was still the line of 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)
I do not know where is the issue,and I really appreciate your help!
I don't think the segmentation fault is caused by the jmp L
instruction.
Look at what I did here:
(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)
As you see, I set a breakpoint at main
and enabled disassembling of every machine instruction executed (display/i $pc
). Then I stepped through the machine instructions (si
). It turns out that the faulty instruction is mov %esi,0x8(%esi)
at 0x80483c1
.
As far as I can tell, the problem is that gdb only shows the next whole statement it executes. Since a statement ends with a semicolon, the whole __asm__("...")
thing counts as one statement and gdb only prints the first line of it, i.e., __asm__("jmp L\n"
, as long as the debugger steps through the __asm__
statement.
So we got that cleared up, now let's figure out what's causing the segmentation fault.
When you have jumped to L
, call sub
is executed. This pushes the 32-bit return address onto the stack. The first instruction in sub
, pop %esi
, fills %esi
with the return address and removes it from the stack.
When you do mov %esi,0x8(%esi)
now, the CPU tries to move %esi
to 0x8
bytes behind where the return address points, that is, within the code segment. And, as it seems, code is read-only on your OS, so the program faults.
Had more time to look at this:
I think you're trying to do a sys_write but everything seems to be getting initialised via the esi register which is being "initialised" as top value on the stack. I'm guessing the programmer is assuming GNU calling standard so the for main(argc, argv): but you don't need to do this; esi on a 32bit system will have the argv argument. But why the pop? Why not declare main explicitly with the arguments as well. I think this is where the confusion is coming in.
To do the jmp without using additional flag use
jmp . + 42
42 is the number of bytes. It could be written in hex too 0x2c.
User contributions licensed under CC BY-SA 3.0