Chapter 8: Protection against File-by-File Disc Copying

File Encryption

To prevent file-by-file copying, it would be ideal to use custom non-standard data formats, which wouldn t be possible to view or play by bypassing the shell program. However, the development of a custom file format requires considerable investment, which is unjustified, because long before the program can make a worthwhile return on this investment, hackers will unbind it from the disc by cracking the protection at the sector level and, thus, be able to engage in disc replication.

Developers of protection mechanisms, therefore, prefer to base them upon existing formats (such as MP3), and simply encrypt the files before writing them to the master disc, then decrypting the CD contents on the fly when playing back. The drawback of this approach is that protection mechanisms based on it are very easy to crack. To do this, it is enough to set the breakpoint to the CreateFile function, wait until the required file is opened, and then trace the EAX register value at the instance of exiting from the function. This value will be the descriptor of the opened file. After that, all that remains is to set the breakpoints to the SetFilePointer/ReadFile functions to make the debugger show up only in cases when our descriptor is passed. The breakpoint set to the memory area containing the data read from the CD will lead the hacker directly to the decryption procedure. Having analyzed its algorithm, the hacker will be able to write a custom decrypting procedure!

If the encryption algorithm is just a trivial XOR (which is most often the case), the disc contents can be cracked even faster! In practice, all non-standard file formats contain a certain volume of more or less predictable information, and, therefore, can be decrypted by an attack based on plain text. For example, AVI, MP2/MP3, WMA, and ASF files contain long chains of consecutive zeros (and/or characters with the code FF ). The encryption key, therefore, is detected by trivially viewing the contents of the protected file in any HEX editor.

Consider the following example. Assume that you have a multimedia CD The Best of Depeche Mode, and the contents of one of its files looks as follows :

Listing 8.8: The hex dump of the header of the file being investigated
image from book
  image from book  
image from book
 

This dump doesn t look like MP3 (MP3 files start with the FF FB signature, which isn t always located in the beginning of the file, however). It doesn t appear as a WAV, either (because WAV files start with the RIFF signature). It doesn t look like a RealAudio file (RealAudio files start with .RMF ), but these files are played in some way or another! Also, at the same time, it is unlikely that the developers of this multimedia CD have designed a custom file format. In all likelihood , this file is encrypted. If this is the case, it is possible to decrypt it!

Let s scroll the HEX editor window down until we encounter the regular sequence shown in Listing 8.9.

Listing 8.9: A regular sequence detected inside the file being investigated
image from book
  image from book  
image from book
 

It is highly probable that in this position, the original file contained a chain of bytes having identical values, for instance, it might be a sequence of zeros or FF bytes, which were XOR ed using a four-byte key.

Since XOR is a symmetric operation, ((A XOR B) XOR A) == B , this means that repeated encryption of the file with its original contents will produce the key. Supposing that there were zeros in this position, the encryption key will be 9E 9D 86 9D . The dots on each side of the key mean that, for the moment, we are not ready to separate the start and end of the regular sequence. Actually, it may be both 9E 9D 86 9D, and 9D 86 9E 9D , or even 86 9D 9E 9D or 9D 9E 9D 86 . However, instead of blindly trying all four variants, let s note that the length of the regular sequence is four. Consequently, the first byte of each period must be located at an offset that is a multiple of four. Hence, the required sequence must be 9D 9E 9D 86 , and because they are located at invalid addresses, all other variants are incorrect. Since the starting addresses of HEX strings displayed by the editor are aligned by the 0x10 bytes boundary (and 0x10 is a multiple of 4), then the first byte of the key must match the starting address of any string.

Now, let us assume that in this position of the original file there was a chain of zeros. Then the encryption key should be as follows: 9D 9E 9D 86 (because (A XOR 0) == A). Start HIEW, press <Enter> to switch to the hex mode, and press <F3> to activate the edit mode. Then press <F8> to open the Enter XOR mask dialog, and enter the hex sequence. After that, you can place something heavy on the <F8> key and go somewhere to relax for a while, because HIEW will take a long time to decrypt the file. As a result, there s nothing else to do other than to take your favorite compiler and write the decryption program yourself. The listing provided below isn t a masterpiece of programming art, but it will do as a working variant developed to quckly close the problem.

