Delphi 为什么嵌入式CRC和当前CRC不同?

Delphi 为什么嵌入式CRC和当前CRC不同?,delphi,delphi-xe5,crc32,Delphi,Delphi Xe5,Crc32,我找到了德尔菲·埃克萨姆勒。它应该嵌入CRC并检查当前CRC。两者应该匹配,但我得到的结果不同。如何修复它?如何加速呢 CRC32Calc.pas unit CRC32Calc; interface uses Classes, SysUtils, windows, messages; type Long = record LoWord: Word; HiWord: Word; end; const CRCPOLY = $EDB88320; procedure

我找到了德尔菲·埃克萨姆勒。它应该嵌入CRC并检查当前CRC。两者应该匹配,但我得到的结果不同。如何修复它?如何加速呢

CRC32Calc.pas

unit CRC32Calc;

interface

uses Classes, SysUtils, windows, messages;

type
  Long = record
    LoWord: Word;
    HiWord: Word;
  end;

const
  CRCPOLY = $EDB88320;

procedure BuildCRCTable;
function RecountCRC(b: byte; CrcOld: LongWord): LongWord;
function GetCRC32(FileName: string; Full: boolean): string;

function SetEmbeddedCRC(FileName: string): string;
function GetEmbeddedCRC(FileName: string): string;

function BytesToHexStr(pB: PByte; BufSize: LongWord): String;
function HexStrToBytes(Str: String): String;

implementation

var
  CRCTable: array [0 .. 512] Of LongWord;

  // A helper routine that creates and initializes
  // the lookup table that is used when calculating a CRC polynomial
procedure BuildCRCTable;
var
  i, j: Word;
  r: LongWord;
begin
  FillChar(CRCTable, SizeOf(CRCTable), 0);
  for i := 0 to 255 do
  begin
    r := i shl 1;
    for j := 8 downto 0 do
      if (r and 1) <> 0 then
        r := (r Shr 1) xor CRCPOLY
      else
        r := r shr 1;
    CRCTable[i] := r;
  end;
end;

// A helper routine that recalculates polynomial relative to the specified byte
function RecountCRC(b: byte; CrcOld: LongWord): LongWord;
begin
  RecountCRC := CRCTable[byte(CrcOld xor LongWord(b))
    ] xor ((CrcOld shr 8) and $00FFFFFF)
end;

// A helper routine that converts Word into String
function HextW(w: Word): string;
const
  h: array [0 .. 15] Of char = '0123456789ABCDEF';
begin
  HextW := '';
  HextW := h[Hi(w) shr 4] + h[Hi(w) and $F] + h[Lo(w) shr 4] + h[Lo(w) and $F];
end;

// A helper routine that converts LongWord into String
function HextL(l: LongWord): string;
begin
  with Long(l) do
    HextL := HextW(HiWord) + HextW(LoWord);
end;

// Calculate CRC32 checksum for the specified file
function GetCRC32(FileName: string; Full: boolean): string;
var
  f: TFileStream;
  i, CRC: LongWord;
  aBt: byte;
begin
  // Build a CRC table
  BuildCRCTable;

  CRC := $FFFFFFFF;
  // Open the file
  f := TFileStream.Create(FileName, (fmOpenRead or fmShareDenyNone));

  // To calculate CRC for the whole file use this loop boundaries
  if Full then
    for i := 0 to f.Size - 1 do
    begin
      f.Read(aBt, 1);
      CRC := RecountCRC(aBt, CRC);
    end
  else
    // To calculate CRC for the file excluding the last 4 bytes
    // use these loop boundaries
    for i := 0 to f.Size - 5 do
    begin
      f.Read(aBt, 1);
      CRC := RecountCRC(aBt, CRC);
    end;

  f.Destroy;
  CRC := Not CRC;

  Result := HextL(CRC);
end;

// Calculate CRC and writes it to the end of file
function SetEmbeddedCRC(FileName: string): string;
var
  f: TFileStream;
  CRCOffset: LongWord;
  CRC: string;
begin
  f := TFileStream.Create(FileName, (fmOpenReadWrite or fmShareDenyNone));
  CRCOffset := f.Size;

  // Append a placeholder for actual CRC to the file
  f.Seek(CRCOffset, TSeekOrigin.soBeginning);
  f.Write(PByte(HexStrToBytes('FFFFFFFF'))^, 4);

  // Obtain CRC
  CRC := GetCRC32(FileName, True);

  // Write CRC to the end of file
  f.Seek(CRCOffset, TSeekOrigin.soBeginning);
  f.Write(PByte(HexStrToBytes(CRC))^, 4);
  f.Destroy;
  Result := CRC;
end;

// Extract the CRC that was stored at last 4 bytes of a file
function GetEmbeddedCRC(FileName: string): string;
var
  f: TFileStream;
  CRCOffset: LongWord;
  pB: PByte;
begin
  GetMem(pB, 4);

  // Open file
  f := TFileStream.Create(FileName, (fmOpenRead or fmShareDenyNone));

  // Proceed upto the end of file
  CRCOffset := f.Size - 4;
  f.Seek(CRCOffset, TSeekOrigin.soBeginning);

  // Read the last four bytes where the CRC is stored
  f.Read(pB^, 4);
  f.Destroy;
  Result := BytesToHexStr(pB, 4);
end;

// A helper routine that converts byte value to string with hexadecimal integer
function BytesToHexStr(pB: PByte; BufSize: LongWord): String;
var
  i, j, b: LongWord;
