Last active
November 2, 2022 02:45
-
-
Save m1lkweed/28632a7f7c08102dcf3b5ef31425e6da to your computer and use it in GitHub Desktop.
Inject a function in-between the current function and its caller
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Must be compiled with optimizations enabled, all options except -O0 are supported | |
#include <stddef.h> | |
#include <inttypes.h> | |
// Injects a function in-between the current function and its caller, | |
// injections are visited in reverse order, see example. | |
[[gnu::always_inline]] static inline void inject(void *addr){ | |
asm("call .+5"); | |
void * volatile *p = __builtin_frame_address(0); | |
*p = __builtin_frob_return_addr(addr); | |
asm("movq %%rsp, %%rbp":::); | |
} | |
// Will only bypass the most recent injection, not all of them | |
[[noreturn, gnu::noinline]] void bypass_injection(const uintptr_t value){ | |
asm("addq $24, %%rsp\n\t" | |
"movq %0, %%rax\n\t" | |
"ret" | |
: | |
:"D"(value) | |
:"rax" | |
); | |
__builtin_unreachable(); | |
} | |
// Bypasses `count` injections | |
[[noreturn, gnu::naked, gnu::noinline]] void bypass_injections(const uintptr_t value, size_t count){ | |
asm volatile("imulq $8, %0\n\t" | |
"addq %0, %%rsp\n\t" | |
"addq $16, %%rsp\n\t" | |
"movq %%rsp, %%rbp\n\t" | |
"movq %1, %%rax\n\t" | |
"ret" | |
:"=S"(count) | |
:"D"(value) | |
:"rax", "rbp" | |
); | |
} | |
// We don't have __usercall yet but this function is essentially | |
// int double_return_value(int value@<eax>){ | |
// return value + value; | |
// } | |
[[gnu::naked]] int double_return_value(){ | |
asm("addl %%eax, %%eax\n\t" | |
"retq" | |
: | |
); | |
} | |
// int double_return_value(int value@<eax>){ | |
// return value + 3; | |
// } | |
[[gnu::naked]] int add_3_to_ret(){ | |
asm("addl $3, %%eax\n\t" | |
"retq" | |
: | |
); | |
} | |
int main(){ | |
inject(double_return_value); | |
inject(add_3_to_ret); | |
// 0 -> 16 | |
// 1 -> 8 | |
// 2 -> 5 | |
// 3+ UB | |
// bypass_injections(5, 2); | |
return 5; // returns 16; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment