/************************************************************************/
/*                                                                      */
/*                                                                      */
/*                                VirusX                                */
/*                                                                      */
/*                           by Steve Tibbett                           */
/*                                                                      */
/*                                                                      */
/*              Please - if you find a new virus, Send me a copy!       */
/*              (And warn me it's on the disk!).  I want to keep        */
/*              this program current.  (Feel free to put something      */
/*              neat on the disk also!)                                 */
/*                                                                      */
/*  This version of VirusX is done with the Lattice 5.0                 */
/*  compiler.  The Lattice compiler, with the help of John Toebes,      */
/*  gave me an executable almost 4K smaller than the best I could       */
/*  get out of Manx.  Reason enough for me to switch!                   */
/*                                                                      */
/*  The Makefile included in the "source.zoo" file you should have      */
/*  gotten in the VirusX.Zoo file this came from, is set up for the     */
/*  MANX Make Utility.  Switching to Lattice's LMK should be easy,      */
/*  but I've had no reason to.  The important thing is the command      */
/*  line switches and the BLINK command line.                           */
/*                                                                      */
/*  Thanks to John Toebes for a lot of help getting it going, and       */
/*  thanks to Dan James for providing the routine down at the bottom    */
/*  that actually takes the IRQ Virus out of executable files.          */
/*                                                                      */
/************************************************************************/
/*                                                                      */
/*  History:                                                            */
/*  --------                                                            */
/*      April '88 or so:  V1.0 written and released.                    */
/*     A few days later:  V1.01 released.  V1.0 wrote garbage to the    */
/*                        disk if it was write protected then fixed.    */
/*          27-March-88:  V1.2 released.  V1.2's purpose in life was    */
/*                        to deal with the Byte Bandit virus.           */
/*                        (Actually, it's well after midnight - make    */
/*                        that March 28th. :)                           */
/*          28-March-88:  Oops, V1.2 was 3K or so bigger than it needed */
/*                        to be.  Fix it, release v1.21.                */
/*           15-June-88:  V1.3, V1.2 cleaned up and made smaller.       */
/*            8-July-88:  V1.4.  Revenge virus checking, Viewbooting,   */
/*                        check for SCA in RAM, more cleaning up.       */
/*           24-July-88:  V1.5, only change was the addition of the     */
/*                        Byte Warrior virus.                           */
/*             1-Aug-88:  V1.6 (busy week), Dan Mosedale sent me the    */
/*                        Northstar Virus.  Nuked it.                   */
/*            18-Aug-88:  V1.7 - after 2 weeks off, got the Obelisk     */
/*                        Softworks crew virus.                         */
/*     a few days later:  V1.71, can't remember why.                    */
/*   September Sometime:  Biggest mistake of my life, released V2.0.    */
/*         3 days later:  Bigger mistake:  Released V2.01 - which was   */
/*                        2.0 with another bug added.  Argh.            */
/*             6-Nov-88:  Finally got some time to clean things up,     */
/*                        check out the startup code bugs, clean up the */
/*                        docs and source, and release V2.1.  There     */
/*                        haven't been any new viruses in about a month */
/*                        now, but I hear one or two are on the way.    */
/*            31-Dec-88:  Got the IRQ virus yesterday.  Neat one!       */
/*                        Releasing V3.0 tonite or tomorrow to handle   */
/*                        it.  See description below.                   */
/*            04-Jan-89:  Got 2 new viruses, released 3.1.              */
/*            18-Feb-89:  And boy, am I tired.  8 (count 'em) 8 new     */
/*                        viruses in this version.  Ack!  DOUBLE        */
/*                        the last version.  New option: CHECK, good    */
/*                        for including VirusX with a commercial        */
/*                        program.  V3.20                               */
/*                                                                      */
/************************************************************************/
/*                                                                      */
/*  Viruses Dealt With:                                                 */
/*  -------------------                                                 */
/*                                                                      */
/*      SCA             - The SCA is the simplest virus to deal with,   */
/*                        as it's not actually DOING anything except    */
/*                        hiding in memory, until you reboot.           */
/*                        We just look at CoolCapture and fix it to get */
/*                        it out of RAM.                                */
/*                                                                      */
/*      Byte Bandit     - The Byte Bandit virus takes the DoIO() vector */
/*                        and redirects it through itself.  Thus, any   */
/*                        attempt to read or write the boot block (ie,  */
/*                        AmigaDOS trying to figure out what kind of    */
/*                        disk it is) results in the BB writing itself  */
/*                        onto that disk.  VirusX couldn't just rewrite */
/*                        the boot block, we have to get him out of RAM */
/*                        first.  This virus also has an interrupt that */
/*                        crashes the machine every 5 minutes or so     */
/*                        after it's infected a few of your disks.  Ow. */
/*                        It stays in memory not via the Capture        */
/*                        vectors, but by a Resident module.            */
/*                                                                      */
/*      Revenge         - Basically, a Byte Bandit clone except it will */
/*                        bring up an obscene pointer a few minutes     */
/*                        after you reboot.  We treat it much like the  */
/*                        byte bandit.                                  */
/*                                                                      */
/*      Byte Warrior    - Jumps right into 1.2 Kickstart.  Won't work   */
/*                        under 1.3.  Hangs around via Resident struct, */
/*                        doesn't do any damage.                        */
/*                                                                      */
/*      North Star      - Like SCA, hangs around via CoolCapture,       */
/*                        killing CoolCapture kills the North Star.     */
/*                                                                      */
/*      Obelisk Softworks Crew                                          */
/*                      - Hangs around via CoolCapture, also            */
/*                        watches reads of DoIO() (but doesn't          */
/*                        infect EVERY disk - onlyt ones you boot       */
/*                        off of)                                       */
/*                                                                      */
/*       IRQ            - This is the FIRST Non-Bootblock Virus.        */
/*                        It copies itself from place to place via the  */
/*                        first executable program found in your        */
/*                        startup-sequence.  It SetFunction's           */
/*                        OldOpenLibrary(), has a KickTagPtr,           */
/*                        and lives in the first hunk of an             */
/*                        infected program.                             */
/*                        THANKS! to Gary Duncan and Henrik Clausen for */
/*                        being the first to send this one to me!       */
/*                                                                      */
/*  Pentagon Circle     - This one looks at the DoIO vector, and has    */
/*                        a CoolCapture vector.  It will write itself   */
/*                        over any virus inserted, but not onto         */
/*                        anything else.  (Neat idea!).  No danger,     */
/*                        easy to eliminate.  Holding left button       */
/*                        while booting with this one shows different   */
/*                        screen colour, but doesn't get rid of it.     */
/*                        Thanks to Bill at CMI (CMI*BILL on Plink)     */
/*                        for sending me this one!                      */
/*                                                                      */
/*  SystemZ Virus Protector                                             */
/*                      - I took this one out.  It's not really a       */
/*                        'Virus' in that it won't overwrite a disk     */
/*                        without asking you first.  Besides, it seems  */
/*                        a lot of people LIKE the SystemZ Virus        */
/*                        Protector (though it isn't perfect).          */
/*                                                                      */
/*   Lamer Exterminator - THIS one was a bugger.  Yet another virus     */
/*                        aimed at hurting people.  Y'see, a Lamer      */
/*                        is apparently the worst kind of pirate -      */
/*                        one who doesn't crack software, doesn't       */
/*                        write software, just collects names and       */
/*                        addresses and collects and spreads software.  */
/*                        Lamers don't do anybody any good - and the    */
/*                        guy behind this Virus took it upon himself    */
/*                        to make their (and our) lives miserabler.     */
/*                        Anyway, this virus loads into RAM into a      */
/*                        different location every time (using a        */
/*                        random location).  It is encrypted on the     */
/*                        disk so you can't SEE the name of it, and     */
/*                        it never actually SHOWS the name (but it's    */
/*                        definately there).  It changes the            */
/*                        encryption key used each time it is written   */
/*                        back to disk.  It has a counter and will      */
/*                        wait until the machine has been reset 2 times */
/*                        OR until 3 disks have been infected, and will */
/*                        then pick a DATA block (Only a DATA block -   */
/*                        FFS disks are safe, I guess), randomly, and   */
/*                        will write the word 'LAMER!' all through it.  */
/*                        This is obviously not good, and will cause    */
/*                        random disk errors.  This is the worst kind   */
/*                        of havoc to wreak on the new user - and this  */
/*                        virus is EVERYWHERE!  I've gotten it from 5   */
/*                        people in the last week alone (all from       */
/*                        different countries!  Ack!).  Anyways, credit */
/*                        for being the first with this one is          */
/*                        Christian Schneider.  Thanks, Christian!      */
/*  Might as well break the margin convention here, eh?  Anyways,       */
/*  something else I thought of about this virus:  It introduces a NEW  */
/*  way for a Virus to stay in RAM.  Y'see, if ExecBase is okay at      */
/*  reboot time (Exec keeps a checksum, among other things, and checks  */
/*  to see if anything has been corrupted quite carefully).  Anyways,   */
/*  if Exec thinks ExecBase is okay, it doesn't bother rebuilding it.   */
/*  Sooo, this virus sets the SumKickData() vector to point at itself.  */
/*  Then at Reboot when this vector gets called after reset, the virus  */
/*  ReInstalls himself.  At least this is what I think is happening.    */
/*  This virus sets up a Resident structure, but never sets the Match   */
/*  Word - either this means we don't need the MatchWord or it means    */
/*  his SumKickData() is doing the recovery job - either way, it's      */
/*  new!  3 points for originality.                                     */
/*                                                                      */
/*  Graffiti - The first virus to come with rotating 3-d graphics!      */
/*             It's neat - you might want to trigger it (I'm not sure   */
/*             how) before nuking it.  Anyway, this one just sets       */
/*             CoolCapture(), does something with DoIO() during the     */
/*             reboot but sets it back to normal before anybody gets    */
/*             to look at it.  Lots of code is taken by the graphics    */
/*             stuff.  I just clear the CoolCapture vector.  [yawn]     */
/*                                                                      */
/*  Old Northstar - Poof.						*/
/*                                                                      */
/*  16 Bit Crew - Well, I didn't actually have to DO anything to get    */
/*		 VirusX to recognize it... because it seems to operate  */
/*               like the Graffiti Virus.  If the 16 bit crew is in     */
/*               RAM, VirusX will say it removed the Graffiti virus.    */
/*               Oh well.  8-)                                          */
/*                                                                      */
/*  DiskDoktor - I spent more time on this one than on any other.       */
/*               Y'see, this virus does lots of things.  The first one  */
/*               for some reason was quite funny to me.  heh            */
/*               What it would do is after you have rebooted 5 times,   */
/*               each time you reboot after that, the virus would eat   */
/*               10K times the total number of reboots - so after       */
/*               rebooting 10 times, you would be short about 100K.     */
/*               This virus also starts up another TASK.  I'm not       */
/*               exactly sure when it happens, but another task named   */
/*               'clipboard.device' will appear at a priority of -120,  */
/*               and will continually bash the Virus' vectors into the  */
/*               Coldcapture, Coolcapture, Warmcapture (which it sets   */
/*               to $ff000000 just to annoy), and the DoIO() vector.    */
/*               When I was working on this one, I figured I just had   */
/*               to restore the old values to the DoIO() vector, but as */
/*               soon as I did so, the Virus restored them - and since  */
/*               I didn't disassemble the entire thing, I didn't realize*/
/*               this until I wasted time looking for other faults.     */
/*               This one also allocates some memory, copies some code  */
/*               out of Exec into this memory, and executes it.  I      */
/*               never bothered to figure out why - Once it's gone, it's*/
/*               gone.                                                  */
/*                                                                      */
/*  Thanks also to Robb Walton for being the first to send one of the   */
/*  other ones, (but I can't remember which one anymore... 8-(  )       */
/************************************************************************/
/*                                                                      */
/*  Notes on making VirusX yourself:  The source is included mainly     */
/*  for your perusal, not so that you can modify it and redistribute    */
/*  it.  I've modified Manx's _main.c module to make the detach         */
/*  from the initial CLI work properly.  I can't redistribute this      */
/*  module since it's copyright manx, so here's VirusX without it.      */
/*  It will compile and run, but if you run it from WB, it won't quit.  */
/*  The version I've supplied should do everything just fine.           */
/*                                                                      */
/************************************************************************/


