A real-world example of such a situation can be seen in JB's ESET CONFidence Crackme Writeup. Good code that I recently used it in another situation, in order to forge a text of a given CRC-32 by inserting 4 bytes at a specific position.
Since I reused most of his code, let's share mine as well (crc32.py):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | #!/usr/bin/env python from struct import pack,unpack # Poly in "reversed" notation -- http://en.wikipedia.org/wiki/Cyclic_redundancy_check POLY = 0xedb88320 # CRC-32-IEEE 802.3 #POLY = 0x82F63B78 # CRC-32C (Castagnoli) #POLY = 0xEB31D82E # CRC-32K (Koopman) #POLY = 0xD5828281 # CRC-32Q def build_crc_tables(): for i in range ( 256 ): fwd = i rev = i << 24 for j in range ( 8 , 0 , - 1 ): # build normal table if (fwd & 1 ) = = 1 : fwd = (fwd >> 1 ) ^ POLY else : fwd >> = 1 crc32_table[i] = fwd & 0xffffffff # build reverse table =) if rev & 0x80000000 = = 0x80000000 : rev = ((rev ^ POLY) << 1 ) | 1 else : rev << = 1 rev & = 0xffffffff crc32_reverse[i] = rev crc32_table, crc32_reverse = [ 0 ] * 256 , [ 0 ] * 256 build_crc_tables() def crc32(s): # same crc32 as in (binascii.crc32)&0xffffffff crc = 0xffffffff for c in s: crc = (crc >> 8 ) ^ crc32_table[(crc ^ ord (c)) & 0xff ] return crc^ 0xffffffff def forge(wanted_crc, str , pos = None ): if pos is None : pos = len ( str ) # forward calculation of CRC up to pos, sets current forward CRC state fwd_crc = 0xffffffff for c in str [:pos]: fwd_crc = (fwd_crc >> 8 ) ^ crc32_table[(fwd_crc ^ ord (c)) & 0xff ] # backward calculation of CRC up to pos, sets wanted backward CRC state bkd_crc = wanted_crc^ 0xffffffff for c in str [pos:][:: - 1 ]: bkd_crc = ((bkd_crc << 8 )& 0xffffffff ) ^ crc32_reverse[bkd_crc >> 24 ] ^ ord (c) # deduce the 4 bytes we need to insert for c in pack( '<L' ,fwd_crc)[:: - 1 ]: bkd_crc = ((bkd_crc << 8 )& 0xffffffff ) ^ crc32_reverse[bkd_crc >> 24 ] ^ ord (c) res = str [:pos] + pack( '<L' , bkd_crc) + str [pos:] assert (crc32(res) = = wanted_crc) return res |
Given a text, a CRC-32 and a position, you can forge a new text having this exact CRC-32 by inserting 4 bytes at the indicated position:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | >>> str = "some text" >>> wanted_crc = 0xdeadbeef >>> for pos in range ( len ( str )): f = forge(wanted_crc, str , pos) print "%-30r CRC32 0x%08x" % (f, crc32(f)) '^q\xb4\x19some text' CRC32 0xdeadbeef 's\x04\xe8\xc66ome text' CRC32 0xdeadbeef 'so8~V\xb5me text' CRC32 0xdeadbeef 'som\x05\xf3\xb4ve text' CRC32 0xdeadbeef 'some\xab\xd5\xc4( text' CRC32 0xdeadbeef 'some }\x9eBZtext' CRC32 0xdeadbeef 'some t:\xfa\x86\rext' CRC32 0xdeadbeef 'some te\x9f\xca\xd9\x9ext' CRC32 0xdeadbeef 'some tex\x11\xae\xf0Ft' CRC32 0xdeadbeef |
Thanks JB :)
Other CRC-32 resources: crctools by Julien Tinnes, libcrc by Y. Guillot, among others.
cool :) saved the script
ReplyDeletePS added a wrap for command line :)
ReplyDeletehttp://dl.dropbox.com/u/8748250/crc32forge.py
Thanks for this. Very useful information.
ReplyDelete