/************************************************************************/ /* */ /* */ /* VirusX */ /* */ /* by Steve Tibbett */ /* and Dan James */ /* */ /* 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!) */ /* */ /* 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 KV, and providing most of the */ /* code that deals with the non-Bootblock viruses. */ /* */ /************************************************************************/ /* */ /* 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 */ /* */ /* 26-Nov-89: Has it been this long? Anyways... I'm */ /* calling this one V4.0. See the real docs */ /* for more information. */ /* */ /************************************************************************/ /* */ /* 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. */ /* */ /* Australian Parasite: Hey - I like this one. It says it will */ /* not destroy game bootsectors or corrupt disks - but it's still a */ /* Virus. What makes this one unique is the way it lets itself */ /* be known. Get this - after so many disk accesses (something like */ /* 600 blocks read off of a floppy), it turns your screen Upside Down!*/ /* Nifty. You can still USE the screen upside down - it just looks, */ /* well, a bit weird. Anyway, it uses the DoIO() vector, the TD */ /* Read vector, starts at SysStkLower, and that's about it. Stays */ /* around via CoolCapture. Thanks to Martyn at 17Bit Software */ /* in England for being the first to send this to me. */ /* */ /* VKill: This one doesn't think it's a virus, and depending on */ /* your point of view, it might not be. It won't write itself to */ /* a nonstandard boot block - so it won't hurt games. But it will */ /* still load into your system, vector your PutMsg() routine */ /* through itself, sit on your supervisor stack, without telling */ /* you. Not good. I have had this one for a while, trying to */ /* decide what to do with it - I guess what convinced me is the */ /* fact that the text message which identifies itself is actually */ /* ENCRYPTED - for a virus killer, this is a pretty questionable */ /* thing to do. */ /* */ /************************************************************************/ /* */ /* 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-( ) */ /* */ /************************************************************************/ #include "virusx.h" #include "virusx.i" void MemCleanup() {} extern struct DOSBase *DOSBase; void chkabort(void) {} int ReadBlock(int block, APTR loc); #define BREAK (SetSignal(0,0) & SIGBREAKF_CTRL_C) /******************************************************************/ /* These string constants are used in multiple places, and thus */ /* save bytes by having only one copy of them. */ /******************************************************************/ char TITLETEXT[] = "VirusX 4.00 by Steve Tibbett"; char CHECKINGTEXT[] = "VirusX: Checking Device DF0:"; char TDName[] = "trackdisk.device"; char ITBodyText[80]; char text[] = "DF?: Boot Sectors"; char BGSCheck[] = { 'D','E','V','S','/',0xa0,0xa0,0xa0,0x20,0x20,0x20,0xa0,0x20,0x20,0x20,0xa0,0x00 }; /**********************************************************************/ /* The Big One */ /**********************************************************************/ extern struct VirusInfo VI[]; /************************************************************************/ /* 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 = FALSE; /* TRUE if the window is big */ int VirusesInBigWindow; /* For setting big window size */ struct Port *diskport; /* trackdisk's port. */ struct IOStdReq *diskreq; /* trackdisk's IOStdReq */ long DisksChecked, DisksInstalled; /* for title bar info */ struct Process *Me; /* for setting the WindowPtr */ int WindowYDelta; /* Big Window Y Size Change */ char CaptureCheck = TRUE; char KickTagCheck = FALSE; char CheckAndQuit = FALSE; char SetPatchFlag = FALSE; struct IntuitionBase *IntuitionBase; /* For Library Bindings */ struct GfxBase *GfxBase; struct Window *Window; struct IntuiMessage *Message; struct ExecBase *ExecBase; struct Screen *Screen; 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. */ void RenderItem(char *Item, int Value); 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; unsigned char *diskbuffer; /************************************************************************/ /* Warning messages. These messages get modified before being */ /* displayed (Unless you DO have a DF9:) */ /************************************************************************/ char TEXTPTR[] = "Danger: The disk in DF?: is"; char NBCTEXT[] = "Danger: The disk in DF?: has"; /*************************************************************************/ /* 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}; /**********************************************************************/ /* It all starts here */ /**********************************************************************/ int main(int argc, char **argv) { x=1; while (argv[x] != 0) { if (argv[x][0] == '-') { switch (toupper(argv[x][1])) { case 'A': NewWindow.Flags |= ACTIVATE; break; case 'C': CaptureCheck = FALSE; break; case 'K': KickTagCheck = TRUE; break; case 'Q': CheckAndQuit = TRUE; break; case 'R': SetPatchFlag = TRUE; break; case 'X': NewWindow.LeftEdge = atoi(&argv[x][2]); break; case 'Y': NewWindow.TopEdge = atoi(&argv[x][2]); break; }; }; x++; }; if ((diskbuffer = AllocMem((long)1024, (long)MEMF_CHIP|MEMF_CLEAR)) == 0) goto OuttaHere; /* These had better not ever fail. If they do, something's Very wrong. */ IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0L); GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0L); ExecBase = (struct ExecBase *)OpenLibrary("exec.library", 0L); Me = (struct Process *)FindTask(0L); Me->pr_WindowPtr = 0; /* We use the same port/request through the whole program. Works OK. */ diskport = CreatePort(0L,0L); diskreq = CreateStdIO(diskport); if ((Window = OpenWindow(&NewWindow)) == NULL) goto Quitter; RP = Window->RPort; Screen = Window->WScreen; /* Set the ChangeCount for the Trackdisk devices */ SetUp(); /* Check RAM out... */ CheckMemoryForViruses(); CheckMemoryForLinkViruses(); CheckBlock(); if (!CheckAndQuit) DoLittle(); Quitter: if (Window != 0) CloseWindow(Window); if (diskport != 0) DeletePort(diskport); if (diskreq != 0) DeleteStdIO(diskreq); FreeMem(diskbuffer, (long)1024 ); OuttaHere: CloseLibrary(GfxBase); CloseLibrary(IntuitionBase); CloseLibrary((struct Library *)ExecBase); return(0); } /**********************************************************************/ /* This is the main VirusX loop. */ /**********************************************************************/ void DoLittle(void) { long Code, Class; /* for storing our IntuiMessage stuff */ char KG2; /* KeepGoing 2. Another boolleean. */ int phase; KG2 = TRUE; SetAPen(RP, 1L); SetBPen(RP, 0L); SetDrMd(RP, (long)JAM2); phase = 0; while (KG2 == TRUE) { if (BREAK) break; Message = (struct IntuiMessage *)GetMsg(Window->UserPort); if (Message == 0) { WaitTOF(); WaitTOF(); WaitTOF(); /* I don't trust Delay() anymore */ WaitTOF(); WaitTOF(); WaitTOF(); if (++phase > 20) { phase = 0; CheckMemoryForLinkViruses(); }; continue; }; Class = Message->Class; Code = Message->Code; ReplyMsg((struct Message *)Message); switch (Class) { case CLOSEWINDOW: KG2 = FALSE; break; case MOUSEBUTTONS: if (Code == MENUDOWN) ToggleBigWindow(); break; case VANILLAKEY: switch (toupper(Code)) { case 'I': ToggleBigWindow(); break; case 'C': for (x=0; x<4; x++) ChangeCount[x] = 10000; CheckBlock(); break; case 27: KG2 = FALSE; break; default: flag = ShowAscii(Code); if (flag == 1) CheckBlock(); }; break; case DISKINSERTED: CheckBlock(); break; }; if (WindowBig) RenderInfo(); }; } /************************************************/ /* Opens trackdisk, finds out who's out there, */ /* and sets Changecount up accordioningly. */ /************************************************/ void SetUp(void) { 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 */ /*********************************************************/ int WhoChanged(void) { int 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.*/ /****************************************************************/ void CheckBlock(void) { long Sum, a, Unit; unsigned long *iptr, *ptr; char drivename[10]; while ((Unit = WhoChanged()) != -1) { short VirusFound = -1, x = 0, Virus = FALSE; CHECKINGTEXT[26] = '0'+Unit; SetWindowTitles(Window, CHECKINGTEXT, (STRPTR)-1); strcpy(drivename, "DF0:"); drivename[2] = '0'+Unit; /* Unit # to open is returned by "WhoChanged()" up above. */ if (Unit == -1) continue; error = OpenDevice(TDName,(long)Unit,diskreq,0L); if (error > 0) continue; error = ReadBootBlock(); DisksChecked++; CloseDevice(diskreq); if (error == FALSE) continue; ptr = (long *)diskbuffer; iptr = (long *)diskbuffer; if (iptr[0] != ID_DOS_DISK) continue; 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) { CheckDriveForLinkViruses(drivename); continue; /* if it's not bootable, we DONT want it! */ }; while (VI[x].Name != 0) { if (Virus == TRUE) break; if (iptr[VI[x].LongWordOffsets[0]] == VI[x].WhatToExpect[0]) if (iptr[VI[x].LongWordOffsets[1]] == VI[x].WhatToExpect[1]) { VI[x].NumFound++; VirusFound = x; Virus = TRUE; break; }; x++; }; /* compare boot block with real boot block. If it's not, notify */ if (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; /* Should check Copy Count flag sometime... */ if (VirusFound != -1) error = MyRequest(VI[VirusFound].Name, 1); else { /* Probably just a custom boot block (or a new virus...) */ char buf[200]; strcpy(buf, NBCTEXT); strcat(buf, "|Nonstandard Boot Code!"); WBenchToFront(); error = SimpleRequest(buf, "Ignore It|Repair It", Window, 0); } if (error != 0)  DoInstall(Unit); /* user wants it neutered. */ }; CheckDriveForLinkViruses(drivename); }; /* End of While Whochanged */ SetWindowTitles(Window, TITLETEXT, (STRPTR)-1); } /********************************************/ /* This is where the boot code gets changed */ /********************************************/ void DoInstall(int un) { int x; /* Rewrite disk? Really? */ error = SimpleRequest("Install New Bootblock?|Are you sure?", "No, Cancel|Yes, Do It", Window, 0); if (error == 0) return; /* user changed his brain. */ DisksInstalled++; error = OpenDevice(TDName, (long)un,diskreq,0L); if (error > 0) return; while (ProtStatus() == TRUE) { error = SimpleRequest("The disk is write protected.", "Forget It|Try Again", Window, 0); if (error != 0) /* error is true or false, depending on user */ continue; CloseDevice((struct IOStdReq *)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((struct IOStdReq *)diskreq); error = diskreq->io_Error; if (error < 19 && error != 29) { diskreq->io_Command = CMD_UPDATE; /* flush buffer to disk */ DoIO((struct IOStdReq *)diskreq); error = diskreq->io_Error; }; MotorOff(); if (error > 19 && error != 29) SetWindowTitles(Window, "Disk Error!", (STRPTR)-1); else SetWindowTitles(Window, "Disk Healed.", (STRPTR)-1); Delay(75L); SetWindowTitles(Window, TITLETEXT, (STRPTR)-1); CloseDevice((struct IOStdReq *)diskreq); } /**********************************************************************/ /* Turn off the Disk Motor */ /**********************************************************************/ void MotorOff(void) { diskreq->io_Length = 0; diskreq->io_Command = TD_MOTOR;/* Motor Off */ DoIO(diskreq); } /* This has to be global */ unsigned long *TD; /**********************************************************************/ /* Check RAM for Known Viruses from Database */ /**********************************************************************/ void CheckMemoryForViruses(void) { short x = 0, y; short LookFlags; char AlertFlag; unsigned long *EB; EB = (unsigned long *)ExecBase; TD = (unsigned long *)FindName(&ExecBase->DeviceList, "trackdisk.device"); while (VI[x].Name != 0) { AlertFlag = FALSE; /* * * Check First * * */ if (VI[x].Handler != 0) AlertFlag = ((VI[x].Handler)()); else for (y=0; y<2; y++) { LookFlags = VI[x].HowToLook[y]; if (LookFlags == 0) continue; if (LookFlags & HTL_TDM1C) { unsigned long *TTD = TD; TTD = TTD - (0x1c / 4); if (LookFlags & HTL_LOOKINDIRECT) TTD = (unsigned long *)*TTD; TTD = (char *)(((unsigned long)TTD)+VI[x].LookOffset[y]); if (*TTD == VI[x].WhatToLookFor[y]) { AlertFlag = TRUE; } else AlertFlag = FALSE; }; if (LookFlags & HTL_DOIO) { unsigned long *TEB; TEB = (char *)(((unsigned long)EB)-0x1c6); if (LookFlags & HTL_LOOKINDIRECT) TEB = (unsigned long *)*TEB; TEB = (char *)(((unsigned long)TEB)+VI[x].LookOffset[y]); if (*TEB == VI[x].WhatToLookFor[y]) { AlertFlag = TRUE; } else AlertFlag = FALSE; }; if (LookFlags & HTL_ABSOLUTE) { unsigned short *S; S = VI[x].WhatToLookFor[y]; if (*S == VI[x].LookOffset[y]) AlertFlag = TRUE; }; /* * * DONE CHECKING, NOW FIX * * */ if (AlertFlag == TRUE) { for (y=0; y<2; y++) { unsigned long *Dest; LookFlags = VI[x].DoToThis[y]; if (LookFlags == 0) continue; if (LookFlags & HTL_CLEARKICKTAGS) ExecBase->KickTagPtr = 0; if (LookFlags & HTL_SETLONG) { unsigned long *ptr; ptr = VI[x].WhatToLookFor[0]; *ptr = VI[x].WhatToLookFor[1]; }; if (LookFlags & HTL_TDM1C) { unsigned char *t; unsigned long *TEB; t = (unsigned char *)TD; t = t - 0x1c; TEB = (unsigned long *)t; Dest = TEB; TEB = (unsigned long *)*TEB; t = (char *)TEB; t = t + VI[x].AtOffset[y]; TEB = (unsigned long *)t; Forbid(); if (LookFlags & HTL_SETTO) { *TEB = VI[x].WithThis[y]; } else Dest[0] = *TEB; Permit(); }; if (LookFlags & HTL_DOIO) { unsigned char *t; unsigned long *TEB; t = (unsigned char *)EB; t = t - 0x1c6; TEB = (unsigned long *)t; Dest = TEB; TEB = (unsigned long *)*TEB; t = (char *)TEB; t = t + VI[x].AtOffset[y]; TEB = (unsigned long *)t; Forbid(); if (LookFlags & HTL_SETTO) *TEB = VI[x].WithThis[y]; else { Dest[0] = *TEB; }; Permit(); }; }; }; }; /* Do this AFTER processing the REAL removal. */ if (VI[x].CoolCapture != 0) { if ((long *)ExecBase->CoolCapture == (long *)VI[x].CoolCapture) { ExecBase->CoolCapture = 0; AlertFlag = TRUE; }; }; if (AlertFlag == TRUE) { MyRequest(VI[x].Name, 2); }; x++; } if ((ExecBase->CoolCapture != NULL) && CaptureCheck) { if (SetPatchFlag) if ((ExecBase->CoolCapture>(APTR)0x80000) && (ExecBase->CoolCapture<(APTR)0x100000)) goto SkipCoolCapCheck; x = SimpleRequest("The system's CoolCapture Vector|is not Zero. This could mean a new|Virus is in RAM, or that some other program|is using this vector. See the|VirusX Documentation for more info.|Clear it?", " Yes | No ", Window, 0); if (x == 0) ExecBase->CoolCapture = NULL; }; if ((ExecBase->ColdCapture != NULL) && CaptureCheck) { if (SetPatchFlag) if ((ExecBase->ColdCapture>(APTR)0x80000) && (ExecBase->ColdCapture<(APTR)0x100000)) goto SkipCoolCapCheck; x = SimpleRequest("The system's ColdCapture Vector|is not Zero. This could mean a new|Virus is in RAM, or that some other program|is using this vector. See the|VirusX Documentation for more info.|Clear it?", " Yes | No ", Window, 0); if (x == 0) ExecBase->ColdCapture = NULL; }; SkipCoolCapCheck: if ((ExecBase->KickTagPtr != NULL) && (KickTagCheck == TRUE)) { x = SimpleRequest("The system's KickTagPtr Vector|is not Zero. This could mean a new|Virus is in RAM, or that some other program|is using this vector. See the|VirusX Documentation for more info.|Clear it?", " Yes | No ", Window, 0); if (x == 0) ExecBase->KickTagPtr = NULL; }; } /**************************************************************/ /* This is the routine that displauys a block as ASCII text. */ /**************************************************************/ int ShowAscii(long key) { int drive, x, y, deltax, deltay; long a; int FLAG=0; drive = key - '0'; if ((drive < 0) || (drive > 3) || (ChangeCount[drive] == -1)) return(0); if ((error = OpenDevice(TDName,(long)drive,diskreq,0L)) > 0) return(0); error = ReadBootBlock(); CloseDevice(diskreq); if (error == FALSE) return(0); /* save the amount we moved the window */ deltax = Window->LeftEdge; deltay = Window->TopEdge; WindowToFront(Window); MoveWindow(Window, -deltax, -deltay); SizeWindow(Window, 278L, 160-WindowYDelta); 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<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); SetAPen(RP, 0L); RectFill(RP, 2, 12, 278, 167); SetWindowTitles(Window, TITLETEXT, (STRPTR)-1); SizeWindow(Window, -278L, -160+WindowYDelta); WaitForNewSize(); if (WindowBig) RenderInfo(); /* deltas plus current position, in case dude moved the window */ MoveWindow(Window, deltax+(-Window->LeftEdge), deltay+(-Window->TopEdge)); Delay(10L); 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. */ /**********************************************************************/ void WaitForNewSize(void) { int Class; while (TRUE) { WaitPort(Window->UserPort); Message = (struct IntuiMessage *)GetMsg(Window->UserPort); Class = Message->Class; ReplyMsg((struct Message *)Message); if (Class != MOUSEBUTTONS) break; }; } /**********************************************************************/ /* Make an AutoRequest. */ /* */ /* Types: */ /* */ /* 1: "is infected with the xxx VIRUS!" */ /* 2: "NOTICE: The `blah' VIRUS was found..." */ /* 3: Cold/capture warning. */ /**********************************************************************/ int MyRequest(char *string, int type) { char buf[255]; switch (type) { case 1: strcpy(ITBodyText, "infected with the `"); strcat(ITBodyText, string); strcat(ITBodyText, "' VIRUS!"); break; case 2: strcpy(ITBodyText, "NOTICE: The `"); strcat(ITBodyText, string); strcat(ITBodyText, "' VIRUS was found"); break; }; WBenchToFront(); switch (type) { case 1: strcpy(buf, TEXTPTR); strcat(buf, "|"); strcat(buf, ITBodyText); return(SimpleRequest(buf, "Ignore It|Repair It", Window, 0)); case 2: strcpy(buf, "NOTICE:|The "); strcat(buf, string); strcat(buf, " VIRUS was found|in memory, and is now Disabled.|Please see the VirusX Documentation|for more information."); return(SimpleRequest(buf, " Will Do. ", Window, SR_ANYKEYQUIT)); }; } /**********************************************************************/ /* Reads the first 1024 bytes into the 'diskbuffer' */ /**********************************************************************/ int ReadBootBlock(void) { if (ReadBlock(0, (APTR)diskbuffer) == FALSE) return(FALSE); /* If we got block 0, Block 1 cannot possibly fail. */ ReadBlock(1, (APTR)&diskbuffer[512]); return(TRUE); } /**********************************************************************/ /* Read a sector to the given memory location */ /**********************************************************************/ int ReadBlock(int block, APTR loc) { diskreq->io_Command = CMD_READ; diskreq->io_Data = loc; diskreq->io_Length = 512; diskreq->io_Offset = block*512; DoIO((struct IOStdReq *)diskreq); if (diskreq->io_Error > 0) return(FALSE); Delay(5); MotorOff(); return(TRUE); } /**********************************************************************/ /* Shove diskbuffer to disk. */ /**********************************************************************/ int WriteBlock(long block) { diskreq->io_Length = 512; diskreq->io_Data = (APTR)diskbuffer; diskreq->io_Command = CMD_WRITE; diskreq->io_Offset = block*512; DoIO(diskreq); if(diskreq->io_Error > 19) return(FALSE); diskreq->io_Command = ETD_UPDATE; DoIO(diskreq); MotorOff(); } /**********************************************************************/ /* Return TRUE if disk is not writable. */ /**********************************************************************/ int ProtStatus(void) { diskreq->io_Flags = 0; diskreq->io_Command = TD_PROTSTATUS; DoIO(diskreq); if(diskreq->io_Error == TDERR_DiskChanged) return TRUE; if(diskreq->io_Actual) return TRUE; return FALSE; } /**********************************************************************/ /* Look for any virus that might appear other than at boot time */ /**********************************************************************/ void CheckMemoryForLinkViruses(void) { if (CheckRAMForIRQ() == 1) MyRequest("IRQ", 2); if (CheckRAMForXeno() == 1) SimpleRequest("A program you ran contained the Xeno virus.|It has been removed from RAM, but VirusX will not|extensively search for it on disk.|Use the KV Utility to check recently executed files.", " Thanks ", Window, SR_ANYKEYQUIT); CheckRamForLamer(); } /**********************************************************************/ /* Check the disk for any non-bootblock Viruses */ /**********************************************************************/ void CheckDriveForLinkViruses(char *drivename) { int err; char buffer[200]; char dirbuffer[80]; char filebuffer[100]; char fnamebuffer[100]; char ssbuffer[80]; char sscommand[80]; char pass; BPTR fp = 0; /** Check for RLamer Virus **/ CheckDiskForRLamer(drivename[2]-'0'); /** GET FIRST COMMAND IN S.S. FOR USE IN CHECKING FOR ANY VIRUS **/ ssbuffer[0] = 0; strcpy(buffer, drivename); strcat(buffer, "S/Startup-Sequence"); fp = Open(buffer, MODE_OLDFILE); if (fp != 0) { /* It's faster to do a single read and find the end of the string myself, than it is to read the S-S character by character */ Read(fp, sscommand, 80); for (x=0; x<80; x++) { if (sscommand[x] == 32 || sscommand[x] == 10 || sscommand[x] == ';') { sscommand[x] = 0; break; }; }; } Close(fp); fp = 0; /** Check for BGS9 Virus **/ strcpy(buffer, drivename); strcat(buffer, BGSCheck); fp = Lock(buffer, ACCESS_READ); if (fp != 0) { BPTR vfp; long VL; vfp = 0; strcpy(buffer, drivename); strcat(buffer, sscommand); vfp = Open(buffer, MODE_OLDFILE); if (vfp == 0) { strcpy(buffer, drivename); strcat(buffer, "C/"); strcat(buffer, sscommand); vfp = Open(buffer, MODE_OLDFILE); if (vfp == 0) { strcpy(buffer, "The disk in "); strcat(buffer, drivename); strcat(buffer, "apparently has been|affected by the BGS9 Virus, but|I cannot find the Virus itself.|See the Documentation for more info."); SimpleRequest(buffer, " Okay ", Window, SR_ANYKEYQUIT); goto OuttaHereNow; } }; /** Now vfp is the virus's file pointer **/ Seek(vfp, 0, OFFSET_END); VL = Seek(vfp, 0, OFFSET_BEGINNING); if (VL != 2608) { char buff[255]; strcpy(buff, "A virus that looks like BGS9 was found,|on the file "); strcat(buff, buffer); strcat(buff, ",|but it's Not the BGS9 virus. You should examine|this file, and the 'Devs' directory on that disk."); SimpleRequest(buff, "Oh No!", Window, 0); } else { char nbuff[80]; int err; Close(vfp); vfp = 0; err = DeleteFile(buffer); if (err != 0) { strcpy(nbuff, drivename); strcat(nbuff, BGSCheck); err = Rename(nbuff, buffer); if (err != 0) { strcpy(buffer, "BGS9 Virus removed from "); strcat(buffer, drivename); SimpleRequest(buffer, " Thank you ", Window, 0); goto OuttaHereNow; }; }; strcpy(buffer, "Error removing BGS9 virus from|device "); strcat(buffer, drivename); strcat(buffer, ", file "); strcat(buffer, sscommand); strcat(buffer, ".|Check your startup sequence (the first command in it),|and look in the DEVS directory."); SimpleRequest(buffer, " Thank you ", Window, 0); }; if (vfp != 0) Close(vfp); }; OuttaHereNow: /** Check for IRQ **/ pass = 0; while (TRUE) { if (pass == 3) break; if (pass > 1 && sscommand[0] == 0) break; switch (pass) { case 0: /* Check DF0:C/DIR */ strcpy(dirbuffer, drivename); strcat(dirbuffer, "C/"); strcpy(filebuffer, "DIR"); break; case 1: /* Check Startup-Sequence */ strcpy(dirbuffer, drivename); strcat(dirbuffer, "C/"); strcpy(filebuffer, sscommand); break; case 2: /* Check the drive for the ssname */ strcpy(dirbuffer, drivename); strcpy(filebuffer, sscommand); break; }; pass++; strcpy(fnamebuffer, dirbuffer); strcat(fnamebuffer, filebuffer); /* if return is 1, we go it. */ err = CheckFileForIRQ(fnamebuffer, 0); if (err == 1) { strcpy(buffer, "NOTICE: The IRQ Virus was found|on the file '"); strcat(buffer, fnamebuffer); strcat(buffer, "'.|Okay to remove?"); WBenchToFront(); err = SimpleRequest(buffer, "Leave it|Remove it", Window, 0); if (err == 0) continue; while (TRUE) { err = CheckFileForIRQ(fnamebuffer, 1); if (err == 1) { SetWindowTitles(Window, "Disk Healed.", (STRPTR)-1); Delay(75); SetWindowTitles(Window, TITLETEXT, (STRPTR)-1); break; } else { err = SimpleRequest("Error removing.|Disk may be write protected.|Try Again?", "Cancel|Retry", Window, 0); if (err == 0) break; } }; }; }; } /**********************************************************************/ /* Switches between the big, rendered-in window, and the small one. */ /**********************************************************************/ void ToggleBigWindow(void) { if (Window == 0) return; VirusesInBigWindow = 0; if (WindowBig == FALSE) { /* Make window big: Step 1, Figure Y Height Needed */ WindowYDelta = 24; /* Start at 24: DisksChecked, DisksInstalled */ x=0; while (VI[x].Name != 0) { if (VI[x].NumFound != 0) { VirusesInBigWindow++; WindowYDelta += 9; }; x++; }; if ((Window->TopEdge+Window->Height+WindowYDelta) > Screen->Height) MoveWindow(Window, 0, -Window->TopEdge); SizeWindow(Window, 0, WindowYDelta); WaitForNewSize(); WindowBig = TRUE; RenderInfo(); } else { /** Make Window Small **/ SizeWindow(Window, 0, -WindowYDelta); WaitForNewSize(); WindowYDelta = 0; WindowBig = FALSE; } } /**********************************************************************/ /* Render the Info Window */ /**********************************************************************/ int ItemY; void RenderInfo(void) { int Num = 0, x = 0, Delta; char buff[80]; while (VI[x].Name != 0) { if (VI[x].NumFound != 0) Num++; x++; }; Delta = (Num-VirusesInBigWindow)*9; if (Delta != 0) { if ((Window->TopEdge+Window->Height+Delta) > Screen->Height) MoveWindow(Window, 0, -Window->TopEdge); SizeWindow(Window, 0, Delta); WindowYDelta += Delta; WaitForNewSize(); }; VirusesInBigWindow = Num; ItemY = 17; SetAPen(RP, 1); SetDrMd(RP, JAM2); RenderItem("Disks Checked:", DisksChecked); RenderItem("Disks Installed:", DisksInstalled); ItemY += 3; x=0; while (VI[x].Name != 0) { if (VI[x].NumFound != 0) { strcpy(buff, VI[x].Name); strcat(buff, " Found:"); RenderItem(buff, VI[x].NumFound); }; x++; }; } /**********************************************************************/ /* Draw an item into the Big Window */ /**********************************************************************/ void RenderItem(char *Item, int Value) { char buff[10]; int Len = strlen(Item); SetAPen(RP, 0); RectFill(RP, 2, ItemY-7, Window->Width-3, ItemY+2); SetAPen(RP, 1); Move(RP, 214-(Len*8), ItemY); Text(RP, Item, Len); Move(RP, 220, ItemY); Len = itoa(buff, Value); while (strlen(buff) < 6) strcat(buff, " "); Text(RP, buff, 5); ItemY += 9; } /**********************************************************************/ /* Convert integer to ASCII */ /**********************************************************************/ int itoa(char *buff, int value) { char buf2[11]; int len = 0; int i = 0; do { buf2[len++] = '0'+(value%10); value = value / 10; } while (value > 0); len--; while (len != -1) { buff[i++] = buf2[len--]; }; buff[i] = 0; return(i); } /**********************************************************************/ /* Do some IRQ Hunting */ /**********************************************************************/ #define VTAG 0x00000109L #define SLONG ((long)sizeof(long)) #define OK 1 /* no error */ #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 */ long inp, *buff, size; int cleanup(int val) { if(inp) Close(inp); if(buff) FreeMem(buff,size); return val; } /**********************************************************************/ /* Check the passed filename for IRQ Virus. */ /* If flag is FALSE, then just determine, don't remove. */ /**********************************************************************/ int CheckFileForIRQ(char *fname, int flag) { BPTR flock; int i = 0; long nhunk; long tbuff[488/4]; buff = 0L; if ((inp = Open(fname, MODE_OLDFILE)) == FALSE) return(FALSE); Read(inp, (char *)&tbuff[0], 487); /* get the first long word */ if(tbuff[0] != 0x000003F3) /* check for executable file */ return cleanup(FALSE); if(tbuff[5] != VTAG) return cleanup(FALSE); Seek(inp,0L,OFFSET_END); /* seek to end of file */ size = Seek(inp,0L,OFFSET_BEGINNING); /* rewind the file to get size */ if(size <= 0L) return cleanup(FALSE); if((buff = AllocMem(size,0L)) == 0) /* mem buffer for file */ return cleanup(FALSE); if(Read(inp,(char *)&buff[0],size) != size) /* read entire file into buffer */ return cleanup(FALSE); nhunk = buff[ 2 ]; /* number of hunks in file */ while(buff[ i++ ] != 0x000003E9) ; if( ((buff[ i+1 ] & 0x0000FFFF) != VSIG1) || ((buff[ i+2 ] & 0xFFFF0000) != VSIG2) ) return cleanup(FALSE); if (!flag) return cleanup(1); Close(inp); if((inp = Open(fname,MODE_NEWFILE)) == 0) return cleanup(FALSE); buff[2] -= 1; buff[4] -= 1; /* readjust program header info */ if(Write(inp,(char *)&buff[0],5L*SLONG) != 5L*SLONG) return cleanup(FALSE); if(Write(inp,(char *)&buff[6],nhunk*SLONG) != nhunk*SLONG) return cleanup(FALSE); i = i + 8L + VTAG; size = (size/SLONG - i)*SLONG; if(Write(inp,(char *)&buff[i],size) != size) return cleanup(FALSE); return cleanup(1); }