Yes you can do this. Finding the location of printSomething could be achieved with a couple different methods depending on the state of ASLR but the easiest way that'll work no matter what is to just use the existing C operator to fetch the address of the function:
&printSomething
You will then need to append the value of that address to your string that you pass to the vulnerable function, e.g. using memcpy
char input[64] = "AAAAA...A"; //64 As
void* printSomethingAddress = &printSomething;
memcpy(input + ipOffset,&printSomethingAddress,(sizeof(void*)));
vulnerableFunction(input);
ipOffset here is the distance from the beginning of the buffer you strcpy to in vulnerableFunction to the location of the saved instruction pointer.
A couple things to be aware of:
That ipOffset distance may change based on subtle differences in the
code and compilation environment. Use a debugger and a disassembler
to help you calculate the correct offset when recompiling your
program.
Set optimization high enough and some of your functions are
likely to go away without warning because the compiler detects that
the code is "dead" - you can mitigate this by making sure to use -O0
and also by introducing "side-effects" that have a meaningful effect
on the program state.
If you compile with stack cookies you're
likely to cause the program to just abort - so make sure you skip em.
If you have any null bytes in the address of printSomething itself
your strcpy might end unexpectedly in the middle of the address. The
bad news is you almost certainly will have null bytes, but the good
news is that those bytes tend to be MSB's rather than LSB's, and
assuming you're compiling this on a little-endian platform that's
unlikely to be a problem since the original return address and
&printSomething likely share those MSB's. As long as you copy at
least 4 bytes of &printSomething to the overflown buffer, you're
probably fine. However if by some unfortunate happenstance
printSomething happens to be 256-byte aligned (aka LSB is 0x00) then
you could have trouble. You can check this with a debugger.
Of course, all of this is technically undefined behavior but that's never stopped anyone before - at a practical level anyway. A good hacker thrives on turning undefined behavior into hacker-controlled behavior.