How to make an integrity check on my program when it starts (CRC32 maybe?, plz read)

Hi,

I want to make an integrity check when my app starts to check if my program got corrupted/altered by a cracker or something.

the problem is I don't know in advance the crc32 checksum of my app, because:

my program works like this:

there is 2 executables, the first (GUI) apply settings on the second exe (the one I want to protect),

so I thought after settings has been applied, I could make a crc32 checksum of this file, and then store it in the resource of this exe (second one), but then, the crc32 checksum would have changed again! :(

any idea?

thx a lot!

500 points for this one
Marc582Asked:
Who is Participating?

[Webinar] Streamline your web hosting managementRegister Today

x
 
ThievingSixConnect With a Mentor Commented:
Ok so I finally had some time to work on this!

Since you can't write to the calling program with Read()/Write(), we had to do something different. That is get the CRC32 from a text file. Now I know your thinking, "That doesn't seem very safe." Well if you think about it it's not that bad.

What happens is you get the crc32 of the program and put it in the text file, if that crc32 is wrong or isn't there then then program doesn't run!

I decided to make this program a console application and have no uses to get it down to its smallest. It's fully commented and you should be able to pick at the code for what you need.

If you need anymore help on the sample or subject please don't hesitate to ask!
program IntegrityTest;
 
{$APPTYPE CONSOLE}
 
//This is the table for the CRC check.
//If has a different hex for each byte
//  for characters in the ASCII code.
const
  Table: array[0..255] of LongWord =
    ($00000000, $77073096, $EE0E612C, $990951BA,
    $076DC419, $706AF48F, $E963A535, $9E6495A3,
    $0EDB8832, $79DCB8A4, $E0D5E91E, $97D2D988,
    $09B64C2B, $7EB17CBD, $E7B82D07, $90BF1D91,
    $1DB71064, $6AB020F2, $F3B97148, $84BE41DE,
    $1ADAD47D, $6DDDE4EB, $F4D4B551, $83D385C7,
    $136C9856, $646BA8C0, $FD62F97A, $8A65C9EC,
    $14015C4F, $63066CD9, $FA0F3D63, $8D080DF5,
    $3B6E20C8, $4C69105E, $D56041E4, $A2677172,
    $3C03E4D1, $4B04D447, $D20D85FD, $A50AB56B,
    $35B5A8FA, $42B2986C, $DBBBC9D6, $ACBCF940,
    $32D86CE3, $45DF5C75, $DCD60DCF, $ABD13D59,
    $26D930AC, $51DE003A, $C8D75180, $BFD06116,
    $21B4F4B5, $56B3C423, $CFBA9599, $B8BDA50F,
    $2802B89E, $5F058808, $C60CD9B2, $B10BE924,
    $2F6F7C87, $58684C11, $C1611DAB, $B6662D3D,
 
    $76DC4190, $01DB7106, $98D220BC, $EFD5102A,
    $71B18589, $06B6B51F, $9FBFE4A5, $E8B8D433,
    $7807C9A2, $0F00F934, $9609A88E, $E10E9818,
    $7F6A0DBB, $086D3D2D, $91646C97, $E6635C01,
    $6B6B51F4, $1C6C6162, $856530D8, $F262004E,
    $6C0695ED, $1B01A57B, $8208F4C1, $F50FC457,
    $65B0D9C6, $12B7E950, $8BBEB8EA, $FCB9887C,
    $62DD1DDF, $15DA2D49, $8CD37CF3, $FBD44C65,
    $4DB26158, $3AB551CE, $A3BC0074, $D4BB30E2,
    $4ADFA541, $3DD895D7, $A4D1C46D, $D3D6F4FB,
    $4369E96A, $346ED9FC, $AD678846, $DA60B8D0,
    $44042D73, $33031DE5, $AA0A4C5F, $DD0D7CC9,
    $5005713C, $270241AA, $BE0B1010, $C90C2086,
    $5768B525, $206F85B3, $B966D409, $CE61E49F,
    $5EDEF90E, $29D9C998, $B0D09822, $C7D7A8B4,
    $59B33D17, $2EB40D81, $B7BD5C3B, $C0BA6CAD,
 
    $EDB88320, $9ABFB3B6, $03B6E20C, $74B1D29A,
    $EAD54739, $9DD277AF, $04DB2615, $73DC1683,
    $E3630B12, $94643B84, $0D6D6A3E, $7A6A5AA8,
    $E40ECF0B, $9309FF9D, $0A00AE27, $7D079EB1,
    $F00F9344, $8708A3D2, $1E01F268, $6906C2FE,
    $F762575D, $806567CB, $196C3671, $6E6B06E7,
    $FED41B76, $89D32BE0, $10DA7A5A, $67DD4ACC,
    $F9B9DF6F, $8EBEEFF9, $17B7BE43, $60B08ED5,
    $D6D6A3E8, $A1D1937E, $38D8C2C4, $4FDFF252,
    $D1BB67F1, $A6BC5767, $3FB506DD, $48B2364B,
    $D80D2BDA, $AF0A1B4C, $36034AF6, $41047A60,
    $DF60EFC3, $A867DF55, $316E8EEF, $4669BE79,
    $CB61B38C, $BC66831A, $256FD2A0, $5268E236,
    $CC0C7795, $BB0B4703, $220216B9, $5505262F,
    $C5BA3BBE, $B2BD0B28, $2BB45A92, $5CB36A04,
    $C2D7FFA7, $B5D0CF31, $2CD99E8B, $5BDEAE1D,
 
    $9B64C2B0, $EC63F226, $756AA39C, $026D930A,
    $9C0906A9, $EB0E363F, $72076785, $05005713,
    $95BF4A82, $E2B87A14, $7BB12BAE, $0CB61B38,
    $92D28E9B, $E5D5BE0D, $7CDCEFB7, $0BDBDF21,
    $86D3D2D4, $F1D4E242, $68DDB3F8, $1FDA836E,
    $81BE16CD, $F6B9265B, $6FB077E1, $18B74777,
    $88085AE6, $FF0F6A70, $66063BCA, $11010B5C,
    $8F659EFF, $F862AE69, $616BFFD3, $166CCF45,
    $A00AE278, $D70DD2EE, $4E048354, $3903B3C2,
    $A7672661, $D06016F7, $4969474D, $3E6E77DB,
    $AED16A4A, $D9D65ADC, $40DF0B66, $37D83BF0,
    $A9BCAE53, $DEBB9EC5, $47B2CF7F, $30B5FFE9,
    $BDBDF21C, $CABAC28A, $53B39330, $24B4A3A6,
    $BAD03605, $CDD70693, $54DE5729, $23D967BF,
    $B3667A2E, $C4614AB8, $5D681B02, $2A6F2B94,
    $B40BBE37, $C30C8EA1, $5A05DF1B, $2D02EF8D);
 
//Quick typedef for some version differences
type
  {$IFDEF VER130}
    TInteger8 = Int64;
  {$ELSE}
  {$IFDEF VER120}
    TInteger8 = Int64;
  {$ELSE}
    TInteger8 = COMP;
  {$ENDIF}
  {$ENDIF}
 
//Begin main CRC calculation
procedure CalcCRC32(p: Pointer; ByteCount: LongWord; var CRCValue: LongWord);
var
  i: LongWord;
  q: ^BYTE;
begin
  q := p;
  //Go through each byte given and
  // select a value from the table
  // too xor with the byte
  for i := 0 to ByteCount - 1 do
  begin
    CRCvalue := (CRCvalue shr 8) xor
      Table[q^ xor (CRCvalue and $000000FF)];
    Inc(q)
  end
end;
//End main CRC calculation
 
//begin File CRC32 calculation
function CalcFileCRC32(FromName: string) : LongWord;
var
  Stream : TextFile; //Converted to Read()/Write()
  Buffer : ShortString;
  Input : ShortString;
begin
  Result := $FFFFFFFF; //max the result
  AssignFile(Stream,FromName);
  try
    try
      Reset(Stream);              //Read the entire program
      Input := '';                //that is being checked
      While Not EOF(Stream) Do
        begin
        ReadLn(Stream,Buffer);
        Input := Input + Buffer;
      end;
      CalcCRC32(Addr(Input[1]), Length(Input), Result)
      // ^ calc the crc32 of the program which is now
      //   in one big long string;
      except
    end;
    Result := not Result //invert the result
  finally
    CloseFile(Stream);
  end;
end;
//End file CRC32 calculation
 
//begin function for the main check
function CheckIntegrity : LongBool;
var
  Self : TextFile;
  CRC32 : LongWord;
begin
  Result := False;
  {Now below is a way to get the programs
   CRC32 and put it to the file Checksum.
   If the cmd line param is 'checksum' then
   it outputs it. If you want todo this in
   another program to make the file check
   then be my guest.}
  If ParamStr(1) = 'checksum' Then
    begin
    CRC32 := CalcFileCRC32(ParamStr(0));
    AssignFile(Self,'Checksum');
    ReWrite(Self);
    Writeln(Self,CRC32);
    CloseFile(Self);
  end
  Else
    begin
    //Read the line of the file Checksum(change it if you want)
    //  to get the CRC of this program
    //Also if they delete the file checksum, the program
    //  doesn't error and takes it as a bad crc32.
    AssignFile(Self,'Checksum');
    Reset(Self);
    While Not EOF(Self) Do
      ReadLn(Self,CRC32);
    CloseFile(Self);
    //If its the same then the result is true.
    //  Meaning the program works, if it doesn't,
    //  the result stays false.
    If CRC32 = CalcFileCRC32(ParamStr(0)) Then
      Result := True;
  end;
end;
 
begin
  //If it works output some text and wait
  //  for enter, if it doesn't close.
  If CheckIntegrity Then
    begin
    Writeln('Working!');
    Readln;
  end;
end.

Open in new window

0
 
ThievingSixCommented:
What I did was:

1) Compile the program
2) Have the program crc32 itself
3) Write the crc32 to the end of the program with a marker.
4) The procedure that is called on start checks to see if step 3 was done, if it was it reads itself back from the end to the marker and compare crc32's, if that doesn't match it closes.

