简体   繁体   中英

Reversing CRC32

I found a code to reverse CRC32 but I don't know how it works, because im not that good in programming, I just started. I just want to compare 2 files, the old and the new one, then in the new fix the CRC32 adding 4 bytes at the end of the file, so the 2 files will have the same CRC32. Here is the code, is in C#:

public class Crc32
{
    public const uint poly = 0xedb88320;
    public const uint startxor = 0xffffffff;

    static uint[] table = null;
    static uint[] revtable = null;

    public void FixChecksum(byte[] bytes, int length, int fixpos, uint wantcrc)
    {
        if (fixpos + 4 > length) return;

        uint crc = startxor;
        for (int i = 0; i < fixpos; i++) {
            crc = (crc >> 8) ^ table[(crc ^ bytes[i]) & 0xff];
        }

        Array.Copy(BitConverter.GetBytes(crc), 0, bytes, fixpos, 4);

        crc = wantcrc ^ startxor;
        for (int i = length - 1; i >= fixpos; i--) {
            crc = (crc << 8) ^ revtable[crc >> (3 * 8)] ^ bytes[i];
        }

        Array.Copy(BitConverter.GetBytes(crc), 0, bytes, fixpos, 4);
    }

    public Crc32()
    {
        if (Crc32.table == null) {
            uint[] table = new uint[256];
            uint[] revtable = new uint[256];

            uint fwd, rev;
            for (int i = 0; i < table.Length; i++) {
                fwd = (uint)i;
                rev = (uint)(i) << (3 * 8);
                for (int j = 8; j > 0; j--) {
                    if ((fwd & 1) == 1) {
                        fwd = (uint)((fwd >> 1) ^ poly);
                    } else {
                        fwd >>= 1;
                    }

                    if ((rev & 0x80000000) != 0) {
                        rev = ((rev ^ poly) << 1) | 1;
                    } else {
                        rev <<= 1;
                    }
                }
                table[i] = fwd;
                revtable[i] = rev;
            }

            Crc32.table = table;
            Crc32.revtable = revtable;
        }
    }
}

Here's some PHP code that will also do what you're looking for I spent a great deal of time trying to do this for legitimate purposes so I hope it helps someone

Functions like this could be used to:

  1. always have a single hash that verifies files (eg all files of a certain type return a common crc, versioning etc. w/o having a database)
  2. modify the way hashes are distributed (eg distributed computing key balancing)
  3. reverse original 4 bytes of a crc32

To test crc32 strings online you can use: http://www.lammertbies.nl/comm/info/crc-calculation.html

See http://www.reversing.be/article.php?story=20061209172953555 from where this was adapted from as I'm not the original author, the original spent a great deal of time on his essay, and it helped in no small way

Here's PHP code which can be used to modify a given file as follows:

<?php

//Calculate the original file's CRC32
$DesiredCRC32 = hexdec(hash_file('crc32b','originalcleanfile.ext'));

//Calculate the newfile's current CRC
$CurrentIncorrectCRC32 = hexdec(hash_file('crc32b','newupdatedfile.ext'));

//Generate a 4 byte string that, if appended to the newfile will result in the original CRC32
echo modCRC($DesiredCRC32,$CurrentIncorrectCRC32);  

// I should note that the original guy that posted this has some incorrect calcs on his page
// but if you read carefully and understand the math, you can pick up where it's incorrect
// and learn a thing or two (I beleive last time I tested this code it was accurate)

// if you wanted to do something via the CLI you could use something like: 
parse_str(implode('&', array_slice($argv, 1)), $_GET);
// and grab the files w/ 
$file1 =  $_GET['a'];
//... etc.

//then you could run it via something like this: 
//c:\php\php -f somefile.php a=c:\original.txt b=c:\new.txt c=c:\newwithcrc.txt