#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <exec/types.h>
#include <intuition/intuition.h>
#include <devices/bootblock.h>
#include <devices/trackdisk.h>		/*   /		       */
#include <exec/execbase.h>		/*  <-- include files  */
#include <exec/memory.h>		/*   \		       */
#include <libraries/dos.h>		
#include <libraries/dosextens.h>
#include <pragmas/all.h>
#include <proto/all.h>
#include <String.h>
#include "virusx.i" /* Virusx.i is an ANSI thing.  It's got Protoypes. */
		    /* (or used to anyway) 			       */

/* Latticeisms */

/* What's that you say?  C is hard to read? */

void MemCleanup() {}
void RawDoFmt(char *, long *, void (*)(), char*);
#pragma syscall RawDoFmt 20a ba9804
void __regargs prbuf(char c);
int __regargs sprintf(char *buf, char *ctl, char *args) { RawDoFmt(ctl, (long *)&args, prbuf, buf); return(strlen(buf)); }
void __regargs prbuf(char c) {__builtin_emit(0x16c0);}

/******************************************************************/
/* In case you're interested, that little mess above is a routine */
/* supplied by John Toebes which changes sprintf() from using the */
/* compiler's library into something that uses the ROM code found */
/* in Kickstart.  Sooo, it made VirusX about 1.2K or so smaller!! */
/* Feel free to steal this and use it wherever.  However, the new */
/* sprintf function can't handle a lot of things - check the Exec */
/* manual (I believe) for details.  Neat formatting here, eh? 8-) */
/******************************************************************/

char WhatHappened;	/* huh?? */

/******************************************************************/
/* These string constants are used in multiple places, and thus   */
/* save bytes by having only one copy of them.                    */
/******************************************************************/
char TITLETEXT[]        = "VirusX 3.20 by Steve Tibbett";
char TDName[]           = "trackdisk.device";
char copystring[]       = "(Copy Count on this disk: %ld)";
char ITBodyText[80];
char CaptureStr[]       = "Capture is pointing at $";
char text[]             = "DF6: Boot Sectors";
char VN_OBELISK[]       = "Obelisk";
char VN_NORTHSTAR[]     = "North Star";
char VN_SCA[]           = "SCA";
char VN_BYTEBANDIT[]    = "Byte Bandit";
char VN_BYTEWARRIOR[]   = "Byte Warrior";
char VN_REVENGE[]       = "Revenge";
char VN_IRQ[]           = "IRQ";
char VN_PENTAGON[]      = "Pentagon Circle";
char VN_LAMER[]		= "Lamer Exterminator";
char VN_HCS[]		= "H.C.S.";
char VN_UFOX[]		= "UltraFox";
char VN_DDOC[]		= "DiskDoc";
char VN_GRAFFITI[]	= "Graffiti";
char VN_Bit16[]		= "16 Bit Crew";
char VN_PHANTASM[]	= "Phantasmumble";	/* Can't remember the whole name */
char VN_OLDNSTAR[]	= "Old Northstar";


/********************************************************************/
/* These counters are for the Info window, one for each virus.      */
/********************************************************************/
int     ObeliskCount;
int     NorthStarCount;
int     SCACount;
int     ByteBanditCount;
int     ByteWarriorCount;
int     RevengeCount;
int     IRQFound;
int	PentagonCount;
int 	LamerXCount;
int	HCSCount;
int	UFoxCount;
int	DDocCount;
int	GRAFFITICount;
int	Bit16Count;
int	PhantasmCount;
int 	OldNStarCount;


/*******************************************************************/
/*  Miscellaneous variables.                                       */
/*******************************************************************/
long    ChangeCount[4];                 /* TD_CHANGECOUNT for 4 drives  */
long    LastSum;                        /* Used in the checksumming     */
long    error;                          /* sort of a temporary variable */
char    WindowBig;                      /* TRUE if the window is big    */
struct  Port *diskport;                 /* trackdisk's port.            */
struct  IOStdReq *diskreq;              /* trackdisk's IOStdReq         */
long    DisksChecked, DisksInstalled;   /* for title bar info           */
long    VirusBase;                      /* ick, whatta name!            */

struct IntuitionBase    *IntuitionBase; /* For Library Bindings         */
struct GfxBase          *GfxBase;
struct Window           *Window;
struct IntuiMessage     *Message;
struct ExecBase         *ExecBase;

