4

I'm using /bin/true as my sample binary (without available main method):

$ lldb /bin/true
(lldb) target create "/bin/true"
Current executable set to '/bin/true' (x86_64).
(lldb) break main
invalid command 'breakpoint main'

Is there any universal way to run the binary and stop the debugger right after the load, so appropriate symbols can be loaded? Something equivalent on breaking on the main method (first line of the code)? Or I need to calculate the entry point manually? If so, how?

1

2 Answers 2

8

Binaries are usually stripped. For ELF binaries, you can check it with file command

$ file /bin/true
/bin/true: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.26, BuildID[sha1]=0x73796652ea437df8ac7b3ba1864a7ac177e27600, stripped

Notice the stripped at the end of file's result. It means, among other things, that symbols have been removed, so it won't find main function.

In order to run the binary and stop the debugger right after the load, there is some kind of universal method that should almost always work (kind of universal, not 100%)

You have to find the entry point, retreived by this command :

$ readelf -h /bin/true | grep "Entry point"
  Entry point address:               0x401264

Then load the binary into your favourite debugger (lldb, gdb, ...) and break on this address.

lldb :

$ lldb /bin/true
(lldb) target create "/bin/true"
Current executable set to '/bin/true' (x86_64).
(lldb) br s -a 0x401264
Breakpoint 1: address = 0x0000000000401264
(lldb) r
...
(lldb)

gdb :

$ gdb -q /bin/true
Reading symbols from /bin/true...(no debugging symbols found)...done.
gdb$ b *0x401264
Breakpoint 1 at 0x401264
gdb$ r
Breakpoint 1, 0x0000000000401264 in ?? ()
gdb$

Once you've loaded your binary and your breakpoint has been triggered, you can display following instructions that will be executed this way :

lldb :

(lldb) x -s4 -fi -c11 $pc
-> 0x401264:    xor    ebp,ebp
   0x401266:    mov    r9,rdx
   0x401269:    pop    rsi
   0x40126a:    mov    rdx,rsp
   0x40126d:    and    rsp,0xfffffffffffffff0
   0x401271:    push   rax
   0x401272:    push   rsp
   0x401273:    mov    r8,0x403560
   0x40127a:    mov    rcx,0x403570
   0x401281:    mov    rdi,0x4011c0
   0x401288:    call   0x401060 <__libc_start_main@plt>

gdb :

gdb$ x/11i $pc
=> 0x401264:    xor    ebp,ebp
   0x401266:    mov    r9,rdx
   0x401269:    pop    rsi
   0x40126a:    mov    rdx,rsp
   0x40126d:    and    rsp,0xfffffffffffffff0
   0x401271:    push   rax
   0x401272:    push   rsp
   0x401273:    mov    r8,0x403560
   0x40127a:    mov    rcx,0x403570
   0x401281:    mov    rdi,0x4011c0
   0x401288:    call   0x401060 <__libc_start_main@plt>

i flag means instruction, and $pc means Program Counter (equivalent of EIP/RIP for 32/64 bits architecures). You can see that __libc_start_main will be called at address 0x401288. Its man page indicates its first argument is a pointer to binary main function. 1st argument is here loaded in rdi register, meaning that main function is located at address 0x4011c0.

You just have to finally place a breakpoint at this address (0x4011c0) and you'll be at the beginning of your binary main function.

Further reading : How to handle stripped binaries with GDB? No source, no symbols and GDB only shows addresses?

Good luck and have fun !

1
  • The easiest way starting with GDB 8.1 is the starti command. No need to manually look for entry point address.
    – Ruslan
    Commented Jan 29, 2019 at 20:52
6

From http://lldb.llvm.org/tutorial.html:

(lldb) process launch --stop-at-entry -- -program_arg value

Note your break main is a gdb command; lldbs error message isnt "no such symbol", it's "invalid command". To do the same in lldb, use

(lldb) breakpoint set --name main

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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