当我调用jmp时,我在c内联汇编中出现了段错误

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了当我调用jmp时,我在c内联汇编中出现了段错误相关的知识,希望对你有一定的参考价值。

当我使用jmp时,我遇到了分段错误。

在第一次,我只是使用jmp 0x30,我得到了分段错误。

我通过使用gdb来调试我的程序,我看到在调用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
"
(gdb) n
0x00000030 in ?? ()
(gdb)

我认为它也可能是一个相对地址。所以我修改了jmp的参数作为calldisassemble main的地址。就是这样的,

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

但我得到了这个

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

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

我发现了这个相关的问题confusing with JMP instruction,我修改了我的代码。

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

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

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

我不知道问题出在哪里,我真的很感谢你的帮助!

答案

我不认为分段错误是由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
"
(gdb) display/i $pc
1: x/i $pc
=> 0x80483be <main+3>:  jmp    0x80483ec <main+49>
(gdb) si
0x080483ec      3       __asm__("jmp L
"
1: x/i $pc
=> 0x80483ec <main+49>: call   0x80483c0 <main+5>
(gdb) si
0x080483c0      3       __asm__("jmp L
"
1: x/i $pc
=> 0x80483c0 <main+5>:  pop    %esi
(gdb) si
0x080483c1      3       __asm__("jmp L
"
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
"
1: x/i $pc
=> 0x80483c1 <main+6>:  mov    %esi,0x8(%esi)
(gdb)

如您所见,我在main设置了断点并启用了对所执行的每个机器指令的拆解(display/i $pc)。然后我逐步完成了机器指令(si)。事实证明,错误的指令是mov %esi,0x8(%esi)0x80483c1

据我所知,问题是gdb只显示它执行的下一个整个语句。由于语句以分号结尾,因此只要调试器逐步执行__asm__("...")语句,整个__asm__("jmp L "就算作一个语句而gdb只打印它的第一行,即__asm__


所以我们清理了一下,现在让我们弄清楚是什么导致了分段错误。

当你跳到L时,call sub被执行。这会将32位返回地址压入堆栈。 sub中的第一条指令pop %esi用返回地址填充%esi并将其从堆栈中删除。 当你现在执行mov %esi,0x8(%esi)时,CPU会尝试将%esi移动到返回地址所指向的0x8字节后面,即代码段内。并且,看起来,代码在您的操作系统上是只读的,因此程序出错。

另一答案

有更多时间来看看这个:

我想你正在尝试做一个sys_write,但是所有东西似乎都是通过esi寄存器初始化的,这个寄存器被“初始化”为堆栈的最高值。我猜测程序员正在假设GNU调用标准所以for main(argc,argv):但你不需要这样做;在32位系统上的esi将具有argv参数。但为什么流行?为什么不明确地用参数声明main。我认为这是混乱的来源。

另一答案

在不使用额外标志的情况下执行jmp

jmp . + 42

42是字节数。它也可以用十六进制写入0x2c。

以上是关于当我调用jmp时,我在c内联汇编中出现了段错误的主要内容,如果未能解决你的问题,请参考以下文章

内联汇编,错误

gnu 内联汇编错误

C语言进阶——内联汇编

C语言进阶——内联汇编

汇编中浮点数的总和数组

长汇编代码问题