From: amead@s.psych.uiuc.edu (Alan Mead)
Subject: Does this work (was My PD editor strikes back)
Organization: UIUC Department of Psychology
Date: Sat, 19 Dec 1992 05:28:08 GMT

A short while ago someone posted about the strange behavior of an
editor to having its object code fiddled with.  I think we all agreed
that the code monitored its own CRC and self-destructed when it found
that it had been modified.

Here is a unit that proports to give your code the same level of
protection.  I also included code that modifies itself so as to
retain arbitrary valiable values ACROSS runs.

In trying to integrate the two bits of code, I fail to see where the
virus protection code is excluding its CRC from later CRC checks???

-alan mead

program modifier;
type
   str7 = string[7];
   modtype = record
               TAG : str7;  { TAG is FIRST field!! }
               Val : byte;
               UserData : array[1..100] of byte;
             end;

const
  modify : modtype = (TAG:'ILL-INI'; Val:0; UserData:( 0,0,0,0,0,0,0,0,0,0,
                                                       0,0,0,0,0,0,0,0,0,0,
                                                       0,0,0,0,0,0,0,0,0,0,
                                                       0,0,0,0,0,0,0,0,0,0,
                                                       0,0,0,0,0,0,0,0,0,0,
                                                       0,0,0,0,0,0,0,0,0,0,
                                                       0,0,0,0,0,0,0,0,0,0,
                                                       0,0,0,0,0,0,0,0,0,0,
                                                       0,0,0,0,0,0,0,0,0,0,
                                                       0,0,0,0,0,0,0,0,0,0 ));

var
  c : longint;
  f : file;
  s : str7;
  i : integer;
  j : byte;

