// wu.cpp -- Unprotect Microsoft Word/Winword Document // Marc Thibault // Word protects a document by XOR'ing a 16-byte key repetitively // through the document file, starting at byte 40. The header (0x180 bytes) // is filthy with zeros including what appears to be over 48 of them at // the end of the header. This program hopes that the last 32 are zeros // (it checks) and extracts the key from this area. Improvements can be // made to this if it ever turns out that these bytes are used for // something. // The encryption key is derived from the user's passphrase by some means // I have not attempted to discover. It is unnecessary, since the // encryption key can be directly discovered and applied. // Call: // wu infile outfile // Exit Status: // 1 too few arguments // 2 can't open given file for input // 3 can't open given file for output // 4 can't find a key (last two rows of header aren't the same) // 5 too short to be a Word file // 6 Problem writing to output file #include #include #ifdef __TURBOC__ #include #endif #ifdef __ZTC__ #include #endif #define Version "1.2" #define VersionDate "26 January 1993" #define keyLength 0x10 #define bufferLength 0x180 #define headerLength 0x180 int findKey(unsigned char buffer[], unsigned char key[]); void fixHeader(unsigned char buffer[], unsigned char key[]); void fixBuffer(unsigned char buffer[], unsigned char key[]); #ifdef debug void showBuffer(unsigned char buf[]); #endif char *copyLeft[] = {"\nMarc Thibault \n", " Oxford Mills, Ontario \n", " This work is released to the public domain. \n", " It may be copied and distributed freely \n", " with appropriate attribution to the author.\n"}; void main(int argc, char *argv[]) { unsigned char buffer[bufferLength]; // data buffer unsigned char key[keyLength]; // encryption key size_t count, check; int i; FILE *crypt, *plain; // ---------------------- if( argc < 3) // file names must be present { cout << "\n Word Unprotect -- Version " << Version; cout << "\n by Marc Thibault, " << VersionDate; cout << "\n Syntax: wu infile outfile \n"; exit (1); } // Open files if( NULL == (crypt = fopen(argv[1], "rb"))) { cout << "\n wu error: can't open the input file\n"; exit (2); } if( NULL == (plain = fopen(argv[2], "wb"))) { cout << "\n wu error: can't open the output file\n"; exit (3); } // Read header from input file count = fread(buffer,1,headerLength,crypt); if(count != bufferLength) { cout << "\n wu error: Input file too short to be a Word File\n"; exit(5); } // Extract the encryption key if(findKey(buffer,key)) { cout << "\n wu error: Couldn't find a key \n"; exit(4); } #ifdef debug cout << "\n Key in hexadecimal is"; for (i=0; i