home *** CD-ROM | disk | FTP | other *** search
- /*
- * file vkill.c
- *
- * Author: Antonio Julio Raposo (ajr@cybill.inesc.pt - LISBOA - PORTUGAL)
- * (Please do not remove my name from this file)
- * This is version 1.3, public domain software, meaning
- * no copyright and *** NO RESPONSABILITY ***
- *
- * usage:
- * 1) compile with Borland's TURBOC 2.0 or equivalent (COMPACT model)
- * 2) run with a command like 'VKILL C:' to clean drive C
- * 3) if it stops accessing the disk and seems stuck, just reset the
- * computer and start over again (this probably will only hapen if you
- * compile a small model or if there are thousands of virus around)
- *
- * 4) I hope you start checking the software you copy, starting a year ago!
- */
- #ifndef __COMPACT__
- # error "must compile with compact model (near functions and far data)"
- #endif
-
- /*
- * Changes from Vkill 1.2:
- * - modified the display of files being checked
- * - now allows the search of only one file or directory
- * - added search only mode, without touching the files
- * Changes from Vkill 1.1 (beta test version):
- * - fixed some minor bugs in the protection scheme
- * - added a line showing the name of the file being scanned
- * Changes from Vkill 1.0:
- * - fixed bug that prevented .EXE files wich had changed in size from
- * beeing cleaned (may happen if you append something to the end of
- * the file.) now the excess length also gets thrown away.
- * - added a feature wich protects the files from beeing infected.
- * - scans also .BIN and .OVL files as .EXE overlays.
- */
-
- #include <stdio.h>
- #include <string.h>
- #include <dir.h>
- #include <io.h>
- #include <dos.h>
- #include <alloc.h>
- #include <ctype.h>
- #include <fcntl.h>
-
- #define _COM 5
- #define _EXE 6
- #define chmod(s,m) _chmod (s, 1, m)
-
- char *pcat (char *, char *);
- char *signature =
- "8ED0BC000750B8C50050CBFC062E8C0631002E8C0639002E8C063D002E8C0641008CC0";
- char *buffer;
-
- struct {
- int dirs, total, com, exe, prot;
- } statistics;
- int prot = 0, clean = 1;
-
- main (int argc, char *argv[])
- {
- char *root, *s, *t, i;
-
- printf ("\n\n VKILL 1.3 - October 1990\n\n");
- printf ("Author: Antonio Julio Raposo. LISBOA - PORTUGAL\n");
- printf ("e-mail: ajr@cybill.inesc.pt\n\n");
- printf ("Mission:\t*** Seek and Terminate. ***\n");
- printf ("Target: \t*** Jerusalem-B virus. ***\n");
- printf ("\tWARNING! The virus damages some files beyond recovery.\n\n");
-
- for (s = signature, t = signature ; *s ; s += 2, t++)
- *t = (*s > '9' ? *s - 'A' + 10 : *s - '0') * 16 +
- (s[1] > '9' ? s[1] - 'A' + 10 : s[1] - '0');
- *t = '\0';
- if ((buffer = farmalloc (0x10000L)) == NULL)
- {
- fprintf (stderr, "not enough memory to run!\n");
- exit (2);
- }
- /* get arguments from command line */
- if (argc < 2)
- usage (*argv);
- for (i = 1 ; i < argc ; i++)
- if (*argv[i] == '/' || *argv[i] == '-')
- for (t = argv[i] + 1 ; *t ; t++)
- switch (*t)
- {
- case 'p': prot = 1; break;
- case 'u': prot = -1; break;
- case 'n': clean = 0; break;
- default: fprintf (stderr, "unknown option /%c. ignored.\n", *t);
- }
- else if (argv[i][1] == ':' && argv[i][2] == '\0')
- {
- root = malloc (4);
- sprintf (root, "%c:\\", toupper (*argv[i]));
- printf ("reading all files\n\n");
- if (readdir (root))
- {
- fprintf (stderr, "couldn't find any files?!\n\nABORTED\n");
- }
- free (root);
- }
- else
- {
- struct ffblk ff;
-
- if (readdir (argv[i]) && !findfirst (argv[i], &ff, 0x37) &&
- !access (argv[i], 0))
- {
- readfile (argv[i], &ff);
- printf ("\n");
- }
- }
-
- printf ("\t\t\t\n\n%d directories searched\n", statistics.dirs);
- printf ("%d files examined\n", statistics.total);
- printf ("%d virus found in com files\n", statistics.com);
- printf ("%d virus found in exe files\n", statistics.exe);
- if (prot < 0)
- printf ("%d protections removed\n", statistics.prot);
- else if (prot > 0)
- printf ("%d files protected\n", statistics.prot);
- printf ("\n\nMission Completed\n\n\n");
- }
-
- int usage (char *name)
- {
- fprintf (stderr, "usage:\t%s [/pun] <drive letter>:[filename]\n", name);
- fprintf (stderr, "\t/p to protect files\n");
- fprintf (stderr, "\t/u to unprotect files\n");
- fprintf (stderr, "\t/n search without cleaning\n");
- exit (1);
- }
-
- int readdir (char *s)
- {
- struct ffblk ff;
- char *all, *file;
-
- all = pcat (s, "*.*");
- if (findfirst (all, &ff, 0x37))
- {
- free (all);
- return -1;
- }
- printf ("searching files in %s\n", s);
- /* first pass: plain files */
- do
- if (!(ff.ff_attrib & FA_DIREC))
- {
- file = pcat (s, ff.ff_name);
- readfile (file, &ff);
- free (file);
- }
- while (!findnext (&ff));
- /* second pass: subdirectories */
- findfirst (all, &ff, 0x37);
- do
- if ((ff.ff_attrib & FA_DIREC) && *ff.ff_name != '.')
- {
- file = pcat (s, ff.ff_name);
- readdir (file);
- free (file);
- }
- while (!findnext (&ff));
- free (all);
- statistics.dirs++;
- return 0;
- }
-
- readfile (char *s, struct ffblk *ff)
- {
- int fd, ftype, virus;
- char *ext;
- long offset;
-
- ext = strchr (ff->ff_name, '.') + 1;
- if (!strcmp (ext, "COM"))
- ftype = _COM;
- else if (!strcmp (ext, "EXE") || !strcmp (ext, "BIN") ||
- !strcmp (ext, "OVL") || !strcmp (ext, "OVG") ||
- !strcmp (ext, "OV1") || !strcmp (ext, "OV2") ||
- !strcmp (ext, "OVR"))
- ftype = _EXE;
- else
- return;
- printf ("%-20s\r", ff->ff_name);
- virus = 1;
- do
- {
- fd = open (s, O_RDONLY | O_BINARY);
- lseek (fd, 0L, SEEK_SET);
- if (ftype == _EXE)
- {
- unsigned *up;
- read (fd, buffer, 0x710);
- up = (unsigned *) buffer;
- offset = -0xC5L + 0x10L * (up[4] + up[11]) + up[10];
- lseek (fd, offset, SEEK_SET);
- }
- read (fd, buffer, 0x710);
- close (fd);
- if (!strcmp (buffer + 0xBA, signature))
- if (ftype == _EXE)
- cleanEXE (s, ff, offset);
- else
- cleanCOM (s, ff);
- else
- virus = 0;
- if (virus)
- printf ("virus found in file %s. %s\007\n",
- s, clean ? "" : "(not cleaned)\007");
- }
- while (virus && clean); /* file my be infected with more than one copy */
- if (prot)
- protect (s, ff);
- statistics.total++;
- }
-
- cleanCOM (char *s, struct ffblk *ff)
- {
- int fd;
- struct ftime ft;
-
- statistics.com ++;
- if (!clean)
- return;
- chmod (s, 0);
- fd = open (s, O_RDWR | O_BINARY);
- getftime (fd, &ft);
- lseek (fd, 0L, SEEK_SET);
- read (fd, buffer, ff->ff_fsize);
- lseek (fd, 0L, SEEK_SET);
- write (fd, buffer + 0x710, ff->ff_fsize - 0x710);
- chsize (fd, ff->ff_fsize - 0x710L);
- ff->ff_fsize -= 0x710L;
- setftime (fd, &ft);
- close (fd);
- chmod (s, ff->ff_attrib);
- }
-
- cleanEXE (char *s, struct ffblk *ff, long offset)
- {
- int fd;
- struct ftime ft;
- unsigned istack_hi, istack_lo, entry_hi, entry_lo, pages, byteslp;
-
- statistics.exe ++;
- if (!clean)
- return;
- chmod (s, 0);
- fd = open (s, O_RDWR | O_BINARY);
- getftime (fd, &ft);
- istack_hi = *(unsigned *) (buffer + 0x45);
- istack_lo = *(unsigned *) (buffer + 0x43);
- entry_hi = *(unsigned *) (buffer + 0x47);
- entry_lo = *(unsigned *) (buffer + 0x49);
- byteslp = (unsigned) (offset % 0x200L);
- pages = (unsigned) (offset / 0x200L);
- if (byteslp != 0)
- pages++;
- chsize (fd, ff->ff_fsize = offset);
- lseek (fd, 0L, SEEK_SET);
- read (fd, buffer, 0x1C);
- lseek (fd, 0L, SEEK_SET);
- *(unsigned *) (buffer + 0x0E) = istack_hi;
- *(unsigned *) (buffer + 0x10) = istack_lo;
- *(unsigned *) (buffer + 0x14) = entry_hi;
- *(unsigned *) (buffer + 0x16) = entry_lo;
- *(unsigned *) (buffer + 0x04) = pages;
- *(unsigned *) (buffer + 0x02) = byteslp;
- *(unsigned *) (buffer + 0x12) = 0;
- write (fd, buffer, 0x1C);
- setftime (fd, &ft);
- close (fd);
- chmod (s, ff->ff_attrib);
- }
-
- protect (char *s, struct ffblk *ff)
- {
- int fd;
- struct ftime ft;
-
- if (!clean) return;
- chmod (s, 0);
- fd = open (s, O_RDWR | O_BINARY);
- getftime (fd, &ft);
- lseek (fd, -5L, SEEK_END);
- read (fd, buffer, 5);
- if (strncmp (buffer, "MsDos", 5))
- {
- if (prot > 0)
- {
- lseek (fd, 0L, SEEK_END);
- write (fd, "MsDos", 5);
- statistics.prot++;
- }
- }
- else
- if (prot < 0)
- {
- chsize (fd, ff->ff_fsize -= 5L);
- statistics.prot++;
- }
- setftime (fd, &ft);
- close (fd);
- chmod (s, ff->ff_attrib);
- }
-
- char *pcat (char *path, char *name)
- {
- register char *aux;
- register int plen = strlen (path);
- aux = malloc (plen + strlen (name) + 2);
- strcpy (aux, path);
- if (*aux != '\0' && aux[plen - 1] != '\\')
- strcat (aux, "\\");
- strcat (aux, name);
- return aux;
- }