/* VirusX - by Steve Tibbett The complete Virus Elimination System! 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 (but not copyrighted) on the disk also!) */ /* History: A few weeks ago: V1.0 written. A few days later: V1.01 released - V1.0 wrote garbage when disk was Write Prot. 27-Mar-88: V1.2 - Added Byte Bandit RAM detection, and disk detection. (Actually, it's well after Midnight - make that 28-Mar-88) Just after uploading V1.2 to Amic BBS: Realized I put the wrong version in the ARC file - Had to rename V1.2 to V1.21... */ /* Created with Aztec C V3.4b using 32 bit ints. */ /* - Ok, it's not the cleanest code in the world - it was written in two days, for a specific purpose, and it works! */ struct Port *diskport; /* disk's port.*/ struct IOStdReq *diskreq; /* disk's IOStdReq */ int DisksChecked, DisksInstalled, SCAFound; /* for title bar info */ char titlebuffer[80]; /* Who needs includes with Aztec? Everything's precompiled! */ #include /* Ok, ONE include... */ /* Amount of boot code we've got (approx): */ #define BSIZE 40 char TDName[] = "trackdisk.device"; /* Saves space */ int ChangeCount[4]; /* TD_CHANGECOUNT for all 4 drives */ int LastSum; /* Used in the checksumming */ int CheckDrives; /* Boolean, from the command line */ int error; /* sort of a temporary variable sort of */ unsigned char diskbuffer[3*512];/* Everything ends up in here. I suppose I should have AllocMem'ed this, but it's SO easy this way */ /* 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, 0, 0, 3, 0x70, 0x43, 0xfa, 0, 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,0,0,0,0,0}; /* for IntuiText's */ char def_font[] ="topaz.font"; struct TextAttr TxtAt_Plain = { (UBYTE *)def_font, 8, FS_NORMAL, FPF_ROMFONT}; /*** Non SCA warning requester IntuiText's ***/ struct IntuiText Body2 = { 0, 1, JAM2, 20,18, &TxtAt_Plain,(UBYTE *)"Nonstandard Boot Code!", NULL }; struct IntuiText Body1 = { 0, 1, JAM2, 20, 8, &TxtAt_Plain, (UBYTE *)NBCTEXT, &Body2 }; struct IntuiText Pos = { 0, 1, JAM2, 7,3, &TxtAt_Plain, "Remove it", NULL }; struct IntuiText Neg = { 0, 1, JAM2, 7,3, &TxtAt_Plain, "Ignore it", NULL }; /***** SCA Danger Requester IntuiText's ******/ struct IntuiText SCABody2 = { 0, 1, JAM2, 20,18, &TxtAt_Plain,(UBYTE *) "infected with an SCA Virus!!", NULL }; struct IntuiText SCABody = { 0, 1, JAM2, 20, 8, &TxtAt_Plain, (UBYTE *)TEXTPTR, &SCABody2 }; struct IntuiText SCAPos = { 0, 1, JAM2, 7,3, &TxtAt_Plain, "Remove it", NULL }; struct IntuiText SCANeg = { 0, 1, JAM2, 7,3, &TxtAt_Plain, "Ignore it", NULL }; /***** BBANDIT Requester IntuiText's ******/ struct IntuiText BBDiskbody3 = { 0, 1, JAM2, 20,30, &TxtAt_Plain, CopyText, NULL }; struct IntuiText BBDiskbody2 = { 0, 1, JAM2, 20,18, &TxtAt_Plain,(UBYTE *) "infected with the Byte Bandit VIRUS!", &BBDiskbody3}; struct IntuiText BBDiskbody = { 0, 1, JAM2, 20, 8, &TxtAt_Plain, (UBYTE *)TEXTPTR, &BBDiskbody2 }; /***** BBandit Notice - Removed from Memory ****/ struct IntuiText BBMem3 = { 0, 1, JAM2, 20,8, &TxtAt_Plain,(UBYTE *) "NOTICE: The Byte Bandit VIRUS was found", NULL }; struct IntuiText BBMem2 = { 0, 1, JAM2, 20,18, &TxtAt_Plain,(UBYTE *) "in memory, and is now disabled. See the", &BBMem3 }; struct IntuiText BBMem1 = { 0, 1, JAM2, 20,28, &TxtAt_Plain,(UBYTE *) "documentation for more information!", &BBMem2 }; struct IntuiText BBMPos = { 0, 1, JAM2, 7,3, &TxtAt_Plain, " Thanks! ", NULL }; struct IntuiText BBMNeg = { 0, 1, JAM2, 7,3, &TxtAt_Plain, " Thanks! ", NULL }; /***** 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 }; struct IntuitionBase *IntuitionBase; struct GfxBase *GfxBase; struct Window *LittleWindow; struct IntuiMessage *Message; struct RastPort *RP; int Keepgoing; /* a boolean flag. it's false when we want out. */ int x, y, i; /* left over from my using Basic */ /*** The Newwindow Structure. ***/ char TITLETEXT[] = "VirusX 1.30 by Steve Tibbett"; struct NewWindow NewLittleWindow = { 128, /* Left, Top, Width, Height */ 0, 309, 10, 0, /* Frontpen, Backpen */ 1, DISKINSERTED | CLOSEWINDOW | VANILLAKEY | MOUSEBUTTONS, /* IDCMP Flagz */ WINDOWDRAG | WINDOWDEPTH | RMBTRAP | WINDOWCLOSE | NOCAREREFRESH, /* Windo Flagz */ NULL, NULL, TITLETEXT, /* My name. Dont touch it!! */ NULL, NULL, 0, 0, 0, 0, WBENCHSCREEN, }; /*********************Da Beginnin*************************/ _main() { int OldPri; /* Come on, folks, is intuition ever NOT going to be available???? */ IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0); /* Same with GfxBase. If GfxBase is gone, we DESERVE to crash. */ GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0); /* Save OldPri so we can restore it later on. We're so nice. */ OldPri = SetTaskPri(FindTask(0), 19); /* and stick us up high. */ diskport = CreatePort(0,0); diskreq = CreateStdIO(diskport); SetUp(); /* Fake the changecount to 1000. */ for (x = 0; x < 4; x++) ChangeCount[x] = 1000; CheckBlock(); /* CheckBlock() checks boot block for virus. */ CheckMemoryForViruses(); /* New to 1.2 - Check is Byte Bandit in RAM? */ DoLittle(); /* The main loop. Do Little. Ya. */ /* restore priorities to saneness, and take off, eh? */ SetTaskPri(FindTask(0), OldPri); DeletePort(diskport); DeleteStdIO(diskreq); exit(FALSE); } /*********************/ DoLittle() { register int Code; register int Class; /* gee */ register int KG2; /* KeepGoing 2. Another booleean. */ LittleWindow = OpenWindow(&NewLittleWindow); if (LittleWindow == NULL) exit(400L); /* No memory to open little window! */ KG2 = TRUE; RP = LittleWindow->RPort; /* easier than typing Move(LittleWindow->RP... all the time */ SetAPen(RP, 1); SetBPen(RP, 0); SetDrMd(RP, JAM2); /* ya. JAM 2! Love that name! */ while (KG2 == TRUE) { sprintf(titlebuffer, "VirusX: Disks Checked: %d Disks Installed: %d Viruses Found: %d", DisksChecked, DisksInstalled, SCAFound); SetWindowTitles(LittleWindow, -1, titlebuffer); Message = GetMsg(LittleWindow->UserPort); while (Message == NULL) { /* Lets be nice to other tasks! Ya! */ Wait(1<UserPort->mp_SigBit); Message = GetMsg(LittleWindow->UserPort); }; Class = Message->Class; Code = Message->Code; if (Message != NULL) ReplyMsg(Message); if (Class == CLOSEWINDOW) { CloseWindow(LittleWindow); exit(FALSE); }; if (Class == DISKINSERTED) CheckBlock(); }; /* KG2 = false, we fell thru to here. Ow. */ CloseWindow(LittleWindow); return; } /********************/ /* Opens trackdisk, finds out who's out there, and sets Changecount up accordioningly. */ /********************/ SetUp() { for (x = 0; x < 4; x++) /* go thru all 4 possible drives */ { ChangeCount[x] = 1000; error = OpenDevice(TDName,x,diskreq,0); if (error > 0) continue; /* no drive here */ }; } /********************************/ /* This routine returns which drive changed disks lately */ /********************************/ WhoChanged() { int RetVal; /* The value we'll return */ RetVal = -1; /* return -1 if all else fails */ for (x = 0; x < 4; x++) { if (ChangeCount[x] == 0) continue; /* no drive here */ error = OpenDevice(TDName,x,diskreq,0); if (error > 0) continue; /* no drive here */ diskreq->io_Command = TD_CHANGESTATE; DoIO(diskreq); if (diskreq->io_Actual != 0) { continue; }; diskreq->io_Command = TD_CHANGENUM; DoIO(diskreq); if (diskreq->io_Actual != ChangeCount[x]) { RetVal = x; ChangeCount[x] = diskreq->io_Actual; CloseDevice(diskreq); goto Out; }; CloseDevice(diskreq); }; Out:; return(RetVal); } /********************************/ CheckBlock() { int Sum, Bootable, Virus; /* Virus is a flag, Bootable is a flag, Sum the cksum. */ int BBandit; /* BBandit is a flag too. Oh well. */ int a, Unit; int SCA; /* don't get scared, it's just a flag. */ while ((Unit = WhoChanged()) != -1) { DisksChecked++; SCA = FALSE; BBandit = FALSE; /* Unit # to open is returned by "WhoChanged()" up above. */ if (Unit == -1) return; error = OpenDevice(TDName,Unit,diskreq,0); if (error > 0) return; /* I've heard stories that pulling a read request to block zero with a length of 1024 will cause the virus to write itself back. Not taking any chances. */ diskreq->io_Command = CMD_READ; diskreq->io_Data = diskbuffer; diskreq->io_Length = 3*512; diskreq->io_Offset = 0; DoIO(diskreq); diskreq->io_Length = 0; diskreq->io_Command = TD_MOTOR; DoIO(diskreq); /* turn off motor */ if (diskreq->io_Error > 19) return; /* disk error, lemme out */ CloseDevice(diskreq); Sum = 0; for (a=0; a<1024; a=a+4) { LastSum = Sum; Sum = Sum + diskbuffer[a+3]; Sum = Sum + (diskbuffer[a+2] * 256); Sum = Sum + (diskbuffer[a+1] * 65536); Sum = Sum + (diskbuffer[a] * (65536 * 256)); if (LastSum > Sum) Sum++; /* took me a while to figger this out */ } if (Sum != 0) return; /* if it's not bootable, we DONT want it! */ if (diskbuffer[0x2b] == '9') if (diskbuffer[0x2c] == '.') if (diskbuffer[0x2d] == '8') if (diskbuffer[0x2e] == '7') { SCAFound++; 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 */ SCAFound++; }; /* compare boot block with real boot block. If it's not, notify God. */ Virus = FALSE; for (x = 0; x < 39; x++) /* nuum of lements 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; if (SCA == TRUE) { /* OH NOOOOO, an SCA virus. Wimpo virus, compared to BBandit */ Delay(1); error = AutoRequest(LittleWindow, &SCABody, &SCAPos, &SCANeg, 0, 0, 320, 70); if (error == TRUE) DoInstall(Unit); /* user wants it fixed. */ Delay(1); } else if (BBandit == TRUE) { /* The Byte Bandit Virus. Tricky bugger, he WAS. Cheats, tho. */ Delay(1); sprintf(CopyText, "(Copy Count on this disk: %d)", (diskbuffer[74]*256)+diskbuffer[75]); error = AutoRequest(LittleWindow, &BBDiskbody, &SCAPos, &SCANeg, 0, 0, 380, 80); if (error == TRUE) DoInstall(Unit); /* User crying for aid */ Delay(1); } else { /* Probably just a custom boot block (or a new virus...) */ Delay(1); error = AutoRequest(LittleWindow, &Body1, &Pos, &Neg, 0, 0, 320, 70); if (error == TRUE) DoInstall(Unit); /* user wants it neutered. */ Delay(1); } }; }; /* End of While Whochanged */ } /********************************/ /* This is where the boot code gets changed */ /********************************/ DoInstall(un) int un; /* unit to write to */ { register int x; register int Sum; int err, a; /* Rewrite disk? Really? */ error = AutoRequest(LittleWindow, &REWBody, &REWPos, &REWNeg, 0, 0, 320, 75); if (error != TRUE) return; /* user changed his brain. */ DisksInstalled++; error = OpenDevice(TDName, un,diskreq,0); 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(LittleWindow, &ERRBody, &ERRPos, &ERRNeg, 0, 0, 280, 75); if (error == TRUE) /* error is true or false, depending on user */ { goto trygain; }; CloseDevice(diskreq); return; /* unrecoverable write protect error!!!!!!!!! */ }; diskreq->io_Command = CMD_READ; diskreq->io_Data = diskbuffer; /* Move the drive head, make some noise so */ diskreq->io_Length = 512; /* folks know we're doing something. */ diskreq->io_Offset = 44*512; DoIO(diskreq); for (x = 0; x < 1024; x++) diskbuffer[x] = 0; /* clear diskbuffer to zero. clean. */ for (x = 0; x < 50; x++) { diskbuffer[x] = bootblock[x]; /* copy boot code into buffer */ }; /* Write it ! */ diskreq->io_Length = 1024; /* here we go! */ diskreq->io_Data = &diskbuffer[0]; diskreq->io_Command = CMD_WRITE; diskreq->io_Offset = 0L; DoIO(diskreq); diskreq->io_Command = CMD_UPDATE; /* flush buffer to disk */ DoIO(diskreq); error = diskreq->io_Error; Delay(5); diskreq->io_Length = 0; diskreq->io_Command = ETD_MOTOR; DoIO(diskreq); /* turn off motor */ CloseDevice(diskreq); if (error > 19) { SetWindowTitles(LittleWindow, "Error, Nothing Done.", -1); } else { SetWindowTitles(LittleWindow, "Disk Healed.", -1); }; Delay(100); SetWindowTitles(LittleWindow, TITLETEXT, -1); } /************************/ CheckMemoryForViruses() { int VirusBase; /* ick, whatta name! */ int Temp; struct ExecBase *ExecBase; int *LongMemPointer; /* Used for reading FROM memory */ ExecBase = OpenLibrary("exec.library", 0); LongMemPointer = FindName(&ExecBase->DeviceList, TDName); Temp = LongMemPointer; Temp = Temp - 0x1c; LongMemPointer = Temp; /* Can't do LongMemPointer - 0x1c because then it's a pointer operation and we get a wrong value */ VirusBase = (*LongMemPointer) - 0x1b8; LongMemPointer = VirusBase; if (*LongMemPointer == ('D'<<24) + ('O'<<16) + ('S'<<8)) /* klugo */ { /* Ok, so we don't really remove it from memory, but we DO render it harmless. */ PatchMem(VirusBase+0xaa, 0x4e71); PatchMem(VirusBase+0xac, 0x4e71); PatchMem(VirusBase+0xae, 0x4e71); PatchMem(VirusBase+0xb0, 0x4e71); /* NOP's */ PatchMem(VirusBase+0x1c2, 0x6000); /* Change Bxx to BRA */ PatchMem(VirusBase+0x2d2, 0x6000); /* Disable TD and VTI code */ PatchMem(VirusBase+0x388, 0x4e75); /* Make sure it doesn't come back */ PatchMem(VirusBase+0x3ea, 0x0000); /* Kill resident matchword */ PatchMem(VirusBase, 0x0000); /* so WE don't find it again */ error = AutoRequest(LittleWindow, &BBMem1, &BBMPos, &BBMNeg, 0, 0, 395, 78); }; CloseLibrary(ExecBase); } /***********************/ /**********************/ PatchMem(loc, val) short *loc; int val; { *loc = val; }