struct IOStdReq         *TimerReq;
struct MsgPort          *TimerPort;

static long fp;

char Keepgoing;         /* A flag.  It's false when we want out.        */
long x, y, i;           /* Left over from my using Basic                */
char flag;              /* Another flag.  Lets start our own country.   */
LONG thing1, thing2;

struct NewWindow NewWindow =
        {
        128,0,  309,10,  0,1,
        DISKINSERTED | CLOSEWINDOW |VANILLAKEY | NEWSIZE | MOUSEBUTTONS,       /* IDCMP Flagz */
        WINDOWDRAG | WINDOWDEPTH | RMBTRAP | WINDOWCLOSE | NOCAREREFRESH, /* Windo Flagz */
        NULL, NULL,TITLETEXT,
        NULL,NULL,0,0,0,0,WBENCHSCREEN,
        };

struct RastPort *RP;

#define BSIZE 40        /* Ha!  I'm not telling what this is! */


/*******************************************************************/
/*  diskbuffer is where all disk io goes to.  it's 3*512 rather    */
/*  than 2*512, because I believe one of the viruses watches for   */
/*  reads of 1024 bytes, so I'm just being safe.                   */
/*******************************************************************/
UBYTE *diskbuffer;


/************************************************************************/
/* Warning messages.  These messages get modified before being          */
/* displayed (Unless you DO have a DF9:)                                */
/************************************************************************/
char TEXTPTR[] = "Danger:  The disk in DF9: is";
char NBCTEXT[] = "Danger:  The disk in DF9: has";  /* What a waste, eh? */
char CopyText[40];

/*************************************************************************/
/*   This is a byte by byte copy of working boot block code.  Check it   */
/*   out if you like.  This is what gets written back to the disk when   */
/*   you ask VirusX to fix a disk.                                       */
/*************************************************************************/
unsigned char bootblock[] = { 'D', 'O', 'S', 0,
0xc0, 0x20, 0x0f, 0x19, 0x00, 0x00, 0x03, 0x70, 0x43, 0xfa, 0x00, 0x18,
0x4e, 0xae, 0xff, 0xa0, 0x4a, 0x80, 0x67, 0x0a, 0x20, 0x40, 0x20, 0x68,
0x00, 0x16, 0x70, 0x00, 0x4e, 0x75, 0x70, 0xff, 0x60, 0xfa, 0x64, 0x6f,
0x73, 0x2e, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x00, 0x00, 0x00,
0x00, 0x00};


/********************************************************************/
/*  My intuition defines.  There's lots of 'em - theyre self explan.*/
/********************************************************************/

struct TextAttr TxtAt_Plain =
        {
        "topaz.font", 8, FS_NORMAL, FPF_ROMFONT
        };

/***  Non SCA warning requester IntuiText's ***/

struct IntuiText Body2 =
        {
        0, 1,  JAM2, 20,18, &TxtAt_Plain, "Nonstandard Boot Code!", NULL
        };

struct IntuiText Body1 =
        {
        0,1, JAM2, 20, 8, &TxtAt_Plain, (UBYTE *)NBCTEXT, &Body2
        };

/*-  This one says "The disk in DFx: is"  -*/

struct IntuiText GenericFirstBody =
        {
        0,1, JAM2, 20,8,&TxtAt_Plain, (UBYTE *)TEXTPTR, 0
        };


/***** Generic IntuiTexts used as of V1.7 ******/
struct IntuiText GenericDiskBody =
        {
        0,1, JAM2, 20,18, &TxtAt_Plain,ITBodyText, &GenericFirstBody
        };

struct IntuiText SCAPos =
        {
        0,1, JAM2, 7,3, &TxtAt_Plain, "Remove it", NULL
        };

struct IntuiText Repair =
        {
        0,1, JAM2, 7,3, &TxtAt_Plain, "Repair it", NULL
        };

struct IntuiText SCANeg =
        {
        0,1, JAM2, 7,3, &TxtAt_Plain, "Ignore it", NULL
        };

/*  Special cases (display copy count) */

/***** BBANDIT Requester IntuiText's ******/
struct IntuiText BBDiskbody2 =
        {
        0,1, JAM2, 20,30, &TxtAt_Plain, CopyText, &GenericFirstBody
        };

struct IntuiText BBDiskbody =
        {
        0,1, JAM2, 20,18, &TxtAt_Plain, ITBodyText, &BBDiskbody2
        };

/***** Revenge on Disk Requester IntuiText's ******/
struct IntuiText RevDiskbody3 =
        {
        0,1, JAM2, 20,30, &TxtAt_Plain, CopyText, &GenericFirstBody
        };

struct IntuiText RevDiskbody =
        {
        0,1, JAM2, 20,18, &TxtAt_Plain,(UBYTE *) "infected with the -Revenge- VIRUS!", &RevDiskbody3
        };


/***** Generic Notice - Removed from Memory ****/
struct IntuiText GRB3 =
        {
        0,1, JAM2, 20,18, &TxtAt_Plain,(UBYTE *) "in memory, and is now disabled.  See the", NULL
        };

struct IntuiText GRB2 =
        {
        0,1, JAM2, 20,28, &TxtAt_Plain,(UBYTE *) "documentation for more information!", &GRB3
        };

struct IntuiText GenericRAMBody =
        {
        0,1, JAM2, 20, 8, &TxtAt_Plain, ITBodyText, &GRB2
        };

struct IntuiText BBMPos =
        {
        0,1, JAM2,  7, 3, &TxtAt_Plain, " Thanks! ", NULL
        };

struct IntuiText Mem3 =
        {
        0,1, JAM2, 20,28, &TxtAt_Plain,(UBYTE *) "some other utility is the cause of it.", NULL
        };

struct IntuiText Mem2 =
        {
        0,1, JAM2, 20,18, &TxtAt_Plain,(UBYTE *) "This could mean a new Virus is in RAM, or", &Mem3
        };

struct IntuiText Mem1 =
        {
        0,1, JAM2, 20, 8, &TxtAt_Plain, 0 , &Mem2
        };


/***** Write Protect Error Requester IntuiText's ******/
struct IntuiText ERRBody2 =
        {
        0,1, JAM2, 20,18, &TxtAt_Plain,(UBYTE *) "Write Protected.", NULL
        };

struct IntuiText ERRBody =
        {
        0,1, JAM2, 20,8, &TxtAt_Plain, (UBYTE *)"DISK ERROR:  Disk is", &ERRBody2
        };

struct IntuiText ERRPos =
        {
        0,1, JAM2, 7,3, &TxtAt_Plain, "Retry", NULL
        };

struct IntuiText ERRNeg =
        {
        0,1, JAM2, 7,3, &TxtAt_Plain, "Cancel", NULL
        };


/***** Rewrite block?  Really? ******/
struct IntuiText REWBody3 =
        {
        0,1, JAM2, 20,28, &TxtAt_Plain,(UBYTE *) "boot sectors?", NULL
        };

struct IntuiText REWBody2 =
        {
        0,1, JAM2, 20,18, &TxtAt_Plain,(UBYTE *) "rewrite that disk's boot", &REWBody3
        };

struct IntuiText REWBody =
        {
        0,1, JAM2, 20,8, &TxtAt_Plain,      (UBYTE *)"Are you sure you want to", &REWBody2
        };

struct IntuiText REWPos =
        {
        0,1, JAM2, 7,3, &TxtAt_Plain, "Yes", NULL
        };

struct IntuiText REWNeg =
        {
        0,1, JAM2, 7,3, &TxtAt_Plain, "No!", NULL
        };


/*********************Da Beginnin*************************/

void main(argc, argv)
int argc;
char **argv;
{

if (argc == 3)
	{
        NewWindow.LeftEdge = atoi(argv[1]);
        NewWindow.TopEdge = atoi(argv[2]);
        };

WindowBig = FALSE;

/* Come on, folks, is intuition ever NOT going to be available???? */
IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0L);

/* Same with GfxBase.  If GfxBase is gone, we DESERVE to crash. */
GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0L);

ExecBase = (struct ExecBase *)OpenLibrary("exec.library", 0);

diskbuffer = AllocMem((long)3*512, (long)MEMF_CHIP|MEMF_CLEAR);
if (diskbuffer == 0)
        {
        /* Okay, okay, it's messy and doesn't close the libraries it
           opens.  Look, if we can't get a measley 1.5K, then the
           system is probably going to crash before the user finds out
           what hit him, and he probably won't blame me.      */
           exit(10);
        };

/*  We use the same port/request through the whole program.  Works OK. */
diskport = CreatePort(0L,0L);
diskreq = CreateStdIO(diskport);

Window = OpenWindow(&NewWindow);
if (Window == NULL)
        goto Quitter;   /* No memory to open little window! */

RP = Window->RPort;

/* This does some setup stuff, I guess, eh? */
SetUp();

/*  Check for Byte Bandit, SCA, Revenge and ByteWarrior, etc. in RAM.  */
CheckMemoryForViruses();

/*  Hmmm, wonder what this does. */
CheckMemoryForIRQVirus();

CheckBlock();

if (argc != 2) 	/* New Feature:  Virusx CHECK will only check disks then quit */
	DoLittle();     /* The main loop.  Do Little.  Ya. */

Quitter:

if (Window != 0) CloseWindow(Window);

if (diskport != 0) DeletePort(diskport);
if (diskreq != 0) DeleteStdIO(diskreq);


CloseLibrary(GfxBase);									/*
CloseDoor(DoorBase);
CloseLibrary(IntuitionBase);								hahah bet I fooled you */  
CloseLibrary((struct Library *)ExecBase);
FreeMem(diskbuffer, (long)3*512);
exit(0);

/* DoorBase?? */
}

/*********************/
DoLittle()
{
long Code;     /* for storing our IntuiMessage stuff */
long Class;
char KG2;      /* KeepGoing 2.  Another booleean. */

KG2 = TRUE;

SetAPen(RP, 1L);
SetBPen(RP, 0L);
SetDrMd(RP, (long)JAM2);

while (KG2 == TRUE)
        {
        Message = (struct IntuiMessage *)GetMsg(Window->UserPort);
        if (Message == 0)
                {
                CheckMemoryForIRQVirus();
                Delay(50);
                continue;
                };

        Class = Message->Class;
        Code = Message->Code;
        ReplyMsg((struct Message *)Message);

        if (Class == CLOSEWINDOW)
                {
                KG2 = FALSE;
                continue;
                };

        if (Class == MOUSEBUTTONS)
                if (Code == MENUDOWN)
                        {
                        Class = VANILLAKEY;
                        Code = 'i';
                        }
                        else continue;

        if (Class == VANILLAKEY)
                {
                char flag;

                switch (toupper(Code))
                        {
                        case 'I':
                                if (WindowBig == TRUE) WindowBig = FALSE;
                                        else WindowBig = TRUE;

                                if (WindowBig == TRUE)
                                        {
                                        if (Window->TopEdge > 0) MoveWindow(Window, 0L, (long)-Window->TopEdge);
                                        SizeWindow(Window, 0L, 200-(Window->Height));
                                        } else SizeWindow(Window, 0L, -Window->Height + 10);

                                WaitForNewSize();
                                break;


                        case 'C':
                                for (x=0; x<4; x++) ChangeCount[x] = 10000;
                                CheckBlock();

                        default:
                                flag = ShowAscii(Code);
                                if (flag == 1) CheckBlock();
                        };
                if (WindowBig == TRUE) DoStats();
                };

        if (Class == DISKINSERTED)
                {
                CheckBlock();
                if (WindowBig == TRUE) DoStats();
                };
        };

}


/************************************************/
/* Opens trackdisk, finds out who's out there,  */
/* and sets Changecount up accordioningly.      */
/************************************************/
SetUp()
{
long x;

for (x = 0; x < 4; x++) /* go thru all 4 possible drives */
        {
        ChangeCount[x] = 1000;
        error = OpenDevice(TDName,(long)x,diskreq,0L);
        if (error > 0)
                {
                ChangeCount[x] = -1;
                } else CloseDevice(diskreq);
        };

}

/*********************************************************/
/* This routine returns which drive changed disks lately */
/*********************************************************/
WhoChanged()
{
char RetVal = -1;       /* The value we'll return */

for (x = 0; x < 4; x++)
        {
        if (ChangeCount[x] == -1)
                continue;       /* no drive here */
        error = OpenDevice(TDName,(long)x,diskreq,(long)0);
        if (error > 0)
                continue;       /* no drive here */

        diskreq->io_Command = TD_CHANGESTATE;
        DoIO(diskreq);
        if (diskreq->io_Actual != 0)
                {
                CloseDevice(diskreq);
                continue;
                };

        diskreq->io_Command = TD_CHANGENUM;
        DoIO(diskreq);
        if (diskreq->io_Actual != ChangeCount[x])
                {
                RetVal = x;
                ChangeCount[x] = diskreq->io_Actual;
                CloseDevice(diskreq);
                break;
                };

        CloseDevice(diskreq);
        };

return(RetVal);
}

