Skip to content

Instantly share code, notes, and snippets.

@3intermute
Last active August 5, 2022 04:23
Show Gist options
  • Save 3intermute/11ba22dba63362431a8cec84aedaffae to your computer and use it in GitHub Desktop.
Save 3intermute/11ba22dba63362431a8cec84aedaffae to your computer and use it in GitHub Desktop.
arm64 syscall hooking
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <asm-generic/unistd.h>
#include "resolve_kallsyms.h"
#include "set_page_flags.h"
#include "direct_syscall_hook.h"
MODULE_LICENSE("GPL");
MODULE_AUTHOR("0xwillow");
MODULE_DESCRIPTION("syscall table hook on arm64, no ftrace");
MODULE_VERSION("1.0");
static asmlinkage int (*orig_mkdirat) (const struct pt_regs *);
asmlinkage int new_mkdirat(const struct pt_regs *regs) {
char __user *pathname_usr_ptr = (char *) regs->regs[1];
char pathname[NAME_MAX] = {0};
strncpy_from_user(pathname, pathname_usr_ptr, NAME_MAX); // 256 bits
pr_info("debug: mkdirat called :D, path (%s), fd (%i), mode (%lli)\n", pathname, (int) regs->regs[0], regs->regs[2]);
if ((int) regs->regs[0] == -1) {
return 0xdeadbeef;
}
return orig_mkdirat(regs);
}
struct direct_syscall_hook hook = {__NR_mkdirat, new_mkdirat, &orig_mkdirat};
static int __init hook_test_mod_init(void) {
pr_info("debug: module loaded\n");
hook_syscall(&hook);
return 0;
}
static void __exit hook_test_mod_exit(void) {
pr_info("debug: module unloaded\n");
}
module_init(hook_test_mod_init);
module_exit(hook_test_mod_exit);
#ifndef _RESOLV_DIRECT_HOOK_H_
#define _RESOLV_DIRECT_HOOK_H_
#include <asm/unistd.h>
#include "resolve_kallsyms.h"
#include "set_page_flags.h"
struct direct_syscall_hook {
int number;
void *new;
void *orig;
};
void **sys_call_table_addr = NULL;
static int resolve_syscall_table(void) {
sys_call_table_addr = kallsyms_lookup_name_("sys_call_table");
return 0;
}
void hook_syscall(struct direct_syscall_hook *hook) {
if (!sys_call_table_addr) {
resolve_syscall_table();
}
*((uintptr_t *) hook->orig) = sys_call_table_addr[hook->number];
pte_t *ptep = page_from_virt(&sys_call_table_addr[hook->number]);
pr_info("debug: ptep @ %pK, pte_write flag (%i)\n", &sys_call_table_addr[hook->number], pte_write(*ptep));
pr_info("debug: flipping write protect flag...\n");
pte_flip_write_protect(page_from_virt(&sys_call_table_addr[hook->number]));
ptep = page_from_virt(&sys_call_table_addr[hook->number]);
pr_info("debug: ptep @ %pK, pte_write flag (%i)\n", &sys_call_table_addr[hook->number], pte_write(*ptep));
sys_call_table_addr[hook->number] = hook->new;
pr_info("debug: hook_syscall of #%i, orig @ %pK, new @%pK, success\n", hook->number, hook->orig, hook->new);
}
void unhook_syscall(struct direct_syscall_hook *hook) {
if (!sys_call_table_addr) {
resolve_syscall_table();
}
sys_call_table_addr[hook->number] = hook->orig;
pr_info("debug: unhook_syscall of #%i, orig restored @ %pK, new @%pK, success\n", hook->number, hook->orig, hook->new);
}
#endif
#ifndef _RESOLV_KALLSYMS_H_
#define _RESOLV_KALLSYMS_H_
#include <linux/kprobes.h>
#include <linux/ftrace.h>
#include <asm/unistd.h>
typedef uintptr_t (*kallsyms_lookup_name_t)(const char *symbol_name);
static kallsyms_lookup_name_t kallsyms_lookup_name__ = NULL;
uintptr_t kprobe_get_func_addr(const char *func_name) {
static struct kprobe kp;
kp.symbol_name = func_name;
if (register_kprobe(&kp) < 0) {
pr_info("debug: kprobe_get_func_addr of %s failed\n", func_name);
return -ENOENT;
}
uintptr_t tmp = kp.addr;
unregister_kprobe(&kp);
pr_info("debug: kprobe_get_func_addr %s @ %pK\n", func_name, tmp);
return tmp;
}
uintptr_t kallsyms_lookup_name_(const char *symbol_name) {
if (!kallsyms_lookup_name__) {
kallsyms_lookup_name__ = kprobe_get_func_addr("kallsyms_lookup_name");
}
uintptr_t tmp = kallsyms_lookup_name__(symbol_name);
pr_info("debug: kallsyms_lookup_name_ %s @ %pK\n", symbol_name, tmp);
return tmp;
}
#endif
#ifndef _SET_PAGE_FLAGS_H_
#define _SET_PAGE_FLAGS_H_
#include <asm/pgtable.h>
#include "resolve_kallsyms.h"
pte_t *page_from_virt(uintptr_t addr) {
pgd_t *pgd;
pud_t *pud;
pmd_t *pmd;
pte_t *ptep;
struct mm_struct *init_mm_ptr = kallsyms_lookup_name_("init_mm");
pgd = pgd_offset(init_mm_ptr, addr);
if (pgd_none(*pgd) || pgd_bad(*pgd)) {
return NULL;
}
pud = pud_offset(pgd, addr);
if (pud_none(*pud) || pud_bad(*pud)) {
return NULL;
}
pmd = pmd_offset(pud, addr);
if (pmd_none(*pmd) || pmd_bad(*pmd)) {
return NULL;
}
ptep = pte_offset_map(pmd, addr);
if (!ptep) {
return NULL;
}
return ptep;
}
void pte_flip_write_protect(pte_t *ptep) {
if (!pte_write(*ptep)) {
*ptep = pte_mkwrite(pte_mkdirty(*ptep));
*ptep = clear_pte_bit(*ptep, __pgprot((_AT(pteval_t, 1) << 7)));
return;
}
pte_wrprotect(*ptep);
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment