Skip to content

Instantly share code, notes, and snippets.

@m1lkweed
Last active November 2, 2022 02:45
Show Gist options
  • Save m1lkweed/28632a7f7c08102dcf3b5ef31425e6da to your computer and use it in GitHub Desktop.
Save m1lkweed/28632a7f7c08102dcf3b5ef31425e6da to your computer and use it in GitHub Desktop.
Inject a function in-between the current function and its caller
// 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