Created
September 2, 2019 10:21
-
-
Save liutgnu/c22f9aaa2ab87e4b88775c5b2cf6f054 to your computer and use it in GitHub Desktop.
It's a demo of function inline hook for arm
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 arm, | |
* Please compile and test in arm32, 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 2 instructions(8 Byte) | |
*/ | |
__attribute__ ((optimize("align-functions"))) int sub(int a, int b) | |
{ | |
int aa = a; | |
int bb = b; | |
return aa - bb; | |
} | |
asm ( | |
"hook_trampoline:\n\t" | |
"b hooked_sub\n\t" | |
".align 12\n\t" // We want page aligned, also required by mprotect | |
"origin_sub_code_space:\n\t" | |
/* | |
* Space for the start 2 instructions of original sub function | |
*/ | |
".word 0\n\t" | |
".word 0\n\t" | |
/* | |
* Space for long jmp back to original | |
* sub function offset 2 instructions(8 Byte) | |
*/ | |
".word 0\n\t" | |
".word 0\n\t" | |
); | |
int hooked_sub(int a, int b) | |
{ | |
void *code_space_addr; | |
__asm__ volatile ("ldr %0, =origin_sub_code_space\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); | |
} | |
void patch_function() | |
{ | |
void *code_space_addr, *hook_trampoline_addr, *return_addr = &sub + 8; | |
__asm__ volatile ("ldr %0, =origin_sub_code_space\n\t":"=r"(code_space_addr)); | |
__asm__ volatile ("ldr %0, =hook_trampoline\n\t":"=r"(hook_trampoline_addr)); | |
/* | |
* Fill in the origin_sub_code_space in asm{} | |
* Long jmp code: | |
* ldr pc, [pc, #-4] | |
.addr | |
*/ | |
memcpy(code_space_addr, &sub, 8); | |
memcpy(code_space_addr + 8, "\x04\xf0\x1f\xe5", 4); | |
memcpy(code_space_addr + 12, &return_addr, 4); | |
/* | |
* Patch the start of sub function | |
* Same long jmp code | |
*/ | |
memcpy(&sub, "\x04\xf0\x1f\xe5", 4); | |
memcpy(&sub + 4, &hook_trampoline_addr, 4); | |
} | |
/* | |
* Before real patch, we need to change permissions of patched-areas | |
*/ | |
int remove_mem_protect() | |
{ | |
void *sub_code_space_addr = NULL; | |
__asm__ volatile("ldr %0, =origin_sub_code_space\n\t":"=r"(sub_code_space_addr)); | |
int ret1 = mprotect(sub_code_space_addr, 16, PROT_READ|PROT_WRITE|PROT_EXEC); | |
int ret2 = mprotect(&sub, 8, 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