There's two types of issues that I think you might be conflating. One is the address of functions called by your shellcode that are provided by the vulnerable application or by libraries loaded, and the other is absolute versus relative jumps within your shellcode.
Library Calls
Let's assume, for a second, that you're attempting a return-to-libc style exploit on a simple binary. So you want the address of system
for a lot of such exploits. Let's build a small binary that prints the address of system
.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
printf("system @%p\n", system);
return 0;
}
Compile and run this a few times:
% gcc -o getsystem getsystem.c
% ./getsystem
system @0x7fdc54419d40
% ./getsystem
system @0x7fbc15b61d40
% ./getsystem
system @0x7fbeacfb6d40
Notice that each time it is run, the address of system
has changed. This is due to a modern security mitigation called ASLR: the C library is loaded at a different base address, so system
will be loaded at a different address. Consequently, your shellcode needs to first locate libc, then call system
at an address relative to the start of the library. (Called the "base address".)
Jumps
In more complex shellcode, you may need to make a jmp
or call
within the payload itself. In such cases, you must have relative jumps and calls, because you do not know the exact address where your shellcode will be loaded. Instead of saying "jump to 0x0804abcd
", you should have "jump 5 bytes forward". This is what is meant by "Position-Independent Code": it can operate when loaded at any position, and not just at some fixed starting address.
Because shellcode is usually loaded on the stack or heap, both of which are subject to various manipulations (ASLR, other data using the stack/heap, threading, etc.), it's impossible to predict an absolute address where your shellcode will land.