/****************************************************************/
/*  Figures out which drive changed disks (using WhoChanged(),  */
/*  And checks it.  Calling this after every DISKINSERTED is OK.*/
/****************************************************************/
CheckBlock()
{
/*  How many register vars can I use, anyway? */
register long Sum, Virus;
register long a, Unit;
char SCA, ByteWarrior, Revenge, BBandit;
char NorthStar, Obelisk, Pentagon, LamerX, HCS;
char DDoc, GRAFFITI, Bit16, Phantasm, OldNStar;
char UFox;
unsigned long *iptr;
unsigned long *ptr;
char drivename[10];

while ((Unit = WhoChanged()) != -1)
        {
        strcpy(drivename, "DF0:");
        drivename[2] = '0'+Unit;

        SCA = FALSE;
        BBandit = FALSE;
        Revenge = FALSE;
        ByteWarrior = FALSE;
        NorthStar = FALSE;
        Obelisk = FALSE;
	Pentagon = FALSE;
	LamerX = FALSE;
	UFox = FALSE;
	HCS = FALSE;
	DDoc = GRAFFITI = Bit16 = Phantasm = OldNStar = FALSE;
		
        /* Unit # to open is returned by "WhoChanged()" up above. */
        if (Unit == -1) return;
        error = OpenDevice(TDName,(long)Unit,diskreq,0L);
        if (error > 0) return;

        DisksChecked++;

        error = ReadBlock();
        CloseDevice(diskreq);
        if (error == FALSE) return;

        ptr = (long *)diskbuffer;
        iptr = (long *)diskbuffer;

        if (iptr[0] != ID_DOS_DISK) return;     /* No DOS/0 */
	
        Sum = 0;
        for (a=0; a<256; a++)
                {
                LastSum = Sum;
                Sum = Sum + ptr[a];
                if (LastSum > Sum) Sum++;  /* took me a while to figger this out */
                }

        if (Sum != 0)
                {
                CheckDriveForIRQ(drivename);
                return; /* if it's not bootable, we DONT want it! */
                };

        if (diskbuffer[0x40] == 0xff)
                if (diskbuffer[0x41] == 0xa0)
                        if (diskbuffer[0x42] == 0x20)
                                if (diskbuffer[0x43] == 0x40)
		{
		PentagonCount++;
		Pentagon = TRUE;
		}

        if (iptr[0x40/4] == 0x13fc00a0)
		{
		DDocCount++;
		DDoc = TRUE;
		}

        if (iptr[0x150/4] == 0x000100bf)
		{
		GRAFFITICount++;
		GRAFFITI = TRUE;
		}

        if (iptr[0x150/4] == 0x3fff2c78)
		{
		Bit16Count++;
		Bit16 = TRUE;
		}

        if (iptr[0x40/4] == 0x4240323c)
		{
		PhantasmCount++;
		Phantasm = TRUE;
		}

        if (iptr[0x40/4] == 0x0007ec1a)
		{
		OldNStarCount++;
		OldNStar = TRUE;
		}

        if (iptr[0x1d0/4] == 0x83353ef0)
        /*
        diskbuffer[0x1d0] == 0x83)
                if (diskbuffer[0x1d1] == 0x35)
                        if (diskbuffer[0x1d2] == 0x3e)
                                if (diskbuffer[0x1d3] == 0xf0)
	*/
		{
		UFoxCount++;
		UFox = TRUE;
		}

        if (diskbuffer[0x40] == 0x51)
                if (diskbuffer[0x41] == 0xc8)
                        if (diskbuffer[0x42] == 0xff)
                                if (diskbuffer[0x43] == 0xfc)
		{
		HCSCount++;
		HCS = TRUE;
		}

        if (diskbuffer[0x40] == 0x03)
                if (diskbuffer[0x41] == 0x61)
                        if (diskbuffer[0x42] == 0x34)
                                if (diskbuffer[0x43] == 0x3c)
		{
		LamerXCount++;
		LamerX = TRUE;
		}
					
       if (diskbuffer[0x34] == 100)
                if (diskbuffer[0xc4] == 48)
                        if (diskbuffer[0xc0] == 68)
                                if (diskbuffer[0xf1] == 7)
                                        {
                                        ByteWarriorCount++;
                                        ByteWarrior = TRUE;
                                        };

        if (diskbuffer[0x2b] == '9')
                if (diskbuffer[0x2c] == '.')
                        if (diskbuffer[0x2d] == '8')
                                if (diskbuffer[0x2e] == '7')
                                        {
                                        ByteBanditCount++;
                                        BBandit = TRUE; /* 9.87 is part of BBandit Virus */
                                        };

        /* check specifically for SCA virus */
        if (diskbuffer[0x149] == 0x28)
                if (diskbuffer[0x14a] == 0x23)
                        if (diskbuffer[0x14b] == 0x7c)
                                        {
                                        SCA = TRUE;     /* CHW is part of SCA virus */
                                        SCACount++;
                                        };

        if (diskbuffer[0xe] == 'I')
                if (diskbuffer[0xf] == 'D')
                        if (diskbuffer[0x10] == '9')
                                if (diskbuffer[0x1a6] == 'f')
                                        {
                                        Revenge= TRUE;
                                        RevengeCount++;
                                        };

        if (diskbuffer[0x12] == 78)
                if (diskbuffer[0x13c] == 68)
                        if (diskbuffer[0x18] == 83)
                                if (diskbuffer[0x19] == 116)
                                        {
                                        NorthStar = TRUE;
                                        NorthStarCount++;
                                        };


        if (diskbuffer[0x38] == 71)
                if (diskbuffer[0xbc] == 83)
                        if (diskbuffer[0x1fb] == 100)
                                if (diskbuffer[0x2d] == 80)
                                        {
                                        Obelisk = TRUE;
                                        ObeliskCount++;
                                        };

        /* compare boot block with real boot block.  If it's not, notify God. */
        Virus = FALSE;

        for (x = 0; x < 39; x++) /* num of bytes in bootblock */
                {
                if (diskbuffer[8+x] != bootblock[8+x])
                        {
                        Virus = TRUE;
                        };
                };

        /* Oh no, a Virus! */
        if (Virus == TRUE)
                {
                NBCTEXT[23] = '0'+Unit; /* change DF9: to real drive in text */
                TEXTPTR[23] = '0'+Unit;
                error = FALSE;

                if (SCA == TRUE)
                        {
                        /* OH NOOOOO, an SCA virus.  Wimpo virus, compared to BBandit
                           but it's a lot nicer code to read. */
                        error = MyRequest(VN_SCA, 1);
                        }
                else if (BBandit == TRUE)
                        {
                        /* The Byte Bandit Virus.  Tricky bugger, he WAS. Cheats, tho. */
                        sprintf(CopyText, copystring, (long)(diskbuffer[74]*256)+diskbuffer[75]);
                        BuildITBodyText(VN_BYTEBANDIT, 1);
                        error = AutoRequest(Window, &BBDiskbody, &SCAPos, &SCANeg, 0L, 0L, 380L, 80L);
                        }
                else if (Revenge == TRUE)
                        {
                        /* Revenge virus.  X rated bugger, lot like Byte Bandit. */
                        sprintf(CopyText, copystring, (long)(diskbuffer[0x3f6]*256)+diskbuffer[0x3f7]);
                        BuildITBodyText(VN_REVENGE, 1);
                        error = AutoRequest(Window, &RevDiskbody, &SCAPos, &SCANeg, 0L, 0L, 380L, 80L);
                        }
                else if (ByteWarrior == TRUE)
                        {
                        /* Byte Warrior.  Very 'friendly' virus.  Ez to get rid of.  */
                        error = MyRequest(VN_BYTEWARRIOR, 1);
                        }
                else if (Pentagon == TRUE)
                        {
                        /* Pentagon Circle.  An 'AntiVirus', and not a bad one at that. */
                        error = MyRequest(VN_PENTAGON, 1);
                        }
                else if (NorthStar == TRUE)
                        {
                        /* NorthStar.  Nice virus - alerts you to others, ez to get rid of */
                        error = MyRequest(VN_NORTHSTAR, 1);
                        }
                else if (Obelisk == TRUE)
                        {
                        /* At least these guys are getting creative with their Graphics! */
                        error = MyRequest(VN_OBELISK, 1);
                        }
                else if (LamerX == TRUE)
                        {
                        /* At least these guys are getting creative with their Graphics! */
                        error = MyRequest(VN_LAMER, 1);
                        }
                else if (HCS == TRUE)
                        {
                        /* At least these guys are getting creative with their Graphics! */
                        error = MyRequest(VN_HCS, 1);
                        }
                else if (UFox == TRUE)
                        {
                        /* yawn */
                        error = MyRequest(VN_UFOX, 1);
                        }
                else if (DDoc == TRUE)
                        {
                        /* yawn */
                        error = MyRequest(VN_DDOC, 1);
                        }
                else if (GRAFFITI == TRUE)
                        {
                        /* yawn */
                        error = MyRequest(VN_GRAFFITI, 1);
                        }
                else if (Bit16 == TRUE)
                        {
                        /* yawn */
                        error = MyRequest(VN_Bit16, 1);
                        }
                else if (Phantasm == TRUE)
                        {
                        /* yawn */
                        error = MyRequest(VN_PHANTASM, 1);
                        }
                else if (OldNStar == TRUE)
                        {
                        /* yawn */
                        error = MyRequest(VN_OLDNSTAR, 1);
                        }
                else
                        {
                        /* Probably just a custom boot block (or a new virus...) */
                        error = AutoRequest(Window, &Body1, &SCAPos, &SCANeg, 0L, 0L, 320L, 70L);
                        }
                if (error == TRUE) DoInstall(Unit); /* user wants it neutered. */
                };
        CheckDriveForIRQ(drivename);
        };  /* End of While Whochanged */

}

/********************************************/
/* This is where the boot code gets changed */
/********************************************/
DoInstall(un)
int un; /* unit to write to */
{
register int x;

/* Rewrite disk?  Really?  */
error = AutoRequest(Window, &REWBody, &REWPos, &REWNeg, 0L, 0L, 320L, 75L);
if (error != TRUE) return;      /* user changed his brain. */

DisksInstalled++;

error = OpenDevice(TDName, (long)un,diskreq,0L);
if (error > 0) return;

TryGain:

        diskreq->io_Command = TD_PROTSTATUS;
        DoIO(diskreq);          /* check if disk is write protected */

        if (diskreq->io_Actual != 0)
                {
                error = AutoRequest(Window, &ERRBody, &ERRPos, &ERRNeg, 0L, 0L, 280L, 75L);
                if (error == TRUE) /* error is true or false, depending on user */
                        {
			goto TryGain;
                        };
	        CloseDevice(diskreq);
	        return; /* unrecoverable write protect error!! Panic!!!!!!! */
		};

for (x = 0; x < 1024; x++)
        diskbuffer[x] = 0;      /* clear diskbuffer to zero.  clean. */

CopyMem(bootblock, diskbuffer, 50L); /* Copy it over */

/* Write it ! */

        error = 0;
        diskreq->io_Length = 1024; /* here we go! */
        diskreq->io_Data = (APTR)diskbuffer;
        diskreq->io_Command = CMD_WRITE;
        diskreq->io_Offset = 0L;
        DoIO(diskreq);
        error = diskreq->io_Error;

if (error < 19)
        {
        diskreq->io_Command = CMD_UPDATE;       /* flush buffer to disk */
        DoIO(diskreq);
        error = diskreq->io_Error;
        };

if (error < 19)
        {
        diskreq->io_Length = 0;
        diskreq->io_Command = ETD_MOTOR;
        DoIO(diskreq);                          /* turn off motor */
        error = diskreq->io_Error;
        };

CloseDevice(diskreq);

if (error > 19)
        {
        SetWindowTitles(Window, "Disk Error!", (STRPTR)-1);
        }
    else
        {
        SetWindowTitles(Window, "Disk Healed.", (STRPTR)-1);
        };

Delay(150L);
SetWindowTitles(Window, TITLETEXT, (STRPTR)-1);
}


