I got segmentation fault in c inline assembly when I called jmp

2

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!

c
assembly
x86
segmentation-fault
inline-assembly
asked on Stack Overflow Sep 25, 2016 by liuhongxuan • edited Apr 12, 2019 by 1201ProgramAlarm

3 Answers

1

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.

answered on Stack Overflow Sep 25, 2016 by cadaniluk • edited Sep 25, 2016 by cadaniluk
0

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.

answered on Stack Overflow Sep 25, 2016 by cdcdcd • edited Sep 25, 2016 by cdcdcd
0

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.

answered on Stack Overflow May 22, 2018 by Abdullah Samarkandi

User contributions licensed under CC BY-SA 3.0