Editing PARAM.PFD

Jump to navigation Jump to search
Warning: You are not logged in. Your IP address will be publicly visible if you make any edits. If you log in or create an account, your edits will be attributed to your username, along with other benefits.

The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then publish the changes below to finish undoing the edit.

Latest revision Your text
Line 1: Line 1:
{{Wikify}}
[[Category:Software]]
[[File:PFD Structure.png|thumbnail|Overview on the PARAM.PFD file structure]]
Alot of this page is filled with speculation and in need of cleanup, making room for proper structured information
 


==Description==
==Description==
'''PFD''' ('''P'''rotected '''F'''iles '''D'''atabase) are responsible to prevent tampering of other files of the same folder, the only purpose is the security of the folder contents. Contains the cryptographic signatures of other files of the same folder (not all, but the ones that developers decided to be important enought to be secured).
'''PFD''' ('''P'''rotected '''F'''iles '''D'''atabase) are responsible to prevent tampering of other files of the same folder, the only purpose is the security of the folder contents. Contains the cryptographic signatures of other files of the same folder (not all, but the ones that developers decided to be important enought to be secured).


Its used in several paths of the PS3, usually to secure data related with the user profile e.g:
Its used in several paths of the PS3, usually to secure data related with the user profile e.g:


  /dev_hdd0/home/0000000*/savedata/SAVEDATA_DIRECTORY/PARAM.PFD <---- in all save game folders
  /dev_hdd0/home/0000000*/savedata/SAVEDATA_DIRECTORY/PARAM.PFD <---- in all save game folders
  /dev_hdd0/home/0000000*/trophy/NPCOMMID/PARAM.PFD <--- in all trophy folders
  /dev_hdd0/home/0000000*/trophy/NPCOMMID/PARAM.PFD <--- in all trohpy folders
  /dev_hdd0/home/0000000*/trophy/_TROPSYS_/PARAM.PFD <---- in the "user trophy index" folder
  /dev_hdd0/home/0000000*/trophy/_TROPSYS_/PARAM.PFD <---- in the "user trophy index" folder


Line 35: Line 31:
  Total file size = 96+24+456+31008+1140+44 = 32768 bytes (0x8000)
  Total file size = 96+24+456+31008+1140+44 = 32768 bytes (0x8000)


'''C Code By Jakes625, Credits to flatz for original source'''
The size of the file is fixed because the number of entries in both '''X table''' & '''Y table''' is 57 (when the entry is not used his position is marked as "not-used"). In the same way... the '''Protected files table''' has an area reserved for a maximun of 114 entries (not used entries are filled with zeroes). As result the file contains the maximun number of possible entries
<code>
    typedef unsigned long int u64;
    typedef unsigned char byte;
 
    typedef struct
    {
        u64 magic; //PDFB
        u64 version; //3 or 4 else error
    } pfd_header_t;
 
    typedef struct
    {
        byte bottom_hash[20];
        byte top_hash[20];
        byte hash_key[20]; //use the decrypted hash_key for sha1 hmac hashing (in sig table)
        byte padding[4];
    } header_table_t;
 
    typedef struct
    {
        u64 num_reserved; //# of entries reserved in entry table (0x39)
        u64 num_total;  //# of total entries (0x72)
        u64 num_used; //# of used entries (the number of files in the folder with pfd)
        u64 hash_entries[39]; //num reserved (* if you prefer)
    } pfd_hash_table_t;
 
    typedef struct
    {
        u64 addition_entry;
        char file_name[65]; //c string
        byte padding_0[7];
        union
        {
            struct
            {
                byte key[64]; //used for file decryption/encryption and sig table hashing
                byte file_hashes[4][20]; //4 hashes from hmac sha1 following the key
                byte padding_1[40];
                u64 file_size;
            };
            byte file_certificate[192];
        }
    } pfd_entry_table_t;
 
    typedef struct
    {
        pfd_header_t header;
        byte header_table_iv[0xF]; //key used for aes cbc decryption of header table
        pfd_header_table_t header_table;
        pfd_hash_table_t hash_table;
        pfd_entry_table_t entry_table;
        byte sig_table[39][20]; //array of 39 signatures (corresponding to hash table) and each signature is 20 bytes long (hmac sha1)
        byte end_padding[44]; //out of memory I think it's 44
    } pfd_file_t;</code>
 