I'll post an example in a bit if someone more experienced knows something better.
0
 
Marc582Author Commented:
yea but when it write it at the end of the file, then the crc32 will be modified no?
0
Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
ThievingSixCommented:
No because when you do the check(after your sure this isn't the first time the program is run) you do the check on the memory all the way up to the marker.
0
 
Marc582Author Commented:
yea and cuz the crc32 thing is in eof, its not exec in memory, not bad :)

I got it I think, thx :P

now any good units that doesn't take much size (under 1 kb) to do this check?

and crc32 is ok? crc32 is a checksum in the same kind of md5 right?
0
 
Marc582Author Commented:
but mm, are you sure the crc32 check is made on memory? I would more think it's made on the file itself
0
 
ThievingSixCommented:
Usage:
procedure Test;
const Input : String = 'abcde';
var
  CRC32: DWORD;
begin
  CalcStringCRC32(Input,CRC32);
  ShowMessage('CRC32 of ' + Input + ' is ' + IntToStr(CRC32));
  CalcFileCRC32(Application.EXEName,CRC32);
  ShowMessage('CRC32 of ' + Application.EXEName + ' is ' + IntToStr(CRC32));
end;
const
  Table: array[0..255] of DWORD =
    ($00000000, $77073096, $EE0E612C, $990951BA,
    $076DC419, $706AF48F, $E963A535, $9E6495A3,
    $0EDB8832, $79DCB8A4, $E0D5E91E, $97D2D988,
    $09B64C2B, $7EB17CBD, $E7B82D07, $90BF1D91,
    $1DB71064, $6AB020F2, $F3B97148, $84BE41DE,
    $1ADAD47D, $6DDDE4EB, $F4D4B551, $83D385C7,
    $136C9856, $646BA8C0, $FD62F97A, $8A65C9EC,
    $14015C4F, $63066CD9, $FA0F3D63, $8D080DF5,
    $3B6E20C8, $4C69105E, $D56041E4, $A2677172,
    $3C03E4D1, $4B04D447, $D20D85FD, $A50AB56B,
    $35B5A8FA, $42B2986C, $DBBBC9D6, $ACBCF940,
    $32D86CE3, $45DF5C75, $DCD60DCF, $ABD13D59,
    $26D930AC, $51DE003A, $C8D75180, $BFD06116,
    $21B4F4B5, $56B3C423, $CFBA9599, $B8BDA50F,
    $2802B89E, $5F058808, $C60CD9B2, $B10BE924,
    $2F6F7C87, $58684C11, $C1611DAB, $B6662D3D,
 
    $76DC4190, $01DB7106, $98D220BC, $EFD5102A,
    $71B18589, $06B6B51F, $9FBFE4A5, $E8B8D433,
    $7807C9A2, $0F00F934, $9609A88E, $E10E9818,
    $7F6A0DBB, $086D3D2D, $91646C97, $E6635C01,
    $6B6B51F4, $1C6C6162, $856530D8, $F262004E,
    $6C0695ED, $1B01A57B, $8208F4C1, $F50FC457,
    $65B0D9C6, $12B7E950, $8BBEB8EA, $FCB9887C,
    $62DD1DDF, $15DA2D49, $8CD37CF3, $FBD44C65,
    $4DB26158, $3AB551CE, $A3BC0074, $D4BB30E2,
    $4ADFA541, $3DD895D7, $A4D1C46D, $D3D6F4FB,
    $4369E96A, $346ED9FC, $AD678846, $DA60B8D0,
    $44042D73, $33031DE5, $AA0A4C5F, $DD0D7CC9,
    $5005713C, $270241AA, $BE0B1010, $C90C2086,
    $5768B525, $206F85B3, $B966D409, $CE61E49F,
    $5EDEF90E, $29D9C998, $B0D09822, $C7D7A8B4,
    $59B33D17, $2EB40D81, $B7BD5C3B, $C0BA6CAD,
 
    $EDB88320, $9ABFB3B6, $03B6E20C, $74B1D29A,
    $EAD54739, $9DD277AF, $04DB2615, $73DC1683,
    $E3630B12, $94643B84, $0D6D6A3E, $7A6A5AA8,
    $E40ECF0B, $9309FF9D, $0A00AE27, $7D079EB1,
    $F00F9344, $8708A3D2, $1E01F268, $6906C2FE,
    $F762575D, $806567CB, $196C3671, $6E6B06E7,
    $FED41B76, $89D32BE0, $10DA7A5A, $67DD4ACC,
    $F9B9DF6F, $8EBEEFF9, $17B7BE43, $60B08ED5,
    $D6D6A3E8, $A1D1937E, $38D8C2C4, $4FDFF252,
    $D1BB67F1, $A6BC5767, $3FB506DD, $48B2364B,
    $D80D2BDA, $AF0A1B4C, $36034AF6, $41047A60,
    $DF60EFC3, $A867DF55, $316E8EEF, $4669BE79,
    $CB61B38C, $BC66831A, $256FD2A0, $5268E236,
    $CC0C7795, $BB0B4703, $220216B9, $5505262F,
    $C5BA3BBE, $B2BD0B28, $2BB45A92, $5CB36A04,
    $C2D7FFA7, $B5D0CF31, $2CD99E8B, $5BDEAE1D,
 
    $9B64C2B0, $EC63F226, $756AA39C, $026D930A,
    $9C0906A9, $EB0E363F, $72076785, $05005713,
    $95BF4A82, $E2B87A14, $7BB12BAE, $0CB61B38,
    $92D28E9B, $E5D5BE0D, $7CDCEFB7, $0BDBDF21,
    $86D3D2D4, $F1D4E242, $68DDB3F8, $1FDA836E,
    $81BE16CD, $F6B9265B, $6FB077E1, $18B74777,
    $88085AE6, $FF0F6A70, $66063BCA, $11010B5C,
    $8F659EFF, $F862AE69, $616BFFD3, $166CCF45,
    $A00AE278, $D70DD2EE, $4E048354, $3903B3C2,
    $A7672661, $D06016F7, $4969474D, $3E6E77DB,
    $AED16A4A, $D9D65ADC, $40DF0B66, $37D83BF0,
    $A9BCAE53, $DEBB9EC5, $47B2CF7F, $30B5FFE9,
    $BDBDF21C, $CABAC28A, $53B39330, $24B4A3A6,
    $BAD03605, $CDD70693, $54DE5729, $23D967BF,
    $B3667A2E, $C4614AB8, $5D681B02, $2A6F2B94,
    $B40BBE37, $C30C8EA1, $5A05DF1B, $2D02EF8D);
 