/************************/

CheckMemoryForViruses()
{
unsigned long *TD;
unsigned short *wordpointer;
unsigned long *LongMemPointer;  /* Used for reading FROM memory */
unsigned long *ptr;
char linebuffer[80];
char *charpointer;
unsigned int x;

/**************- Check for Byte Bandit (look at TD Vector) *************/
/*  (Byte Bandit isn't at a fixed location.  Depends on your RAM.      */

/* LongMemPointer = &trackdisk.device */
TD = (unsigned long *)FindName(&ExecBase->DeviceList, TDName);

x = (unsigned int) TD;
x = x - 0x1c;
ptr = (unsigned long *) x;
LongMemPointer = (unsigned long *) *ptr;
x = (unsigned int) LongMemPointer;
x = x - 0x1b8;
LongMemPointer = (unsigned long *) x;

if (*LongMemPointer == ID_DOS_DISK)     /* klugo */
       	{
        /* Ok, so we don't really remove it from memory, but we DO render
       	   it harmless. */
        Disable();
       	charpointer = (char *)VirusBase;
        charpointer[0xaa] = 0x4e;
       	charpointer[0xac] = 0x4e;
        charpointer[0xae] = 0x4e;
       	charpointer[0xb0] = 0x4e;
        charpointer[0xab] = 0x71;
       	charpointer[0xad] = 0x71;
        charpointer[0xaf] = 0x71;    /* Isn't this code terrible?  Ick! */
       	charpointer[0xb1] = 0x71;    /* I didn't know what I was doing when */
        charpointer[0x1c2] = 0x60;   /* I wrote this.  (excuses... 8-)  */
       	charpointer[0x1c3] = 0;
        charpointer[0x2d2] = 0x60;
       	charpointer[0x2d3] = 0;
        charpointer[0x388] = 0x4e;
       	charpointer[0x389] = 0x75;
        charpointer[0x3ea] = 0;
       	charpointer[0x3eb] = 0;
        charpointer[0] = 0;
       	Enable();

        MyRequest(VN_BYTEBANDIT, 2);
       	};
	

TD = (unsigned long *)FindName(&ExecBase->DeviceList, TDName);
x = (unsigned int) TD;
x = x - 0x1c;
LongMemPointer = (unsigned long *)x;
LongMemPointer = (unsigned long *)LongMemPointer[0];
x = (unsigned int)LongMemPointer;
x = x - 0x17c;
LongMemPointer = (unsigned long *)x;

if (*LongMemPointer == ID_DOS_DISK)	/* ptr == VirusBase */
	{
	char *a;
	long *src, *dest;
	long *vbase;
	
	*LongMemPointer = 0;	/* Kill DOS\0 */

	vbase = LongMemPointer;
	
	/* Disable, then repair vectors. */
	Disable();

	/* addr of real TD vector */
	src = &vbase[0x3a8/4];
	a = (char *)ExecBase;
	a = a - 0x264;
	dest = (unsigned long *)a;
	*dest = *src;
	
	src = (unsigned long *) &vbase[0x3ac/4];
	a = (char *)TD;
	a = a - 0x1c;
	dest = (unsigned long *)a;
	*dest = *src;
	
	Enable();
	
	ExecBase->KickTagPtr = 0;	/* Sorry, I know it's cruel */

        MyRequest(VN_LAMER, 2);

	}

	


/****************- Look for Revenge Virus (at $7e000) ****************/
if ((unsigned long)ExecBase->CoolCapture == (unsigned long)516192)
        {
        /* Fix the CoolCapture vector */
        ExecBase->CoolCapture = 0;

        Disable();

        wordpointer = (unsigned short *)(0x7e000);
        wordpointer[0] = 0;

        wordpointer = (unsigned short *)(0x7e000+0x1e0);
        wordpointer[0] = 0x4ef9;
        wordpointer[1] = 0x0007;
        wordpointer[2] = 0xe066;

        wordpointer = (unsigned short *)0x7e2da;
        wordpointer[0] = 0x4ef9;
        wordpointer[1] = 0x0007;
        wordpointer[2] = 0xe06c;

        Enable();

        MyRequest(VN_REVENGE, 2);
        };

/******************** See if SCA is in RAM ***************************/
if ((long)ExecBase->CoolCapture == (long)0x7ec3e)
        {
        ExecBase->CoolCapture = 0;
        MyRequest(VN_SCA, 2);
        };

/******************** See if Graffiti is in RAM ***************************/
if ((long)ExecBase->CoolCapture == (long)0x7ec58)
        {
        ExecBase->CoolCapture = 0;
        MyRequest(VN_GRAFFITI, 2);
        };

/******************** How about Phantasmumble? ***************************/
if ((long)ExecBase->CoolCapture == (long)0x7ec74)
        {
        ExecBase->CoolCapture = 0;
        MyRequest(VN_PHANTASM, 2);
        };

/******************** Yoo hoo?  HCS?  Are you here? ******************/
if ((long)ExecBase->CoolCapture == (long)0x7ec64)
        {
        /* You are, you little dickens.  */
        
        ExecBase->CoolCapture = 0;
	
	/* Scat! */
	
	x = (unsigned int) ExecBase;
	x = x - 0x1c6;
	ptr = (unsigned long *)x;
	
	LongMemPointer = (unsigned long *)0x7ef9c;
	
	*ptr = *LongMemPointer;	/* un-Step on DoIO() vector */

        MyRequest(VN_HCS, 2);
        };

/**************************** DiskDoktor? ****************************/
wordpointer = ExecBase->CoolCapture;
if (*wordpointer == 0x2c79)
	{
	if (wordpointer[3] == 0x203c)
		{
		int x;
		
		Disable();
		
		x = ExecBase;
		x = x - 0x1c6;
		LongMemPointer = (long *)x;
		
		wordpointer = (UWORD *)*LongMemPointer;

		x = (int)wordpointer;
		x = x + (0x15c);
		wordpointer = (UWORD *)x;
		*wordpointer = 0x4e75;

		x = (int)wordpointer;
		x = x + 0x1e2;
		wordpointer = (UWORD *)x;
		*wordpointer = 0x4e75;
		
 		x = (int)ExecBase;
		x = x - 0x1c6;
		ptr = (long *)x;
		
		x = (int)*ptr;
		x = x + 2;
		LongMemPointer = (long *)x;
				
		*ptr = *LongMemPointer;

		ExecBase->CoolCapture = 0;
		ExecBase->ColdCapture = 0;
		ExecBase->WarmCapture = 0;

		Enable();
		
		MyRequest(VN_DDOC, 2);
		};
	};


/******************** It's the Australian UltraFox  ******************/
if ((long)ExecBase->CoolCapture == (long)0x7ed36)
        {
        UWORD *wordptr;

 	ExecBase->CoolCapture = 0;
	
	x = (unsigned int) ExecBase;
	x = x - 0x1c6;
	ptr = (unsigned long *)x;
	wordptr = (UWORD *)ptr;
	if (wordptr[0] == 0x0007)
		{
		LongMemPointer = (unsigned long *)0x7eb38;
		*ptr = *LongMemPointer;	/* un-Step on DoIO() vector */
		};
		
        MyRequest(VN_UFOX, 2);
        };

/***************** Check for Obelisk  *******************************/
if ((APTR)ExecBase->CoolCapture == (APTR)0x7e86c)
        {
        ExecBase->CoolCapture = 0;
        ptr = (unsigned long *)0x7e88a;
        Forbid();
        ptr[0] = 10;
        Permit();
        MyRequest(VN_OBELISK, 2);
        };

/******************** How about North Star? **************************/
if ((APTR)ExecBase->CoolCapture == (APTR)0x7ec0e)
        {
        ExecBase->CoolCapture = 0;
        MyRequest(VN_NORTHSTAR, 2);
        };

/********************* Check for Byte Warrior ************************/
wordpointer = (unsigned short *)0x7f800;
if ( wordpointer[0] == (0x444f) )
        {
        wordpointer = (unsigned short *)0x7f954;
        if (wordpointer[0] == 0x4afc)
                {
                wordpointer[0] = 0;             /* Kill resident matchtag */

                Forbid();

                wordpointer = (unsigned short *)0x7f972;
                wordpointer[0] = 0x4ef9;
                wordpointer[1] = 0x00fc;
                wordpointer[2] = 0x06dc;

                wordpointer =  (unsigned short *)0x7f800;
                wordpointer[0] = 0;

                Permit();

                MyRequest(VN_BYTEWARRIOR, 2);
                };
        };

/******************** See if Pentagon is in RAM ***************************/
if ((long)ExecBase->CoolCapture == (long)0x7fb4c)
        {
        ExecBase->CoolCapture = 0;

        /* He sometimes has the DoIO() setfunctioned, I can't figure out
           when, but even if he does, he doesn't do any harm anyway, and
           with CoolCapture set to 0, he'll be gone at next reboot.  */
           
        MyRequest(VN_PENTAGON, 2);
	};
	

if (ExecBase->CoolCapture != 0)
        {
        sprintf(linebuffer, "Cool%s%lx", CaptureStr, ExecBase->CoolCapture);
        if (MyRequest(linebuffer, 3) == TRUE) ExecBase->CoolCapture = 0;
        }

if (ExecBase->ColdCapture != 0)
        {
        sprintf(linebuffer, "Cold%s%lx", CaptureStr, ExecBase->ColdCapture);
        if (MyRequest(linebuffer, 3) == TRUE) ExecBase->ColdCapture = 0;
        }

if (ExecBase->WarmCapture != 0)
        {
        sprintf(linebuffer, "Warm%s%lx", CaptureStr, ExecBase->WarmCapture);
        if (MyRequest(linebuffer, 3) == TRUE) ExecBase->WarmCapture = 0;
        }
}


