Pandora Exploit

Because of too much misinformation and general speculation this page will be a proper documentation of the Pandora Exploit (same exploit used for CFW).

For now it’ll just be a straight copy-paste of a post I made on QJ forums (will be updated with more info later):

Yes the block was small enough to bruteforce (hence why you couldnt sign a whole EBOOT, would have to bruteforce the whole thing). The private key wasnt bruteforced though (not that it would matter if it were though, the algorithms are still unknown).

How the decryption works is this, the data is first encrypted and then the encrypted data is signed. When passed to the crypto engine, first it checks the signature and if it’s valid it will decrypt the data (algorithms for both the encryption & signature are unknown, not that I know of anyway, maybe someone knows…or not ).

The fake encrypted data is bruteforced to decrypt into your chosen data (to be able to exploit the preipl). And the signature for your fake encrypted data is bruteforced again to make it appear valid in the eyes of the crypto engine so that it will will go ahead and decrypt your fake encrypted data.

The preipl exploit works like this:

First a decrypted ipl block:
0×00: load address
0×04: data size
0×08: entry address
0x0C: checksum of previous block
0×10: data

A typical example might be
0x040F1EA0
0x00000F50
0×00000000
0xB71C6EBA
…data…

Which means load 0xF50-byte data to 0x040F1EA0. 0xB71C6EBA is the checksum of the previous block. Then entry address is 0 since it hasnt reached the end yet and there are more blocks to load. Once it has loaded all the ipl blocks the very last block will have entry address of where the whole ipl has been loaded (typically 0x040F0000). And will then jump to that address.

Preipl pseudocode for loading & decrypting the ipl:

C:
  1. int iplBlockNumber = 0;
  2. u32 checksum = 0;
  3.  
  4. // load/decrypt all encrypted ipl blocks
  5. while(1)
  6. {
  7.     // copy an encrypted ipl block to 0xBFD00000-0xBFD01000 (4KB embedded cpu ram)
  8.     if (LoadIplBlock(iplBlockNumber, block) <0)
  9.         while(1);
  10.  
  11.     // decrypt the ipl block in place (uh oh…)
  12.     if (DecryptIplBlock(block, block))
  13.         while(1);
  14.  
  15.     // first block will have zero as its checksum since there is no previous block (another uh oh…)
  16.     if (block->checksum != checksum)
  17.         while(1);
  18.  
  19.     // load the ‘data’ section of the ipl block to the specified address (0x040Fxxxx range)
  20.     if (block->loadaddr)
  21.         checksum = memcpy(block->loadaddr, block->data, block->blocksize);
  22.  
  23.     // reached the end of the ipl, jump to the entry address (0x040F0000)
  24.     if (block->entry)
  25.     {
  26.         // clear caches
  27.         Dcache();
  28.         Icache();
  29.  
  30.         // jump to ipl – do not return
  31.         block->entry();
  32.     }
  33.  
  34.     iplBlockNumber++;
  35. }

As the preipl loads the first ipl block (the fake one), it decrypts the block in-place, ie. the decrypted block just overwrites your encrypted block. The fake block only decrypts into four bytes of all 0′s so it ends up only overwriting the first four bytes of your fake block (with four 0′s) after decryption.

The fake signed block:

C:
  1. 00000000: 00 00 00 00 00 00 00 00 00 01 D0 BF 00 00 00 00
  2. 00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  3. 00000020: 52 A1 05 CD 3A 52 59 28 0A D1 31 F1 BD 87 2E CC
  4. 00000030: 14 DA 02 2F 77 88 C7 66 F3 32 07 BD 1A 08 9E 4C
  5. 00000040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  6. 00000050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  7. 00000060: 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  8. 00000070: 04 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00
  9. 00000080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  10. 00000090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  11. 000000A0: 00 00 00 00 00 00 00 00 00 00 00 01 C6 5F 74 12

The most important parts to note:
0×20-0x3F is the bruteforced hash signatures
0xA0-0xAF is the bruteforced encrypted data
0×70-0×73 is the size of the decrypted data (only 4 bytes)

A slight flaw in the crypto engine allowed the bruteforce to be performed on a magnitude-times smaller scale than normally required.

After decryption, the preipl thinks the data is now a decrypted ipl block.
So note the first 0×10 bytes:
0×00000000 (load address which was faked to four 0′s when decrypted)
0×00000000 (size of the block to load, none)
0xBFD00100 (the entry address, the most important part, where your unsigned code is located)
0×00000000 (checksum)

It passes the checksum test (with 0×00000000), it skips the loading of any data (since the loadaddr has been faked to 0×00000000), see’s the entry address of 0xBFD00100 and thinks it has reached the end of the ipl and so goes jumps to that address (which is where your unsigned code will be).

So that’s essentially it in a nutshell. But dont let a quick 5 min. summary of the exploit underestimate the enourmous effort involved in bringing it to fruition (as the final product known as Pandora).