Listing 8.10: [/etc/DeXOR.c] A demo example of a simple decryptor
image from book
 /*----------------------------------------------------------------------------------------------  *  *       XORs THE FILE CONTENTS BY ARBITRARY MASK   *       ==========================================   *   * Build 0x001 @ 09.07.2003  ----------------------------------------------------------------------------------------------*/  #include <stdio.h>  #define MAX_LEN 666          // Max. mask length  #define MAX_BUF_SIZE (100*1024)  // Read buffer size  #define FDECODE "decrypt.dat"        // Name of decrypted file  main(int argc, char **argv)  {   long a, b;   long key_len;   FILE *fin, *fout;   long buf_size, real_size;   unsigned char key[MAX_LEN];   unsigned char buf [MAX_BUF_SIZE];  if (argc<3)       // HELP on the command-line options  {      fprintf(stderr,"USAGE: DeXOR.exe file_name AA BB CC DD EE...\n");      return 0;  } // Finding the key length and setting the buffer size  // equal to its multiple  key_len = argc - 2; buf_size = MAX_BUF_SIZE - (MAX_BUF_SIZE % key_len);  // Retrieving keys from the command line into the key array  for (a = 0; a < key_len; a++)  {       // Converting from HEX-ASCII to long       b = strtol(argv[a+2], &" ", 16);       if (b > 0xFF)       // Check for maximum allowed value           {fprintf(stderr, "-ERR: val %x not a byte\x7\n", b); return -1;}       key [a] = b;     // Storing the value of the next byte of the key  }  printf("build a key:"); // Displaying the key (for control)  for(a=0; a < key_len; a++) printf ("%02X", key [a]); printf ("\n");  // Opening the file for reading or writing  fin = fopen(argv[1], "rb"); fout=fopen(FDECODE, "wb");  if ((fin=0)   (fout=0))      { fprintf(stderr, "-ERR: file open error\x7\n"); return -1;}  // Main processing loop  while (real_size=fread(buf, 1, buf_size, fin))  {      // Loop by the buffer      for (a = 0; a < real_size; a+=key_len)      {           // Loop by the key           for(b=0; b < key_len; b++)               buf[a+b] ^= key[b];      }      // Flushing the encrypted (decrypted) buffer to disk      if (0 == fwrite(buf, 1, real_size, fout))      {          fprintf(stderr, "-ERR: file write error\x7\n");          return -1;      }   }   // Exiting  } 
image from book
 

Let s compile this program and start it: image from book  DeXOR.c 03 strangerlove.dat 9D 9E 9D 86 . It would appear that we have failed! The decrypted file doesn t look like an MP3 or a file of any other format. However, this simply means that this wasn t a chain of zeros. Instead, it was something else ”a sequence of FF characters, for instance. To test our assumption, let s XOR the 9D9E9D86h regular sequence by the number FFFFFFh . If we are lucky, we will get the original key as a result of this operation. To do this, we will once again need HIEW, or even the built-in Windows Calculator. Start Windows Calculator, and select the Scientific option from the View menu. Then set the Hex radio button (or press <F5>, as alternative). Enter the value 9D9E9D86 , then click the XOR button and enter FFFFFFFF . Then press <Enter>. The calculator will reply with 62616279 . This is the key for which we are looking. Enter it into the DeXOR program (separate bytes by blanks), and

after renaming the file Strangerlove.dat with the name Strangerlove.mp3, it can be played using any MP3 player. Files of other formats contained on the protected CD can be decrypted in a similar way (naturally, they will have different decryption keys, but the method of finding the keys will be the same).

What conclusions can we draw from this discussion? If you are going to encrypt files with predictable contents, choose an encryption-key length that is comparable to the lengths of predictable sequences, or, better still, a key length that exceeds this length by a number of times. As an alternative, you can use more advanced encryption algorithms instead of XOR (if, that is, you aren t too lazy to implement them).

