Reputation: 65
Everything works:
#include <stdio.h>
int (* func)(const char * fmt, ...);
int main()
{
func = (void *)0x400420; /* printf pointer */
printf("printf address: %p\n", printf);
func("func() calling\n");
return 0;
}
But this does not work:
#include <stdio.h>
int (* func)(const char * fmt, ...);
int main()
{
func = (void *)0x400420; /* printf pointer */
/* printf("printf address: %p\n", printf); */
func("func() calling\n");
return 0;
}
Whats I am doing wrong? Tell me, please. Can I call printf (or some other function) by its pointer?
Upvotes: 4
Views: 965
Reputation: 3
on windows 7, compiler: mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0
int main()
{
int c = 5;
int (*pr)(const char *const _Format, ...);
pr = &printf;
(*pr)("%d\n", c);
return 0;
}
compiles and runs. you can follow the instructions in this video Pointers in C / C++ [Full Course] to get a better understanding. Around the 3 hour mark, the instructor starts talking about function pointers.
Upvotes: 0
Reputation: 20392
Two possibilites (which actually have the same primary cause):
You're doing static linking. This would mean that the linker doesn't need to pull in printf from libc, so printf doesn't get linked into your program at all.
You're doing dynamic linking, but on your architecture function pointers don't actually point to the function itself, but its dynamic trampoline. This means that the magic pointer you found is to a trampoline that only got created because you actually called printf from your program.
I'm pretty sure you're dynamically linking. Let's see how this works in practice with this simple program:
#include <stdio.h>
int
main(int argc, char **argv)
{
void *foo = (void *)printf;
return 0;
}
We compile and link this, and then disassemble. This is the relevant instruction that loads the address of printf into a local variable.
4004cf: 48 c7 45 f8 c0 03 40 movq $0x4003c0,-0x8(%rbp)
Notice that the pointer is 0x4003c0 which quite similar to what your pointer was. But wait a second. The address of this instruction is 0x4004cf. This is awfully close to where the printf pointer points, in fact it's in the same page, so it's impossible that this is a pointer to libc. Let's see what's at that address:
00000000004003c0 <printf@plt>:
4003c0: ff 25 92 04 20 00 jmpq *0x200492(%rip)
4003c6: 68 00 00 00 00 pushq $0x0
4003cb: e9 e0 ff ff ff jmpq 4003b0 <_init+0x18>
This is part of the program, not libc. If you change the program to call printf, it will actually jump to this address. This is the dynamic trampoline I was talking about. "plt" here stands for Procedure Linkage Table and it's the magic that the dynamic linker uses to be able to resolve function calls without modifying the text segment of your program.
Your problem is that you removed any link to printf in your program. Since it's not there, the linker will not generate this trampoline and you just set your pointer to point to something random that happened to be generated at that address.
Btw. Actually referencing printf in your program won't be enough to make tricks like this work. It's likely that calling just one other function will put PLT entries for that function at the same place that the trampoline for printf was generated. You're definitely not guaranteed where those trampolines end up and in my experience with how linkers generate code it will be seemingly random (because ordering of PLT entries is affected by ordering of internal hash tables in the linker). In other words, this only has a decent chance to work when your program looks exactly like the program that you used to print the address.
Upvotes: 3
Reputation: 1975
Change your code to evaluate printf address instead of putting it fixed:
#include <stdio.h>
int (* func)(const char * fmt, ...);
int main()
{
func = printf; /* printf pointer */
func("func() calling\n");
return 0;
}
Upvotes: 3