当我使用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\n"
(gdb) n
0x00000030 in ?? ()
(gdb)
我认为它也可能是一个相对地址。所以我将jmp
的参数修改为来自call
的{{1}}的地址。
就像这样,
disassemble 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;
}
我发现了这个相关的问题confusing with JMP instruction,我修改了我的代码。
Breakpoint 1, main () at f.c:3
3 __asm__("jmp 0x080483e6\n"
(gdb) n
Program received signal SIGSEGV, Segmentation fault.
0x0000002a in ?? ()
(gdb)
但它不适合我,在调用#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
我不知道问题出在哪里,我真的很感谢你的帮助!
答案 0 :(得分: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__("...")
,整个__asm__("jmp L\n"
事件就算作一个语句而gdb只打印它的第一行,即__asm__
。声明。
所以我们清理了一下,现在让我们弄清楚导致分段错误的原因。
当您跳转到L
时,会执行call sub
。这会将32位返回地址压入堆栈。 sub
中的第一条指令pop %esi
用返回地址填充%esi
并将其从堆栈中删除。
现在执行mov %esi,0x8(%esi)
时,CPU会尝试将%esi
移动到返回地址所指向的0x8
个字节后面,即代码段内。并且,看起来,代码在您的操作系统上是只读的,因此程序会出错。
答案 1 :(得分:0)
有更多时间看这个:
我认为你正在尝试做一个sys_write但是所有东西似乎都是通过esi寄存器初始化的,这个寄存器被“初始化”为堆栈的最高值。我猜测程序员正在假设GNU调用标准所以for main(argc,argv):但你不需要这样做;在32位系统上的esi将具有argv参数。但为什么流行?为什么不明确地用参数声明main。我认为这就是混乱的来源。
答案 2 :(得分:0)
在不使用额外标志的情况下执行jmp
logo
42是字节数。它也可以用十六进制写入0x2c。