type
  {$IFDEF VER130}
    TInteger8 = Int64;
  {$ELSE}
  {$IFDEF VER120}
    TInteger8 = Int64;
  {$ELSE}
    TInteger8 = COMP;
  {$ENDIF}
  {$ENDIF}
 
procedure CalcCRC32(p: Pointer; ByteCount: DWORD; var CRCValue: DWORD);
var
  i: DWORD;
  q: ^BYTE;
begin
  q := p;
  for i := 0 to ByteCount - 1 do
  begin
    CRCvalue := (CRCvalue shr 8) xor
      Table[q^ xor (CRCvalue and $000000FF)];
    Inc(q)
  end
end;
 
function CalcStringCRC32(s: string; out CRC32: DWORD): Boolean;
var
  CRC32Table: DWORD;
begin
  CRC32Table := $FFFFFFFF;
  CalcCRC32(Addr(Table[0]), SizeOf(Table), CRC32Table);
  CRC32Table := not CRC32Table;
 
  if CRC32Table <> $6FCF9E13 then ShowMessage('CRC32 Table CRC32 is ' +
      IntToHex(Crc32Table, 8) +
      ', expecting $6FCF9E13')
  else
  begin
    CRC32 := $FFFFFFFF;
    if Length(s) > 0
      then CalcCRC32(Addr(s[1]), Length(s), CRC32);
    CRC32 := not CRC32;
  end;
