2
=> 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 ?? ()

I can't understand why segmentation fault occur in 0x7fffffffef0c. After segmentation fault rip jump to 0x7fffffffef12 instead of 0x7fffffffef0c. Is this mean 0x7fffffffef0c is error handler?

Michael Petch
  • 46,082
  • 8
  • 107
  • 198
Damotorie
  • 586
  • 7
  • 25

2 Answers2

2

It appears that gdb stepped over the syscall instruction and some of the surrounding instructions. The SIGSEGV probably has something to with the value of the rcx register, used in the instruction at 0x7fffffffef12. If you want gdb to stop at every instruction rather than proceeding over function calls, stepi is likely to be better for that than nexti.

The instruction at 0x7fffffffef12 (the presumed location of the crash) seems strange; other instructions in that disassembly also seem strange. If I look at the same address range in a gdb session on my own system, what I see in that part of that page is a bunch of null terminated strings which looks a whole lot like pieces of my command line, and then my environment. The addresses of the first three match the first three elements of argv in my main frame, and argv itself is also in that page.

It might be interesting to examine the addresses you disassembled with x/s rather than x/i. In my session (in the main frame) x/29s argv[0] shows a bunch of stuff in that address range.

If it turns out that your crash occurred while attempting to treat your environment as code, perhaps the more interesting question is how a branch to that range of addresses occurred. If gdb shows a coherent backtrace for this crash, that might provide some insight.

Eirik Fuller
  • 1,454
  • 11
  • 9
  • I thought `SIGSEGV` was occurred because of `0x7fffffffef0c`. Because after executing `0x7fffffffef0c`, GDB alerts Program received signal SIGSEGV. It's wrong? Also I want to know gdb can skip instruction without execution while using `nexti` – Damotorie Oct 07 '16 at 00:18
  • 1
    GDB's notification of `SIGSEGV` is correct; your assumption that it occurs at instruction `0x00007fffffffef0c` is probably incorrect. As mentioned, using `stepi` rather than `nexti` is likely to provide a more meaningful indication of what's going on. There is a distinction between `after` and `immediately after` which matters here. – Eirik Fuller Oct 07 '16 at 00:23
  • @user4929293: [SYSCALL destroys rcx and r11](http://stackoverflow.com/questions/2535989/what-are-the-calling-conventions-for-unix-linux-system-calls-on-x86-64), as well as modifying rax with the return value. See also other links from the [x86 tag wiki](http://stackoverflow.com/tags/x86/info), and the gdb tips at the bottom. `ni` probably skipped multiple instructions because gdb thought they were from an inlined function or something. (maybe an assembler macro?) `ni` doesn't descend into CALL instructions, but I didn't think it normally skipped anything else. But just use `si`. – Peter Cordes Oct 07 '16 at 20:07
  • A simple experiment suggests that `nexti` and `stepi` work the same way for instructions surrounding a `syscall` instruction (in both cases gdb stops at each instruction), but that could conceivably vary across gdb versions (I'm using 7.11.1), or the precise instructions surrounding the `syscall`. I wouldn't expect debug symbols to matter, and either way they aren't present for these instructions. In short, I'm beginning to doubt the beginning of this answer. In any case, I believe that including a backtrace would improve the question. – Eirik Fuller Oct 07 '16 at 20:41
0

GDB says you faulted at 0x00007fffffffef12, which is the add %cl,0x4e(%rcx,%rcx,2), as @Eirik's answer explained.

SYSCALL destroys rcx and r11, as well as modifying rax with the return value.

See also other links from the tag wiki, and the gdb tips at the bottom. Use layout asm and layout reg to make it easy to follow RIP and register values as you single step.


ni probably skipped multiple instructions because gdb thought they were from an inlined function or something. (maybe an assembler macro?) ni doesn't descend into CALL instructions, but I didn't think it normally skipped anything else. But just use si.


rex.RB push %r11 after the add is also unlikely to be useful. Did you on purpose pick the two registers destroyed by SYSCALL? Also, a PUSH with a REX prefix with REX.W=0 will fault as an illegal instruction. push r/m32 is not encodeable in 64-bit mode, despite the phrasing of the text in Intel's manual.

Oh, I think the code after SYSCALL is just data ("/bin/sh" or something) or just junk, not meant to be executed at all, since SYS_execve is 59 (0x3b) and the OP is probably hoping it doesn't return.

Apparently this is shellcode, so that explains the push/pop instead of mov %rsp, %rdi and other weird stuff, presumably to avoid 0x00 bytes. Might have been nice to mention that, so those of us who missed the [shell] tag could have avoided wasting a bunch of time discussing the weird stuff.

Community
  • 1
  • 1
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • 1
    As mentioned in the most recent update to my answer, I doubt the code in which the crash occurred is actual code. You can get interesting instruction sequences when disassembling a contiguous set of null terminated strings. – Eirik Fuller Oct 07 '16 at 20:26
  • This isn't code golf but I know one reason he doesn't do `mov $0x3b, %eax` is because that would encode a 0x00 in the output bytes, and since this is shell code he is avoiding 0x00 being part of the instructions. This is also the reason why he encoded the string and negated the result so that the nul terminator on the string would not appear in the resulting binary. – Michael Petch Oct 07 '16 at 20:28
  • @EirikFuller: oh good call, yes that's highly likely. argv[] and env[] are on the stack above the initial value of RSP on process entry. Like Michael, I was starting to wonder if this was shellcode, since those RIP addresses looked like stack. – Peter Cordes Oct 07 '16 at 20:30
  • A bogus function pointer dereference is one possible explanation for this crash; a backtrace would provide more insight. – Eirik Fuller Oct 07 '16 at 20:31
  • @EirikFuller: or mismatched push/pop in hand-written asm could turn a data pointer into a return address. – Peter Cordes Oct 07 '16 at 20:32
  • The question was tagged `shell` but it really should be `shellcode` and it is a continuation of all his other shellcode related questions. I have modified the tags – Michael Petch Oct 07 '16 at 20:32
  • 1
    I also suspect that `add %cl,0x4e(%rcx,%rcx,2)` `push %r11` is junk on the stack. It contains the ASCII characters for `LINAS`. I'm guessing his original source probably didn't have code after the `syscall` so what you are seeing is junk. He likely doesn't care that shell code crashes after it does its job. – Michael Petch Oct 07 '16 at 20:41