Given a position-independent, statically-linked, stripped binary, there does not appear to be a way in GDB to set a breakpoint at the entry point without disabling ASLR.

  • break start and similar functions do not work, because there is no symbolic information
  • set stop-on-solib-events 1 does not work as the binary is not dynamically linked
  • break *0xdeadbeef for the entry point does not work, as the entry point is unresolved until the binary starts
  • catch load does not work, as it does not load any libraries
  • start does not work, as main is not defined and no libraries are loaded

Without patching the binary, what mechanism can I use to break at the first instruction executed?


Since a now-deleted response to the question said that a PIE statically-linked binary is impossible, a trivial example is the linker itself.

It is statically linked.

$ ldd /lib/x86_64-linux-gnu/ld-2.19.so
    statically linked

It is executable.

$ strace /lib/x86_64-linux-gnu/ld-2.19.so
execve("/lib/x86_64-linux-gnu/ld-2.19.so", ["/lib/x86_64-linux-gnu/ld-2.19.so"], [/* 96 vars */]) = 0
brk(0)                                  = 0x7ff787b3d000
writev(2, [{"Usage: ld.so [OPTION]... EXECUTA"..., 1373}], 1Usage: ld.so [OPTION]... EXECUTABLE-FILE [ARGS-FOR-PROGRAM...]

It is position-independent.

$ readelf -h /lib/x86_64-linux-gnu/ld-2.19.so | grep DYN
  Type:                              DYN (Shared object file)


It looks like this can be done with Python by utilizing some of the events made available: http://asciinema.org/a/19078

However, I'd like a native-GDB solution.

A successful solution will break at _start in ld.so when executed directly without disabling ASLR. It should look something like this:

sh $ strip -s /lib/x86_64-linux-gnu/ld-2.19.so -o ld.so
sh $ gdb ./ld.so
(gdb) $ set disable-randomization off
(gdb) $ <your magic commands>
(gdb) $ x/i $pc
=> 0x7f9ba515d2d0:     mov    rdi,rsp
(gdb) $ info proc map
process 10432
Mapped address spaces:

        Start Addr           End Addr       Size     Offset objfile
    0x7f9ba515c000     0x7f9ba517f000    0x23000        0x0 /lib/x86_64-linux-gnu/ld-2.19.so 
    0x7f9ba537e000     0x7f9ba5380000     0x2000    0x22000 /lib/x86_64- linux-gnu/ld-2.19.so
    0x7f9ba5380000     0x7f9ba5381000     0x1000        0x0 
    0x7fffc34c7000     0x7fffc38ca000   0x403000        0x0 [stack]
    0x7fffc398b000     0x7fffc398d000     0x2000        0x0 [vdso]
0xffffffffff600000 0xffffffffff601000     0x1000        0x0 [vsyscall]

UPDATE: GDB 8.1 has a starti command, as mentioned below by /u/ruslan

Setting a breakpoint on an unmapped address before starting the target process does this, effectively. It's not correct functionality, but rather a side-effect of the failure to set the breakpoint.

(gdb) break *0
Breakpoint 1 at 0x0
(gdb) r
Starting program: /home/user/ld.so 
Error in re-setting breakpoint 1: Warning:
Cannot insert breakpoint 1.
Cannot access memory at address 0x0

Cannot insert breakpoint 1.
Cannot access memory at address 0x0

(gdb) x/i $pc
=> 0x7faae3a25cd0:      mov    rdi,rsp

Starting with GDB 8.1, there's a special command for this: starti. Example GDB session:

$ gdb /bin/true
Reading symbols from /bin/true...(no debugging symbols found)...done.
(gdb) starti
Starting program: /bin/true 

Program stopped.
0xf7fdd800 in _start () from /lib/ld-linux.so.2
(gdb) x/5i $pc
=> 0xf7fdd800 <_start>: mov    eax,esp
   0xf7fdd802 <_start+2>:       call   0xf7fe2160 <_dl_start>
   0xf7fdd807 <_dl_start_user>: mov    edi,eax
   0xf7fdd809 <_dl_start_user+2>:       call   0xf7fdd7f0
   0xf7fdd80e <_dl_start_user+7>:       add    ebx,0x1f7e6

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.