为什么在推送指令时使用SIGSEGV

时间:2016-10-06 13:57:23

标签: assembly gdb x86-64 system-calls shellcode

=> 0x7fffffffeefc:  xor    %eax,%eax
   0x7fffffffeefe:  movabs $0xff978cd091969dd1,%rbx
   0x7fffffffef08:  neg    %rbx
   0x7fffffffef0b:  push   %rbx
   0x7fffffffef0c:  push   %rsp
   0x7fffffffef0d:  pop    %rdi
   0x7fffffffef0e:  mov    $0x3b,%al
   0x7fffffffef10:  syscall 
   0x7fffffffef12:  add    %cl,0x4e(%rcx,%rcx,2)
   0x7fffffffef16:  rex.RB push %r11
(gdb) nexti
0x00007fffffffeefe in ?? ()
(gdb) nexti
0x00007fffffffef08 in ?? ()
(gdb) nexti
0x00007fffffffef0b in ?? ()
(gdb) nexti
0x00007fffffffef0c in ?? ()
(gdb) nexti

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

我无法理解0x7fffffffef0c中出现分段错误的原因。分段后,故障rip跳转到0x7fffffffef12而不是0x7fffffffef0c。这意味着0x7fffffffef0c是错误处理程序吗?

2 个答案:

答案 0 :(得分:2)

似乎gdb跨过了syscall指令和一些周围的指令。 SIGSEGV可能与rcx寄存器的值有关,在0x7fffffffef12的指令中使用。如果您希望gdb在每条指令处停止而不是继续执行函数调用,那么stepi可能比nexti更好。

0x7fffffffef12处的指令(崩溃的假定位置)似乎很奇怪;反汇编中的其他说明似乎也很奇怪。如果我在我自己的系统上查看gdb会话中的相同地址范围,我在该页面的那一部分看到的是一堆空终止字符串,它看起来很像我的命令行,然后是我的环境。前三个地址匹配主框架中argv的前三个元素,而argv本身也在该页面中。

检查使用x/s而不是x/i反汇编的地址可能会很有趣。在我的会话中(在主框架中)x/29s argv[0]显示了该地址范围内的一堆东西。

如果在尝试将您的环境视为代码时发生了崩溃,那么更有趣的问题可能是如何分支到该范围的地址。如果gdb显示此崩​​溃的连贯回溯,则可能会提供一些见解。

答案 1 :(得分:0)

GDB表示,您在0x00007fffffffef12时遇到了问题,这是add %cl,0x4e(%rcx,%rcx,2),正如@ Eirik的答案所解释的那样。

SYSCALL destroys rcx and r11,以及使用返回值修改rax。

另请参阅 tag wiki中的其他链接以及底部的gdb提示。使用layout asmlayout reg可以轻松跟踪RIP并在单步执行时注册值。

ni可能跳过了多条指令,因为gdb认为它们来自内联函数或其他东西。 (也许是汇编程序宏?)ni不会进入CALL指令,但我认为它通常不会跳过任何其他内容。但只需使用si

添加后

rex.RB push %r11也不太可能有用。您是否故意挑选SYSCALL销毁的两个寄存器?此外,具有REX.W = 0的REX前缀的PUSH将作为非法指令进行故障。 push r/m32无法在64位模式despite the phrasing of the text in Intel's manual编码。

哦,我认为SYSCALL之后的代码只是数据("/bin/sh"或其他东西)或者只是垃圾,根本不应该执行,因为SYS_execve是59(0x3b)并且OP可能希望它不会不回来。

显然这是shellcode,因此解释了push / pop而不是mov %rsp, %rdi和其他奇怪的东西,大概是为了避免0x00个字节。可能很高兴提到这一点,所以我们这些错过[shell]标签的人可以避免浪费大量时间来讨论奇怪的东西。