home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Elysian Archive
/
AmigaElysianArchive.iso
/
virus
/
kv.lzh
/
kv.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-11-26
|
19KB
|
846 lines
/*
kv - removes the IRQ virus from an executable file.
compile with Manx C - 16 bit mode ok
Routine IRQ_Kill() does the work, the rest is a vehicle
This program will also detect one varient of the Lamer virus in memory
and deactivate it.
Also checks for the BGS9 virus
Djj 8/25/89
*/
#include <exec/types.h>
#include <exec/exec.h>
#include <libraries/dos.h>
#include <intuition/intuition.h>
#include <devices/trackdisk.h>
#include <exec/execbase.h>
#include <exec/resident.h>
#include <stdio.h>
#define VERSION "KV ver 2.0 09/01/89 Djj"
#define VTAG 0x00000109L /* virus hunk length */
#define VSIG1 0x0000FFFEL /* part of virus signature */
#define VSIG2 0x61000000L /* part of virus signature */
#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 DEADXENO -9 /* disabled XENO found */
#define GOTHIM OK /* removed virus from file */
static UBYTE txt[40];
static long inp, *buff, size;
extern long Open(), Seek(), Read(), Write(), *AllocMem();
long DOSBase, IntuitionBase, OpenLibrary();
int Xeno = FALSE;
struct IntuiText Msg3 = { 3, 1, JAM2, 10, 30, 0,(UBYTE*)NULL, NULL };
struct IntuiText Msg2 = { 2, 1, JAM2, 10, 20, 0,(UBYTE*)NULL, &Msg3 };
struct IntuiText Msg1 = { 2, 1, JAM2, 10, 10, 0,(UBYTE*)NULL, &Msg2 };
struct IntuiText OKText = { 3, 1, JAM2, 6, 3, 0,(UBYTE*)" OK ", NULL };
main(argc,argv)
char **argv;
{
static char opts[] = "aAiIbBlL", *strchr();
char *posn, *temp;
int lamer = 0, irq = 0, bgs = 0, cnt = 1;
int indx, i, args;
if(argc < 2)
usage(argv[0]);
IntuitionBase = OpenLibrary("intuition.library",0L);
DOSBase = OpenLibrary("dos.library",0L);
args = argc;
for(i = 1; i < argc; i++)
{
temp = argv[ i ];
if(*temp == '?')
usage();
if(*temp++ == '-')
{
args--;
while(*temp)
{
if((posn = strchr(opts,*temp)) == 0)
{
printf("Unknown option %c\n",*temp++);
continue;
}
indx = posn - opts;
switch(indx)
{
case 2: case 3:
irq = 1; temp++;
break;
case 4: case 5:
bgs = 1; temp++;
break;
case 6: case 7:
lamer = 1; temp++;
break;
case 0: case 1:
bgs = lamer = 1; temp++;
break;
}
}
}
else
{
CheckIRQ(argv[i]);
}
}
if(lamer)
CheckLamer();
if(bgs)
Check_BGS9();
exit(cleanup(1));
}
CheckIRQ(dev)
char *dev;
{
int err;
char *pat = 0, *name = 0, *scdir(), *malloc(), ch;
/*
scan argument list for filenames. Use each name as input to the
wildcard expander. If a name ends with `:' or `/' then it's a
device or directory. As a favor to the user, append the wildcard
`*' character to the end of that name.
*/
printf("Checking for IRQ and Xeno virus on %s\n",dev);
if(pat) free(pat);
pat = malloc(strlen(dev)+1); /* leave room for `*' if needed */
if(pat == 0)
{
puts("Out of memory");
exit(cleanup(20));
}
strcpy(pat,dev); /* get filename from command line */
ch = pat[ strlen(pat)-1 ];
if(ch == ':' || ch == '/')
strcat(pat,"*");
/*
do this until no more names can be squeezed out of this argument
*/
while(1)
{
if((name = scdir(pat)) == NULL)
break;
err = IRQ_Kill(name); /* check for and possibly remove virus */
switch(err)
{
case GOTHIM:
printf("\2337m");
printf("Found and disabled the %s virus in \"%s\"!\n",
(Xeno) ? "XENO" : "IRQ", name);
printf("\2330m");
if(!Xeno)
{
DisplayBeep(0L);
Msg1.IText = (UBYTE *)"Found the IRQ virus in file";
Msg3.IText = (UBYTE *)"IRQ virus removed";
}
else
{
Msg1.IText = (UBYTE *)"Found the XENO virus in file";
Msg3.IText = (UBYTE *)"XENO virus disabled";
}
Msg2.IText = txt;
sprintf(txt," %s",name);
if(!Xeno)
putmsg();
else
Delay(20L);
break;
case NOFILE: printf("\tcan't find \"%s\"\n",name);
break;
case SEEKERR: printf("\tseek error on \"%s\"\n",name);
break;
case ALLOCERR: printf("\tcan't allocate memory\n");
break;
case READERR: printf("\terror reading \"%s\"\n",name);
break;
case VIRUSNF: printf("\"%s\" was OK\n",name);
break;
case WRITERR: printf("\terror writing to \"%s\"\n",name);
printf("\tFile \"%s\" is corrupt...replace it\n",name);
break;
case OPENERR: printf("\terror opening \"%s\" for write\n",name);
break;
case NOTEXE: printf("\t\"%s\" is not an executable file\n",name);
break;
case DEADXENO: printf("found disabled XENO virus in \"%s\"\n",name);
}
}
}
CheckLamer()
{
puts("Checking for Lamer virus");
Check_Memory_Lamer();
Check_Disk_Lamer();
}
cleanup(val)
int val;
{
if(inp)
{
Close(inp);
inp = 0;
}
if(buff)
{
FreeMem(buff,size);
buff = 0;
}
return val;
}
IRQ_Kill(fname)
char *fname;
{
int i = 0;
long fhunk, lhunk, nhunk, val, len;
inp = 0L; buff = 0L;
if((inp = Open(fname,OLD)) == 0) /* open the desired file */
return NOFILE;
Read(inp,&val,SLONG); /* get the first long word */
if(val != 0x000003F3L) /* check for executable file */
return cleanup(NOTEXE);
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,buff,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 */
i = 5 + lhunk - fhunk + 1;
Xeno = FALSE;
if(buff[5] != VTAG)
{
if(buff[ i + 0x116 ] != 'astf')
return cleanup(VIRUSNF);
else
{
Xeno = TRUE;
if(buff[i+2] == 0x60000462)
return cleanup(DEADXENO);
}
}
/*
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(!Xeno)
if( ((buff[ i+2 ] & 0x0000FFFF) != VSIG1)
|| ((buff[ i+3 ] & 0xFFFF0000) != VSIG2) )
return cleanup(VIRUSNF);
/*
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); inp = 0;
if((inp = Open(fname,NEW)) == 0)
return cleanup(OPENERR);
if(!Xeno) /* readjust program header info */
{
buff[2] -= 1;
buff[4] -= 1;
/* write new header */
if(Write(inp,buff,5L*SLONG) != 5L*SLONG)
return cleanup(WRITERR);
if(Write(inp,&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 + 9L + VTAG;
size = (size/SLONG - i)*SLONG;
/* and write old code out to file, ignoring virus hunk */
if(Write(inp,&buff[i],size) != size)
return cleanup(WRITERR);
/* we're done, the file is clean and intact */
return cleanup(GOTHIM);
}
else /* Xeno virus */
{
buff[i+2] = 0x60000462;
/* now fix the code segment length and write it out */
if(Write(inp,buff,size) != size)
return cleanup(WRITERR);
/* we're done, the file is clean and intact */
return cleanup(GOTHIM);
}
}
usage(name)
char *name;
{
printf("%s\n\n",VERSION);
printf("%s will detect and remove one type of `Lamer' and `BGS' virus \n",name);
printf("from all floppies in the system. It will also detect and remove\n");
printf("IRQ virus V41.0 from executable files and detect and disable the\n");
printf("XENO virus in executable files\n\n");
printf("Usage: %s -LIBA { filename ... }\n\n",name);
printf("\t-L or -l check for Lamer virus on all floppies\n");
printf("\t-B or -b check for BGS-9 virus on all floppies\n");
printf("\t-I or -i NAME check for IRQ and Xeno virus on NAME\n");
printf("\t-A or -a do all of the above\n\n");
printf("\t`*' (unix style) wildcards allowed\n");
printf("\tex. %s -i C:* or %s -i C: will check all files in C:\n",
name,name);
printf("\t\tfor the IRQ and Xeno virus\n");
printf("\t %s DF0:C/ will check all files in DF0:C\n",name);
exit(cleanup(20));
}
#define LAMER_ID "clist 33.80"
Check_Memory_Lamer()
{
struct ExecBase **ExecPtr = 4;
APTR *KTagPtr = (APTR *)(*ExecPtr)->KickTagPtr;
APTR Lamer, TestKTag();
while(*KTagPtr)
{
/*
If hi bit is set, then this is a pointer to a KickTag array. Reset
the bit and use the resulting address to get the address of the
next KickTag array.
*/
while((ULONG)*KTagPtr & 0x80000000)
KTagPtr = (APTR *)((ULONG)*KTagPtr & 0x7FFFFFFF);
/*
if the Lamer is found, invalidate the KickTag element here by
changing the KickTag element to a pointer to a KickTag array which
points to the next element. A cheap shot, but effective
*/
if(Lamer = TestKTag( *KTagPtr ))
{
if(KillLamer(Lamer))
{
*KTagPtr = (APTR)((ULONG)(KTagPtr+1) | 0x80000000);
SumKickData(); /* do the real SumKickData */
Msg1.IText = txt;
sprintf(txt,"Lamer virus found at %08lx",Lamer);
putmsg();
return;
}
}
KTagPtr++;
}
}
/*
This is supposed to compute the correct Kick memory checksum to
allow the users RAD: disk to recover on the next reboot.
The SumKickData vector was recovered from the virus and reinstalled
in the execbase structure by KillLamer()
*/
SumKickData()
{
#asm
move.l 4,a6
jsr -$264(a6) ;calculate checksum
move.l d0,$22A(a6) ;store it
#endasm
}
KillLamer(addr)
APTR addr;
{
#define RTS 0x70014E75 /* moveq.l #1,d0 rts */
struct ExecBase **ExecPtr = 4;
/*
I think that the Lamer is in memory. I'm going to test several
locations within the virus body to be sure that it is the exact
virus I'm familiar with. The test array has memory offsets from
addr and the contents I expect to see there.
*/
static APTR test[] = {
0x0A6, 0x2F3A0EEC, /* SumKick routine */
0x166, 0x2F3A0E3C, /* DoIO routine */
0x246, 0x2F3A0D64, /* TDRead routine */
0x2B8, 0x287A0D0C, /* Trigger point */
0x5AE, 0x2C780004 /* Disk Trasher */
};
/*
I'm going to pull the vipers fangs by placing RTS instructions in
key areas. One area is his Resident Initialization vector - that'll
stop him from living through a re-boot (provided he's not on the
boot disk that is)
*/
static APTR rts[] = {
0, /* Keep from initializing on reset */
0x2B8, /* disable one trigger point */
0x5AE, /* stop the disk trasher */
0x6D8, /* stop the alerts */
0x73C /* his ReBoot exit */
};
int i;
APTR ptr;
UBYTE *vec, *mem;
ULONG *vect, FindName();
for(i = 0; i < sizeof(test)/sizeof(ULONG); i+= 2)
{
ptr = addr+test[ i ];
if( *ptr != test[ i+1 ] )
{
if(*ptr != RTS)
{
Msg2.IText = (UBYTE *)"I don't know this one";
Msg3.IText = (UBYTE *)"virus NOT removed!";
return 0;
}
else
{
Msg3.IText = (UBYTE *)"It's OK! It's been deactivated";
return 0;
}
}
}
for(i = 0; i < sizeof(rts)/sizeof(ULONG); i++)
{
ptr = addr+rts[ i ];
*ptr = RTS;
}
/*
Get the SumKickData vector from the virus and reinstall it in the
ExecBase jump table.
*/
vec = (UBYTE *)(*ExecPtr);
vect = (ULONG *)(vec - 0x264+2); /* ExecBase offset */
ptr = addr+0x3E5; /* Offset from Lamer Init vector */
*vect = (ULONG)*ptr; /* restore vector */
/*
Get the Trackdisk read vector from the virus and reinstall it
*/
vect = (ULONG *)(FindName(&(*ExecPtr)->DeviceList,TD_NAME)-0x1c);
ptr = addr + (0xFAC/4);
*vect = (ULONG)*ptr;
Msg3.IText = (UBYTE *)"Virus removed!";
return 1;
}
/*
Test the Resident structure ID string to see if it matches the one
the Lamer uses. Return the structures Init vector if true, NULL if
not
*/
APTR TestKTag( res )
struct Resident *res;
{
if(strncmp(LAMER_ID,res->rt_IdString,strlen(LAMER_ID)) == 0)
return res->rt_Init;
return (APTR)NULL;
}
struct Port *diskport = 0, *CreatePort();
struct IOExtTD *diskreq = 0, *CreateExtIO();
#define SEC_SIZE 512L
#define ROOT 880L
#define HASHCHAIN 124
#define WRITE_PROTECTED -1
#define NO_DISK -2
UBYTE *diskdata = 0;
UBYTE invisible[] = "DF0:\240\240\240\240\240";
UBYTE newfile[] = "DF0:DANGERVIRUS";
WriteBlock(block)
long block;
{
LONG offset;
MotorOn();
offset = block * SEC_SIZE;
diskreq->iotd_Req.io_Length = SEC_SIZE;
diskreq->iotd_Req.io_Data = (APTR)diskdata;
diskreq->iotd_Req.io_Command = CMD_WRITE;
diskreq->iotd_Req.io_Offset = offset;
DoIO(diskreq);
if(diskreq->iotd_Req.io_Error != 0)
printf("I/O error %d\n",diskreq->iotd_Req.io_Error);
diskreq->iotd_Req.io_Command = ETD_UPDATE;
DoIO(diskreq);
MotorOff();
}
ReadBlock(block)
long block;
{
LONG offset;
MotorOn();
offset = block * SEC_SIZE;
diskreq->iotd_Req.io_Length = SEC_SIZE;
diskreq->iotd_Req.io_Data = (APTR)diskdata;
diskreq->iotd_Req.io_Command = CMD_READ;
diskreq->iotd_Req.io_Offset = offset;
DoIO(diskreq);
if(diskreq->iotd_Req.io_Error != 0)
printf("I/O error %d\n",diskreq->iotd_Req.io_Error);
MotorOff();
}
MotorOn()
{
diskreq->iotd_Req.io_Length = 1;
diskreq->iotd_Req.io_Command = TD_MOTOR;
DoIO(diskreq);
}
MotorOff()
{
diskreq->iotd_Req.io_Length = 0;
diskreq->iotd_Req.io_Command = TD_MOTOR;
DoIO(diskreq);
}
CheckDOS()
{
ReadBlock(0L);
if(diskdata[0] == 'D' && diskdata[1] == 'O' && diskdata[2] == 'S')
return 1;
return 0;
}
DiskStatus()
{
diskreq->iotd_Req.io_Flags = 0;
diskreq->iotd_Req.io_Command = TD_PROTSTATUS;
DoIO(diskreq);
if(diskreq->iotd_Req.io_Error == TDERR_DiskChanged)
return NO_DISK;
if(diskreq->iotd_Req.io_Actual)
return WRITE_PROTECTED;
return OK;
}
Check_Disk_Lamer()
{
int i;
for(i = 0; i < 4; i++)
{
if(OpenDiskResource(i) == 0)
return;
CheckDisk(i);
CloseDiskResource();
}
}
OpenDiskResource(num)
int num;
{
struct ExecBase **ExecPtr = 4;
ULONG td, FindName();
td = FindName(&(*ExecPtr)->DeviceList,TD_NAME);
diskdata = (UBYTE *)AllocMem(SEC_SIZE,(LONG)(MEMF_CHIP | MEMF_CLEAR));
diskport = CreatePort(0L,0L);
if(diskport == NULL || diskdata == NULL)
exit(cleanup(20));
diskreq = CreateExtIO(diskport,(long)sizeof(struct IOExtTD));
if(diskreq == NULL)
{
DeletePort(diskport);
exit(cleanup(20));
}
if(OpenDevice(TD_NAME,(LONG)num,diskreq,0L))
return 0;
return 1;
}
CloseDiskResource()
{
if(diskreq)
{
CloseDevice(diskreq);
DeleteExtIO(diskreq,(long)sizeof(struct IOExtTD));
DeletePort(diskport);
}
if(diskdata)
FreeMem(diskdata,SEC_SIZE);
diskreq = 0;
diskdata = 0;
}
CheckDisk(num)
int num;
{
int i;
long *buff, Virus = 0, block, link = 0, before = 0, after = 0;
unsigned long lock, Lock(), CheckSum();
char drive[5];
if(DiskStatus() == NO_DISK || CheckDOS() == 0)
return;
invisible[2] = newfile[2] = 0x30 + num;
if((lock = Lock(invisible,ACCESS_READ)) == DOSFALSE)
return;
UnLock(lock);
strncpy(drive,invisible,4); drive[4] = 0;
if(DiskStatus() == WRITE_PROTECTED)
{
#ifdef CLI
printf("CAUTION! Lamer Virus found on drive %4s\n",drive);
printf("Disk is write protected. Make disk writable\n");
#else
Msg1.IText = txt;
sprintf(txt,"Lamer Virus found on %4s",drive);
Msg2.IText = (UBYTE *)"Disk is write protected";
Msg3.IText = (UBYTE *)"Make disk writable";
putmsg();
#endif
return;
}
if((lock = Lock(newfile,ACCESS_READ)) != DOSFALSE)
{
UnLock(lock);
DeleteFile(newfile);
}
if(Rename(invisible,newfile) == DOSFALSE)
{
printf("WARNING - attempt to rename virus has failed\n");
printf("The virus hides in an invisible file on drive %4s\n",drive);
}
else
{
printf("NOTICE! - Lamer virus found on drive %4s\n",drive);
printf("The virus has been renamed to %4sDANGERVIRUS.\n",drive);
printf("Please delete this file and edit your Startup-Sequence file\n");
printf("to remove the invisible filename found on the first line\n");
}
/* virus is present */
ReadBlock(ROOT);
buff = (long *)diskdata;
Virus = buff[ 15 ];
for(i = 14; i > 6; i--)
if(before = buff[ i ])
break;
if(before == 0)
return;
for(i = 16; i < 81; i++)
if(after = buff[ i ])
break;
if(after == 0)
return;
block = before;
do {
ReadBlock(block);
link = buff[ HASHCHAIN ];
if(link == after)
{
buff[ HASHCHAIN ] = buff[ 5 ] = 0;
buff[ 5 ] = CheckSum(buff);
WriteBlock(block);
break;
}
} while(block = link);
}
unsigned long CheckSum(block)
unsigned long block[];
{
int cnt;
unsigned long sum = 0;
for(cnt = 0; cnt < 128; cnt++)
sum += block[ cnt ];
return (~sum + 1);
}
putmsg()
{
AutoRequest(NULL,&Msg1,NULL,&OKText,NULL,NULL,300L,80L);
}
UBYTE BGS_name[] = "DF0:devs/\240\240\240 \240 \240";
UBYTE newname[] = "DF0:devs/OLD_PROGRAM.BGS9";
Check_BGS9(num)
{
int i;
puts("Checking for BGS virus");
for(i = 0; i < 4; i++)
{
if(OpenDiskResource(i) == 0)
return;
CheckDiskBGS(i);
CloseDiskResource();
}
}
CheckDiskBGS(num)
int num;
{
ULONG file;
UBYTE drive[5];
int i;
if(DiskStatus() == NO_DISK || CheckDOS() == 0)
return;
BGS_name[2] = num + '0';
if((file = Lock(BGS_name,ACCESS_READ)) != DOSFALSE)
{
UnLock(file);
strncpy(drive,BGS_name,4); drive[4] = 0;
sprintf(txt,"BGS virus found on %s",drive);
Msg1.IText = txt;
if(DiskStatus() == WRITE_PROTECTED)
{
Msg2.IText = (UBYTE *)"Disk is write protected";
Msg3.IText = (UBYTE *)"Make disk writable";
putmsg();
CloseDiskResource();
return;
}
newname[2] = num + '0';
if(Rename(BGS_name,newname) == DOSFALSE)
{
Msg3.IText = (UBYTE *)"Rename failed";
}
putmsg();
printf("You must now examine %sS/Startup-Sequence",drive);
puts(" and note the name of the first");
puts("executable file. That file contains the BGS virus\n");
puts("DELETE that file and replace it with a know good copy");
puts("You might also want to remove or rename the file located in");
printf("%s/devs. It contains the original program replaced",drive);
puts(" by the BGS virus");
}
}