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 ----- ------------------------------------------------------------------------