Created
September 4, 2023 10:30
-
-
Save liutgnu/037e2bc3d8ac174cde0ea78af88eb70a to your computer and use it in GitHub Desktop.
It's a demo of function inline hook for ppc64le
This file contains hidden or 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
/* | |
* This program is a demo of function inline hook for ppc64le, | |
* Please compile and test in ppc64le, WITHOUT any compile optimization | |
* | |
* Function sub will be hooked by hooked_sub, when invoke function sub, | |
* hooked_sub will be invoked first, then it can decide whether to invoke the | |
* original sub or not. | |
*/ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <sys/mman.h> | |
/* | |
* We want the function to be page aligned, required by mprotect. | |
* And we want the function length longer than 14 instructions(56 Byte) | |
*/ | |
__attribute__ ((aligned(2 << 16))) int sub(int a, int b) | |
{ | |
int aa = a; | |
int bb = b; | |
return aa - bb; | |
} | |
int hooked_sub(int a, int b) | |
{ | |
void *code_space_addr; | |
__asm__ volatile ( | |
"addis %0,2,origin_sub_code_space@toc@ha\n\t" | |
"addi %0,%0,origin_sub_code_space@toc@l\n\t": | |
"=r"(code_space_addr) | |
); | |
int (*origin_sub)(int, int) = (int (*)(int, int))(code_space_addr); | |
printf("We can view parameters in hooked_sub: %d, %d\n", a, b); | |
printf("Now resume origin sub\n"); | |
return (*origin_sub)(a, b); | |
} | |
asm ( | |
"hook_trampoline:\n\t" | |
"ld 10, 0(1)\n\t" | |
"mtlr 10\n\t" | |
"ld 10, 16(1)\n\t" | |
"addi 1, 1, 32\n\t" | |
"b hooked_sub\n\t" | |
".align 16\n\t" // We want page aligned, also required by mprotect | |
"origin_sub_code_space:\n\t" | |
/* | |
* Space for the start 14 instructions of original sub function | |
*/ | |
".long 0\n\t" | |
".long 0\n\t" | |
".long 0\n\t" | |
".long 0\n\t" | |
".long 0\n\t" | |
".long 0\n\t" | |
".long 0\n\t" | |
".long 0\n\t" | |
".long 0\n\t" | |
".long 0\n\t" | |
".long 0\n\t" | |
".long 0\n\t" | |
".long 0\n\t" | |
".long 0\n\t" | |
/* | |
* Space for long jmp back to original | |
* sub function offset 14 instructions(56 Byte) | |
*/ | |
".long 0\n\t" | |
".long 0\n\t" | |
".long 0\n\t" | |
".long 0\n\t" | |
".long 0\n\t" | |
".long 0\n\t" | |
".long 0\n\t" | |
".long 0\n\t" | |
".long 0\n\t" | |
".long 0\n\t" | |
".long 0\n\t" | |
".long 0\n\t" | |
".long 0\n\t" | |
".long 0\n\t" | |
); | |
void patch_function() | |
{ | |
void *code_space_addr, *hook_trampoline_addr, *return_addr = &sub + 40; | |
__asm__ volatile ( | |
"addis %0,2,origin_sub_code_space@toc@ha\n\t" | |
"addi %0,%0,origin_sub_code_space@toc@l\n\t": | |
"=r"(code_space_addr) | |
); | |
__asm__ volatile ( | |
"addis %0,2,hook_trampoline@toc@ha\n\t" | |
"addi %0,%0,hook_trampoline@toc@l\n\t": | |
"=r"(hook_trampoline_addr) | |
); | |
/* | |
* Fill in the origin_sub_code_space in asm{} | |
* Long jmp code: | |
stdu 10, -16(1) # push r10 | |
mflr 10 | |
stdu 10, -16(1) # push lr | |
bcl 20,31,.+4 | |
mflr 10 | |
ld 10, 16(10) | |
mtctr 10 | |
bctr | |
.addr(low) | |
.addr(high) | |
ld 10, 0(1) | |
mtlr 10 | |
ld 10, 16(1) | |
addi 1, 1, 32 | |
*/ | |
memcpy(code_space_addr, &sub, 56); | |
memcpy(code_space_addr + 56, "\xf1\xff\x41\xf9\xa6\x02\x48\x7d\xf1\xff\x41\xf9\x05\x00\x9f\x42\xa6\x02\x48\x7d\x10\x00\x4a\xe9\xa6\x03\x49\x7d" | |
"\x20\x04\x80\x4e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x41\xe9\xa6\x03\x48\x7d\x10\x00\x41\xe9\x20\x00\x21\x38", 56); | |
memcpy(code_space_addr + 56 + 32, &return_addr, 8); | |
/* | |
* Patch the start of sub function | |
* Same long jmp code | |
*/ | |
memcpy(&sub, "\xf1\xff\x41\xf9\xa6\x02\x48\x7d\xf1\xff\x41\xf9\x05\x00\x9f\x42\xa6\x02\x48\x7d\x10\x00\x4a\xe9\xa6\x03\x49\x7d" | |
"\x20\x04\x80\x4e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x41\xe9\xa6\x03\x48\x7d\x10\x00\x41\xe9\x20\x00\x21\x38", 56); | |
memcpy(&sub + 32, &hook_trampoline_addr, 8); | |
} | |
/* | |
* Before real patch, we need to change permissions of patched-areas | |
*/ | |
int remove_mem_protect() | |
{ | |
void *sub_code_space_addr = NULL; | |
__asm__ volatile ( | |
"addis %0,2,origin_sub_code_space@toc@ha\n\t" | |
"addi %0,%0,origin_sub_code_space@toc@l\n\t": | |
"=r"(sub_code_space_addr) | |
); | |
int ret1 = mprotect(sub_code_space_addr, 56 * 2, PROT_READ|PROT_WRITE|PROT_EXEC); | |
int ret2 = mprotect(&sub, 56, PROT_READ|PROT_WRITE|PROT_EXEC); | |
return (ret1|ret2); | |
} | |
int main() | |
{ | |
if (remove_mem_protect()) { | |
printf("mprotect error!\n"); | |
return -1; | |
} | |
printf("***************************************************\n"); | |
printf("This is the result of unhooked sub(2, 100): %d\n", sub(2, 100)); | |
printf("This is the result of unhooked sub(50, 2): %d\n", sub(50, 2)); | |
printf("***************************************************\n"); | |
patch_function(); | |
printf("This is the result of hooked sub(2, 100): %d\n", sub(2, 100)); | |
printf("This is the result of hooked sub(50, 2): %d\n", sub(50, 2)); | |
printf("***************************************************\n"); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment