85

After loading an executable into gdb, how do I break at the entry point, before the first instruction is executed?

The executable I'm analyzing is a piece of malware that's encrypted so break main does absolutely nothing.

rickythefox
  • 6,601
  • 6
  • 40
  • 62
  • For `lldb`, see: [How to stop debugger right after the execution?](http://reverseengineering.stackexchange.com/q/9583/12021) – kenorb Aug 08 '15 at 16:59
  • related: https://reverseengineering.stackexchange.com/questions/8724/set-a-breakpoint-on-gdb-entry-point-for-stripped-pie-binaries-without-disabling – Ciro Santilli OurBigBook.com Jul 11 '18 at 16:15

5 Answers5

116

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
Ruslan
  • 18,162
  • 8
  • 67
  • 136
  • 6
    This answer should be propagated somehow, as this is the most neat solution as of gdb 8.1 release. – Géza Török Dec 19 '18 at 15:56
  • 1
    This solution breaks at the first instruction in `/lib/ld-linux.so.2` which could be meaningless when one is interested in the first instruction of the given executable. – codeman48 Dec 27 '21 at 07:09
  • @codeman48 this is true only for a dynamic executable. But, if you really want to debug a dynamic executable starting from `main`, put a breakpoint at `__libc_start_main` and take its first parameter as the address of your new breakpoint. You'll miss static initialization though, so be careful. – Ruslan Dec 27 '21 at 08:04
  • @Ruslan yes on static builds it will work. For dynamic builds, in my understanding, a working approach would be to know the `Entry point address:` in the output of `readelf -h ` and setting up a break point there. I have always seen this address pointing to `_start` after which `__libc_start_main` is called, and then `main`... – codeman48 Dec 27 '21 at 10:37
74

The info files command might give you an address you can break on:

(gdb) info files
    ...
    Entry point: 0x80000000
    ...
(gdb) break *0x80000000
(gdb) run
Jeff Ames
  • 1,424
  • 10
  • 18
  • This doesn't actually work for me with a simple ELF generated by `fasm /dev/stdin test <<< $'format ELF executable\nint3'`. – Ruslan Jul 30 '17 at 10:17
  • 1
    (If I understood correctly) the load address is not the same as the virtual address, according to [this answer](https://stackoverflow.com/a/10492208), for some programs. Before the program is run, the shown address is the virtual address according to the program, not necessarily the load address. – user202729 Jul 30 '18 at 04:09
  • 3
    Yeah, from my experience, right after starting `gdb` it shows `0x10e0`. I set a break point, run, and it fails to insert breakpoint. But at this point `i files` shows `0x5555555550e0` as an entry point. And with this one it works. – x-yuri Sep 11 '18 at 23:26
  • It doesn't work for some crafted files without sections(for example, files generated with upx). In general case you have to copy entrypoint address from `readelf -h $binary` output manually. – quant2016 Aug 18 '20 at 11:25
21

This hack was obsoleted by starti, but useful if you're stuck with older GDB.

The no-brainer solution is to use the side-effect of failure to set a breakpoint:

$ gdb /bin/true
Reading symbols from /bin/true...(no debugging symbols found)...done.
(gdb) b *0
Breakpoint 1 at 0x0
(gdb) r
Starting program: /bin/true 
Warning:
Cannot insert breakpoint 1.
Cannot access memory at address 0x0

(gdb) disas
Dump of assembler code for function _start:
=> 0xf7fdd800 <+0>:     mov    eax,esp
   0xf7fdd802 <+2>:     call   0xf7fe2160 <_dl_start>
End of assembler dump.

(gdb) d 1       # delete the faulty breakpoint

(You need to delete the invalid breakpoint before you can continue or single-step.)

Idea taken from this answer at RE.SE.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Ruslan
  • 18,162
  • 8
  • 67
  • 136
  • Interestingly I couldn't use breakpoints in GDB at a Go application until your solution. Any other method doesn't work. –  Aug 01 '17 at 11:37
  • worked well for me too, but then even `stepi` was failing, so I had also to use `delete breakpoints` to proceed further. – Ped7g Oct 14 '17 at 14:31
  • 1
    @Ped7g you could just delete the exact breakpoint you set to fail, in the above example it'd be `d 1`. No need to delete all. – Ruslan Oct 14 '17 at 15:09
7

"b _start" or "b start" might or might not work. If not, find out the entrypoint address with readelf/objdump and use "b *0x<hex address>".

Igor Skochinsky
  • 24,629
  • 2
  • 72
  • 109
  • Weird thing is it breaks at the entry point specified in the header and the disassembly looks good, but a straight disassembly of the executable shows garbage. But you answered the question. ;) BTW, honored to get an answer from a guy at Hex-Rays! – rickythefox May 07 '12 at 14:26
  • `_init` from `cru/init-first.c` seems to be run even before `_start` or the entry address in GCC 4.8 glibc 2.19 Ubuntu 14.04 when I try `b _init; run` in GDB. What is going on? – Ciro Santilli OurBigBook.com Jul 13 '15 at 08:06
  • Asked at: http://stackoverflow.com/questions/31379422/why-is-init-from-glibcs-csu-init-first-c-called-before-start-even-if-start-i – Ciro Santilli OurBigBook.com Jul 13 '15 at 09:14
  • Even if it does work, it may not be the first user-space instruction in a dynamically-linked executable. The dynamic linker runs first. – Peter Cordes Oct 04 '19 at 10:52
7

After loading an executable into gdb, how do I break at the entry point, before the first instruction is executed?

You can find what functions are called before int main() with set backtrace past-main on and after finding them set a breakpoint on them and restart your program:

>gdb  -q  main
Reading symbols from /home/main...done.
(gdb) set backtrace past-main on
(gdb) b main
Breakpoint 1 at 0x40058a: file main.cpp, line 25.
(gdb) r
Starting program: /home/main

Breakpoint 1, main () at main.cpp:25
25        a();
(gdb) bt
#0  main () at main.cpp:25
#1  0x0000003a1d81ed1d in __libc_start_main () from /lib64/libc.so.6
#2  0x0000000000400499 in _start ()
(gdb) b _start
Breakpoint 2 at 0x400470
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/main

Breakpoint 2, 0x0000000000400470 in _start ()