The size of the file is fixed because the number of entries in both '''X table''' & '''Y table''' is 57 (when the entry is not used their position is marked as "not-used"). In the same way... the '''Protected files table''' has an area reserved for a maximum of 114 entries (not used entries are filled with zeroes). As result the file contains the maximum number of possible entries


*Useful game saves used in this page as examples
*Useful game saves used in this page as examples
Line 174: Line 114:
  From 0x78 to 0x240
  From 0x78 to 0x240
  Size = 456 bytes
  Size = 456 bytes
  Entry length = 8 bytes
  Entry lenght = 8 bytes
  Number of entries = 57
  Number of entries = 57


Each entry can contain a "file index" (from 0x00 to 0x71... or 1 to 114 in decimal) that is pointing (or is assigned) to one of the files in the '''Protected files table'''. How this assignation works is unknown
Each entry can contain a "file index" (from 0x00 to 0x71... or 1 to 114 in decimal) that is pointing (or is asigned) to one of the files in the '''Protected files table'''. How this assignation works is unknown


If the "file index" is 72 (position 115) it means that is pointing out of the '''Protected files table''' (not used)
If the "file index" is 72 (position 115) it means that is pointing out of the '''Protected files table''' (not used)
Line 185: Line 125:
The table does not fills with entries from top to bottom, usually the first entries are not used (marked as 72) followed by entries with whatever number from 0 to 71 (by now the entries used seems random), and mixed with more 72's entries
The table does not fills with entries from top to bottom, usually the first entries are not used (marked as 72) followed by entries with whatever number from 0 to 71 (by now the entries used seems random), and mixed with more 72's entries


Used entries has a number assigned by their position in the table e.g:
Used entries has a number asigned by his position in the table e.g:


*Mirror's edge game save '''X table'''
*Mirror's edge game save '''X table'''
Line 358: Line 298:
  From 0x240 to 0x7B60
  From 0x240 to 0x7B60
  Size = 31008 bytes
  Size = 31008 bytes
  Entry length = 272 bytes
  Entry lenght = 272 bytes
  Number of reserved entries = 114
  Number of reserved entries = 114
  Number of used entries = variable from 1 to 114
  Number of used entries = variable from 1 to 114
Line 376: Line 316:
|}
|}


*Notes
*Note
Certificate: The first 64 bytes are the entry key used to decrypt PARAM.SFO (or whatever entry the file is) and the next 80 bytes are the 4 hmac sha1 hashes. PARAM.SFO has more than other files because it goes through a different hashing process using the param sfo encryption key as do others such as trophies and console id etc. Then 40 bytes of padding, followed by (u64) (8 bytes) of the file size of the file entry
Certificate: When the file is PARAM.SFO the certificate is longer and maybe uses imput data from "PARAMS" and/or "ACCOUNT_ID" inside PARAM.SFO. Encrypted by VTRM using the same portability algorithm. Key is unknown yet. The first 0x10 and the second 0x10 bytes are randomly generated (key/iv?).


Encrypted by VTRM using the same portability algorithm. Key is unknown yet. The first 0x10 and the second 0x10 bytes are randomly generated (key/iv?).
Each entry can store the signature of one of the files in the folder, there is always an entry used to store the signature of [[PARAM.SFO]], this gives a maximun number of protected files generated by the game of 113. Used entries fills the table from top to bottom, not-used entries are placed at the end of the table filled with zeroes


Each entry can store the signature of one of the files in the folder, there is always an entry used to store the signature of [[PARAM.SFO]], this gives a maximum number of protected files generated by the game of 113. Used entries fills the table from top to bottom, not-used entries are placed at the end of the table filled with zeroes
The first 8 bytes of each entry (Virtual Index ID) works in the same way than the entries in the '''X table''', when not used are marked as "72" and when used are randomnly placed asigning a "file index" to the entry. This "file index" does not matches with the position of the entry in the '''Protected files table''' itself... (e.g: indexed 0x06 is in position 14)


The first 8 bytes of each entry (Virtual Index ID) works in the same way than the entries in the '''X table''', when not used are marked as "72" and when used are randomly placed assigning a "file index" to the entry. This "file index" does not matches with the position of the entry in the '''Protected files table''' itself... (e.g: indexed 0x06 is in position 14)
For a theoricall file with alll entries used (114 protected files), half of the "file index" numbers will be spreaded between the '''X table''' (can only contain 57) ant the first 8 bytes of some entries in the '''Protected files table''' (the other 57)
 
For a theoretical file with all entries used (114 protected files), half of the "file index" numbers will be spreaded between the '''X table''' (can only contain 57) ant the first 8 bytes of some entries in the '''Protected files table''' (the other 57)


*Mirror's edge game save '''Protected Files Table'''
*Mirror's edge game save '''Protected Files Table'''
Line 466: Line 404:
  From 0x7B60 to 0x7FD4
  From 0x7B60 to 0x7FD4
  Size = 1140 bytes
  Size = 1140 bytes
  Entry length = 20 bytes (SHA-1 HMAC digest)
  Entry lenght = 20 bytes (SHA-1 HMAC digest)
  Number of entries = 57
  Number of entries = 57


Is directly related with the '''X table''', both matches in the total number of entries (57) and which ones are used (e.g. when the '''X table''' has a entry in position 12... the '''Y table''' has position 12 used)  
Is directly related with the '''X table''', both matches in the total number of entries (57) and wich ones are used (e.g. when the '''X table''' has a entry in position 12... the '''Y table''' has position 12 used)  


Only used entries contains a real SHA1-HMAC hash. It can be the SHA1-HMAC hash of entry (a concatenation of 0x41 bytes of '''File Name''' and 0xC0 bytes of '''File certificate''' is used as data) or some unknown SHA1-HMAC hash (hash of file data related to the entry?). Unused entries have a "default" hash (SHA1-HMAC of empty data). In a theoretical PARAM.PFD with no files listed, the '''Y table''' would have all their 57 entries with a default hash).
Only used entries contains a real SHA1-HMAC hash. It can be the SHA1-HMAC hash of entry (a concatenation of 0x41 bytes of '''File Name''' and 0xC0 bytes of '''File certificate''' is used as data) or some unknown SHA1-HMAC hash (hash of file data related to the entry?). Unused entries have a "default" hash (SHA1-HMAC of empty data). In a theoricall PARAM.PFD with no files listed, the '''Y table''' would have all his 57 entries with a default hash).


The '''Y table''' has a repeating pattern so an entry for each potential file with the blank entry (I.E. no file) being represented by the repeating byte pattern.
The '''Y table''' has a repeating pattern so an entry for each potential file with the blank entry (I.E. no file) being represented by the repeating byte pattern.
Line 621: Line 559:
*5.- Fill "Y table" with "not-used" entries (from 0x7B60 to 0x7FD4... paste 57 times the "not used" value for this table copyed previously)
*5.- Fill "Y table" with "not-used" entries (from 0x7B60 to 0x7FD4... paste 57 times the "not used" value for this table copyed previously)


After cleaning-up the tables and regenerating its hashes, the behaviour of the PS3 when trying to load this "BLANKED.PFD" file can give some possible results:
After cleaning-up the tables and regenerating his hashes, the behaviour of the PS3 when trying to load this "BLANKED.PFD" file can give some possible results:
*File is valid, is loaded, but there is "something" that states this file originally had X "protected files" listed.... but now there is none = epic fail
*File is valid, is loaded, but there is "something" that states this file originally had X "protected files" listed.... but now there is none = epic fail
*File is valid, is loaded, and PARAM.SFO is added to the list of protected files (this is something that seems to happen "by default"), consequently the PARAM.PFD is updated, both files are valid = partial win
*File is valid, is loaded, and PARAM.SFO is added to the list of protected files (this is something that seems to happen "by default"), consequently the PARAM.PFD is updated, both files are valid = partial win
*File is valid, is loaded, no protected files are added to the list = epic win
*File is valid, is loaded, no protected files are added to the list = epic win


It depends of the function that creates/updates the .PFD which files needs to be added to the list of "protected files" (this is done the first time when the file is created), but probably games can add more files for their game saves
It depends of the function that creates/updates the .PFD wich files needs to be added to the list of "protected files" (this is done the first time when the file is created), but probably games can add more files for his game saves


The theory is simple... is a valid file with empty tables, it's something not tested yet, but if somebody finds a way to generate the header hashes... this theory is the next test that worths a try
The theory is simple... is a valid file with empty tables, is something not tested yet, but if somebody finds a way to generate the header hashes... this theory is the next test that worths a try


===The "virtual index"===
===The "virtual index"===
Mirror's edge has a total of 33 "protected files" (listed in the protected files table)... this number matches with the 33 "indexed" numbers that are spreading between "X table" and "protected files table" itself... if we place all the entries from all tables together we can reorder all by using their ID number in a "virtual index"
Mirror's edge has a total of 33 "protected files" (listed in the protected files table)... this number matches with the 33 "indexed" numbers that are spreading between "X table" and "protected files table" itself... if we place all the entries from all tables together we can reorder all by using his ID number in a "virtual index"


{| class="wikitable"
{| class="wikitable"
Line 712: Line 650:


===More brainstorming===
===More brainstorming===
*The maximum number of entries in the '''Protected files table''' (114) is exactly the double than the maximum number of entries in '''X table''' (57) & '''Y table''' (57). Or from other point of view 114 = 57 + 57
*The maximun number of entries in the '''Protected files table''' (114) is exactly the double than the maximun number of entries in '''X table''' (57) & '''Y table''' (57). Or from other point of view 114 = 57 + 57
**Seems obvious that there is an "index number" assigned to each "protected file", but their positions are "scrambled"
**Seems obvious that there is an "index number" assigned to each "protected file", but his positions are "scrambled"




*The order of the files in the "protected files table" is based on timestamps (not alphabetically, not by size). Or in other words... tt's related with how the PARAM.PFD was generated for first time
*The order of the files in the "protected files table" is based in his timestamps (not alphabetically, not by size). Or in other words... is related with how the PARAM.PFD was generated for first time
**The original order when the file was created for first time (based on these timestamps), when the files in the list are updated by the ps3 (its timestamps change) keep their original position. When new files are added to the "protected files list table"... they are added to the end of the list, based on these timestamps.
**Is the original order when the file was created for first time (based in his timestamps), when the files in the list are updated by the ps3 (his timestamp changes) they keeps his original position. When new files are added to the "protected files list table"... are added to the end of the list, based in his timestamps.
**When several "protected files" have the same timestamp (something very probable because can be generated by the game very fast)... the order is alphabetical
**When several "protected files" has the same timestamp (something very probable because can be generated by the game very fast)... the order is alphabeticall
**So when ordering them, the timestamp is preferent... and when a timestamp matches it uses their name (alphabetically)
**So when ordering them, the timestamp is preferent... and when timestamp matches is used his name (alphabetically)




*Indexed files in the '''X table''' has a different number for each one, never repeats, but there is not direct relationship between the number of entries in '''X table''' & '''Y table''' (both are fixed to 57) and the number of files listed in the '''Protected files table''' (114)... the most logical explain if that this 114 "protected files" can be linked to both tables (57 each)... but in fact the only table that stores crypto is the '''Y table''' (limited to 57)... so what trick they used ? hmmmm
*Indexed files in the '''X table''' has a different number for each one, never repeats, but there is not direct relationship between the number of entries in '''X table''' & '''Y table''' (both are fixed to 57) and the numer of files listed in the '''Protected files table''' (114)... the most logicall explain if that this 114 "protected files" can be linked to both tables (57 each)... but in fact the only table that stores crypto is the '''Y table''' (limited to 57)... so what trick they used ? hmmmm




*What are this index in the '''X table''' and in the '''Protected files table''' itself?, its positions seems to be random (but the number of indexed files matches with the number of "protected files"), seems like an old school "lucas arts games" anticheat card where you pick 2 values and by mixing them you get the unlock code :D
*What are this index in the '''X table''' and in the '''Protected files table''' itself?, his positions seems to be random (but the number of indexed files matches with the number of "protected files"), seems like an old school "lucas arts games" anticheat card where you pick 2 values and by mixing them you get the unlock code :D
**Seems to be "jumps" from one table to the other. The files are read in order by the ps3 by "jumping" using its "index nº" to locate the next one... "Index nº0" seems to be located always at position 8 in the "X-Table" (offset 0xB8). In most complex PARAM.SFO (e.g: heavy rain, mirror's edge or motogp10/11) the value at this position is replaced by another "index nº" (by now seems random) that is pointing to the "protected files table" index area of each entry (where index nº0 is located). How this "jumps" works is partially unknown and by now is only notable in the first jump
**Seems to be "jumps" from one table to the other. The files are readed in order by the ps3 by "jumping" using his "index nº" to locate the next one... "Index nº0" seems to be located always at position 8 in the "X-Table" (offset 0xB8). In most complex PARAM.SFO (e.g: heavy rain, mirror's edge or motogp10/11) the value at this position is replaced by another "index nº" (by now seems random) that is pointing to the "protected files table" index area of each entry (where index nº0 is located). How this "jumps" works is partially unknown and by now is only notable in the first jump




Line 732: Line 670:


Discussion thread ---> http://www.ps3hax.net/showthread.php?p=392684#post392684
Discussion thread ---> http://www.ps3hax.net/showthread.php?p=392684#post392684
==Mechanism Diagrams==
These diagrams illustrate the mechanisms used by the PARAM.PFD to protect the files. '''For the PARAM.SFO there seems to be a slightly different mechanism!'''
===Decryption / Encryption of protected files===
[[File:PFD Decrypt.png|boderless|The decryption mechanism of the PARAM.PFD]]
[[File:PFD Encrypt.png|boderless|The Encryption mechanism of the PARAM.PFD]]
===PARAM.PFD file modification process===
After you have modified a decrypted file using a hex-editor or whatever you encrypt it back. Now you need to do these steps in this order to update the PARAM.PFD:
# update the file hashes in the protected files table entries
# update the y table signatures
# calculate the y table HMACSHA1
# calculate the tables_header + x table HMACSHA1
# encrypt the header_table
[[File:PFD Filehashes.png|boderless| update the file hashes in the protected files table entries]]
[[File:PFD Ytablesignatures.png|boderless| update the y table signatures]]
[[File:PFD XytableHMAC.png|boderless| calculate the xy table HMACSHA1]]
[[File:PFD Header table.png|boderless| encrypt the header_table]]
==Related Work==
[https://github.com/BuXXe/PARAM.PFD-PS3-Demons-Souls-Savegame-Tool Github for a Python 2.7 PARAM.PFD (decryption/encryption/signing) for Demon's Souls]
{{File Formats}}<noinclude>[[Category:Main]]</noinclude>
Please note that all contributions to PS3 Developer wiki are considered to be released under the GNU Free Documentation License 1.2 (see PS3 Developer wiki:Copyrights for details). If you do not want your writing to be edited mercilessly and redistributed at will, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource. Do not submit copyrighted work without permission!

To protect the wiki against automated edit spam, we kindly ask you to solve the following hCaptcha:

Cancel Editing help (opens in new window)