The task of obtaining a long non-periodic encryption key can actually be elegantly carried out using a random (or, more precisely, a pseudo-random ) number generator. As you probably remember, the pseudo-random sequence generated by the rand() library function is constant at each program start. Therefore, it is an excellent but, at the same time, not self-evident key! The program provided below does exactly this.

Listing 8.11: [crackme.765B98ECh.c] Using rand() for storing the encryption key
image from book
 /*------------------------------------------------------------------------------  *   *       IMPLICIT GENERATION OF THE DECRYPTION KEY USING RAND()   *       ======================================================   *  * Encrypts and decrypts files using the rand() function   * for generating the key; since rand() generates the same sequence any time   * the program is started, specified by srand(), we get a very long   * non-periodic encryption key, "blinding" plain-text attacks.   * Besides, if we modify the rand() code slightly, IDA will be unable   * to detect it. This wont seriously complicate an attempt at cracking, however,   * since rand() implementation is strangely primitive in most cases.   *        Additional protection levels are ensured by complicating the   * data-processing algorithm (for example, it is possible to create the entire   * series of decryptors, only one of which would produce useful data,   * while others will return senseless garbage).   *   *        NOTE: To encrypt the original file, start the program   * with the "-crypt" command-line option. You only need to do this once   * (the file available on the companion CD is already encrypted, and an attempt   * to encrypt it will produce the opposite resultthe file will be decrypted   * and saved to the disk in decrypted form).   *  * Build 0x001 09.07.2003  ------------------------------------------------------------------------------*/  #include <stdio.h>  #include <math.h>  #define FNAME    "file.dat"     // The name of the file to be encrypted or decrypted  #define MAX_SIZE (100*1024)     // Max. possible file size  #define SEED     0x666     // Setting the rand() sequence                             // This can be any number.                             // It simply has to be present!  //--[crypt]------------------------------------------------------------------ // fname -     - file name  // buf         - pointer to the buffer to which the decrypted data must be loaded  // buf_size    - buffer size  // need_store  - is it necessary to store encrypted or decrypted file on the disk?  //        :0   do not write, != 0   write  //--------------------------------------------------------------------------- crypt(char *fname, char *buf, int buf_size, int need_store)  {       FILE *f;       long a, b;       // Do not forget to initialize the random number generator explicitly.       // If other branches of the program also use rand(),       // the decryption result will "float".       s rand (SEED);       // Opening the decrypted file       f=f open (fname, "rb"); if (f==0) return -1;       // Loading data into the buffer       a = fread(buf, 1, buf_size, f); if (!a   (a == buf_size)) return -1;       // (En  de) crypt the buffer contents using the key       // generated on the fly by the rand() function       for (b = 0; b < a; b++) buf[b] ^= (rand() % 255); fclose (f);       // Debugging for automatic file encryption       if (need_store)       {            f=fopen(f name, "wb");   if (f==0) return -1;            fwrite(buf, 1, a, f); fclose (f); return -1;       }       return a;  } main(int argc, char** argv)  {       long a, x;       long need_store=0;       unsigned char buf [MAX_SIZE];       // TITLE       fprintf (srderr, "crackme 765b98ec by Kris Kaspersky\n");       //If there is the debug key -crypt encrypt       if ((argc > 1) && !strcmp(argv[1], "-crypt")) need_store++;       // Load the FNAME file, decrypt and display its contents.       if ((x=Crypt(FNAME, buf, MAX_SIZE, need_s tore))!=-!)            for (a = 0; a < x; a++) printf("%c", buf [a]);  } 
image from book
 


CD Cracking Uncovered. Protection against Unsanctioned CD Copying
CD Cracking Uncovered: Protection Against Unsanctioned CD Copying (Uncovered series)
ISBN: 1931769338
EAN: 2147483647
Year: 2003
Pages: 60

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net