home *** CD-ROM | disk | FTP | other *** search
/ Amiga Elysian Archive / AmigaElysianArchive.iso / virus / kv.lzh / kv.c < prev    next >
C/C++ Source or Header  |  1989-11-26  |  19KB  |  846 lines

  1. /*
  2.     kv - removes the IRQ virus from an executable file.
  3.     compile with Manx C - 16 bit mode ok
  4.  
  5.     Routine IRQ_Kill() does the work, the rest is a vehicle
  6.  
  7.     This program will also detect one varient of the Lamer virus in memory
  8.     and deactivate it.  
  9.  
  10.     Also checks for the BGS9 virus
  11.  
  12.             Djj  8/25/89
  13. */
  14. #include <exec/types.h>
  15. #include <exec/exec.h>
  16. #include <libraries/dos.h>
  17. #include <intuition/intuition.h>
  18. #include <devices/trackdisk.h>
  19. #include <exec/execbase.h>
  20. #include <exec/resident.h>
  21. #include <stdio.h>
  22.  
  23.  
  24. #define VERSION  "KV  ver 2.0  09/01/89  Djj"
  25.  
  26. #define    VTAG     0x00000109L        /* virus hunk length */
  27. #define VSIG1    0x0000FFFEL        /* part of virus signature */
  28. #define VSIG2    0x61000000L        /* part of virus signature */
  29.  
  30. #define    BEGIN     OFFSET_BEGINNING
  31. #define END         OFFSET_END
  32. #define OLD         MODE_OLDFILE
  33. #define NEW         MODE_NEWFILE
  34.  
  35. #define SLONG     ((long)(sizeof(long)))
  36.  
  37. #define    OK        1            /* no error */
  38.  
  39. #define    NOFILE   -1            /* can't find file */
  40. #define    SEEKERR  -2            /* seek error on file */
  41. #define ALLOCERR -3            /* can't allocate memory */
  42. #define READERR     -4            /* error reading file */
  43. #define VIRUSNF  -5            /* virus not found in file */
  44. #define WRITERR  -6            /* error writing to file */
  45. #define OPENERR  -7            /* error opening file for write */
  46. #define NOTEXE   -8            /* not an executable file */
  47.  
  48. #define DEADXENO -9            /* disabled XENO found */
  49. #define GOTHIM     OK            /* removed virus from file */
  50.  
  51. static UBYTE txt[40];
  52. static long inp, *buff, size;
  53. extern long Open(), Seek(), Read(), Write(), *AllocMem();
  54. long DOSBase, IntuitionBase, OpenLibrary();
  55.  
  56. int    Xeno = FALSE;
  57.  
  58. struct IntuiText Msg3 = { 3, 1, JAM2, 10, 30, 0,(UBYTE*)NULL, NULL  };
  59. struct IntuiText Msg2 = { 2, 1, JAM2, 10, 20, 0,(UBYTE*)NULL, &Msg3 };
  60. struct IntuiText Msg1 = { 2, 1, JAM2, 10, 10, 0,(UBYTE*)NULL, &Msg2 };
  61.  
  62. struct IntuiText OKText  = { 3, 1, JAM2, 6, 3, 0,(UBYTE*)" OK ", NULL };
  63.  
  64.  
  65. main(argc,argv)
  66. char **argv;
  67. {
  68.     static char opts[] = "aAiIbBlL", *strchr();
  69.     char   *posn, *temp;
  70.     int lamer = 0, irq = 0, bgs = 0, cnt = 1;
  71.     int  indx, i, args;
  72.  
  73.  
  74.     if(argc < 2)
  75.         usage(argv[0]);
  76.  
  77.     IntuitionBase = OpenLibrary("intuition.library",0L);
  78.     DOSBase = OpenLibrary("dos.library",0L);
  79.  
  80.     args = argc;
  81.     for(i = 1; i < argc; i++)
  82.     {
  83.         temp = argv[ i ];
  84.         if(*temp == '?')
  85.             usage();
  86.         if(*temp++ == '-')
  87.         {
  88.             args--;
  89.             while(*temp)
  90.             {
  91.                 if((posn = strchr(opts,*temp)) == 0)
  92.                 {
  93.                     printf("Unknown option %c\n",*temp++);
  94.                     continue;
  95.                 }
  96.                 indx = posn - opts;
  97.                 switch(indx)
  98.                 {
  99.                     case 2: case 3:
  100.                                     irq = 1; temp++;
  101.                                     break;
  102.                     case 4: case 5:
  103.                                     bgs = 1; temp++;
  104.                                     break;
  105.                     case 6: case 7:
  106.                                     lamer = 1; temp++;
  107.                                     break;
  108.                     case 0: case 1:
  109.                                     bgs = lamer = 1; temp++;
  110.                                     break;
  111.                 }
  112.             }
  113.         }
  114.         else
  115.         {
  116.             CheckIRQ(argv[i]);
  117.         }
  118.     }
  119.  
  120.  
  121.     if(lamer)
  122.         CheckLamer();
  123.  
  124.     if(bgs)
  125.         Check_BGS9();
  126.     
  127.     exit(cleanup(1));
  128. }
  129.  
  130. CheckIRQ(dev)
  131. char *dev;
  132. {
  133.     int err;
  134.     char *pat = 0, *name = 0, *scdir(), *malloc(), ch;
  135. /*
  136.     scan argument list for filenames.  Use each name as input to the
  137.     wildcard expander.  If a name ends with `:' or `/' then it's a
  138.     device or directory.  As a favor to the user, append the wildcard
  139.     `*' character to the end of that name.
  140. */
  141.     printf("Checking for IRQ and Xeno virus on %s\n",dev);
  142.     if(pat) free(pat);
  143.     pat = malloc(strlen(dev)+1);    /* leave room for `*' if needed */
  144.  
  145.     if(pat == 0)
  146.     {
  147.         puts("Out of memory");
  148.         exit(cleanup(20));
  149.     }
  150.     strcpy(pat,dev);        /* get filename from command line */
  151.  
  152.     ch = pat[ strlen(pat)-1 ];
  153.     if(ch == ':' || ch == '/')
  154.         strcat(pat,"*");
  155.  
  156. /*
  157.     do this until no more names can be squeezed out of this argument
  158. */
  159.     while(1)
  160.     {
  161.         if((name = scdir(pat)) == NULL)
  162.             break;    
  163.         err = IRQ_Kill(name);    /* check for and possibly remove virus */
  164.  
  165.         switch(err)
  166.         {
  167.         case GOTHIM:
  168.                         printf("\2337m");
  169.                         printf("Found and disabled the %s virus in \"%s\"!\n",
  170.                                 (Xeno) ? "XENO" : "IRQ", name);
  171.                         printf("\2330m");
  172.  
  173.                         if(!Xeno)
  174.                         {
  175.                             DisplayBeep(0L);
  176.                             Msg1.IText = (UBYTE *)"Found the IRQ virus in file";
  177.                             Msg3.IText = (UBYTE *)"IRQ virus removed";
  178.                         }
  179.                         else
  180.                         {
  181.                             Msg1.IText = (UBYTE *)"Found the XENO virus in file";
  182.                             Msg3.IText = (UBYTE *)"XENO virus disabled";
  183.                         }
  184.                         Msg2.IText = txt;
  185.                         sprintf(txt,"   %s",name);
  186.  
  187.                         if(!Xeno)
  188.                             putmsg();
  189.                         else
  190.                             Delay(20L);
  191.                         break;
  192.         case NOFILE:       printf("\tcan't find \"%s\"\n",name);
  193.                         break;
  194.         case SEEKERR:      printf("\tseek error on \"%s\"\n",name);
  195.                         break;
  196.         case ALLOCERR:     printf("\tcan't allocate memory\n");
  197.                         break;
  198.         case READERR:    printf("\terror reading \"%s\"\n",name);
  199.                         break;
  200.         case VIRUSNF:      printf("\"%s\" was OK\n",name);
  201.                         break;
  202.         case WRITERR:      printf("\terror writing to \"%s\"\n",name);
  203.                         printf("\tFile \"%s\" is corrupt...replace it\n",name);
  204.                         break;
  205.         case OPENERR:      printf("\terror opening \"%s\" for write\n",name);
  206.                         break;
  207.         case NOTEXE:       printf("\t\"%s\" is not an executable file\n",name);
  208.                         break;
  209.         case DEADXENO:    printf("found disabled XENO virus in \"%s\"\n",name); 
  210.         }
  211.     }
  212. }
  213.  
  214. CheckLamer()   
  215. {
  216.     puts("Checking for Lamer virus");
  217.     Check_Memory_Lamer();
  218.     Check_Disk_Lamer();
  219. }
  220.  
  221. cleanup(val)
  222. int val;
  223. {
  224.     if(inp)
  225.     {
  226.         Close(inp);
  227.         inp = 0;
  228.     }
  229.     if(buff)
  230.     {
  231.         FreeMem(buff,size);
  232.         buff = 0;
  233.     }
  234.     return val;
  235. }
  236.  
  237.  
  238. IRQ_Kill(fname)
  239. char *fname;
  240. {
  241.     int   i = 0;
  242.     long  fhunk, lhunk, nhunk, val, len;
  243.  
  244.     inp = 0L;  buff = 0L;
  245.  
  246.     if((inp = Open(fname,OLD)) == 0)    /* open the desired file */
  247.         return NOFILE;
  248.  
  249.     Read(inp,&val,SLONG);                /* get the first long word */
  250.     if(val != 0x000003F3L)                /* check for executable file */
  251.         return cleanup(NOTEXE);
  252.  
  253.     Seek(inp,0L,END);                /* seek to end of file */
  254.     size = Seek(inp,0L,BEGIN);        /* rewind the file to get size */
  255.     if(size <= 0L)
  256.         return cleanup(SEEKERR);
  257.  
  258.     if((buff = AllocMem(size,0L)) == 0)    /* mem buffer for file */
  259.         return cleanup(ALLOCERR);
  260.  
  261.     if(Read(inp,buff,size) != size)    /* read entire file into buffer */
  262.         return cleanup(READERR);
  263.  
  264.     nhunk = buff[ 2 ];        /* number of hunks in file */
  265.     fhunk = buff[ 3 ];        /* first hunk */
  266.     lhunk = buff[ 4 ];        /* last hunk */
  267.  
  268. /*
  269.     the IRQ virus inserts his code as the first hunk in the file
  270.     we can find the first hunk in the 6th longword of the file
  271. */
  272.     /* find the start of the virus hunk */
  273.     i = 5 + lhunk - fhunk + 1;
  274.  
  275.     Xeno = FALSE;
  276.  
  277.     if(buff[5] != VTAG)
  278.     {
  279.         if(buff[ i + 0x116 ] != 'astf')
  280.             return cleanup(VIRUSNF);
  281.         else
  282.         {
  283.             Xeno = TRUE;
  284.             if(buff[i+2] == 0x60000462)
  285.                 return cleanup(DEADXENO);
  286.         }
  287.     }
  288.  
  289. /*
  290.     The virus checks the first hunk for it's signature to prevent
  291.     reinfecting an already infected program.  It actually checks for
  292.     0xFFFE6100 which is the lower half of a move.m instruction and
  293.     the upper half of a bsr instruction.  Here we do the same.
  294.     i points to the virus code hunk length.
  295. */
  296.     if(!Xeno)
  297.         if( ((buff[ i+2 ] & 0x0000FFFF) != VSIG1) 
  298.          || ((buff[ i+3 ] & 0xFFFF0000) != VSIG2) )
  299.             return cleanup(VIRUSNF);
  300.  
  301. /*
  302.     close the file and reopen it with write access
  303.     mode NEW will effectivly delete the old file contents so if a
  304.     file error occurs before we finish, the file will be corrupt
  305. */
  306.     Close(inp);  inp = 0;
  307.  
  308.     if((inp = Open(fname,NEW)) == 0)
  309.         return cleanup(OPENERR);
  310.  
  311.     if(!Xeno)    /* readjust program header info */
  312.     {
  313.         buff[2] -= 1;
  314.         buff[4] -= 1;
  315. /* write new header */
  316.         if(Write(inp,buff,5L*SLONG) != 5L*SLONG)
  317.             return cleanup(WRITERR);
  318.  
  319.         if(Write(inp,&buff[6],nhunk*SLONG) != nhunk*SLONG)
  320.             return cleanup(WRITERR);
  321.  
  322. /*
  323.     subtract length of virus hunk and overhead from file size
  324.     i was calculated earlier
  325. */
  326.         i = i + 9L + VTAG;
  327.         size = (size/SLONG - i)*SLONG;
  328.  
  329. /* and write old code out to file, ignoring virus hunk */
  330.         if(Write(inp,&buff[i],size) != size)
  331.             return cleanup(WRITERR);
  332.  
  333. /* we're done, the file is clean and intact */
  334.         return cleanup(GOTHIM);
  335.     }
  336.     else        /* Xeno virus */
  337.     {
  338.         buff[i+2] = 0x60000462;
  339.  
  340. /* now fix the code segment length and write it out */
  341.  
  342.         if(Write(inp,buff,size) != size)
  343.             return cleanup(WRITERR);
  344.  
  345. /* we're done, the file is clean and intact */
  346.         return cleanup(GOTHIM);
  347.     }
  348. }
  349.  
  350. usage(name)
  351. char *name;
  352. {
  353.     printf("%s\n\n",VERSION);
  354.     printf("%s will detect and remove one type of `Lamer' and `BGS' virus \n",name);
  355.     printf("from all floppies in the system.  It will also detect and remove\n");
  356.     printf("IRQ virus V41.0 from executable files and detect and disable the\n");
  357.     printf("XENO virus in executable files\n\n");
  358.     printf("Usage: %s -LIBA { filename ... }\n\n",name);
  359.     printf("\t-L or -l       check for Lamer virus on all floppies\n");
  360.     printf("\t-B or -b       check for BGS-9 virus on all floppies\n");
  361.     printf("\t-I or -i NAME  check for IRQ and Xeno virus on NAME\n");
  362.     printf("\t-A or -a       do all of the above\n\n");
  363.     printf("\t`*' (unix style) wildcards allowed\n");
  364.     printf("\tex. %s -i C:*  or  %s -i C:  will check all files in C:\n",
  365.         name,name);
  366.     printf("\t\tfor the IRQ and Xeno virus\n");
  367.     printf("\t    %s DF0:C/ will check all files in DF0:C\n",name);
  368.     exit(cleanup(20));
  369. }
  370.  
  371. #define LAMER_ID    "clist 33.80"
  372.  
  373. Check_Memory_Lamer()
  374. {
  375.     struct ExecBase **ExecPtr = 4;
  376.     APTR *KTagPtr = (APTR *)(*ExecPtr)->KickTagPtr;
  377.     APTR Lamer, TestKTag();
  378.  
  379.     while(*KTagPtr)
  380.     {
  381. /*
  382.     If hi bit is set, then this is a pointer to a KickTag array.  Reset
  383.     the bit and use the resulting address to get the address of the
  384.     next KickTag array.
  385. */
  386.         while((ULONG)*KTagPtr & 0x80000000)
  387.             KTagPtr = (APTR *)((ULONG)*KTagPtr & 0x7FFFFFFF);
  388.  
  389. /*
  390.     if the Lamer is found, invalidate the KickTag element here by
  391.     changing the KickTag element to a pointer to a KickTag array which
  392.     points to the next element.  A cheap shot, but effective
  393. */
  394.         if(Lamer = TestKTag( *KTagPtr ))
  395.         {
  396.             if(KillLamer(Lamer))
  397.             {
  398.                 *KTagPtr = (APTR)((ULONG)(KTagPtr+1) | 0x80000000);
  399.  
  400.                 SumKickData();        /* do the real SumKickData */
  401.  
  402.                 Msg1.IText = txt;
  403.                 sprintf(txt,"Lamer virus found at %08lx",Lamer);
  404.                 putmsg();
  405.                 return;
  406.             }
  407.         }
  408.         KTagPtr++;
  409.     }
  410. }
  411.  
  412. /*
  413.     This is supposed to compute the correct Kick memory checksum to
  414.     allow the users RAD: disk to recover on the next reboot.
  415.     The SumKickData vector was recovered from the virus and reinstalled
  416.     in the execbase structure by KillLamer()
  417. */
  418.  
  419. SumKickData()
  420. {
  421. #asm
  422.     move.l    4,a6
  423.     jsr    -$264(a6)            ;calculate checksum
  424.     move.l    d0,$22A(a6)        ;store it
  425. #endasm
  426. }
  427.  
  428. KillLamer(addr)
  429. APTR addr;
  430. {
  431. #define    RTS    0x70014E75    /* moveq.l  #1,d0   rts */
  432.     struct ExecBase **ExecPtr = 4;
  433.  
  434. /*
  435.     I think that the Lamer is in memory.  I'm going to test several
  436.     locations within the virus body to be sure that it is the exact
  437.     virus I'm familiar with.  The test array has memory offsets from
  438.     addr and the contents I expect to see there.
  439. */
  440. static    APTR test[] = {
  441.         0x0A6, 0x2F3A0EEC,        /* SumKick routine */
  442.         0x166, 0x2F3A0E3C,        /* DoIO routine */
  443.         0x246, 0x2F3A0D64,        /* TDRead routine */
  444.         0x2B8, 0x287A0D0C,        /* Trigger point */
  445.         0x5AE, 0x2C780004        /* Disk Trasher */
  446. };
  447.  
  448. /*
  449.     I'm going to pull the vipers fangs by placing RTS instructions in
  450.     key areas.  One area is his Resident Initialization vector - that'll
  451.     stop him from living through a re-boot (provided he's not on the
  452.     boot disk that is)
  453. */
  454. static    APTR rts[] = {
  455.         0,                /* Keep from initializing on reset */
  456.         0x2B8,            /* disable one trigger point */
  457.         0x5AE,            /* stop the disk trasher */
  458.         0x6D8,            /* stop the alerts */
  459.         0x73C            /* his ReBoot exit */
  460. };
  461.  
  462.     int i;
  463.     APTR ptr;
  464.     UBYTE *vec, *mem;
  465.     ULONG *vect, FindName();
  466.  
  467.     for(i = 0; i < sizeof(test)/sizeof(ULONG); i+= 2)
  468.     {
  469.         ptr = addr+test[ i ];
  470.         if( *ptr != test[ i+1 ] )
  471.         {
  472.             if(*ptr != RTS)
  473.             {
  474.                 Msg2.IText = (UBYTE *)"I don't know this one";
  475.                 Msg3.IText = (UBYTE *)"virus NOT removed!";
  476.                 return 0;
  477.             }
  478.             else
  479.             {
  480.                 Msg3.IText = (UBYTE *)"It's OK! It's been deactivated";
  481.                 return 0;
  482.             }
  483.         }
  484.     }
  485.     for(i = 0; i < sizeof(rts)/sizeof(ULONG); i++)
  486.     {
  487.         ptr = addr+rts[ i ];
  488.         *ptr = RTS;
  489.     }
  490.  
  491. /*
  492.     Get the SumKickData vector from the virus and reinstall it in the
  493.     ExecBase jump table.
  494. */
  495.     vec = (UBYTE *)(*ExecPtr);
  496.     vect = (ULONG *)(vec - 0x264+2);    /* ExecBase offset */
  497.     ptr = addr+0x3E5;                    /* Offset from Lamer Init vector */
  498.     *vect = (ULONG)*ptr;                /* restore vector */
  499.  
  500. /*
  501.     Get the Trackdisk read vector from the virus and reinstall it
  502. */
  503.     vect = (ULONG *)(FindName(&(*ExecPtr)->DeviceList,TD_NAME)-0x1c);
  504.     ptr = addr + (0xFAC/4);
  505.     *vect = (ULONG)*ptr;
  506.  
  507.     Msg3.IText = (UBYTE *)"Virus removed!";
  508.     return 1;
  509. }
  510.  
  511. /*
  512.     Test the Resident structure ID string to see if it matches the one
  513.     the Lamer uses.  Return the structures Init vector if true, NULL if
  514.     not
  515. */
  516. APTR TestKTag( res )
  517. struct Resident *res;
  518. {
  519.     if(strncmp(LAMER_ID,res->rt_IdString,strlen(LAMER_ID)) == 0)
  520.         return res->rt_Init;
  521.     return (APTR)NULL;
  522. }
  523.  
  524. struct Port *diskport = 0, *CreatePort();
  525. struct IOExtTD *diskreq = 0, *CreateExtIO();
  526.  
  527. #define SEC_SIZE        512L
  528. #define ROOT            880L
  529. #define HASHCHAIN        124
  530. #define WRITE_PROTECTED -1
  531. #define NO_DISK            -2
  532.  
  533. UBYTE *diskdata = 0;
  534. UBYTE invisible[] = "DF0:\240\240\240\240\240";
  535. UBYTE newfile[] = "DF0:DANGERVIRUS";
  536.  
  537. WriteBlock(block)
  538. long block;
  539. {
  540.     LONG offset;
  541.  
  542.     MotorOn();
  543.  
  544.     offset = block * SEC_SIZE;
  545.  
  546.     diskreq->iotd_Req.io_Length  = SEC_SIZE;
  547.     diskreq->iotd_Req.io_Data    = (APTR)diskdata;
  548.     diskreq->iotd_Req.io_Command = CMD_WRITE;
  549.     diskreq->iotd_Req.io_Offset  = offset;
  550.  
  551.     DoIO(diskreq);
  552.  
  553.     if(diskreq->iotd_Req.io_Error != 0)
  554.         printf("I/O error %d\n",diskreq->iotd_Req.io_Error);
  555.  
  556.     diskreq->iotd_Req.io_Command = ETD_UPDATE;
  557.     DoIO(diskreq);
  558.  
  559.     MotorOff();
  560. }
  561.  
  562. ReadBlock(block)
  563. long block;
  564. {
  565.     LONG offset;
  566.  
  567.     MotorOn();
  568.  
  569.     offset = block * SEC_SIZE;
  570.  
  571.     diskreq->iotd_Req.io_Length  = SEC_SIZE;
  572.     diskreq->iotd_Req.io_Data    = (APTR)diskdata;
  573.     diskreq->iotd_Req.io_Command = CMD_READ;
  574.     diskreq->iotd_Req.io_Offset  = offset;
  575.  
  576.     DoIO(diskreq);
  577.  
  578.     if(diskreq->iotd_Req.io_Error != 0)
  579.         printf("I/O error %d\n",diskreq->iotd_Req.io_Error);
  580.  
  581.     MotorOff();
  582. }
  583.   
  584. MotorOn()
  585. {
  586.     diskreq->iotd_Req.io_Length  = 1;
  587.     diskreq->iotd_Req.io_Command = TD_MOTOR;
  588.     DoIO(diskreq);
  589. }
  590.  
  591. MotorOff()
  592. {
  593.     diskreq->iotd_Req.io_Length  = 0;
  594.     diskreq->iotd_Req.io_Command = TD_MOTOR;
  595.     DoIO(diskreq);
  596. }
  597.   
  598. CheckDOS()
  599. {
  600.     ReadBlock(0L);
  601.     if(diskdata[0] == 'D' && diskdata[1] == 'O' && diskdata[2] == 'S')
  602.         return 1;
  603.     return 0;
  604. }
  605.  
  606. DiskStatus()
  607. {
  608.     diskreq->iotd_Req.io_Flags   = 0;
  609.     diskreq->iotd_Req.io_Command = TD_PROTSTATUS;
  610.  
  611.     DoIO(diskreq);
  612.  
  613.     if(diskreq->iotd_Req.io_Error == TDERR_DiskChanged)
  614.         return NO_DISK;
  615.  
  616.     if(diskreq->iotd_Req.io_Actual)
  617.         return WRITE_PROTECTED;
  618.  
  619.     return OK;
  620. }
  621.  
  622. Check_Disk_Lamer()
  623. {
  624.     int i;
  625.  
  626.     for(i = 0; i < 4; i++)
  627.     {
  628.         if(OpenDiskResource(i) == 0)
  629.             return;
  630.  
  631.         CheckDisk(i);
  632.  
  633.         CloseDiskResource();
  634.     }
  635. }
  636.  
  637. OpenDiskResource(num)
  638. int num;
  639. {
  640.     struct ExecBase **ExecPtr = 4;
  641.     ULONG td, FindName();
  642.  
  643.     td = FindName(&(*ExecPtr)->DeviceList,TD_NAME);
  644.     diskdata = (UBYTE *)AllocMem(SEC_SIZE,(LONG)(MEMF_CHIP | MEMF_CLEAR));
  645.  
  646.     diskport = CreatePort(0L,0L);
  647.     if(diskport == NULL || diskdata == NULL)
  648.         exit(cleanup(20));
  649.  
  650.     diskreq = CreateExtIO(diskport,(long)sizeof(struct IOExtTD));
  651.     if(diskreq == NULL)
  652.     {
  653.         DeletePort(diskport);
  654.         exit(cleanup(20));
  655.     }
  656.  
  657.     if(OpenDevice(TD_NAME,(LONG)num,diskreq,0L))
  658.         return 0;
  659.  
  660.     return 1;
  661. }
  662.  
  663. CloseDiskResource()
  664. {
  665.     if(diskreq)
  666.     {
  667.         CloseDevice(diskreq);
  668.         DeleteExtIO(diskreq,(long)sizeof(struct IOExtTD));
  669.         DeletePort(diskport);
  670.     }
  671.  
  672.     if(diskdata)
  673.         FreeMem(diskdata,SEC_SIZE);
  674.  
  675.     diskreq  = 0;
  676.     diskdata = 0;
  677. }
  678.  
  679. CheckDisk(num)
  680. int num;
  681. {
  682.     int i;
  683.     long *buff, Virus = 0, block, link = 0, before = 0, after = 0;
  684.     unsigned long lock, Lock(), CheckSum();
  685.     char drive[5];
  686.  
  687.     if(DiskStatus() == NO_DISK || CheckDOS() == 0)
  688.         return;
  689.  
  690.     invisible[2] = newfile[2] = 0x30 + num;
  691.  
  692.     if((lock = Lock(invisible,ACCESS_READ)) == DOSFALSE)
  693.         return;
  694.     UnLock(lock);
  695.  
  696.     strncpy(drive,invisible,4); drive[4] = 0;
  697.  
  698.     if(DiskStatus() == WRITE_PROTECTED)
  699.     {
  700. #ifdef CLI
  701.         printf("CAUTION! Lamer Virus found on drive %4s\n",drive);
  702.         printf("Disk is write protected.  Make disk writable\n");
  703. #else
  704.         Msg1.IText = txt;
  705.         sprintf(txt,"Lamer Virus found on %4s",drive);
  706.         Msg2.IText = (UBYTE *)"Disk is write protected";
  707.         Msg3.IText = (UBYTE *)"Make disk writable";
  708.         putmsg();
  709. #endif
  710.         return;
  711.     }
  712.  
  713.     if((lock = Lock(newfile,ACCESS_READ)) != DOSFALSE)
  714.     {
  715.         UnLock(lock);
  716.         DeleteFile(newfile);
  717.     }
  718.  
  719.     if(Rename(invisible,newfile) == DOSFALSE)
  720.     {
  721.         printf("WARNING - attempt to rename virus has failed\n");
  722.         printf("The virus hides in an invisible file on drive %4s\n",drive);
  723.     }
  724.     else
  725.     {
  726.         printf("NOTICE! - Lamer virus found on drive %4s\n",drive);
  727.         printf("The virus has been renamed to %4sDANGERVIRUS.\n",drive);
  728.         printf("Please delete this file and edit your Startup-Sequence file\n");
  729.         printf("to remove the invisible filename found on the first line\n");
  730.     }
  731. /* virus is present */
  732.     ReadBlock(ROOT);
  733.  
  734.     buff = (long *)diskdata;
  735.  
  736.     Virus = buff[ 15 ];
  737.  
  738.     for(i = 14; i > 6; i--)
  739.         if(before = buff[ i ])
  740.             break;
  741.  
  742.     if(before == 0)
  743.         return;
  744.  
  745.     for(i = 16; i < 81; i++)
  746.         if(after = buff[ i ])
  747.             break;
  748.  
  749.     if(after == 0)
  750.         return;
  751.  
  752.     block = before;
  753.     do {
  754.         ReadBlock(block);
  755.  
  756.         link = buff[ HASHCHAIN ];
  757.  
  758.         if(link == after)
  759.         {
  760.             buff[ HASHCHAIN ] = buff[ 5 ] = 0;
  761.             buff[ 5 ] = CheckSum(buff);
  762.             WriteBlock(block);
  763.             break;
  764.         }
  765.     } while(block = link);
  766. }
  767.  
  768. unsigned long CheckSum(block)
  769. unsigned long block[];
  770. {
  771.     int cnt;
  772.     unsigned long sum = 0;
  773.     for(cnt = 0; cnt < 128; cnt++)
  774.         sum += block[ cnt ];
  775.     return (~sum + 1);
  776. }
  777.  
  778. putmsg()
  779. {
  780.     AutoRequest(NULL,&Msg1,NULL,&OKText,NULL,NULL,300L,80L);
  781. }
  782.  
  783. UBYTE BGS_name[] = "DF0:devs/\240\240\240   \240   \240";
  784. UBYTE newname[] = "DF0:devs/OLD_PROGRAM.BGS9";
  785.  
  786.  
  787. Check_BGS9(num)
  788. {
  789.     int i;
  790.  
  791.     puts("Checking for BGS virus");
  792.  
  793.     for(i = 0; i < 4; i++)
  794.     {
  795.         if(OpenDiskResource(i) == 0)
  796.             return;
  797.  
  798.         CheckDiskBGS(i);
  799.  
  800.         CloseDiskResource();
  801.     }
  802. }
  803.  
  804. CheckDiskBGS(num)
  805. int num;
  806. {
  807.     ULONG    file;
  808.     UBYTE    drive[5];
  809.     int i;
  810.  
  811.     if(DiskStatus() == NO_DISK || CheckDOS() == 0)
  812.         return;
  813.  
  814.     BGS_name[2] = num + '0';
  815.     if((file = Lock(BGS_name,ACCESS_READ)) != DOSFALSE)    
  816.     {
  817.         UnLock(file);
  818.         strncpy(drive,BGS_name,4); drive[4] = 0;
  819.         sprintf(txt,"BGS virus found on %s",drive);
  820.         Msg1.IText = txt;
  821.  
  822.         if(DiskStatus() == WRITE_PROTECTED)
  823.         {
  824.             Msg2.IText = (UBYTE *)"Disk is write protected";
  825.             Msg3.IText = (UBYTE *)"Make disk writable";
  826.             putmsg();
  827.             CloseDiskResource();
  828.             return;
  829.         }
  830.         newname[2] = num + '0';
  831.         if(Rename(BGS_name,newname) == DOSFALSE)
  832.         {
  833.             Msg3.IText = (UBYTE *)"Rename failed";
  834.         }
  835.         putmsg();
  836.  
  837.         printf("You must now examine %sS/Startup-Sequence",drive);
  838.         puts(" and note the name of the first");
  839.         puts("executable file.  That file contains the BGS virus\n");
  840.         puts("DELETE that file and replace it with a know good copy");
  841.         puts("You might also want to remove or rename the file located in");
  842.         printf("%s/devs.  It contains the original program replaced",drive);
  843.         puts(" by the BGS virus");
  844.     }
  845. }
  846.