Reverse Engineering Asked by Zach Riggle on March 17, 2021
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 informationset stop-on-solib-events 1
does not work as the binary is not dynamically linkedbreak *0xdeadbeef
for the entry point does not work, as the entry point is unresolved until the binary startscatch load
does not work, as it does not load any librariesstart
does not work, as main
is not defined and no libraries are loadedWithout 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
Warning:
Cannot insert breakpoint 1.
Cannot access memory at address 0x0
(gdb) x/i $pc
=> 0x7faae3a25cd0: mov rdi,rsp
Correct answer by Zach Riggle on March 17, 2021
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
Answered by Ruslan on March 17, 2021
You can define gdb function to break on first argument of libc_star_main. The first si/ni is to load libc itself. Put it in your .gdbinit file.
define bmain
si
ni
b __libc_start_main
c
b *($rdi)
c
end
Answered by p0tr3c on March 17, 2021
Just stumbled across this and thought I would add a bit.
If you want to stop at the entry point of a stripped, dynamically-linked program, I recommend the following procedure.
starti
so that the loader maps it into memory.
(By default GDB turns off ASLR for your program, but this method will work either way.)info file
to get the address of the entry point. This will show virtual addresses after start (that's why we used starti
first).cont
to get to the breakpoint.$ gdb /usr/bin/ls
(gdb) starti
(gdb) info file
...
Local exec file:
`/usr/bin/ls', file type elf64-x86-64.
Entry point: 0x55555555a7d0
...
(gdb) b *0x55555555a7d0
(gdb) cont
...
Breakpoint 1, 0x000055555555a7d0 in ?? ()
(gdb) x/i $rip
=> 0x55555555a7d0: endbr64
Now, if you want main
on Linux, step ahead through the disassembly until you find out how rdi
is being set (assuming the usual crt0.o
has been linked to start the C runtime).
(gdb)
0x55555555a7f1: lea rdi,[rip+0xffffffffffffe5f8] # 0x555555558df0
Ah ha! We can find main
(even without any symbols) at 0x555555558df0.
(gdb) b *0x555555558df0
(gdb) cont
Now you are at main
.
Leaving this here in case someone else comes along with the same question.
Answered by Stacy J on March 17, 2021
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP