2

It appears that GDB is unable to handle binaries which switch code segments.

Using pwntools*, it's trivial to generate a 32-bit intel binary which uses retf to switch to the 64-bit code segment. Linux supports this, and everything "works fine".

>>> print shellcraft.to_64bit()
    push 0x33
    jmp 2f
1:
    retf
2:
    call 1b

>>> print shellcraft.amd64.mov('rax', 0xdeadbeefcafebabe)
mov rax, 0xdeadbeefcafebabe

We can assemble these to binary:

>>> asm(shellcraft.to_64bit())
'j3\xeb\x01\xcb\xe8\xfa\xff\xff\xff'

>>> asm(shellcraft.amd64.mov('rax', 0xdeadbeefcafebabe), arch='amd64')
'H\xb8\xbe\xba\xfe\xca\xef\xbe\xad\xde'

And stick it all into an ELF:

>>> ELF.from_bytes('j3\xeb\x01\xcb\xe8\xfa\xff\xff\xff' + 'H\xb8\xbe\xba\xfe\xca\xef\xbe\xad\xde')
[*] '/var/folders/4h/rrwj8fpj1cqcfb83syr_f930008rd2/T/pwn-asm-NbnRYW/step3-elf'
    Arch:     i386-32-little
    RELRO:    No RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x8049000)
    RWX:      Has RWX segments

For StackExchange users looking to reproduce this without installing pwntools, the full binary data is:

7f454c4601010100000000000000000002000300010000007490040834000000a000000000000000340020000200280003000200010000000000000000900408009004088900000089000000070000000010000051e57464000000000000000000000000000000000000000007000000100000006a33eb01cbe8faffffff48b8bebafecaefbeadde00002e7368737472746162002e7368656c6c636f64650000000000000000000000000000000000000000000000000000000000000000000000000000000000000b00000001000000070000007490040874000000150000000000000000000000010000000000000001000000030000000000000000000000890000001600000000000000000000000100000000000000

Now, when we run this under GDB, we end up with the register state we expect, but there's no way to see the extended registers, or convince it to switch architectures -- or display the correct disassembly!

$ gdb -q --nx --nh "/home/user/step3-elf"
Reading symbols from /home/user/step3-elf...(no debugging symbols found)...done.
(gdb) x/5i 0x8049074
   0x8049074:   push   $0x33
   0x8049076:   jmp    0x8049079
   0x8049078:   lret
   0x8049079:   call   0x8049078
   0x804907e:   dec    %eax
(gdb) b *0x8049074
Breakpoint 1 at 0x8049074
(gdb) r
Starting program: /home/user/step3-elf

Breakpoint 1, 0x08049074 in ?? ()
(gdb) si
0x08049076 in ?? ()
(gdb)
0x08049079 in ?? ()
(gdb)
0x08049078 in ?? ()
(gdb)
0x0804907e in ?? ()
(gdb) x/i $pc
=> 0x804907e:   dec    %eax
(gdb) i r eax
eax            0x0  0
(gdb) ni
0x08049088 in ?? ()
(gdb) i r eax
eax            0xcafebabe   -889275714
(gdb) set arch i386:x86-64
warning: Selected architecture i386:x86-64 is not compatible with reported target architecture i386
Architecture `i386:x86-64' not recognized.
The target architecture is set automatically (currently i386)

How can I convince GDB to show the correct, 64-bit disassembly, when it refuses to switch architectures? Even info reg all does not display all of the registers (e.g. RAX) correctly.

*to_64bit() is not in a released version of pwntools

  • 1
    What version of gdb are you using ? And, is it the multiarch version ? – perror Dec 8 '17 at 7:49
  • 1
    During a ctf I faced the same problem. If you're okay with using another debugger, fdbg worked fine. But it has not that many significant features. – sudhackar Dec 9 '17 at 7:14
  • GDB 7.12, multiarch isn't necessary since it's a host-architecture binary. "set arch" shows "i386:x86-64" as a supported option. I re-tried with gdb-multiarch with identical results. – Zach Riggle Dec 11 '17 at 21:33
-1

CPUs and OSes can support switching between 32 and 64 bit execution modes kind of easily thanks to how 32bit mode backwards compatibility was made in AMD64. This was kind of a requirement to avoid having the majority of system binaries duplicated on 64bit machines to execute 32bit code (which is still pretty common to be solely distributed).

This isn't quite the case for debuggers and some process manipulation tools that in some cases are required to bundle 64bit helper processes or ship both 32 and 64 bit binaries. Switching between 32 and 64 bit execution modes is indeed only a far jump away, but supporting that by a debugger is a lot more complicated. Transition/translation functions must be provided for the debugger's internal states (not the the debugged process's state, some APIs simply cannot cross process bitness boundaries, etc.

This is not to say it's impossible, merely to explain why this may not be available yet.

  • GDB supports switching architectures at runtime via the "set arch" command. However, since GDB has access to the original file, it is preventing me from performing the switch. – Zach Riggle Dec 11 '17 at 21:33
  • @ZachRiggle set architecture is used to switch architectures while GDB is running, but not while a debugged process is running. Those are two totally different things. – NirIzr Dec 11 '17 at 21:40

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.