2014-01-13 33 views
1

我找到了this Delphi檢測。它應該嵌入CRC並檢查當前的CRC。兩者都應該匹配,但我得到不同的結果。如何解決它?如何加快速度?爲什麼嵌入式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 = 'ABCDEF'; 
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

program AppendCRC; 

{$APPTYPE CONSOLE} 

uses 
    SysUtils, Classes, 
    CRC32Calc in '..\CRC32Checker\CRC32Calc.pas'; 

var 
    FileName: string; 

begin 
    { TODO -oUser -cConsole Main : Insert code here } 
    if ParamCount = 1 then 
    begin 
    FileName := ParamStr(1); 
    // Verify whether a file exists 
    if not FileExists(FileName) then 
    begin 
     WriteLn('The specified file does not exist.'); 
     Exit; 
    end; 
    WriteLn('Full checksum (before): ' + GetCRC32(FileName, True)); 
    SetEmbeddedCRC(FileName); 
    WriteLn('Half checksum: ' + GetCRC32(FileName, False)); 
    WriteLn('Full checksum (after): ' + GetCRC32(FileName, True)); 
    WriteLn('GetEmbeddedCRC: :' + GetEmbeddedCRC(FileName)); 
    WriteLn('The checksum was successfully embedded.') 
    end 
    else 
    begin; 
    WriteLn('Wrong parameters.'); 
    WriteLn('Parameter1 - Full path to file.');; 
    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。

+0

我建議你在這裏放置相關的代碼部分,這是一個很好的問題。 StackOverflow旨在在網站上提供答案和問題,而不是在任何時候可能消失的外部鏈接中。並要求人們經歷下載ZIP的麻煩,減少了獲得正確答案的機會。 –

回答

1

你應該明白這段代碼的工作原理。 總體思路是將CRC作爲額外的4個字節,從EXE結構中附加到文件的末尾。 (更好的想法是將CRC放入EXE Header中的特殊字段中)。然而,這引起了母雞和卵子的問題:在我們計算CRC並嵌入之後--CRC文件被改變(CRC的值被附加)並且改變的文件的CRC也改變。

所以你基本上必須實現CRC計算的兩種模式/功能:對於整個文件和沒有最後4個字節的文件。你應該使用後一種模式在附加後計算CRC(你稱之爲嵌入),前一種計算CRC之前在香草剛剛編譯的程序中計算CRC。

您的GetCRC32函數總是剪切文件中的最後4個字節,因此在嵌入之前,它僅計算文件某些部分的CRC,而不計算整個文件的CRC。但是有兩種不同的模式。 PS:您也可以將CRC嵌入到NTFS備用數據流中,如MyApp.exe程序和CRC存儲爲MyApp.exe:CRC

PPS。我認爲在GetCRC32中使用非緩衝讀取字節應該非常慢。如果可能的話,最好使用TBytesStream將整個文件讀入內存,然後在通常的數組循環中掃描。或者以4096字節的塊而不是字節變量讀取它。 對於最後一個非完整緩衝區,例如,您將用零清理剩餘的緩衝區。

+0

我會修改SetEmbeddedCRC,不僅計算並在文件末尾添加CRC,還要添加標記(或簽名),以便GetEmbeddedCRC和SetEmbeddedCRC識別文件中是否存在CRC。如果已經有一個CRC,在計算CRC時它將被跳過。 CRC簽名可以是CRC的另一個4字節。添加到文件的總字節數爲8個字節。 – fpiette

+0

這是什麼意思?爲什麼不使用GetCRC32模式,忽略或忽略最後一個字節? –

+0

感謝您的報價,但NTFS備用流不是我想要的。 –