PARAM.PFD: Difference between revisions

From PS3 Developer wiki
Jump to navigation Jump to search
m (fixed link to the discussion thread)
(big cleanup/update)
Line 30: Line 30:
  Total file size = 120+456+31008+1140+44 = 32768 bytes (0x8000)
  Total file size = 120+456+31008+1140+44 = 32768 bytes (0x8000)


The size is fixed because the number of entries in both '''X table''' & '''Y table''' is 57 (when the entry is not used his position is reserved and marked as "not-used"). In the same way... the '''Protected files table''' has the space reserved for a maximun of 114 entries (usually most of them are not used and are filled with zeroes). As result the file contains the maximun number of possible entries
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


*Note
*Useful game saves used in this page as examples
Entries in the '''Protected files table''' (114) is exactly the double than the entries in '''X table''' (57) & '''Y table''' (57)
**http://www.gamefaqs.com/ps3/941950-mirrors-edge/saves (the first one region North America). Mirror: http://www.multiupload.nl/SWJ4Y4H7ER
**http://www.gamefaqs.com/ps3/933123-heavy-rain/saves
 
The structure of the PARAM.PFD used in Mirror's edge game save can be considered "rare", this wiki page uses this file for explaining the structure because is perfect to understand how it works, the structure contains all the "problems" not present in "standard" files that can be considered unknown... there are other game saves that can be used (MotoGP10, Heavy rain)... but the list of protected files in heavy rain contains more than 100 files (use heavy rain if you are coding an app as a "stress test")


===Header===
===Header===
Line 39: Line 42:
  Size = 120 bytes
  Size = 120 bytes


The end of the header is not clear at first sight, but it can be deduced by counting the number of entries in '''X table''' & '''Y table''' and comparing the positions used in both
The end of the header is not clear at first sight, but it can be deduced by counting the number of entries in '''X table''' & '''Y table''' and comparing the positions used in both. e.g: look for one used entry in the "Y table" and count his position in this table... then look for other used entry in the "X" (both tables matches in the used entries). Then count towards behind to find the first entry (the start of the first entry is the start of the '''X table'''). So the start of the '''X table''' is the end offset of the header
 
e.g. look for one used entry in the "Y table" and count his position in this table... then look for other used entry in the "X" (both tables matches in the used entries). Then count towards behind to find the first entry (the start of the first entry is the start of the '''X table''')