/**************************************************************/
/*  This is the routine that displauys a block as ASCII text. */
/**************************************************************/
ShowAscii(key)
long key;
{
int drive;
int x,y;
int deltax, deltay;
long a;
int FLAG=0;

struct RastPort *RP;
RP = Window->RPort;

drive = key - '0';

if ((drive < 0) || (drive > 3) || (ChangeCount[drive] == -1)) return;

error = OpenDevice(TDName,(long)drive,diskreq,0L);
if (error > 0) return;

error = ReadBlock();

CloseDevice(diskreq);

if (error == FALSE) return;

/* save the amount we moved the window */
deltax = Window->LeftEdge;
deltay = Window->TopEdge;

MoveWindow(Window, -deltax, -deltay);

if (WindowBig == FALSE) SizeWindow(Window, 278L, 160L);
        else SizeWindow(Window, 278L, 0L);

WaitForNewSize();

SetAPen(RP, 0L);
RectFill(RP, 2, 12, 278, 167);

SetAPen(RP, 3L);
Move(RP, (long)(14+(12*8)), 165L);
Text(RP, "Block 0", 7L);
Move(RP, (long)(324+(12*8)), 165L);
Text(RP, "Block 1", 7L);
SetAPen(RP, 1L);

text[2] = key;
SetWindowTitles(Window, text, (STRPTR)-1);

x=0; y=0;

SetAPen(RP, 1L);
SetDrMd(RP, JAM2);

for (a=0; a<512; a=a+32)
        {
        Move(RP, (long)(10+(x*8)), (long)20+(y*9));
        Text(RP, &diskbuffer[a], 32L);

        Move(RP, (long)(320+(x*8)), (long)20+(y*9));
        Text(RP, &diskbuffer[a+512], 32L);
        y++;
        };

Wait(1<<Window->UserPort->mp_SigBit);
Message = (struct IntuiMessage *)GetMsg(Window->UserPort);

/*  If a disk was inserted, we want CheckBlock() to happen later on some time */
if (Message->Class == DISKINSERTED) FLAG=1;
ReplyMsg((struct Message *)Message);

if (WindowBig == FALSE)
        SizeWindow(Window, -278L, -160L);
        else SizeWindow(Window, -278L, 0L);

SetWindowTitles(Window, TITLETEXT, (STRPTR)-1);
WaitForNewSize();

/* deltas plus current position, in case dude moved the window */
MoveWindow(Window, deltax+(-Window->LeftEdge), deltay+(-Window->TopEdge));
Delay(2L);
return(FLAG);
}


/*
 When you do a SizeWindow() command, you have to wait for a NEWSIZE
 IntuiMessage before drawing in it.  That's all this routine does.
 */
WaitForNewSize()
{
while (TRUE)
        {
        WaitPort(Window->UserPort);
        Message = (struct IntuiMessage *)GetMsg(Window->UserPort);
        if (Message->Class != NEWSIZE)
                {
                ReplyMsg((struct Message *)Message);
                continue;
                };
        ReplyMsg((struct Message *)Message);
        break;
        };
}

/*
        type:

                1 == "is infected with the xxxx VIRUS!"
                2 == "somethin about virus in ram"
                3 == virus in cold/cool/warm capture
*/

BuildITBodyText(text, type)
char *text;
int type;
{
switch (type)
        {
        case 1:
                strcpy(ITBodyText, "infected with the `");
                strcat(ITBodyText, text);
                strcat(ITBodyText, "' VIRUS!");
                break;
        case 2:
                strcpy(ITBodyText, "NOTICE:  The `");
                strcat(ITBodyText, text);
                strcat(ITBodyText, "' VIRUS was found");
                break;
        };
}

/***** an attempt to save space *********/
MyRequest(string, type)
char *string;
int type;
{
if (type != 3)
        {
        BuildITBodyText(string, type);
        } else
        {
        Mem1.IText = string;
        };

if (type == 1) return(AutoRequest(Window, &GenericDiskBody, &SCAPos, &SCANeg, 0L, 0L, 420L, 80L));
if (type == 2) return(AutoRequest(Window, &GenericRAMBody, &BBMPos, &BBMPos, 0L, 0L, 420L, 78L));
if (type == 3) return(AutoRequest(Window, &Mem1, &Repair, &SCANeg, 0L, 0L, 420L, 78L));
}


/********* DoStats() **********/
DoStats()
{
char linebuffer[80];

SetAPen(RP, 0L);
RectFill(RP, 2L, 11L, 303L, Window->Height-13);
SetAPen(RP, 1L);

sprintf(linebuffer, "  Disks Checked: %ld", DisksChecked);
Out(20, linebuffer);

sprintf(linebuffer, "Disks Installed: %ld", DisksInstalled);
Out(29, linebuffer);

Out(43, "    Viruses Found:");

PV(52, VN_SCA, SCACount);
PV(61, VN_BYTEBANDIT, ByteBanditCount);
PV(70, VN_NORTHSTAR, NorthStarCount);
PV(79, VN_BYTEWARRIOR, ByteWarriorCount);
PV(88, VN_REVENGE, RevengeCount);
PV(97, VN_OBELISK, ObeliskCount);
PV(106, VN_IRQ, IRQFound);
PV(115, VN_PENTAGON, PentagonCount);
PV(124, VN_HCS, HCSCount);
PV(133, VN_DDOC, DDocCount);
PV(142, VN_GRAFFITI, GRAFFITICount);
PV(151, VN_Bit16, Bit16Count);
PV(160, VN_PHANTASM, PhantasmCount);
PV(169, VN_OLDNSTAR, OldNStarCount);
PV(178, VN_UFOX, UFoxCount);
PV(187, VN_LAMER, LamerXCount);
}

/****************** Ok, we're REALLY being chintzy here. */
PV(num, name, howmany)
int num;
char *name;
int howmany;
{
char linebuffer[80];

sprintf(linebuffer, "%-19s: %ld", name, howmany);
Out(num, linebuffer);
}

/***************************************** Cheap?  Me?  Nooooo....     */
/* This will write text to the column number in NUM, the text in Name. */
/*  Or something like that. ********************************************/
Out(num, name)
int num;
char *name;
{
int len;
len = 0;

while (name[len] != 0) len++;

Move(RP, 20L, (long)num);
Text(RP, name, len);
}


ReadBlock()
{
diskreq->io_Command = CMD_READ;
diskreq->io_Data = (APTR)diskbuffer;
diskreq->io_Length = 3*512;
diskreq->io_Offset = 0;
DoIO(diskreq);
if (diskreq->io_Error > 0) return(FALSE);
diskreq->io_Length = 0;
diskreq->io_Command = TD_MOTOR;
DoIO(diskreq);
return(TRUE);
}

