home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / t / tcsel003.zip / SELFMOD.PAS < prev    next >
Pascal/Delphi Source File  |  1992-10-17  |  8KB  |  223 lines

  1. {$X+}
  2. unit selfmod;
  3.  
  4.  { Author Trevor J Carlsen - released into the public domain 1991            }
  5.  {        PO Box 568                                                         }
  6.  {        Port Hedland                                                       } 
  7.  {        Western Australia 6721                                             }
  8.  {        Voice +61 91 73 2026  Data +61 91 73  2569                         }
  9.  {        FidoNet 3:690/644                                                  }
  10.  { Allows a program to self modify a typed constant in the .exe file.  It    }
  11.  { also performs an automatic checksum type .exe file integrity check.       }
  12.  { A longint value is added to the end of the exe file.  This can be read by }
  13.  { a separate configuration program to enable it to determine the start of   }
  14.  { the programs configuration data area.  To use this the configuration      }
  15.  { typed constant should be added immediately following the declaration of   }
  16.  { ExeData.                                                                  }
  17.  
  18.  { Where this unit is used, it should always be the FIRST unit listed in the }
  19.  { uses declaration area of the main program.                                }
  20.  
  21.  { Requires DOS 3.3 or later.  Program must not be used with PKLite or LZExe }
  22.  { or any similar exe file compression programs. It may also cause           }
  23.  { difficulties on a network or virus detection programs.                    }
  24.  
  25.  { The stack size needed is at least 9,000 bytes.                            }
  26.  
  27. interface
  28.  
  29. uses
  30.   globals;
  31.  
  32. type
  33.   ExeDatatype    = record
  34.                      IDStr      : str7;
  35.                      UserName   : str35;
  36.                      FirstTime  : boolean;
  37.                      NumbExecs  : shortint;
  38.                      Hsize      : word;
  39.                      ExeSize    : longint;
  40.                      CheckSum   : longint;
  41.                      StartConst : longint;
  42.                      RegCode    : longint;
  43.                    end;
  44. const
  45.   ExeData : ExeDatatype = (IDStr     : 'ID-AREA';
  46.                            UserName  : '';
  47.                            FirstTime : true;
  48.                            NumbExecs : -1;
  49.                            Hsize     : 0;
  50.                            ExeSize   : 0;
  51.                            CheckSum  : 0;
  52.                            StartConst: 0;
  53.                            RegCode   : 0);
  54.  
  55.  
  56. {$I p:\prog\freeload.inc} { Creates CodeStr that MUST match RegStr }
  57.  
  58. {$I p:\prog\registed.inc} { Creates CodeChkStr that MUST hash to RegCode}
  59.  
  60. const
  61.   mark  : byte = 0;
  62.  
  63. var
  64.   first : boolean;
  65.  
  66. procedure Hash(p : pointer; numb : byte; var result: longint);
  67.  
  68. function Write2Exec(var data; size: word): boolean;
  69.  
  70. implementation
  71.  
  72.  
  73. procedure Hash(p : pointer; numb : byte; var result: longint);
  74.   { When originally called numb must be equal to sizeof    }
  75.   { whatever p is pointing at.  If that is a string numb   }
  76.   { should be equal to length(the_string) and p should be  }        
  77.   { ptr(seg(the_string),ofs(the_string)+1)                 }
  78.   var
  79.     temp,
  80.     w    : longint;
  81.     x    : byte;
  82.  
  83.   begin
  84.     temp := longint(p^);  RandSeed := temp;
  85.     for x := 0 to (numb - 4) do begin
  86.       w := random(maxint) * random(maxint) * random(maxint);
  87.       temp := ((temp shr random(16)) shl random(16)) +
  88.                 w + MemL[seg(p^):ofs(p^)+x];
  89.     end;
  90.     result := result xor temp;
  91.   end;  { Hash }
  92.  
  93.  
  94. procedure InitConstants;
  95.   var
  96.     f           : file;
  97.     tbuff       : array[0..1] of word;
  98.   
  99.   function GetCheckSum : longint;  
  100.     { Performs a checksum calculation on the exe file }
  101.     var
  102.       finished  : boolean;
  103.       x,
  104.       CSum      : longint;
  105.       BytesRead : word;
  106.       buffer    : array[0..4095] of word;
  107.     begin
  108.       {$I-}
  109.       seek(f,0);
  110.       finished := false;  CSum := 0;  x := 0;
  111.       BlockRead(f,buffer,sizeof(buffer),BytesRead);
  112.       while not finished do begin             { do the checksum calculations }
  113.         repeat         { until file has been read up to start of config area }
  114.           inc(CSum,buffer[x mod 4096]);
  115.           inc(x);
  116.           finished := ((x shl 1) >= ExeData.StartConst); 
  117.         until ((x mod 4096) = 0) or finished;
  118.         if not finished then                { data area has not been reached }
  119.           BlockRead(f,buffer,sizeof(buffer),BytesRead);          
  120.       end;
  121.       GetCheckSum := CSum;
  122.     end; { GetCheckSum }
  123.     
  124.       
  125.   begin
  126.     assign(f, ParamStr(0));
  127.     {$I-} Reset(f,1);
  128.     with ExeData do begin
  129.       first := FirstTime;
  130.       if FirstTime and (IOResult = 0) then begin
  131.         Seek(f,2);                   { this location has the executable size }
  132.         BlockRead(f,tbuff,4);
  133.         ExeSize := tbuff[0]+(pred(tbuff[1]) shl 9);
  134.         seek(f,8);                                    {  get the header size }
  135.         BlockRead(f,hsize,2);
  136.         FirstTime := false;
  137.         StartConst := longint(hsize+Seg(ExeData)-PrefixSeg) shl 4 + 
  138.                       Ofs(ExeData) - 256;
  139.         CheckSum := GetCheckSum;
  140.         Seek(f,StartConst);
  141.         BlockWrite(f,ExeData,sizeof(ExeData));
  142.         seek(f,FileSize(f));
  143.         BlockWrite(f,StartConst,4);
  144.       end
  145.       else
  146.         if GetCheckSum <> CheckSum then begin
  147.           writeln('File has been tampered with.  Checksum incorrect');
  148.           halt;
  149.         end;
  150.     end;  { with }    
  151.     Close(f); {$I+}
  152.     if IOResult <> 0 then begin
  153.       writeln('Unable to initialise program');
  154.       halt;
  155.     end;  
  156.   end; { InitConstants }
  157.  
  158.  
  159. function Write2Exec(var data; size: word): boolean;
  160.  { Writes a new typed constant into the executable file after first checking }
  161.  { that it is safe to do so.  It does this by ensuring that the IDString is  }
  162.  { at the file offset expected.                                              }
  163.   const
  164.     FName : str40 = '';
  165.   var
  166.      f          : file;
  167.      st         : str8;
  168.      BytesRead  : word;
  169.   begin
  170.     if UseCfg then begin
  171.       if length(FName) = 0 then begin
  172.         TempStr    := ParamStr(0);
  173.         TempStrLen := pos('.',TempStr) - 2;
  174.         FName      := TempStr + ' .   ';
  175.         {                        │ │││                                       }
  176.         {                        │ ││└────»» #255                            }
  177.         {                        │ │└─────»» #32                             }
  178.         {                        │ └──────»» #255                            }
  179.         {                        └────────»» #255                            }
  180.         { Using the above file name for the configuration file makes the     }
  181.         { deletion of the file difficult for the average user.               }
  182.       end; { if length }
  183.       assign(f, FName);
  184.       if exist(FName) then begin
  185.         {$I-}
  186.         reset(f,1);
  187.         if first then begin
  188.           first := false;
  189.           BlockRead(f, ExeData, ofs(mark)-ofs(ExeData),BytesRead)
  190.         end else
  191.           BlockWrite(f,data,size);
  192.       end else begin
  193.         rewrite(f,1);
  194.         BlockWrite(f,Data,size);
  195.       end;
  196.       close(f);
  197.       {$I+}
  198.       Write2Exec := IOResult = 0;
  199.     end else begin
  200.       assign(f, ParamStr(0));
  201.       {$I-} Reset(f,1);
  202.       Seek(f,longint(ExeData.Hsize+Seg(ExeData)-PrefixSeg) shl 4
  203.                      + Ofs(ExeData)- 256);
  204.       BlockRead(f,st,9);
  205.       if st = ExeData.IDStr then { all Ok to proceed } begin
  206.         Seek(f,longint(ExeData.Hsize+Seg(data)-PrefixSeg) shl 4
  207.                        + Ofs(data)- 256);
  208.         BlockWrite(f,data,size);
  209.         Close(f); {$I+}
  210.         Write2Exec := IOResult = 0;
  211.       end else
  212.         Write2Exec := false;
  213.     end;
  214.   end; { Write2Exec }
  215.   
  216. begin
  217.   first :=  true;
  218.   if not UseCfg then
  219.     InitConstants
  220.   else
  221.     Write2Exec(ExeData,ofs(mark)-ofs(ExeData));
  222. end.
  223.