begin
  SetLength(Result, 2 * BufSize);

  for i := 1 to BufSize do
  begin
    for j := 0 to 1 do
    begin
      if j = 1 then
        b := pB^ div 16
      else
        b := pB^ - (pB^ div 16) * 16;
      case b of
        0:
          Result[2 * i - j] := '0';
        1:
          Result[2 * i - j] := '1';
        2:
          Result[2 * i - j] := '2';
        3:
          Result[2 * i - j] := '3';
        4:
          Result[2 * i - j] := '4';
        5:
          Result[2 * i - j] := '5';
        6:
          Result[2 * i - j] := '6';
        7:
          Result[2 * i - j] := '7';
        8:
          Result[2 * i - j] := '8';
        9:
          Result[2 * i - j] := '9';
        10:
          Result[2 * i - j] := 'A';
        11:
          Result[2 * i - j] := 'B';
        12:
          Result[2 * i - j] := 'C';
        13:
          Result[2 * i - j] := 'D';
        14:
          Result[2 * i - j] := 'E';
        15:
          Result[2 * i - j] := 'F';
      end;
    end;

    Inc(pB);
  end;
end;

// A helper routine that converts string with hexadecimal integer to byte value
function HexStrToBytes(Str: String): String;
var
  b, b2: byte;
  lw, lw2, lw3: LongWord;
begin
  lw := Length(Str) div 2;
  SetLength(Result, lw);

  for lw2 := 1 to lw do
  begin
    b := 0;

    for lw3 := 0 to 1 do
    begin
      case Str[2 * lw2 - lw3] of
        '0':
          b2 := 0;
        '1':
          b2 := 1;
        '2':
          b2 := 2;
        '3':
          b2 := 3;
        '4':
          b2 := 4;
        '5':
          b2 := 5;
        '6':
          b2 := 6;
        '7':
          b2 := 7;
        '8':
          b2 := 8;
        '9':
          b2 := 9;
        'a':
          b2 := 10;
        'b':
          b2 := 11;
        'c':
          b2 := 12;
        'd':
          b2 := 13;
        'e':
          b2 := 14;
        'f':
          b2 := 15;
        'A':
          b2 := 10;
        'B':
          b2 := 11;
        'C':
          b2 := 12;
        'D':
          b2 := 13;
        'E':
          b2 := 14;
        'F':
          b2 := 15;
      else
        b2 := 0;
      end;

      if lw3 = 0 then
        b := b2
      else
        b := b + 16 * b2;
    end;

    Result[lw2] := char(b);
  end;
end;

end.
我的结果是:

AppendCRC.exe Hello_Delphi_World.exe
Full checksum (before): 1912DA64
Half checksum: 1912DA64
Full checksum (after): B3F0A43E
GetEmbeddedCRC: :4400A000
The checksum was successfully embedded.

我使用的是Delphi XE5。

您应该了解此代码的工作原理。 总体思路是将CRC作为EXE结构之外的额外4个字节附加到文件末尾。(更好的办法是在开始时将CRC放入EXE头中的一个特殊字段)

然而,这引发了母鸡和鸡蛋的问题:在我们计算CRC并嵌入它之后,CRC文件被更改(附加CRC的值),并且更改文件的CRC也会更改

因此,您基本上必须实现CRC计算的两种模式/功能:整个文件和没有最后4个字节的文件。您应该使用后一种模式来计算附加后的CRC(您称之为嵌入),使用前一种模式在刚刚编译的程序上计算附加前的CRC

GetCRC32函数总是从文件中剪切最后4个字节,因此在嵌入之前,它只计算文件的某个部分的CRC,而不是整个文件的CRC。但是必须有两种不同的模式

PS:您还可以将CRC“嵌入”到NTFS备用流中,比如将
MyApp.exe
程序和CRC存储为
MyApp.exe:CRC

PPS。我认为在GetCRC32中使用无缓冲的逐字节读取应该非常慢。如果可能的话,最好使用TBytesStream将文件作为一个整体读入内存,然后以通常的循环方式扫描阵列。或者通过4096字节的块而不是字节变量来读取它。
对于最后一个不完整的缓冲区,您可以使用零来清除缓冲区的其余部分。

我建议您将相关代码部分放在这里,从而解决这个问题。StackOverflow的设计目的是让答案和问题出现在网站上,而不是出现在任何时候都可能消失的外部链接中。让人们经历下载ZIP的麻烦会降低你得到正确答案的机会。我会修改SetEmbeddedCRC,使其不仅计算并在文件末尾添加CRC,还可以添加一个标记(或签名),以便GetEmbeddedCRC和SetEmbeddedCRC识别文件中是否存在CRC。如果已经存在CRC,则在计算CRC时将跳过该CRC。CRC签名可以是CRC的CRC的另一个4字节。添加到文件中的总字节数是8字节。这有什么意义?为什么不使用GetCRC32模式,忽略或不忽略最后字节?谢谢你的提议,但NTFS备用流不是我想要的。没有标记,GetCRC无法判断CRC是否错误或根本没有CRC。@fpiette我认为在实际意义上没有区别。EXE是否有“签名”之分
AppendCRC.exe Hello_Delphi_World.exe
Full checksum (before): 1912DA64
Half checksum: 1912DA64
Full checksum (after): B3F0A43E
GetEmbeddedCRC: :4400A000
The checksum was successfully embedded.