begin

  writeln('Tag field is now : ',Modify.TAG);
  writeln('Value field is now: ',Modify.Val);
  Modify.Val := Modify.Val + 1;
  writeln('Next time, it will be: ',Modify.Val);
  repeat
    writeln( 'Set any memory location (0 or 1-100)? ' );
    readln( i );
    if ( i>0 ) AND ( i<=100 ) then
      begin
        writeln( 'Location ',i,' currently equals ',
                  Modify.UserData[i],', new value?' );
        readln( j );
        Modify.UserData[i] := j;
      end;
  until i = 0;

  assign(f,ParamStr(0)); { open file currently running (will only work under }
  reset(f,1);            { DOS 3+; set buffer size to 1  }

  c := filesize(f);      { set c to current file size (because data is }
  c := c - SizeOf(s);    { probably at end of file); subtract off size of s }
  s := '';

  {- loop towards front of file looking until match or file starts -}
  While (c > 0) and (s <> Modify.TAG) do
    begin
      Seek(f,c);
      Blockread(f,s,SizeOf(s));
      Dec(c);
    end;

  {- seek to the offset of the found string write new record -}
  if c > 0 then
    begin
      Seek(f,c+1);
      BlockWrite(f,Modify,SizeOf(Modify));
    end;

  close(f);

end.


unit VirCheck;
interface
uses dos;

  { ==================================================================

                              Unit: VirCheck v1.0
                            Author: Igal Brener
                                    Solid State Institute and
                                    Physics Department
                                    Technion, Haifa
                                    Israel
                           e-mail.: ssrecib@technion.bitnet
                                    ssrecib@techunix.bitnet
                        July, 1990.
    ==================================================================
  The subroutine CheckVirus is based on the program "AUTOINST.PAS" posted
  to usenet news, group comp.lang.pascal  by David Dubois. For details,
  see his documentation. After compilation, on the first run of your
  program, this subroutine will calculate the checksum of the EXE file
  (passed as a parameter to the subroutine),
  and store it again on disk (on the same EXE file). Next time you will
  run your program, the subroutine will compare the new checksum with the
  one stored, and if there is a discrepancy, you will get a notice.
  The checksum calculation is done excluding the variable InstallBlock
  which retains the checksum, the flag used for detecting which run
  you are doing, and the last date your file was checked.
  In order to make this routine work with big EXE files,
  I have decided to read the EXE file from disk in records of length
  RecSize, a constant you can change in the subroutine FindChecksum.
  I've chosen records of ~10K, since I'm always short of heap space.
  There is no check to see weather the EXE file exists, but this can
  be easily added.

          Any comments or problems, use my e-mail address.

                              Igal Brener.


    ==================================================================}
procedure CheckVirus(FileName:string);

type
    InstallBlockType = record
                      already : integer;
                      checksum : longint;
                      date_Year, date_Month, date_Day: Word;
                     end;
    Instptr= array[1..12] of byte;



const
    InstallBlock : InstallBlockType

              = ( already : 0;
                  checksum : 0;
                   date_Year: 0;
                   date_Month: 0;
                   date_Day: 0);

implementation
procedure CheckVirus(FileName:string);

var
    c : Longint;
    pInst : ^Instptr;
    i  : integer;
    y,m,d,dow: Word;

{*****************************************************************************}
procedure ReInstall;

var
    ExeFile    : file;
    HeaderSize: word;

begin
    assign    ( ExeFile, FileName );
    reset     ( ExeFile, 1 );

    seek      ( ExeFile, 8 );
    blockread ( ExeFile, HeaderSize, sizeof ( HeaderSize ) );

    seek      ( ExeFile,   16 * (   longint ( seg ( InstallBlock ) )
                                  - PrefixSeg
                                  + HeaderSize          )
                         + ofs ( InstallBlock )
                         - 256                           );

    blockwrite ( ExeFile, InstallBlock, sizeof ( InstallBlock ) );

    close      ( ExeFile );
end;

{****************************************************************************}
procedure Findchecksum ( var Checksum: Longint);

const
    RecSize=10000;

type
    barr = array[1..RecSize] of byte;

var
    ExeFile : file;
    t : word;
    b : byte;
    fpointer, pSize, bytesleft, i: Longint;
    DirInfo: SearchRec;
    p : ^barr;

begin
    assign    ( ExeFile, FileName );
    reset     ( ExeFile, 1 );
    checksum := 0;
    fpointer := 0;

    FindFirst(Filename, Archive, DirInfo);
    bytesleft := DirInfo.Size;

    { If available heap space is less than RecSize, we don't execute
         this routine}
    if MemAvail>RecSize then
    begin
         while bytesleft>0 do
         begin
              {Here we read RecSize bytes at a time from the EXE file}
              if RecSize<bytesleft then pSize :=RecSize
                   else pSize := bytesleft;

              GetMem ( p, pSize);
              seek      ( ExeFile, fpointer );
              blockread ( ExeFile, p^, pSize );
              i := 1;
              while i <= pSize do
              begin
                   checksum := checksum + p^[i];
                   inc(i);
              end;

              FreeMem ( p, pSize);
              bytesleft := bytesleft - pSize;
              fpointer := fpointer + pSize;
         end;

         close      ( ExeFile );
    end;
end;

{****************************************************************************}

begin {of CheckVirus}

    GetDate(y,m,d,dow);

    with InstallBlock do
    begin
         if already=1 then writeln('** Last date your file was verified: ',
              date_Month:2, '/', date_Day:2, '/', date_Year:4);
         Writeln('** Please wait, checking EXE file ... **');
         findchecksum( c );

         if already=1 then
         begin
              pInst := @InstallBlock;
              i := 1;
              While i<=Sizeof(InstallBlock) do
              begin
                   c := c - pInst^[i];
                   inc(i);
              end;
              if c<>checksum then
              begin
                   writeln('** Your EXE file has been changed: possible virus!!');
                   Writeln(chr(7), 'Press return ');
                   Readln;
              end;
         end
         else
         begin
              checksum := c;
              already := 1;
         end;

         date_Year := y;
         date_Month:= m;
         date_Day  := d;
         { update .EXE file only if checksum is ok, or if this is the first time
         it is run }
         if c=checksum then ReInstall;
    end;
end;

end.