Yes, this is called Position Independent Executable (PIE). It randomizes the base address of the executable. It is enabled by default nowadays in most cases by gcc/the linker.
There are several ways to statically determine whether a binary is built with PIE. One method is to use file
; a PIE binary reports "shared object" (since that's what it is) compared to just "executable". Other tools e.g. checksec
can tell you as well. You will certainly know when you open the program in your debugger and the program addresses look nothing like what you're used to.
If the binary is not stripped, you should be able to set breakpoints normally using function names after the executable has started. However, a stripped binary becomes much more difficult; I am not aware of a way to do that effectively.
You can do cat /proc/<PID>/maps
on the process to view the memory mappings. The ones you want will show as mapped to the executable on disk. The first value should give you the starting offset.
Here's an example on my current process, cat
:
$ cat /proc/self/maps
559912213000-559912215000 r--p 00000000 07:00 1191827 /usr/bin/cat
559912215000-55991221a000 r-xp 00002000 07:00 1191827 /usr/bin/cat
55991221a000-55991221d000 r--p 00007000 07:00 1191827 /usr/bin/cat
55991221d000-55991221e000 r--p 00009000 07:00 1191827 /usr/bin/cat
55991221e000-55991221f000 rw-p 0000a000 07:00 1191827 /usr/bin/cat
559912b4c000-559912b6d000 rw-p 00000000 00:00 0 [heap]
<snip>
In this case, 0x559912213000
would be your base address.