Suppose we have some C code that calls upon a function though a function pointer, whether it be through a function pointer table or a function pointer passed as parameter or other, like so:
/* ... some other code .. */
void (*f)(void) = something; // f function pointer to some function
(*f)();
This should be compiled to (or something equivalent)
mov %rcx, [something] ; here f=ecx
callq *%rcx
Question: does %ecx
always point to a function prologue or can it point to a small peice of code at the end on a function?
Example:
void big_func(){
/* lots of code here */
printf("bar");
printf("foo");
}
void small_func(){
printf("foo");
With big_func
C compiled to
; some more code up here
1: 48 8d 3d c4 0e 00 00 lea %rdi,[0xec4+%rip] ;ptr to "bar"
2: b8 00 00 00 00 mov %eax,$0x0
3: e8 e6 fe ff ff callq 1030 <printf@plt>
4: 48 8d 3d b7 0e 00 00 lea %rdi,[0xeb7+%rip] ;ptr to "foo"
5: b8 00 00 00 00 mov %eax,$0x0
6: e8 d5 fe ff ff callq 1030 <printf@plt>
7: b8 00 00 00 00 mov %eax,$0x0
8: 5d pop %rbp
9: c3 ret
Is it possible for a call to small_func
to point to 4:
as it's entry point? Does this happen ever (with a generic compiler like gcc) or only with some human modifying the assembly code behind the scenes?
Question limits:
- Consider all assembly code code compiled by a non-specialised compiler (like gcc, clang etc., without fancy asm quirks for performance behind the scenes)
- Only consider normal behaviour. Let's imagine the developer is a nice person and doesn't implement any pesky undefined behaviour
Additional mini-question: What happens would happen of one intentionally modifies the function pointer to skip some bytes from a function prologue? Is this considered undefined behaviour?
Example:
void (*f)(void) = something; // f function pointer to some function
f=(void (*func_ptr)(void)) ((*char)f+2)
(*f)(); //skips `push ebp`
EDIT: I should have been more clear as of why this question is asked. It is in the context of a research master, seeking a new way to mitigate ROP based attacks at a very low software or hardware level. If it were possible for indirect calls to point somewhere else than a function prologue it could break one of our tag-based implementation (missing the tag and terminating the program after incorrectly detecting an attack)