end;
 
procedure CalcFileCRC32(FromName: string; var CRCvalue: DWORD);
  var TotalBytes: TInteger8;
  var error: Word;
var
  Stream: TMemoryStream;
begin
  error := 0;
  CRCValue := $FFFFFFFF;
  Stream := TMemoryStream.Create;
  try
    try
      Stream.LoadFromFile(FromName);
      if Stream.Size > 0 then CalcCRC32(Stream.Memory, Stream.Size, CRCvalue)
      except
        on E: EReadError do
          error := 1
    end;
    CRCvalue := not CRCvalue
  finally
    Stream.Free
  end;
end;

Open in new window

0
 
ThievingSixCommented:
Just read your newest post this is what you would do:

It's just something I quickly rattled down, i'll post some checked code in about an hour after dinner.




procedure Test;
var
  MyStream : TFileStream;
  sCRC32Length : String;
  CRC32Length : Integer;
  CRC32,fCRC32 : String
begin
MyStream := TFileStream.Create(Application.EXEName); //Make a TFileStream of the application
 
MyStream.Position := MyStream.Size - 2; //the last two digits is the length of the crc32
 
MyStream.Read(sCRC32Length,2); //read the last two chars of text and use as length
 
CRC32Length := StrToInt(sCRC32Length) //You must put the .Read into a text)
 
