[comp.lang.pascal] Virus checking unit for Turbo Pascal

ssrecib@vmsa.technion.ac.il (07/06/90)

     Well, here is a subroutine for checking if your EXE file has been
changed after the last run. It is based on the program posted by David
Dubois on how to store information back into the EXE file. Foe explanation
read the comments on the unit itself. After the unit listing, there
is a short program (which yoy'll have to call 'vircheck.pas') which tests
the unit. I've tried this with TP5.5 and a VERY big program, and everything
seems to work fine.

            Good luck,
                         Igal Brener.
                         ssrecib@technion.bitnet
                         ssrecib@techunix.bitnet







------------------------------------------------------------------------
---         S T A R T     O F     U N I T                         -----
------------------------------------------------------------------------

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.


------------------------------------------------------------------------
---         E N D         O F     U N I T                         -----
------------------------------------------------------------------------



------------------------------------------------------------------------
---       S T A R T       O F     P R O G R A M                   -----
------------------------------------------------------------------------


program tryvirus;
uses vircheck;



begin { Main }

    CheckVirus('tryvirus.exe');


    { >>> your program <<<<}



end.

------------------------------------------------------------------------
---       E N D           O F     P R O G R A M                   -----
------------------------------------------------------------------------