/************************************************************************/
/*                                                                      */
/*                                                                      */
/*                                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 my first 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.              */
/*                                                                      */
/************************************************************************/
/*                                                                      */
/*  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                                             */
/*                      - This is another 'virus protector' that        */
/*                        can write itself to disks.  Anything that     */
/*                        spreads itself, under any name, is a          */
/*                        virus.  Doesn't do anything except during     */
/*                        a reboot, then examines disks and writes      */
/*                        over viruses.  Again, from CMI*BILL.          */
/*                                                                      */
/*  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 <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"


/* Latticeisms */
void MemCleanup() {}


/********************************************************************/
/* These string constants are used in multiple places, and thus     */
/* save bytes by having only one copy of them.                      */
/********************************************************************/
char TITLETEXT[]        = "VirusX 3.10 by Steve Tibbett";
char TDName[]           = "trackdisk.device";
char copystring[]       = "(Copy Count on this disk: %d)";
char ITBodyText[80];
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_SYSTEMZ[]	= "SystemZ";
char CaptureStr[]       = "Capture is pointing at $";
char text[]             = "DF6: Boot Sectors";

#define WIN_SIZE 	122L

/* Release Date of this version of VirusX */
char date[]             = "January 4, 1988";


/********************************************************************/
/* 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	SystemZCount;


/*******************************************************************/
/*  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         */
int     DisksChecked, DisksInstalled;   /* for title bar info           */
long    VirusBase;                      /* ick, whatta name!            */
char    FromCLI;                        /* True if run from CLI         */
struct Process *Process;

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;
{

FromCLI = TRUE;

switch (argc)
        {
        case 0:
                FromCLI = FALSE;
                break;

        case 3:
                NewWindow.LeftEdge = atoi(argv[1]);
                NewWindow.TopEdge = atoi(argv[2]);
                break;
        };

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)
        {
        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! */

Process = (struct Process *)FindTask(0L);
Process->pr_ConsoleTask = 0;

RP = Window->RPort;

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

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

CheckMemoryForIRQVirus();

CheckBlock();

DoLittle();     /* The main loop.  Do Little.  Ya. */

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

CloseLibrary(GfxBase);
CloseLibrary(IntuitionBase);
CloseLibrary((struct Library *)ExecBase);
FreeMem(diskbuffer, (long)3*512);
exit(0);
}

/*********************/
DoLittle()
{
register long Code;     /* for storing our IntuiMessage stuff */
register long Class;
register 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(60);
                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 (Code)
                        {
                        case 'i':
                        case 'I':
                                if (WindowBig == TRUE) WindowBig = FALSE;
                                        else WindowBig = TRUE;

                                if (WindowBig == TRUE)
                                        {
                                        if (Window->TopEdge > (180-WIN_SIZE)) MoveWindow(Window, 0L, (long)-Window->TopEdge);
                                        SizeWindow(Window, 0L, WIN_SIZE);
                                        } else SizeWindow(Window, 0L, -WIN_SIZE);

                                WaitForNewSize();
                                break;


                        case 'c':
                        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();
                };
        };

CloseWindow(Window);
}


/************************************************/
/* 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, SystemZ;
register unsigned long *iptr;
unsigned long *ptr;
char drivename[10];

while ((Unit = WhoChanged()) != -1)
        {
        sprintf(drivename, "DF%c:", Unit+'0');

        SCA = FALSE;
        BBandit = FALSE;
        Revenge = FALSE;
        ByteWarrior = FALSE;
        NorthStar = FALSE;
        Obelisk = FALSE;
	Pentagon = FALSE;
	SystemZ = 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 /*1024/4 cuz we're dealing with ptr math now*/  ; 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[0x42] == 0x40)
					{
					PentagonCount++;
					Pentagon = TRUE;
					}
					
	if (diskbuffer[0x170] == 0xfe)
		if (diskbuffer[0x171] == 0x3a)
			if (diskbuffer[0x172] == 0x4c)
				if (diskbuffer[0x173] == 0xdf)
					{
					SystemZCount++;
					SystemZ = 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[8] == 'C')
                if (diskbuffer[9] == 'H')
                        if (diskbuffer[10] == 'W')
                                        {
                                        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, (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, (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 (SystemZ == TRUE)
                        {
                        /* SystemZ, Very benign, but it can spread */
                        error = MyRequest(VN_SYSTEMZ, 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
                        {
                        /* 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, "Error, Nothing Done.", (STRPTR)-1);
        }
    else
        {
        SetWindowTitles(Window, "Disk Healed.", (STRPTR)-1);
        };

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


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

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

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

/* LongMemPointer = &trackdisk.device */
LongMemPointer = (long *)FindName(&ExecBase->DeviceList, TDName);
Temp = (long)LongMemPointer;
Temp = Temp - 0x1c;
LongMemPointer = (long *)Temp;
VirusBase = (*LongMemPointer) - 0x1b8;
LongMemPointer = (unsigned long *)VirusBase;

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;
        charpointer[0xb1] = 0x71;

        charpointer[0x1c2] = 0x60;
        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);
        };

/****************- 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);
        };

/***************** 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);
	};
	
/********************* Check for Byte Warrior ************************/
wordpointer = (unsigned short *)0x7f4e0;
if ( wordpointer[0] == (0x4afc) )
        {
	if (wordpointer[1] == 0x0007)
		{
		wordpointer[0] = 0;
		
		MyRequest(VN_SYSTEMZ, 2);
		};
	}



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

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

if (ExecBase->WarmCapture != 0)
        {
        sprintf(linebuffer, "Warm%s%x", 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, 60L);

WaitForNewSize();

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, -60L);

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, 380L, 80L));
if (type == 2) return(AutoRequest(Window, &GenericRAMBody, &BBMPos, &BBMPos, 0L, 0L, 395L, 78L));
if (type == 3) return(AutoRequest(Window, &Mem1, &Repair, &SCANeg, 0L, 0L, 395L, 78L));
}


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

SetAPen(RP, 0L);
RectFill(RP, 2L, 11L, 303L, (WIN_SIZE + 7));
SetAPen(RP, 1L);

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

sprintf(linebuffer, "Disks Installed: %d", 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_SYSTEMZ, SystemZCount);
}

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

sprintf(linebuffer, "%-16s: %d", 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)
        {

/*
        printf("Setting $%x to $%x\n", OpenLibVectorPtr, OldOldOpenLibVector[0]);
*/

        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) continue;
                if (chr == 0x0a) continue;
                if (chr == ';') continue;
                if (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, "[33;1mNOTICE[m:  The [1mIRQ[m 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
                        {
                        sprintf(buffer, "Error #%d removing virus.  Check file.\n", err);
                        WriteFP(fp, buffer);
                        }
                };
        };

WriteFP(fp, "\nHit [1mRETURN[m 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  fhunk, lhunk, 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 */
        fhunk = buff[ 3 ];              /* first hunk */
        lhunk = buff[ 4 ];              /* last hunk */

/*
        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);
}