So the start of the '''X table''' is the end offset of the header
*Mirror's edge game save '''Header'''
0000  00 00 00 00 50 46 44 42  00 00 00 00 00 00 00 03 |....PFDB........|
0010  69 15 2C 97 81 2B 25 C5  2A D4 FA 18 E4 B8 16 A8 |i.,..+%.*.......|
0020  7C 1F 5C 28 A7 EE 4D 39  22 AD C8 28 E6 CD 78 88 ||.\(..M9"..(..x.|
0030  98 0F 33 B6 23 94 EE E9  97 06 77 4E 71 91 24 13 |..3.#.....wNq.$.|
0040  A7 CF DB E5 E3 8E 8D 0C  5B CF 88 07 FC B7 B5 9C |........[.......|
0050  4C 5A 3D 98 39 04 B6 CE  ED E2 71 52 AA 9C 2F 85 |LZ=.9.....qR../.|
0060  00 00 00 00 00 00 00 39  00 00 00 00 00 00 00 72 |.......9.......r|
0070  00 00 00 00 00 00 00 21                          |.......!


{| class="wikitable"
{| class="wikitable"
|-
|-
! Offset !! Size !! Value !! Description
! Offset !! Size !! Value !! Description !! Notes
|-
| 0x00 || 0x08 bytes || PFDB || Magic value in ASCII
|-
|-
| 0x08 || 0x08 bytes || 0000000000000003 || constant
| 0x00 || 0x08 bytes || PFDB || Magic value || in ASCII
|-
|-
| 0x10 || 0x10 bytes || random bytes || key to en/decrypt
| 0x08 || 0x08 bytes || 00000000 00000003 || '''constant''' ||
|-
|-
| 0x20 || 0x14 bytes || hmac sha1|| encrypted, decrypted by vtrm
| 0x10 || 0x10 bytes || 69152C97 812B25C5 2AD4FA18 E4B816A8 || random bytes ??? || Key to en/decrypt
|-
|-
| 0x34 || 0x14 bytes || hmac sha1|| encrypted, decrypted by vtrm
| 0x20 || 0x14 bytes || 7C1F5C28 A7EE4D39 22ADC828 E6CD7888 980F33B6 || '''hmac sha1''' || Encrypted, decrypted by vtrm
|-
|-
| 0x48 || 0x14 bytes || hmac sha1|| encrypted, decrypted by vtrm
| 0x34 || 0x14 bytes || 2394EEE9 9706774E 71912413 A7CFDBE5 E38E8D0C || '''hmac sha1''' || Encrypted, decrypted by vtrm
|-
|-
| 0x5C || 0x04 bytes || || padding, encrypted by vtrm
| 0x48 || 0x14 bytes || 5BCF8807 FCB7B59C 4C5A3D98 3904B6CE EDE27152 || '''hmac sha1'''. Encrypted, decrypted by vtrm
|}
 
{| class="wikitable"
|-
|-
! Offset !! Size !! Value !! Description
| 0x5C || 0x04 bytes || AA9C2F85 || '''padding''' || encrypted by vtrm
|-
|-
| 0x60 || 0x08 bytes || 0000000000000039 || Number of reserved entries in the '''X table''' & '''Y table''' (57 in decimal)
| 0x60 || 0x08 bytes || 0000000000000039 || Number of reserved entries in the '''X table''' & '''Y table''' (57 in decimal) || ??? seems correct in all the examples found, but is speculation
|-
|-
| 0x68 || 0x08 bytes || 0000000000000072 || Number of reserved entries in the '''Protected files table''' (114 in decimal)
| 0x68 || 0x08 bytes || 0000000000000072 || Number of reserved entries in the '''Protected files table''' (114 in decimal) || ??? seems correct in all the examples found, but is speculation
|-
|-
| 0x70 || 0x08 bytes || 00000000000000** || Number of used entries in the '''Protected files table''' (it can vary from 1 to 114 in decimal)
| 0x70 || 0x08 bytes || 0000000000000021 || Number of used entries in the '''Protected files table''' (33 in decimal) || Can vary, from 1 to 114 in decimal (or from 0x00 to 0x71)
|-
|-
|}
|}
:
 
*Note: The last 3 entries (from 0x60 to 0x78) probably are not part of the file header... probably must be considered the "header of the next table" (X table), but by now is more simple to explain the structure this way, and is not a big problem to fix later


===X table===
===X table===
Line 92: Line 97:
Used entries has a number asigned by his position in the table e.g:
Used entries has a number asigned by his position in the table e.g:


*Example of a standard '''X table'''
*Mirror's edge game save '''X table'''
  00000070                           00 00 00 00 00 00 00 72          .......r|
  0070                           00 00 00 00 00 00 00 72          .......r|
  00000080 00 00 00 00 00 00 00 '''03'''  00 00 00 00 00 00 00 72  |...............r|
  0080 00 00 00 00 00 00 00 '''01'''  00 00 00 00 00 00 00 72  |...............r|
  00000090 00 00 00 00 00 00 00 72 00 00 00 00 00 00 00 72  |.......r.......r|
  0090 00 00 00 00 00 00 00 '''0C''' 00 00 00 00 00 00 00 72  |...............r|
  000000a0 00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 72 |.......r.......r|
  00a0 00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 '''1F''' |.......r........|
  000000b0 00 00 00 00 00 00 00 72 00 00 00 00 00 00 00 '''00'''  |.......r........|
  00b0 00 00 00 00 00 00 00 '''10''' 00 00 00 00 00 00 00 '''1B'''  |................|
  000000c0 00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 72 |.......r.......r|
  00c0 00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 '''14''' |.......r........|
  000000d0 00 00 00 00 00 00 00 '''01''' 00 00 00 00 00 00 00 72  |...............r|
  00d0 00 00 00 00 00 00 00 72 00 00 00 00 00 00 00 72  |.......r.......r|
  000000e0 00 00 00 00 00 00 00 72 00 00 00 00 00 00 00 72 |.......r.......r|
  00e0 00 00 00 00 00 00 00 '''0B''' 00 00 00 00 00 00 00 '''0D''' |................|
  000000f0 00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 72  |.......r.......r|
  00f0 00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 72  |.......r.......r|
  00000100 00 00 00 00 00 00 00 72 00 00 00 00 00 00 00 72 |.......r.......r|
  0100 00 00 00 00 00 00 00 '''15''' 00 00 00 00 00 00 00 '''19''' |................|
  00000110 00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 72 |.......r.......r|
  0110 00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 '''13''' |.......r........|
  00000120 00 00 00 00 00 00 00 72 00 00 00 00 00 00 00 72  |.......r.......r|
  0120 00 00 00 00 00 00 00 '''17''' 00 00 00 00 00 00 00 72  |...............r|
  00000130 00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 72 |.......r.......r|
  0130 00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 '''0E''' |.......r........|
  00000140 00 00 00 00 00 00 00 72 00 00 00 00 00 00 00 72  |.......r.......r|
  0140 00 00 00 00 00 00 00 '''11''' 00 00 00 00 00 00 00 72  |...............r|
  00000150 00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 72 |.......r.......r|
  0150 00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 '''18''' |.......r........|
  00000160 00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 72  |.......r.......r|
  0160 00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 72  |.......r.......r|
  00000170 00 00 00 00 00 00 00 72 00 00 00 00 00 00 00 72 |.......r.......r|
  0170 00 00 00 00 00 00 00 '''1A''' 00 00 00 00 00 00 00 '''12''' |................|
  00000180 00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 72  |.......r.......r|
  0180 00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 72  |.......r.......r|
  00000190 00 00 00 00 00 00 00 72 00 00 00 00 00 00 00 72  |.......r.......r|
  0190 00 00 00 00 00 00 00 '''04''' 00 00 00 00 00 00 00 72  |...............r|
  000001a0 00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 72 |.......r.......r|
  01a0 00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 '''1C''' |.......r.......r|
  000001b0 00 00 00 00 00 00 00 72 00 00 00 00 00 00 00 72  |.......r.......r|
  01b0 00 00 00 00 00 00 00 '''07''' 00 00 00 00 00 00 00 72  |...............r|
  000001c0 00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 72  |.......r.......r|
  01c0 00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 72  |.......r.......r|
  000001d0 00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 72  |.......r.......r|
  01d0 00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 72  |.......r.......r|
  000001e0 00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 72 |.......r.......r|
  01e0 00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 '''03''' |.......r........|
  000001f0 00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 72  |.......r.......r|
  01f0 00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 72  |.......r.......r|
  00000200 00 00 00 00 00 00 00 72 00 00 00 00 00 00 00 72  |.......r.......r|
  0200 00 00 00 00 00 00 00 '''1D''' 00 00 00 00 00 00 00 72  |...............r|
  00000210 00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 72 |.......r.......r|
  0210 00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 '''20''' |.......r........|
  00000220 00 00 00 00 00 00 00 72 00 00 00 00 00 00 00 '''02''' |.......r........|
  0220 00 00 00 00 00 00 00 '''0F''' 00 00 00 00 00 00 00 72 |...............r|
  00000230 00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 72 |.......r.......r|
  0230 00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 '''1E''' |.......r........|
In this table there are 25 entries used
Only 4 entries used:
-File index nº 1 (00) linked to position 9
-File index nº 2 (01) linked to position 12
-File index nº 3 (02) linked to position 55
-File index nº 4 (03) linked to position 2


{| class="wikitable"
{| class="wikitable"
|-
|-
! Some possible values !! Description
! Position in table !! Virtual Index ID ?
|-
| 1 || {{No}}
|-
| 2 || 0x01
|-
| 3 || {{No}}
|-
| 4 || 0x0C
|-
| 5 || {{No}}
|-
| 6 || {{No}}
|-
| 7 || 0x1F
|-
| 8 || 0x10
|-
| 9 || 0x1B
|-
| 10 || {{No}}
|-
| 11 || 0x14
|-
| 12 || {{No}}
|-
| 13 || {{No}}
|-
| 14 || 0x0B
|-
| 15 || 0x0D
|-
| 16 || {{No}}
|-
| 17 || {{No}}
|-
| 18 || 0x15
|-
| 19 || 0x19
|-
| 20 || {{No}}
|-
| 21 || 0x13
|-
| 22 || 0x17
|-
| 23 || {{No}}
|-
| 24 || {{No}}
|-
| 25 || 0x0E
|-
| 26 || 0x11
|-
| 27 || {{No}}
|-
| 28 || {{No}}
|-
| 29 || 0x18
|-
| 30 || {{No}}
|-
| 31 || {{No}}
|-
| 32 || 0x1A
|-
| 33 || 0x12
|-
| 34 || {{No}}
|-
| 35 || {{No}}
|-
| 36 || 0x04
|-
| 37 || {{No}}
|-
| 38 || {{No}}
|-
| 39 || 0x1C
|-
| 40 || 0x07
|-
| 41 || {{No}}
|-
| 42 || {{No}}
|-
| 43 || {{No}}
|-
| 44 || {{No}}
|-
| 45 || {{No}}
|-
| 46 || {{No}}
|-
| 47 || 0x03
|-
| 48 || {{No}}
|-
| 49 || {{No}}
|-
| 50 || 0x1D
|-
| 51 || {{No}}
|-
| 52 || {{No}}
|-
| 53 || 0x20
|-
| 54 || 0x0F
|-
| 55 || {{No}}
|-
| 56 || {{No}}
|-
| 57 || 0x1E
|-
|}
 
{| class="wikitable"
|-
! Other possible values !! Description
|-
|-
| 0000000000000000 || File index nº 1
| 0000000000000000 || File index nº 1
Line 144: Line 264:
|-
|-
|}
|}
:


===Protected files table===
===Protected files table===
Line 162: Line 281:
In fact, for a theoricall file with alll entries used, 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'''
In fact, for a theoricall file with alll entries used, 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'''


Example of a "non-standard" '''Protected files table''' with 4 entries and 8 bytes length each
*Mirror's edge game save '''Protected Files Table'''
0000000000000072 0000000000000001 0000000000000000 0000000000000002
8 entries used in this table
{| class="wikitable"
The "file index" of each entry of this '''Protected files table''' can be translated as:
|-
-File index nº 1 (00) assigned as position 3
! Position in table !! Virtual Index ID ? !! File Name !! Unknown ? !! Certificate ? !! File Size
-File index nº 2 (01) assigned as position 2
|-
-File index nº 3 (02) assigned as position 4
| 1 || {{No}} || PARAM.SFO || 00568CD8 || longer than others || 00000AB0
|-
| 2 || {{No}} || SAVTOC0.BIN || 00568CD8 || || 0000058C
|-
| 3 || {{No}} || SAV33.BIN || 00568CD8 || || 00000584
|-
| 4 || {{No}} || SAV14.BIN || 00568CD8 || || 00009543
|-
| 5 || {{No}} || SAV3.BIN || 00568CD8 || || 0000848F
|-
| 6 || {{No}} || SAV22.BIN || 00568CD8 || || 00008221
|-
| 7 || {{No}} || SAV21.BIN || 00568CD8 || || 00009D66
|-
| 8 || {{No}} || SAV13.BIN || 00568CD8 || || 00009EF5
|-
| 9 || {{No}} || SAV5.BIN || 00568CD8 || || 0000CD1B
|-
| 10 || {{No}} || SAV6.BIN || 00568CD8 || || 0000B3AF
|-
| 11 || {{No}} || SAV7.BIN || 00568CD8 || || 00008266
|-
| 12 || {{No}} || SAV8.BIN || 00568CD8 || || 00007618
|-
| 13 || {{No}} || SAV16.BIN || 00568CD8 || || 0000B95A
|-
| 14 || 0x06 || SAV0.BIN || 00568CD8 || || 00009F4D
|-
| 15 || {{No}} || SAV19.BIN || 00568CD8 || || 0000A11B
|-
| 16 || {{No}} || SAV15.BIN || 00568CD8 || || 0000CC00
|-
| 17 || {{No}} || SAV20.BIN || 00568CD8 || || 000109F0
|-
| 18 || {{No}} || SAV11.BIN || 00568CD8 || || 00009C0A
|-
| 19 || {{No}} || SAV12.BIN || 00568CD8 || || 0000948D
|-
| 20 || {{No}} || SAV9.BIN || 00568CD8 || || 0000C712
|-
| 21 || {{No}} || SAV17.BIN || 00568CD8 || || 0000E4FD
|-
| 22 || 0x02 || SAV18.BIN || 00568CD8 || || 0000AE4D
|-
| 23 || {{No}} || SAV2.BIN || 00568CD8 || || 0000CD55
|-
| 24 || 0x05 || SAV1.BIN || 00568CD8 || || 000098B3
|-
| 25 || 0x16 || SAV23.BIN || 00568CD8 || || 00004FBE
|-
| 26 || {{No}} || SAV10.BIN || 00568CD8 || || 0000ADBD
|-
| 27 || {{No}} || SAV35.BIN || 00568CD8 || || 00008E2E
|-
| 28 || 0x00 || SAVTOC1.BIN || 00568CD8 || || 00000108
|-
| 29 || {{No}} || SAV36.BIN || 00568CD8 || || 00009CBE
|-
| 30 || 0x08 || SAV26.BIN || 00568CD8 || || 0000B4D7
|-
| 31 || 0x09 || SAV27.BIN || 00568CD8 || || 00009FD1
|-
| 32 || 0x0A || SAV28.BIN || 00568CD8 || || 00007D73
|-
| 33 || {{No}} || SAV38.BIN || 00568CD8 || || 0000D401
|-
| Up to 114 || {{No}} || {{No}} || {{No}} || {{No}} || {{No}}
|-
|}


*Each entry has this structure
{| class="wikitable"
{| class="wikitable"
|-
|-
Line 185: Line 373:
|-
|-
|}
|}
:


===Y table===
===Y table===
Line 193: Line 380:
  Number of entries = 57
  Number of entries = 57


All the entries contains the same "20 bytes string", only the used ones has a different "20 bytes string"
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)
in the other '''X table''' (in a theoricall PARAM.PFD with no files listed, the "Y table" would have all his 57 entries with the same string)
 
All the entries contains the same "20 bytes string", only the used entries contains a different "20 bytes string" (in a theoricall PARAM.PFD with no files listed, the "Y table" would have all his 57 entries with the same string)


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)
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.
 
*Mirror's edge game save '''Y table'''
When a entry in this table is not used is "marked" with a "standard" value... for mirror's edge game save is: '''5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0'''
 
{| class="wikitable"
|-
! Position in table !! ???
|-
| 1 || 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
|-
| 2 || other
|-
| 3 || 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
|-
| 4 || other
|-
| 5 || 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
|-
| 6 || 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
|-
| 7 || other
|-
| 8 || other
|-
| 9 || other
|-
| 10 || 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
|-
| 11 || other
|-
| 12 || 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
|-
| 13 || 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
|-
| 14 || other
|-
| 15 || other
|-
| 16 || 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
|-
| 17 || 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
|-
| 18 || other
|-
| 19 || other
|-
| 20 || 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
|-
| 21 || other
|-
| 22 || other
|-
| 23 || 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
|-
| 24 || 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
|-
| 25 || other
|-
| 26 || other
|-
| 27 || 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
|-
| 28 || 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
|-
| 29 || other
|-
| 30 || 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
|-
| 31 || 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
|-
| 32 || other
|-
| 33 || other
|-
| 34 || 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
|-
| 35 || 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
|-
| 36 || other
|-
| 37 || 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
|-
| 38 || 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
|-
| 39 || other
|-
| 40 || other
|-
| 41 || 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
|-
| 42 || 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
|-
| 43 || 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
|-
| 44 || 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
|-
| 45 || 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
|-
| 46 || 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
|-
| 47 || other
|-
| 48 || 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
|-
| 49 || 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
|-
| 50 || other
|-
| 51 || 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
|-
| 52 || 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
|-
| 53 || other
|-
| 54 || other
|-
| 55 || 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
|-
| 56 || 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
|-
| 57 || other
|-
|}


The '''Y table''' has a repeating pattern so an entry for each potential file with the blank entry (I.E. no file)
A screencapture of this table with the width fixed (each entry is one row)... there is a total of 57 entries, 25 of them used. http://img6.imagebanana.com/img/q82sh1dj/Ytablemirrorsedge.jpg
being represented by the repeating byte pattern.


===Padding===
===Padding===
  Size = 44 bytes
  Size = 44 bytes
Not much to say about this padding, is an area filled with zeroes to increase the size of the file to 32768 bytes (0x8000)
==Cryptography and Speculation==
===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 his ID number in a "virtual index"
{| class="wikitable"
|-
! Virtual Index ID !! Placement/position !! File Name
|-
| 0x00 || protected files table / position 28 || SAVTOC1.BIN
|-
| 0x01 || X table / position 2 || {{No}}
|-
| 0x02 || protected files table / position 22 || SAV18.BIN
|-
| 0x03 ||  X table / position 47 || {{No}}
|-
| 0x04 ||  X table / position 36 || {{No}}
|-
| 0x05 || protected files table / position 24 || SAV1.BIN
|-
| 0x06 || protected files table / position 14 || SAV0.BIN
|-
| 0x07 || X table / position 40 ||  {{No}}
|-
| 0x08 || protected files table / position 30 || SAV26.BIN
|-
| 0x09 || protected files table / position 31 || SAV27.BIN
|-
| 0x0A || protected files table / position 32 || SAV28.BIN
|-
| 0x0B || X table / position 14 || {{No}}
|-
| 0x0C ||  X table / position 4 || {{No}}
|-
| 0x0D ||  X table / position 15 || {{No}}
|-
| 0x0E ||  X table / position 25 || {{No}}
|-
| 0x0F ||  X table / position 54 || {{No}}
|-
| 0x10 ||  X table / position 8 || {{No}}
|-
| 0x11 ||  X table / position 26 || {{No}}
|-
| 0x12 ||  X table / position 33 || {{No}}
|-
| 0x13 ||  X table / position 21 || {{No}}
|-
| 0x14 ||  X table / position 11 || {{No}}
|-
| 0x15 ||  X table / position 18 || {{No}}
|-
| 0x16 || protected files table / position 25 || SAV23.BIN
|-
| 0x17 ||  X table / position 22 || {{No}}
|-
| 0x18 ||  X table / position 29 || {{No}}
|-
| 0x19 ||  X table / position 19 || {{No}}
|-
| 0x1A ||  X table / position 32 || {{No}}
|-
| 0x1B ||  X table / position 9 || {{No}}
|-
| 0x1C ||  X table / position 39 || {{No}}
|-
| 0x1D ||  X table / position 50 || {{No}}
|-
| 0x1E ||  X table / position 57 || {{No}}
|-
| 0x1F ||  X table / position 7 || {{No}}
|-
| 0x20 ||  X table / position 53 || {{No}}
|-
|}
===More brainstorming===
Entries in the '''Protected files table''' (114) is exactly the double than the entries in '''X table''' (57) & '''Y table''' (57)


==Cryptography==
Unknown by now, but some questions rises...
Unknown by now, but some questions rises...



Revision as of 04:38, 17 July 2012


Description

This files 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:

/dev_hdd0/home/0000000*/savedata/SAVEDATA_DIRECTORY/PARAM.PFD <---- in all save game 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

Usually PARAM.SFO is one of the files listed (and supervised) by PARAM.PFD but this can vary.

Every time one of the files listed in the Protected files table inside the PARAM.PFD is updated... the PARAM.PFD itself needs to be updated to store the new signature of the updated file. e.g:

  • When you save a game there is some text that changes inside PARAM.SFO with your current "gameplay time", "character level", etc...
  • When you unlock a new trophy the file TROPUSR.DAT is updated with this new data
  • When you install new trophies (with a "trophy installer" in .TRP format) from a new game the TROPSYS.DAT is updated to index the new trophy installation

... In all this cases, there is a PARAM.PFD in the same folder that has been updated to store the new "signatures" of the other updated files

More info on other related file formats: PARAM.SFO Game Saves Trophy files.

Structure

Header (120 bytes)
X table (456 bytes)
Protected files table(31008 bytes)
Y table (1140 bytes)
Padding (44 bytes)

Total file size = 120+456+31008+1140+44 = 32768 bytes (0x8000)

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

The structure of the PARAM.PFD used in Mirror's edge game save can be considered "rare", this wiki page uses this file for explaining the structure because is perfect to understand how it works, the structure contains all the "problems" not present in "standard" files that can be considered unknown... there are other game saves that can be used (MotoGP10, Heavy rain)... but the list of protected files in heavy rain contains more than 100 files (use heavy rain if you are coding an app as a "stress test")

Header

From 0x0 to 0x78
Size = 120 bytes

The end of the header is not clear at first sight, but it can be deduced by counting the number of entries in X table & Y table and comparing the positions used in both. e.g: look for one used entry in the "Y table" and count his position in this table... then look for other used entry in the "X" (both tables matches in the used entries). Then count towards behind to find the first entry (the start of the first entry is the start of the X table). So the start of the X table is the end offset of the header

  • Mirror's edge game save Header
0000  00 00 00 00 50 46 44 42  00 00 00 00 00 00 00 03 |....PFDB........|
0010  69 15 2C 97 81 2B 25 C5  2A D4 FA 18 E4 B8 16 A8 |i.,..+%.*.......|
0020  7C 1F 5C 28 A7 EE 4D 39  22 AD C8 28 E6 CD 78 88 ||.\(..M9"..(..x.|
0030  98 0F 33 B6 23 94 EE E9  97 06 77 4E 71 91 24 13 |..3.#.....wNq.$.|
0040  A7 CF DB E5 E3 8E 8D 0C  5B CF 88 07 FC B7 B5 9C |........[.......|
0050  4C 5A 3D 98 39 04 B6 CE  ED E2 71 52 AA 9C 2F 85 |LZ=.9.....qR../.|
0060  00 00 00 00 00 00 00 39  00 00 00 00 00 00 00 72 |.......9.......r|
0070  00 00 00 00 00 00 00 21                          |.......!
Offset Size Value Description Notes
0x00 0x08 bytes PFDB Magic value in ASCII
0x08 0x08 bytes 00000000 00000003 constant
0x10 0x10 bytes 69152C97 812B25C5 2AD4FA18 E4B816A8 random bytes ??? Key to en/decrypt
0x20 0x14 bytes 7C1F5C28 A7EE4D39 22ADC828 E6CD7888 980F33B6 hmac sha1 Encrypted, decrypted by vtrm
0x34 0x14 bytes 2394EEE9 9706774E 71912413 A7CFDBE5 E38E8D0C hmac sha1 Encrypted, decrypted by vtrm
0x48 0x14 bytes 5BCF8807 FCB7B59C 4C5A3D98 3904B6CE EDE27152 hmac sha1. Encrypted, decrypted by vtrm
0x5C 0x04 bytes AA9C2F85 padding encrypted by vtrm
0x60 0x08 bytes 0000000000000039 Number of reserved entries in the X table & Y table (57 in decimal) ??? seems correct in all the examples found, but is speculation
0x68 0x08 bytes 0000000000000072 Number of reserved entries in the Protected files table (114 in decimal) ??? seems correct in all the examples found, but is speculation
0x70 0x08 bytes 0000000000000021 Number of used entries in the Protected files table (33 in decimal) Can vary, from 1 to 114 in decimal (or from 0x00 to 0x71)
  • Note: The last 3 entries (from 0x60 to 0x78) probably are not part of the file header... probably must be considered the "header of the next table" (X table), but by now is more simple to explain the structure this way, and is not a big problem to fix later

X table

From 0x78 to 0x240
Size = 456 bytes
Entry lenght = 8 bytes
Number of entries = 57

Each entry can contain a "file index" that points to the Protected files table from 0x00 to 0x71 (from 1 to 114 in decimal)

If the "file index" is 72 it means that is pointing out of the Protected files table (not used)

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, and mixed with more 72's entries

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

  • Mirror's edge game save X table
0070                           00 00 00 00 00 00 00 72           .......r|
0080  00 00 00 00 00 00 00 01  00 00 00 00 00 00 00 72  |...............r|
0090  00 00 00 00 00 00 00 0C  00 00 00 00 00 00 00 72  |...............r|
00a0  00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 1F  |.......r........|
00b0  00 00 00 00 00 00 00 10  00 00 00 00 00 00 00 1B  |................|
00c0  00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 14  |.......r........|
00d0  00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 72  |.......r.......r|
00e0  00 00 00 00 00 00 00 0B  00 00 00 00 00 00 00 0D  |................|
00f0  00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 72  |.......r.......r|
0100  00 00 00 00 00 00 00 15  00 00 00 00 00 00 00 19  |................|
0110  00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 13  |.......r........|
0120  00 00 00 00 00 00 00 17  00 00 00 00 00 00 00 72  |...............r|
0130  00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 0E  |.......r........|
0140  00 00 00 00 00 00 00 11  00 00 00 00 00 00 00 72  |...............r|
0150  00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 18  |.......r........|
0160  00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 72  |.......r.......r|
0170  00 00 00 00 00 00 00 1A  00 00 00 00 00 00 00 12  |................|
0180  00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 72  |.......r.......r|
0190  00 00 00 00 00 00 00 04  00 00 00 00 00 00 00 72  |...............r|
01a0  00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 1C  |.......r.......r|
01b0  00 00 00 00 00 00 00 07  00 00 00 00 00 00 00 72  |...............r|
01c0  00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 72  |.......r.......r|
01d0  00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 72  |.......r.......r|
01e0  00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 03  |.......r........|
01f0  00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 72  |.......r.......r|
0200  00 00 00 00 00 00 00 1D  00 00 00 00 00 00 00 72  |...............r|
0210  00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 20  |.......r........|
0220  00 00 00 00 00 00 00 0F  00 00 00 00 00 00 00 72  |...............r|
0230  00 00 00 00 00 00 00 72  00 00 00 00 00 00 00 1E  |.......r........|

In this table there are 25 entries used

Position in table Virtual Index ID ?
1 No
2 0x01
3 No
4 0x0C
5 No
6 No
7 0x1F
8 0x10
9 0x1B
10 No
11 0x14
12 No
13 No
14 0x0B
15 0x0D
16 No
17 No
18 0x15
19 0x19
20 No
21 0x13
22 0x17
23 No
24 No
25 0x0E
26 0x11
27 No
28 No
29 0x18
30 No
31 No
32 0x1A
33 0x12
34 No
35 No
36 0x04
37 No
38 No
39 0x1C
40 0x07
41 No
42 No
43 No
44 No
45 No
46 No
47 0x03
48 No
49 No
50 0x1D
51 No
52 No
53 0x20
54 0x0F
55 No
56 No
57 0x1E
Other possible values Description
0000000000000000 File index nº 1
0000000000000001 File index nº 2
0000000000000002 File index nº 3
0000000000000071 File index nº 114
0000000000000072 Out of Protected files table (not used)

Protected files table

From 0x240 to 0x7B60
Size = 31008 bytes
Entry lenght = 272 bytes
Number of entries = variable from 1 to 114

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

The first 8 bytes of each entry (file index) works in the same way than the entries in the X table, usually not used (72) and when used are randmonly placed asigning an "file index" to the entry

This "file index" does not matches with the position of the entry in the Protected files table itself... so seems that this "indexes files" are ???virtually reordered???

In fact, for a theoricall file with alll entries used, 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

  • Mirror's edge game save Protected Files Table

8 entries used in this table

Position in table Virtual Index ID ? File Name Unknown ? Certificate ? File Size
1 No PARAM.SFO 00568CD8 longer than others 00000AB0
2 No SAVTOC0.BIN 00568CD8 0000058C
3 No SAV33.BIN 00568CD8 00000584
4 No SAV14.BIN 00568CD8 00009543
5 No SAV3.BIN 00568CD8 0000848F
6 No SAV22.BIN 00568CD8 00008221
7 No SAV21.BIN 00568CD8 00009D66
8 No SAV13.BIN 00568CD8 00009EF5
9 No SAV5.BIN 00568CD8 0000CD1B
10 No SAV6.BIN 00568CD8 0000B3AF
11 No SAV7.BIN 00568CD8 00008266
12 No SAV8.BIN 00568CD8 00007618
13 No SAV16.BIN 00568CD8 0000B95A
14 0x06 SAV0.BIN 00568CD8 00009F4D
15 No SAV19.BIN 00568CD8 0000A11B
16 No SAV15.BIN 00568CD8 0000CC00
17 No SAV20.BIN 00568CD8 000109F0
18 No SAV11.BIN 00568CD8 00009C0A
19 No SAV12.BIN 00568CD8 0000948D
20 No SAV9.BIN 00568CD8 0000C712
21 No SAV17.BIN 00568CD8 0000E4FD
22 0x02 SAV18.BIN 00568CD8 0000AE4D
23 No SAV2.BIN 00568CD8 0000CD55
24 0x05 SAV1.BIN 00568CD8 000098B3
25 0x16 SAV23.BIN 00568CD8 00004FBE
26 No SAV10.BIN 00568CD8 0000ADBD
27 No SAV35.BIN 00568CD8 00008E2E
28 0x00 SAVTOC1.BIN 00568CD8 00000108
29 No SAV36.BIN 00568CD8 00009CBE
30 0x08 SAV26.BIN 00568CD8 0000B4D7
31 0x09 SAV27.BIN 00568CD8 00009FD1
32 0x0A SAV28.BIN 00568CD8 00007D73
33 No SAV38.BIN 00568CD8 0000D401
Up to 114 No No No No No
  • Each entry has this structure
Size Value Description
008 bytes 00000000000000** File index (value 72 = Not indexed)
064 bytes EXAMPLE.WTF Name of the file included the point and the extension in ASCII (Null-terminated)
008 bytes :Wtf-o0- In ASCII, Usually zeroed (crysis2 savedata contains the string "CELL" and heavenly sword contains "s:Music") ???Unknown???
188 bytes ????????... Certificate for the file. When the file is PARAM.SFO then the certificate is bigger in size and uses imput data from the attribute "PARAMS" and/or "ACCOUNT_ID" inside PARAM.SFO. Method unknown (Null-terminated)
004 bytes 1A2B3C4D Size of the file in bytes

Y table

From 0x7B60 to 0x7FD4
Size = 1140 bytes
Entry lenght = 20 bytes (some kind of sha-1 hash??)
Number of entries = 57

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)

All the entries contains the same "20 bytes string", only the used entries contains a different "20 bytes string" (in a theoricall PARAM.PFD with no files listed, the "Y table" would have all his 57 entries with the same string)

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.

  • Mirror's edge game save Y table

When a entry in this table is not used is "marked" with a "standard" value... for mirror's edge game save is: 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0

Position in table ???
1 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
2 other
3 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
4 other
5 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
6 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
7 other
8 other
9 other
10 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
11 other
12 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
13 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
14 other
15 other
16 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
17 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
18 other
19 other
20 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
21 other
22 other
23 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
24 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
25 other
26 other
27 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
28 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
29 other
30 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
31 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
32 other
33 other
34 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
35 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
36 other
37 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
38 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
39 other
40 other
41 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
42 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
43 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
44 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
45 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
46 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
47 other
48 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
49 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
50 other
51 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
52 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
53 other
54 other
55 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
56 5A7EAF6D 029992D0 7580EBCA 42698114 9F2C5DF0
57 other

A screencapture of this table with the width fixed (each entry is one row)... there is a total of 57 entries, 25 of them used. http://img6.imagebanana.com/img/q82sh1dj/Ytablemirrorsedge.jpg

Padding

Size = 44 bytes

Not much to say about this padding, is an area filled with zeroes to increase the size of the file to 32768 bytes (0x8000)




Cryptography and Speculation

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 his ID number in a "virtual index"

Virtual Index ID Placement/position File Name
0x00 protected files table / position 28 SAVTOC1.BIN
0x01 X table / position 2 No
0x02 protected files table / position 22 SAV18.BIN
0x03 X table / position 47 No
0x04 X table / position 36 No
0x05 protected files table / position 24 SAV1.BIN
0x06 protected files table / position 14 SAV0.BIN
0x07 X table / position 40 No
0x08 protected files table / position 30 SAV26.BIN
0x09 protected files table / position 31 SAV27.BIN
0x0A protected files table / position 32 SAV28.BIN
0x0B X table / position 14 No
0x0C X table / position 4 No
0x0D X table / position 15 No
0x0E X table / position 25 No
0x0F X table / position 54 No
0x10 X table / position 8 No
0x11 X table / position 26 No
0x12 X table / position 33 No
0x13 X table / position 21 No
0x14 X table / position 11 No
0x15 X table / position 18 No
0x16 protected files table / position 25 SAV23.BIN
0x17 X table / position 22 No
0x18 X table / position 29 No
0x19 X table / position 19 No
0x1A X table / position 32 No
0x1B X table / position 9 No
0x1C X table / position 39 No
0x1D X table / position 50 No
0x1E X table / position 57 No
0x1F X table / position 7 No
0x20 X table / position 53 No




More brainstorming

Entries in the Protected files table (114) is exactly the double than the entries in X table (57) & Y table (57)

Unknown by now, but some questions rises...


Why the files are listed in this order and not in other in the "files table" ?

Because are not listed alphabetically, neither by size


Indexes files (in the X table) seems to have different number for every 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 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?, his positions seems to be random, 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

But here what is random is the positions, and index numbers of the entries in the X table, and the indexed files in the Protected files table ??? 2 index ???



Discussion thread ---> http://www.ps3hax.net/showthread.php?p=392684#post392684