public static function modCRC($ExistingCRC, $DesiredCRC){

$crc32lookup = array(
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, 
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, 
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, 
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
);

//More Description:
//Want to append bytes: X  Y  Z  W 
//Take for register  a3 a2 a1 a0  (a is the 'already calculated' crc for string)
//Note that a3 is the most significant byte and a0 the least.
// f is the wanted new CRC byte string, and xyzw is the modification pad

/*
I'll show it a little different way:
a0 + X                  =(1)  points to  b3 b2 b1 b0  in table
a1 + b0 + Y             =(2)  points to  c3 c2 c1 c0  in table
a2 + b1 + c0 + Z        =(3)  points to  d3 d2 d1 d0  in table
a3 + b2 + c1 + d0 + W   =(4)  points to  e4 e3 e2 e1  in table
     b3 + c2 + d1 + e0  =f0
          c3 + d2 + e1  =f1
               d3 + e2  =f2
                    e3  =f3
    (1)  (2)  (3)  (4)
(figure 4)

This is reversed in the same way as the 16bit version. I shall give an example with real values. For the table values use the CRC-32 table in the appendix.
Take for CRC register before, a3 a2 a1 a0 -> AB CD EF 66
Take for CRC register after, f3 f2 f1 f0 -> 56 33 14 78 (wanted value)
Here we go:

First byte of entries            entry   value
e3=f3                     =56 -> 35h=(4) 56B3C423 for e3 e2 e1 e0
d3=f2+e2      =33+B3      =E6 -> 4Fh=(3) E6635C01 for d3 d2 d1 d0
c3=f1+e1+d2   =14+C4+63   =B3 -> F8h=(2) B3667A2E for c3 c2 c1 c0
b3=f0+e0+d1+c2=78+23+5C+66=61 -> DEh=(1) 616BFFD3 for b3 b2 b1 b0

Now we have all needed values, then
X=(1)+         a0=         DE+66=B8
Y=(2)+      b0+a1=      F8+D3+EF=C4
Z=(3)+   c0+b1+a2=   4F+2E+FF+CD=53
W=(4)+d0+c1+b2+a3=35+01+7A+6B+AB=8E
(final computation)
*/
  $ExistingCRC =  ~$ExistingCRC;
  $DesiredCRC = ~$DesiredCRC;

        //a3a2a1a0
        $a3 = (($ExistingCRC & 0xFF000000) >> 24) & 0x000000FF;
        $a2 = ($ExistingCRC & 0x00FF0000) >> 16;
        $a1 = ($ExistingCRC & 0x0000FF00) >> 8;
        $a0 = ($ExistingCRC & 0x000000FF);      

        //f3f2f1f0
        $f3 = (($DesiredCRC & 0xFF000000) >> 24) & 0x000000FF;
        $f2 = ($DesiredCRC & 0x00FF0000) >> 16;
        $f1 = ($DesiredCRC & 0x0000FF00) >> 8;
        $f0 = ($DesiredCRC & 0x000000FF);
        //echo "Existing CRC:" . dechex($ExistingCRC) . " DesiredCRC:" . dechex($DesiredCRC) . "<BR>";
        //echo "a3:" . dechex($a3) . " a2:" . dechex($a2) . " a1:" . dechex($a1) . " a0:" . dechex($a0) . "<br>";
        //echo "f3:" . dechex($f3) . " f2:" . dechex($f2) . " f1:" . dechex($f1) . " f0:" . dechex($f0) . "<br>";

        //capture e3/e2/e1/e0/(4) values
        for ($i = 0; $i < 256; $i++)
        {    
                if (($crc32lookup[$i] & 0xFF000000  ) == ($DesiredCRC & 0xFF000000)){
                $e3 = (($crc32lookup[$i] & 0xFF000000) >> 24) & 0x000000FF;
                $e2 = ($crc32lookup[$i] & 0x00FF0000) >> 16;
                $e1 = ($crc32lookup[$i] & 0x0000FF00) >> 8;
                $e0 = ($crc32lookup[$i] & 0x000000FF);
                $four = $i; 
                break;
                }
        }
        //echo "e3:" . dechex($e3) . " e2:" . dechex($e2) . " e1:" . dechex($e1) . " e0:" . dechex($e0) . "<br>";

        //$d3=f2+e2      =33+B3      =E6 -> 4Fh=(3) E6635C01 for d3 d2 d1 d0
        $d3 = $f2^$e2;    //lookup $d3 and assign the values for d2/d1/d0/(3)
        for ($i = 0; $i < 256; $i++)
        {       
                if (($crc32lookup[$i] & 0xFF000000  ) == ($d3 << 24)){
                $d2 = ($crc32lookup[$i] & 0x00FF0000) >> 16;
                $d1 = ($crc32lookup[$i] & 0x0000FF00) >> 8;
                $d0 = ($crc32lookup[$i] & 0x000000FF);
                $three = $i; 
                break;
                }
        }
        //echo "d3:" . dechex($d3) . " d2:" . dechex($d2) . " d1:" . dechex($d1) . " d0:" . dechex($d0) . "<br>";
        //c3=f1+e1+d2   =14+C4+63   =B3 -> F8h=(2) B3667A2E for c3 c2 c1 c0
        $c3 = $f1^$e1^$d2;

        for ($i = 0; $i < 256; $i++)
        {   
                if (($crc32lookup[$i] & 0xFF000000  ) == ($c3 << 24)){
                $c2 = ($crc32lookup[$i] & 0x00FF0000) >> 16;
                $c1 = ($crc32lookup[$i] & 0x0000FF00) >> 8;
                $c0 = ($crc32lookup[$i] & 0x000000FF);
                $two = $i; 
                break;
                }
        }
        //echo "c3:" . dechex($c3) . " c2:" . dechex($c2) . " c1:" . dechex($c1) . " c0:" . dechex($c0) . "<br>";
        //b3=f0+e0+d1+c2=78+23+5C+66=61 -> DEh=(1) 616BFFD3 for b3 b2 b1 b0
        $b3 = $f0^$e0^$d1^$c2;
        for  ($i = 0; $i < 256; $i++)
        {   
                if (($crc32lookup[$i] & 0xFF000000  ) == ($b3 << 24)){
                $b2 = ($crc32lookup[$i] & 0x00FF0000) >> 16;
                $b1 = ($crc32lookup[$i] & 0x0000FF00) >> 8;
                $b0 = ($crc32lookup[$i] & 0x000000FF);
                $one = $i;
                break;
                }
        }
        /*
        Now we have all needed values, then
        X=(1)+         a0=         DE+66=B8
        Y=(2)+      b0+a1=      F8+D3+EF=C4
        Z=(3)+   c0+b1+a2=   4F+2E+FF+CD=53
        W=(4)+d0+c1+b2+a3=35+01+7A+6B+AB=8E
        (final computation)
        */
        $X = $one ^ $a0;
        $Y = $two ^ $b0^$a1;
        $Z = $three ^ $c0^$b1^$a2;
        $W = $four ^ $d0 ^ $c1 ^ $b2^$a3;

    //echo "Four:" . dechex($four) . " Three:" .dechex($three)." Two:".dechex($two)."One:" .dechex($one) . "<br>";
    //echo "X:" . dechex($X) . " Y:" . dechex($Y) . " Z:" . dechex($Z) . " W:" . dechex($W) . "<br>";
    return chr($X) .  chr($Y) . chr($Z) . chr($W);
}
?>

Would you like to know how it works, or how to use it?

If it's the later, than from the code signature:

public void FixChecksum(byte[] bytes, int length, int fixpos, uint wantcrc)

It seems that you put the contents of your second file to an array (with additional 4 bytes at the end for the fix), and pass it as the bytes parameter. You pass the lengths of this array as the length parameter, you pass the offset to the place to insert the fix to, (in this case length - 4) as fixpos parameter, and you put your desired CRC as wantcrc parameter, you can obtain this value, by calculating CRC of the first file.

FixChecksum method appears to write the 4 bytes fix in the array you have provided at the offset you have provided. After you've made the call to FixChecksum you just need to write the results to your second file.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM