Skip to content

Instantly share code, notes, and snippets.

@liutgnu
Created September 2, 2019 10:21
Show Gist options
  • Save liutgnu/c22f9aaa2ab87e4b88775c5b2cf6f054 to your computer and use it in GitHub Desktop.
Save liutgnu/c22f9aaa2ab87e4b88775c5b2cf6f054 to your computer and use it in GitHub Desktop.
It's a demo of function inline hook for arm
/*
* 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