├── Makefile ├── README.md └── main.c /Makefile: -------------------------------------------------------------------------------- 1 | MODULE_NAME := hack 2 | RESMAN_CORE_OBJS:=main.o 3 | RESMAN_GLUE_OBJS:= 4 | ifneq ($(KERNELRELEASE),) 5 | obj-m := $(MODULE_NAME).o 6 | $(MODULE_NAME)-objs:=$(RESMAN_GLUE_OBJS) $(RESMAN_CORE_OBJS) 7 | else 8 | KDIR := /home/wangchuan/Xiaomi_Kernel_OpenSource 9 | all: 10 | make -j$(nproc) -C $(KDIR) M=$(shell pwd) ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- modules 11 | rm -rf *.o *.mod .*.*.cmd *.mod.o *.mod.c *.symvers *.order .tmp_versions 12 | clean: 13 | rm -rf *.ko *.o *.mod .*.*.cmd *.mod.o *.mod.c *.symvers *.order *.lds .tmp_versions 14 | .PHONY: clean 15 | endif 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # linux_kernel_hook_arm64 2 | A example hook syscall of ioctl 3 | Used some code project of Apatch 4 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | 13 | #define bits(n, high, low) (((n) << (63u - (high))) >> (63u - (high) + (low))) 14 | 15 | typedef asmlinkage long (*syscall_ioctl_t)(unsigned int fd, unsigned int cmd, unsigned long arg);//4.14版本的ioctl是通过栈传递 所以fd cmd 和arg是三个参数 asmlinkage的意思是指定这个函数是由栈传递的参数 16 | typedef unsigned long (*kallsyms_lookup_name_t)(const char *name); 17 | typedef long (*new_syscall_ioctl_t)(const struct pt_regs *);//4.19版本以上通过寄存器传递参数所以不用加asmlinkage 默认不加就是通过寄存器传递参数 18 | kallsyms_lookup_name_t (*my_kallsyms_lookup_name)(const char *name); 19 | unsigned long *__sys_call_table; 20 | unsigned long start_address; 21 | unsigned long finish_address; 22 | syscall_ioctl_t original_ioctl;//保存低版本ioctl 23 | 24 | #if LINUX_VERSION_CODE > KERNEL_VERSION(4, 14, 186) 25 | new_syscall_ioctl_t new_original_ioctl;//保存高版本ioctl 26 | #endif 27 | 28 | static int setts(int value) { 29 | struct file *file; 30 | loff_t pos = 0; 31 | char buf[2]; 32 | 33 | file = filp_open("/proc/sys/kernel/kptr_restrict", O_WRONLY, 0); 34 | if (IS_ERR(file)) { 35 | printk(KERN_ERR "Failed to open /proc/sys/kernel/kptr_restrict\n"); 36 | return -EFAULT; 37 | } 38 | 39 | snprintf(buf, sizeof(buf), "%d", value); 40 | 41 | kernel_write(file, buf, strlen(buf), &pos); 42 | 43 | filp_close(file, NULL); 44 | 45 | return 0; 46 | } 47 | static uintptr_t read_kallsyms(const char *symbol) { 48 | struct file *file; 49 | loff_t pos = 0; 50 | char *buf; 51 | char sym_name[256]; 52 | char *addr_str; 53 | char *type_str; 54 | char *name_str; 55 | uintptr_t addr; 56 | char type; 57 | mm_segment_t old_fs; 58 | struct seq_file *seq; 59 | file = filp_open("/proc/kallsyms", O_RDONLY, 0); 60 | if (IS_ERR(file)) { 61 | printk(KERN_ERR "无法打开kallsyms\n"); 62 | return -EFAULT; 63 | } 64 | 65 | old_fs = get_fs(); 66 | set_fs(get_ds()); 67 | 68 | buf = kmalloc(4096, GFP_KERNEL); 69 | if (!buf) { 70 | filp_close(file, NULL); 71 | set_fs(old_fs); 72 | return -ENOMEM; 73 | } 74 | 75 | seq = file->private_data; 76 | if (!seq) { 77 | printk(KERN_ERR "失败\n"); 78 | kfree(buf); 79 | filp_close(file, NULL); 80 | set_fs(old_fs); 81 | return -EFAULT; 82 | } 83 | 84 | while (seq_read(file, buf, 4096, &pos) > 0) { 85 | char *line = buf; 86 | while (*line) { 87 | char *end = strchr(line, '\n'); 88 | if (end) *end = '\0'; 89 | addr_str = line; 90 | type_str = strchr(line, ' '); 91 | if (!type_str) break; 92 | *type_str++ = '\0'; 93 | name_str = strchr(type_str, ' '); 94 | if (!name_str) break; 95 | *name_str++ = '\0'; 96 | 97 | addr = simple_strtoull(addr_str, NULL, 16); 98 | type = *type_str; 99 | strncpy(sym_name, name_str, sizeof(sym_name) - 1); 100 | sym_name[sizeof(sym_name) - 1] = '\0'; 101 | 102 | if (strcmp(sym_name, symbol) == 0) { 103 | //printk(KERN_INFO "Torlins Symbol: %s, Address: %llx, Type: %c\n", sym_name, addr, type); 104 | kfree(buf); 105 | filp_close(file, NULL); 106 | set_fs(old_fs); 107 | return addr; 108 | } 109 | 110 | if (end) line = end + 1; 111 | else break; 112 | } 113 | } 114 | return -1; 115 | } 116 | unsigned long get_kallsyms_lookup_name_addr(void) 117 | { 118 | unsigned long ret = 0; 119 | setts(0); 120 | ret = read_kallsyms("kallsyms_lookup_name"); 121 | return ret; 122 | } 123 | 124 | static uint64_t page_size_t = 0; 125 | static uint64_t page_level_c = 0; 126 | static uint64_t page_shift_t = 0; 127 | 128 | static uint64_t pgd_k_pa = 0; 129 | static uint64_t pgd_k = 0; 130 | 131 | __attribute__((no_sanitize("cfi"))) void init_page_util(void) 132 | { 133 | uint64_t tcr_el1; 134 | uint64_t ttbr1_el1; 135 | uint64_t va_bits; 136 | 137 | uint64_t t1sz; 138 | uint64_t tg1; 139 | uint64_t baddr; 140 | uint64_t page_size_mask; 141 | //util_find_kallsyms(); 142 | // printk("[db] kallsyms_lookup_name_fun_: %lx\n", kallsyms_lookup_name_fun_); 143 | asm volatile("mrs %0, tcr_el1" : "=r"(tcr_el1)); 144 | 145 | t1sz = bits(tcr_el1, 21, 16); 146 | 147 | tg1 = bits(tcr_el1, 31, 30); 148 | 149 | va_bits = 64 - t1sz; 150 | 151 | page_shift_t = 12; 152 | if (tg1 == 1) { 153 | page_shift_t = 14; 154 | } else if (tg1 == 3) { 155 | page_shift_t = 16; 156 | } 157 | page_size_t = 1 << page_shift_t; 158 | 159 | page_level_c = (va_bits - 4) / (page_shift_t - 3); 160 | 161 | asm volatile("mrs %0, ttbr1_el1" : "=r"(ttbr1_el1)); 162 | baddr = ttbr1_el1 & 0xFFFFFFFFFFFE; 163 | page_size_mask = ~(page_size_t - 1); 164 | pgd_k_pa = baddr & page_size_mask; 165 | pgd_k = (uint64_t)phys_to_virt(pgd_k_pa); 166 | printk("[db]page_size_t: %lx\n", page_size_t); 167 | printk("[db]page_level_c: %lx\n", page_level_c); 168 | printk("[db]page_shift_t: %lx\n", page_shift_t); 169 | printk("[db]pgd_k_pa: %lx\n", pgd_k_pa); 170 | printk("[db]pgd_k: %lx\n", pgd_k); 171 | } 172 | 173 | 174 | uint64_t *pgtable_entry(uint64_t pgd, uint64_t va) 175 | { 176 | 177 | uint64_t pxd_bits = page_shift_t - 3; 178 | uint64_t pxd_ptrs = 1u << pxd_bits; 179 | uint64_t pxd_va = pgd; 180 | uint64_t pxd_pa = virt_to_phys((void*)pxd_va); 181 | uint64_t pxd_entry_va = 0; 182 | uint64_t block_lv = 0; 183 | int64_t lv = 0; 184 | //int64_t lv; 185 | if(page_shift_t == 0 || page_level_c == 0 || page_shift_t == 0) 186 | return NULL; 187 | // ================ 188 | // Branch to some function (even empty), It can work, 189 | // I don't know why, if anyone knows, please let me know. thank you very much. 190 | // ================ 191 | //__flush_dcache_area((void *)pxd_va, page_size_t); 192 | 193 | for (lv = 4 - page_level_c; lv < 4; lv++) { 194 | uint64_t pxd_shift = (page_shift_t - 3) * (4 - lv) + 3; 195 | uint64_t pxd_index = (va >> pxd_shift) & (pxd_ptrs - 1); 196 | pxd_entry_va = pxd_va + pxd_index * 8; 197 | if (!pxd_entry_va) return 0; 198 | uint64_t pxd_desc = *((uint64_t *)pxd_entry_va); 199 | if ((pxd_desc & 0b11) == 0b11) { // table 200 | pxd_pa = pxd_desc & (((1ul << (48 - page_shift_t)) - 1) << page_shift_t); 201 | } else if ((pxd_desc & 0b11) == 0b01) { // block 202 | // 4k page: lv1, lv2. 16k and 64k page: only lv2. 203 | uint64_t block_bits = (3 - lv) * pxd_bits + page_shift_t; 204 | pxd_pa = pxd_desc & (((1ul << (48 - block_bits)) - 1) << block_bits); 205 | block_lv = lv; 206 | } else { // invalid 207 | return 0; 208 | } 209 | // 210 | pxd_va = (uint64_t)phys_to_virt((phys_addr_t)pxd_pa); 211 | if (block_lv) { 212 | break; 213 | } 214 | } 215 | #if 0 216 | uint64_t left_bit = page_shift + (block_lv ? (3 - block_lv) * pxd_bits : 0); 217 | uint64_t tpa = pxd_pa + (va & ((1u << left_bit) - 1)); 218 | uint64_t tlva = phys_to_virt(tpa); 219 | uint64_t tkimg = phys_to_kimg(tpa); 220 | if (tlva != va && tkimg != va) { 221 | return 0; 222 | } 223 | #endif 224 | return (uint64_t *)pxd_entry_va; 225 | } 226 | 227 | inline uint64_t *pgtable_entry_kernel(uint64_t va) 228 | { 229 | return pgtable_entry(pgd_k, va); 230 | } 231 | 232 | 233 | long new_hook_ioctl(const struct pt_regs *kregs) 234 | { 235 | long ret = 0; 236 | printk("gt_hook_successful_ioctl"); 237 | ret = new_original_ioctl(kregs); 238 | return ret; 239 | } 240 | 241 | asmlinkage long hook_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) 242 | { 243 | long ret = 0; 244 | printk("gt_hook_ioctl"); 245 | ret = original_ioctl(fd, cmd, arg); 246 | return ret; 247 | } 248 | 249 | static int hook_func(unsigned long hook_function, int nr, 250 | unsigned long *sys_table) 251 | { 252 | uint64_t orginal_pte; 253 | uint64_t *pte; 254 | if(nr<0) 255 | return 3004; 256 | 257 | pte = pgtable_entry_kernel((uint64_t)&sys_table[nr]); 258 | if(pte == NULL) 259 | return 3007; 260 | 261 | 262 | orginal_pte = *pte; 263 | *pte = (orginal_pte | PTE_DBM) & ~PTE_RDONLY; 264 | flush_tlb_all(); 265 | 266 | sys_table[nr] = hook_function; 267 | 268 | //orginal_pte = *pte; 269 | *pte = orginal_pte; 270 | flush_tlb_all(); 271 | } 272 | 273 | 274 | 275 | static unsigned long *obtain_syscall_table_bf(unsigned long start_address, unsigned long finish_address, unsigned long sys_close_addr) 276 | { 277 | unsigned long *syscall_table; 278 | unsigned long int i; 279 | 280 | for (i = start_address; i < finish_address; i += sizeof(void *)) { 281 | syscall_table = (unsigned long *)i; 282 | if (syscall_table[__NR_close] == sys_close_addr) 283 | return syscall_table; 284 | } 285 | return NULL; 286 | } 287 | 288 | static int __init my_module_init(void) { 289 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(4, 14, 186) 290 | hook_func((unsigned long)hook_ioctl, __NR_ioctl, __sys_call_table); 291 | #else 292 | hook_func((unsigned long)new_hook_ioctl, __NR_ioctl, __sys_call_table); 293 | //__sys_call_table[__NR_ioctl] = (unsigned long)new_hook_ioctl; 294 | #endif 295 | 296 | return 0; 297 | } 298 | 299 | static void __exit my_module_exit(void) { 300 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(4, 14, 191) 301 | hook_func((unsigned long)original_ioctl, __NR_ioctl, __sys_call_table); 302 | #else 303 | hook_func((unsigned long)new_original_ioctl, __NR_ioctl, __sys_call_table); 304 | //__sys_call_table[__NR_ioctl] = (unsigned long)new_original_ioctl;; 305 | #endif 306 | } 307 | 308 | module_init(my_module_init); 309 | module_exit(my_module_exit); 310 | 311 | MODULE_LICENSE("GPL"); 312 | MODULE_DESCRIPTION("Custom syscall module using kprobes"); 313 | MODULE_AUTHOR("wangchuan"); --------------------------------------------------------------------------------