MyStream.Position := MyStream.Size - (CRC32Length + 2); //set the position to where the crc32 is
 
MyStream.Read(fCRC32,CRC32Length); //read the crc32
 
MyStream.Position := 1; //set back to the begginning to compare crc
 
MyStream.Read(FileBuffer,MyStream.Size - (CRC32Length + 2)); //read the original file
 
CalcStringCRC32(FileBuffer,CRC32); //get the crc32 of the original file
 
If fCRC32 <> CRC32 Then
  begin
  ShowMessage('Corrupt EXE file')
  Application.Terminate;
end;
 
end;

Open in new window

0
 
Marc582Author Commented:
I can't use stream for size reason :/
0
 
ThievingSixCommented:
Icky Icky!

What are your size restrictions and on what, the EXE file, source, etc.

What about read()/write()?
0
 
Marc582Author Commented:
when you use streams, you must add classes or something, and it adds about 100 kb, my current exe size is just 12 kb
0
 
ThievingSixCommented:
Then do the same thing with Read()/Write()
I raelly can't do it for you atm, working on my own server project atm. I will in a bit though.
0
 
Marc582Author Commented:
to be sure I understand well, is it that should I do:

after all settings applied on the server, I do a crc32 checksum, I write this crc32 checksum in end of file (EOF),

then on the server side, when it opens, it read the crc32 checksum, copy his own file to another place, remove the eof, then check the crc32 and compare it with the one retrieved?
0
 
ThievingSixCommented:
You do realize that the way I get the CRC32 checksum is done by MemoryStreams.
0
 
Marc582Author Commented:
yea but I doubt I can do the same thing with read/write ?
0
 
Marc582Author Commented:
so I would have to bring a text file along with my exe? nan not possible!

but thx
0
 
ThievingSixCommented:
You don't have much room for choice as I see it(I could be wrong), you could use encrypted registry settings if you wanted, let me know if you need help with that.

Unfortunately, the only way to get it working within the self crc is with streams. Also it wouldn't be a text file but a non-extentioned file.
0
 
Marc582Author Commented:
it's just 1 file, I don't want to bring other file with it

I think my idea is the only solution, you don't think so?
0
 
ThievingSixCommented:
The server side check? I'm actually trying to accomplish something similar now but getting socket errors and bind errors everywhere...
0
 
Computer101Commented:
Forced accept.

Computer101
EE Admin
0
All Courses

From novice to tech pro — start learning today.