// crcspoof.cpp : main project file. #include #include #include #include #include #include /* srand, rand */ #include /* time */ using namespace System; using namespace std; typedef unsigned __int32 UI32; class CrcZip { public: explicit CrcZip(UI32 a_r=~0) : r(a_r){} enum {gf=0xdb710641}; // This is the generator UI32 r; // residual, polynomial mod gf void clk(int i=0); // clock in data, bit at a time void update(char *pbuf, int len); // update crc residual operator UI32(){return ~r;}; // object yields current CRC void clkrev(); // clk residual backwards }; // This reverses CrcZip::clk(0) // in Galois terms: R := i + R*X void CrcZip::clkrev() { if (r & 0x80000000) r = (r << 1) ^ gf; else r = (r << 1); } // this is the basic "gut's" of crc calcuation. // and updates the crc's 32 bit residual for a // single bit, in terms of galois theory // this is: R := R*X^(-1) void CrcZip::clk(int i) { r ^= i; // rotation combined with possible xor of "gf" if (1 & r) r = ((r^gf) >> 1) | 0x80000000; else r >>= 1; } // This does a byte at a time by calculating the // crc bit by bit, lsb first. Slow, but clear. void CrcZip::update(char *pbuf, int len) { while (len--) { int bitcnt, byte = *pbuf++; for (bitcnt=0; bitcnt < 8; bitcnt++) { clk(byte & 1); byte >>= 1; } } } int readfile(char *filename, char **memblock, int *size) { streampos sizeOfFile; ifstream file (filename, ios::in|ios::binary|ios::ate); if (!file) { return 0; } else { sizeOfFile = file.tellg(); *size++ = sizeOfFile; *memblock = new char [*size]; file.seekg (0, ios::beg); file.read (*memblock, *size); file.close(); return 1; } } int main(array ^args) { CrcZip crc; char * memblock, * memblock2; char replacementinfo[500], replacementbytes[5]; int size, i, randomOffset; if (readfile("sample1.txt", &memblock, &size)) { /* initialize random seed: */ srand (time(NULL)); /* generate random offset with gauaranteed 4 byte span */ randomOffset = (rand() % (size-4)) + 1; CrcZip crc1, crc1a, crc1b; memblock[size]=0; memblock2 = new char [size]; for(i=0; i < size; ++i) { memblock2[i]='0'; } ofstream ofile("sample2.txt", ios_base::binary); ofile.write(memblock2, size); crc1.update(memblock, size); crc1a.update(memblock2, size); CrcZip crcSpoof(crc1a^crc1); for (int i =0; i < (size-randomOffset)*8; i++) crcSpoof.clkrev(); *(reinterpret_cast(memblock2+randomOffset)) ^= crcSpoof.r; // We now have a string that produces the desired crc when zipped ofstream ofile2("sample3.txt", ios_base::binary); ofile2.write(memblock2, size); memcpy(replacementbytes, memblock2+randomOffset, 4); crc1b.update(memblock2, size); sprintf(replacementinfo, "The ASCII and hexadecimal values of those four bytes are as follows: %c (%0.2X), %c (%0.2X), %c (%0.2X), %c (%0.2X), and they are now at position %d within the string of zeroes which will be written to the spoof file sample3.txt", (char) *replacementbytes, ((char) *(replacementbytes)) & 0x000000FF, (char) *(replacementbytes+1), ((char) *(replacementbytes+1) & 0x000000FF), (char) *(replacementbytes+2), ((char) *(replacementbytes+2) & 0x000000FF), (char) *(replacementbytes+3), ((char) *(replacementbytes+3) & 0x000000FF), randomOffset); cout << "File sample1.txt's contents has been successfully read into memory taking up " << size << " bytes" << endl << "the file reads as follows: \"" << memblock << "\"" << endl << endl; cout << "The CRC-32 for the sample1.txt file is hexadecimal " << hex << setfill('0') << setw(8) << uppercase << crc1 << endl << endl; cout << "We will now create sample2.txt file which is the same size as sample1.txt but only contains a string of zeroes" << endl << "File sample2.txt's CRC-32 number is hexadecimal " << hex << setfill('0') << setw(8) << uppercase << crc1a << endl << endl; cout << "We will now replace four consecutive (specially calculated) bytes suited to random generated position/offset " << dec << randomOffset << " within the string of zeroes which will yield the same CRC-32 value as file sample1.txt and thus spoof it ..." << endl << endl; cout << replacementinfo << endl << endl; cout << "File sample3.txt's CRC-32 number is " << hex << setfill('0') << setw(8) << uppercase << crc1b << endl << endl; cout << "While size and CRC-32 numbers for sample1.txt and sample3.txt are the same, their contents aren't proving that CRC-32 numbers are not unique for same sized files;" << endl; cout << "however if your original file strictly contains text only ASCII values, the spoof file is guaranteed not to - meaning it will contain some non-text characters." << endl << endl; delete[] memblock; delete[] memblock2; } else { cout << "Couldn't open file" << endl << endl; } return 0; }