unsigned long *OpenLibVectorPtr;
unsigned long *EntryForOldOpenLib;
unsigned long *OldOldOpenLibVector;


CheckMemoryForIRQVirus()
{
long *Array;
int Num;

Array = (long *)4;
Array = (long *)Array[0];
Num = (int)Array;
Num = Num - 0x196;

OpenLibVectorPtr = (unsigned long *)Num;

EntryForOldOpenLib = (unsigned long *)OpenLibVectorPtr[0];
OldOldOpenLibVector = (unsigned long *)(((char *)EntryForOldOpenLib) + 0x12);

if (EntryForOldOpenLib[0] == 0x2f3a0010)
        {
        OpenLibVectorPtr[0] = OldOldOpenLibVector[0];
        ExecBase->KickTagPtr = 0;
        MyRequest(VN_IRQ, 2);
        };
}


/********************************/

CheckDriveForIRQ(drivename)
char *drivename;
{
int err;
char buffer[80];
char dirbuffer[80];
char filebuffer[100];
char tempbuffer[100];
char FoundInDir;
char FoundInFname;
char chr;
int index;
char pass;

FoundInDir = FALSE;
FoundInFname = FALSE;
filebuffer[0] = 0;

pass = 0;

sprintf(dirbuffer, "%sC/DIR", drivename);
err = CheckFileForIRQ(dirbuffer,0);
if (err == 1)
        {
        IRQFound++;
        FoundInDir = TRUE;
        }
        else dirbuffer[0] = 0;


index = 0;

sprintf(tempbuffer, "%ss/Startup-Sequence", drivename);
fp = Open(tempbuffer, MODE_OLDFILE);
if (fp == 0)
        filebuffer[0] = 0;
        else
        {
        while (TRUE)
                {
                err = Read(fp, &chr, 1);
                if (err == 0) break;
                if ((chr == 34) || (chr == 0x0a) || (chr == ';') || (chr == ' ')) continue;
                break;
                };

        if (err != 0)
                {
                while (TRUE)
                        {
                        filebuffer[index++] = chr;
                        filebuffer[index] = 0;
                        err = Read(fp, &chr, 1);
                        if (err == 0) break;
                        if (chr == 34) break;
                        if (chr == 0x0a) break;
                        if (chr == ';') break;
                        if (chr == 32) break;
                        };
                };

        Close(fp);

        sprintf(buffer, "%s%s", drivename, filebuffer);

        err = CheckFileForIRQ(buffer, 0);
        if (err == -1)
                {
                sprintf(buffer, "C:%s", filebuffer);
                err = CheckFileForIRQ(buffer, 0);
                };

        strcpy(filebuffer, buffer);

        if (err == 1)
                {
                FoundInFname = TRUE;
                IRQFound++;
                }
                else filebuffer[0] = 0;
        };

if (FoundInDir == FALSE && FoundInFname == FALSE) return(0);

WBenchToFront();
fp = Open("CON:70/20/500/100/VirusX", MODE_NEWFILE);
if (fp == 0) return(0);

WriteFP(fp, "NOTICE:  The IRQ Virus was found on volume ");
WriteFP(fp, drivename);
WriteFP(fp, "\n");

while (TRUE)
        {
        if (pass == 0)
                {
                strcpy(tempbuffer, dirbuffer);
                }
        else if (pass == 1)
                {
                strcpy(tempbuffer, filebuffer);
                }
        else if (pass == 2) break;

        pass++;

        if (tempbuffer[0] == 0) continue;

        sprintf(buffer, "\nIn the command: %s\n", tempbuffer);
        WriteFP(fp, buffer);
        WriteFP(fp, "Okay to remove it? [Y]: ");
        Read(fp, buffer, 3);
        if (toupper(buffer[0]) == 'Y')
                {
                err = CheckFileForIRQ(tempbuffer, 1);
                if (err == 1)
                        {
                        WriteFP(fp, "Virus removed.\n");
                        } else
                        {
                        WriteFP(fp, "Error removing virus.  Check file.\n");
                        }
                };
        };

WriteFP(fp, "\nHit RETURN to continue...");
Read(fp, buffer, 3);
Close(fp);
}

WriteFP(fp, string)
int fp;
char *string;
{
Write(fp, string, strlen(string));
}

/********************************/

#define VTAG     0x00000109L
#define BEGIN    OFFSET_BEGINNING
#define END              OFFSET_END
#define OLD              MODE_OLDFILE
#define NEW              MODE_NEWFILE
#define SLONG    ((long)sizeof(long))
#define OK        1                     /* no error */

#define NOFILE   -1                     /* can't find file */
#define SEEKERR  -2                     /* seek error on file */
#define ALLOCERR -3                     /* can't allocate memory */
#define READERR  -4                     /* error reading file */
#define VIRUSNF  -5                     /* virus not found in file */
#define WRITERR  -6                     /* error writing to file */
#define OPENERR  -7                     /* error opening file for write */
#define NOTEXE   -8                     /* not an executable file */

#define GOTHIM   OK                     /* removed virus from file */

#define VTAG     0x00000109L            /* virus hunk length */
#define VSIG1    0x0000FFFEL            /* part of virus signature */
#define VSIG2    0x61000000L            /* part of virus signature */


static long inp, *buff, size;

cleanup(val)
int val;
{
        if(inp)         Close(inp);
        if(buff)        FreeMem(buff,size);
        return val;
}

CheckFileForIRQ(fname, flag)
char *fname;
int flag;
{

        int   i = 0;
        long  nhunk;
        long tbuff[488/4];

        inp = 0L;  buff = 0L;

        if((inp = Open(fname,OLD)) == 0)        /* open the desired file */
                return NOFILE;

        Read(inp,(char *)&tbuff[0],487);                                /* get the first long word */
        if(tbuff[0] != 0x000003F3)                              /* check for executable file */
                return cleanup(NOTEXE);

        if(tbuff[5] != VTAG)
                return cleanup(VIRUSNF);

        Seek(inp,0L,END);                               /* seek to end of file */
        size = Seek(inp,0L,BEGIN);              /* rewind the file to get size */
        if(size <= 0L)
                return cleanup(SEEKERR);

        if((buff = AllocMem(size,0L)) == 0)     /* mem buffer for file */
                return cleanup(ALLOCERR);

        if(Read(inp,(char *)&buff[0],size) != size)     /* read entire file into buffer */
                return cleanup(READERR);

        nhunk = buff[ 2 ];              /* number of hunks in file */

/*
        the IRQ virus inserts his code as the first hunk in the file
        we can find the first hunk in the 6th longword of the file
*/
        /* find the start of the virus hunk */
        while(buff[ i++ ] != 0x000003E9)
                ;
/*
        The virus checks the first hunk for it's signature to prevent
         reinfecting an already infected program.  It actually checks for
        0xFFFE6100 which is the lower half of a move.m instruction and
        the upper half of a bsr instruction.  Here we do the same.
    i points to the virus code hunk length.
*/
        if( ((buff[ i+1 ] & 0x0000FFFF) != VSIG1)
     || ((buff[ i+2 ] & 0xFFFF0000) != VSIG2) )
                return cleanup(VIRUSNF);

        if (flag == 0)
                return cleanup(1);

/*
        close the file and reopen it with write access
        mode NEW will effectivly delete the old file contents so if a
        file error occurs before we finish, the file will be corrupt
*/
        Close(inp);
        if((inp = Open(fname,NEW)) == 0)
                return cleanup(OPENERR);

        buff[2] -= 1;   buff[4] -= 1;   /* readjust program header info */

/* write new header */
        if(Write(inp,(char *)&buff[0],5L*SLONG) != 5L*SLONG)
                return cleanup(WRITERR);

        if(Write(inp,(char *)&buff[6],nhunk*SLONG) != nhunk*SLONG)
                return cleanup(WRITERR);

/*
        subtract length of virus hunk and overhead from file size
        i was calculated earlier
*/
        i = i + 8L + VTAG;
        size = (size/SLONG - i)*SLONG;

/* and write old code out to file, ignoring virus hunk */
        if(Write(inp,(char *)&buff[i],size) != size)
                return cleanup(WRITERR);

/* we're done, the file is clean and intact */
        return cleanup(GOTHIM);
}
