ISO.BIN.EDAT: Difference between revisions

From PS3 Developer wiki
Jump to navigation Jump to search
 
(147 intermediate revisions by 24 users not shown)
Line 1: Line 1:
==iso.bin structure (decrypted)==
== ISO.BIN.EDAT ==
 
ISO.BIN.EDAT is an encryted container format. First step to work with it is to decrypt it <!--more info an internal links to other wiki pages needed-->
 
After decryption, we should refer to ISO.BIN.EDAT as ISO.BIN.DAT (without the "E"... so the EDAT became a DAT).
 
==ISO.BIN.DAT (decrypted)==
This can be considered an intermediate container composed by the ISO.BIN + a 40 bytes signature at bottom<br>
For the purpose of this wiki page and the concept of extracting data  from layers like an onion we need to delete the last 40 bytes to convert a ISO.BIN.DAT into a ISO.BIN<br>
The signature is intended as a sanity check to the ISO.BIN data. In other words if you are going to modify the ISO.BIN you will need to generate a new signature for it when rebuilding it<br>
Example source-code to generate the 40 byte signature can be found in sign3.py which is part of [https://github.com/sahlberg/pop-fe pop-fe].
 
==ISO.BIN structure==
All offsets are in little endian (except in the last table where there are two counters in decimal)
All offsets are in little endian (except in the last table where there are two counters in decimal)


Line 5: Line 17:
  1 cluster = 16 blocks = 1024*16 bytes =16384 bytes (0x4000)
  1 cluster = 16 blocks = 1024*16 bytes =16384 bytes (0x4000)


  discs_start ----------> 0x000400 (disc1), 0x100400 (disc2), 0x200400 (disc3), 0x300400 (disc4), etc...
  disc_starts ----------> 0x000400 (disc1), 0x100400 (disc2), 0x200400 (disc3), 0x300400 (disc4), etc...
  discs_keys -----------> 0x000C00 (disc1), 0x100C00 (disc2), 0x200C00 (disc3), 0x300C00 (disc4), etc...
  disc_tocs -----------> 0x000C00 (disc1), 0x100C00 (disc2), 0x200C00 (disc3), 0x300C00 (disc4), etc...
  discs_map_tables ----> 0x004400 (disc1), 0x104400 (disc2), 0x204400 (disc3), 0x304400 (disc4), etc...
  disc_map_tables ----> 0x004400 (disc1), 0x104400 (disc2), 0x204400 (disc3), 0x304400 (disc4), etc...


===iso.bin Header===
===Header (optional)===
  1 block = 1024 bytes (0x400)
  1 block = 1024 bytes (0x400)
Always exists in PS1 classic multidiscs (the example below is from ff8), in the official PS1 classics single disc doesnt exists, but the custom PS1 classics single discs can use it (there are custom tools that adds it in all cases)


{| class="wikitable"
{| class="wikitable"
|-
|-
! Block Nº !! Offset !! Length !! Name !! Example !! Dexcription
! Block Nº !! Offset !! Length !! Name !! Example !! Description
|-
|-
| rowspan="5" style="background-color:#DDDDDD;" | 0 <br /> '''common_header''' || 0x0000 || 16 bytes (0x10) || '''ckecksum''' || variable || checksum of the header block... or checksum of the whole file ?
| rowspan="5" style="background-color:#DDDDDD;" | 0 <br /> '''common_header''' || 0x0000 || 0x10 (16 bytes) || '''magic''' || PSTITLEIMG000000 ||  
|-
|-
| 0x0010 || 496 bytes (0x1F0) || ''padding'' || ||
| 0x0010 || 0x1F0 (496 bytes) || ''padding'' || ||
|-
|-
| 0x0200 || 100 bytes (0x64) || '''discs_start_offsets''' || 00 04 00 00 || 25 chunks of 4 bytes ... each chunk = start position of each disc, in games with only 1 disc only the first 4 bytes are used
| 0x0200 || 0x64 (100 bytes) || '''discs_start_offsets''' || 00 04 00 00 || 25 chunks of 4 bytes ... each chunk = start position of each disc, in games with only 1 disc only the first 4 bytes are used
|-
|-
| 0x0264 || 16 bytes (0x10) || '''game_id''' || _SLES_12345 || common identifyer for all discs
| 0x0264 || 0x10 (16 bytes) || '''game_id''' || _SLES_12345 || common identifyer for all discs
|-
|-
| 0x0274 || 396 bytes (0x18C) || ''padding'' || ||
| 0x0274 || 0x18C (396 bytes) || ''padding'' || ||
|-
|-
|}
|}


===iso.bin Disc map===
===Section===
  64 clusters, 1024 blocks, 10485576 bytes (0x100000)
  64 clusters, 1024 blocks, 10485576 bytes (0x100000)


This structure is repeated one time for every disc of the game all them joined together consecutively, the whole space is reserved even when there is no data used
This structure is repeated one time for every disc of the game all them joined together consecutivelys (the example below is from ff8), the whole space is reserved even when there is no data used


{| class="wikitable"
{| class="wikitable" style="line-height:120%"
|-
|-
! Cluster Nº !! Block Nº !! Offset !! Length !! Name !! Example !! Notes
! Cluster Nº !! Block Nº !! Offset !! Length !! Name !! Example !! Notes
|-
|-
| rowspan="24" style="background-color:#DDDDDD;" | 0 <br /> '''Disc map header''' || rowspan="2" style="background-color:#DDDDDD;" | 1 || 0x0400 || 16 bytes (0x10) || '''magic''' || PSISOIMG0000 || different for "psp minis" (i dont remember)..... probably another for "ps2 classics" (speculation)
| rowspan="28" style="background-color:#DDDDDD;" | 0 <br /> '''Disc map header''' || rowspan="3" style="background-color:#DDDDDD;" | 1 || 0x0000 || 0x00C (12 bytes) || '''magic''' || PSISOIMG0000 || In "PSP Minis" It's NPUMDIMG ([[Environments|NP]] UMD Image) ..... probably another for "ps2 classics" (speculation)
|-
| 0x000C || 0x004 (4 bytes) || '''section size''' || || Offset from the start of the PSISOIMG section to the next section<br>For uncompressed images this is usually 0x100000 + size of iso-image padded to 0x9300<br>If the disc contains CD-DA tracks then this number will also include all the ATRACK encoded audio that follows after the disk image.
|-
|-
| 0x0410 || 1008 bytes (0x3F0) || ''padding'' || ||
| 0x0010 || 0x3F0 (1008 bytes) || ''padding'' || ||
|-
|-
| rowspan="2" style="background-color:#DDDDDD;" | 2 || 0x0800 || 16 bytes (0x10) || '''disc_id''' || _SLES_12345 || in games with several discs each disc has a different id
| rowspan="5" style="background-color:#DDDDDD;" | 2 || 0x0400 || 0x010 (16 bytes) || '''disc id''' || _SLES_12345 || in games with several discs each disc has a different id
|-
|-
| 0x0810 || 1008 bytes (0x3F0) || ''padding'' || ||
| 0x0410 || 0x14 (20 bytes) || ''padding'' || ||
|-
|-
| rowspan="2" style="background-color:#DDDDDD;" | 3 || 0x0C00 || 32 bytes (0x20) || '''disc_key ?''' || variable || <------------------ key to decrypt the disc1.iso ?
| 0x0424 || 0x4 (4 bytes) || '''Ad hoc ps1 config revision''' || 0x12345 (bcd) || Ad hoc game config revision in bcd little endian.
|-
|-
| 0x0C20 || 992 bytes (0x3E0) || ''padding'' || ||
| 0x042C || up to 0x40 (64 bytes) || '''Ad hoc ps1 configs''' || 0x01, 0x40 || Ad hoc game configs in little endian. Single config is 4 bytes command and 4 bytes param for said command. Up to 8 Commands is supported. ps1_netemu only. ISO.BIN.EDAT exclusive.
|-
|-
| style="background-color:#DDDDDD;" | 4 || 0x1000 || 1024 bytes (0x400) || ''not used'' || ||
| 0x046C || 0x394 (916 bytes) || ''padding'' || ||
|-
|-
| rowspan="5" style="background-color:#DDDDDD;" | 5 || 0x1400 || 724 bytes (0x2D4) || ''padding'' || ||
| rowspan="2" style="background-color:#DDDDDD;" | 3 || 0x0800 || 0x3FС (1020 bytes) || '''[[ISO.BIN.EDAT#Disc toc table|Disc toc table]]''' || variable || Table of content, like CUE sheet, supports upto 99 entries (102 entries total)
|-
|-
| 0x16D4 || 2 bytes (0x02) || '''block size ?''' || 1024 || <--- this is wrong, but matches for the first disc
| 0x0BFC || 0x004 (4 bytes) || '''disc start offset''' || 0x100000 ||
|-
|-
| 0x16D6 || 2 bytes (0x02) || '''number of clusters''' || 64 || its always 64 clusters (so seems to be right)
| style="background-color:#DDDDDD;" | 4 || 0x0C00 || 0x400 (1024 bytes) || '''[[ISO.BIN.EDAT#Audio tracks table|Audio tracks table]]''' || || Datas of audio tracks (2-65). offset, size, and more
|-
|-
| 0x16D8 || 2 bytes (0x02) || '''number of blocks ?''' || 1024 || <--- this is wrong, but matches for the first disc
| rowspan="5" style="background-color:#DDDDDD;" | 5 || 0x1000 || 0x220 (544 bytes) || '''[[ISO.BIN.EDAT#Audio tracks table|Audio tracks table]]''' || || Datas of audio tracks (66-99). offset, size, and more
|-
|-
| 0x16DA || 294 bytes (0x126) || ''padding'' || ||
| 0x12B0 || 0x004 (4 bytes) || '''Libcrypt Magic Word''' || 0x1234 || Little endian. Magic word is used as an answer to COP0 BPC reads for libcrypt games.
|-
|-
| style="background-color:#DDDDDD;" | 6 || 0x1800 || 1024 bytes (0x400) || ''not used'' || ||
| 0x12D4 || 0x004 (4 bytes) || '''subchannel offset''' || 0x100400 || Offset to where subchannel data is stored. This is used with libcrypt.
|-
|-
| style="background-color:#DDDDDD;" | 7 || 0x1C00 || 1024 bytes (0x400) || ''not used'' || ||
| 0x12D8 || 0x004 (4 bytes) || '''subchannel count''' || 0x178 || Number of subchannel blocks. Each block is 12 bytes.
|-
|-
| style="background-color:#DDDDDD;" | 8 || 0x2000 || 1024 bytes (0x400) || ''not used'' || ||
| 0x12DC || 0x124 (292 bytes) || ''padding'' || ||
|-
|-
| style="background-color:#DDDDDD;" | 9 || 0x2400 || 1024 bytes (0x400) || ''not used'' || ||
| style="background-color:#DDDDDD;" | 6 || 0x1400 || 0x400 (1024 bytes) || ''not used'' || ||
|-
|-
| style="background-color:#DDDDDD;" | 10 || 0x2800 || 1024 bytes (0x400) || ''not used'' || ||
| style="background-color:#DDDDDD;" | 7 || 0x1800 || 0x400 (1024 bytes) || ''not used'' || ||
|-
|-
| style="background-color:#DDDDDD;" | 11 || 0x2C00 || 1024 bytes (0x400) || ''not used'' || ||
| style="background-color:#DDDDDD;" | 8 || 0x1C00 || 0x400 (1024 bytes) || ''not used'' || ||
|-
|-
| style="background-color:#DDDDDD;" | 12 || 0x3000 || 1024 bytes (0x400) || ''not used'' || ||
| style="background-color:#DDDDDD;" | 9 || 0x2000 || 0x400 (1024 bytes) || ''not used'' || ||
|-
|-
| style="background-color:#DDDDDD;" | 13 || 0x3400 || 1024 bytes (0x400) || ''not used'' || ||
| style="background-color:#DDDDDD;" | 10 || 0x2400 || 0x400 (1024 bytes) || ''not used'' || ||
|-
|-
| style="background-color:#DDDDDD;" | 14 || 0x3800 || 1024 bytes (0x400) || ''not used'' || ||
| style="background-color:#DDDDDD;" | 11 || 0x2800 || 0x400 (1024 bytes) || ''not used'' || ||
|-
|-
| style="background-color:#DDDDDD;" | 15 || 0x3C00 || 1024 bytes (0x400) || ''not used'' || ||
| style="background-color:#DDDDDD;" | 12 || 0x2C00 || 0x400 (1024 bytes) || ''not used'' || ||
|-
|-
| rowspan="2" style="background-color:#DDDDDD;" | 16 || 0x4000 || 16 bytes (0x10) || '''checksum''' || 1CCE0033 60C6E8A6 B36A972D 00EAFDBF || seems to be the checksum of this block, and because this block is always unused... this checksum is always the same
| style="background-color:#DDDDDD;" | 13 || 0x3000 || 0x400 (1024 bytes) || ''not used'' || ||
|-
|-
| 0x4010 || 1008 bytes (0x3F0) || ''padding'' || ||
| style="background-color:#DDDDDD;" | 14 || 0x3400 || 0x400 (1024 bytes) || ''not used'' || ||
|-
|-
| rowspan="2" style="background-color:#DDDDDD;" | 1 <br /> '''Disc map table''' || style="background-color:#DDDDDD;" | 17 || 0x4400 || variable || '''Disc map table''' || || rowspan="3" style="background-color:#DDDDDD;" | divided in chunks of 32 bytes. See table below
| style="background-color:#DDDDDD;" | 15 || 0x3800 || 0x400 (1024 bytes) || ''not used'' || ||
|-
| rowspan="2" style="background-color:#DDDDDD;" | 16 || 0x3C00 || 0x010 (16 bytes) || '''checksum''' || <abbr title="1CCE003360C6E8A6B36A972D00EAFDBF">0x1CCE0033...</abbr> || It seems to be the checksum of this block, and because this block is always unused the checksum is always <small>1CCE003360C6E8A6B36A972D00EAFDBF</small>
|-
| 0x3C10 || 0x3F0 (1008 bytes) || ''padding'' || ||
|-
| rowspan="2" style="background-color:#DDDDDD;" | 1 <br /> '''[[ISO.BIN.EDAT#Disc map table|Disc map table]]''' || style="background-color:#DDDDDD;" | 17 || 0x4000 || variable || '''[[ISO.BIN.EDAT#Disc map table|Disc map table]]''' || || Divided in chunks of 32 bytes
|-
|-
| style="background-color:#DDDDDD;" | Up to 32 || || || ||
| style="background-color:#DDDDDD;" | Up to 32 || || || ||
|-
|-
| style="background-color:#DDDDDD;" | Up to 64 <br /> '''Disc map table''' || || || ||
| style="background-color:#DDDDDD;" | Up to 64 <br /> '''[[ISO.BIN.EDAT#Disc map table|Disc map table]]''' || || || ||
|-
|}
 
====Disc toc table====
Entry structure:
{| class="wikitable"
|-
! Entry Nº !! Offset !! Length !! Name !! Example !! Notes
|-
| rowspan="10" style="background-color:#DDDDDD;" | 1 || 0x00 || 0x01 (1 byte) || '''TYPE''' || 0x41/0x01 || entry flags
|-
| 0x01 || 0x01 (1 byte) || '''TNO''' || 00 || always zero
|-
| 0x02 || 0x01 (1 byte) || '''POINT''' || 0xA0/0xA1/0xA2/0x01/0x02/0x03/etc || increases
|-
| 0x03 || 0x01 (1 byte) || '''MIN''' || varies || decimal
|-
| 0x04 || 0x01 (1 byte) || '''SEC''' || varies || decimal
|-
| 0x05 || 0x01 (1 byte) || '''FRAME''' || varies || decimal
|-
| 0x06 || 0x01 (1 byte) || '''ZERO''' || 00  || always zero
|-
| 0x07 || 0x01 (1 byte) || '''PMIN''' || varies || decimal
|-
| 0x08 || 0x01 (1 byte) || '''PSEC''' || varies || decimal
|-
| 0x09 || 0x01 (1 byte) || '''PFRAME''' || varies || decimal
|-
| style="background-color:#DDDDDD;" | Up to 102 || || || || || same structure than the previous entry
|}
 
====Audio tracks table====
Entry structure:
{| class="wikitable"
|-
! Entry Nº !! Offset !! Length !! Name !! Example !! Notes
|-
| rowspan="4" style="background-color:#DDDDDD;" | 1 || 0x00 || 0x04 (4 bytes) || '''offset''' ||  ||
|-
| 0x04 || 0x04 (4 bytes) || '''size''' ||  ||
|-
| 0x08 || 0x04 (4 bytes) || '''unknown_0''' ||  || always zeroed
|-
| 0x0C || 0x04 (4 bytes) || ''enc_key'' || || encryption key (or 0 if not encrypted)
|-
|-
| style="background-color:#DDDDDD;" | Up to 98 || || || || || same structure than the previous entry
|}
|}
The audio tracks themselves are raw ATRAC3 streams without a header.
One way to create such blobs is to use the atracdenc encoder and strip of the first 0x60 bytes which is the header. The resulting blob is what the Audio tracks table entries will point to.


====iso.bin Disc map table====
====Disc map table====
The table has an area reserved of 1032192 bytes. Divided in 32256 entries, of 32 bytes each entry. The number of used entryes in the file_table can vary (seems to be dependant of the .iso contents). The number of entries availables to store data is affected by a checksum (16 bytes) that is present only in the the last block of each cluster (in block nº16 of every cluster)
The table has an area reserved of 1032192 bytes. Divided in 32256 entries, of 32 bytes each entry. The number of used entryes in the file_table can vary (seems to be dependant of the .iso contents). The number of entries availables to store data is affected by a checksum (16 bytes) that is present only in the the last block of each cluster (in block nº16 of every cluster)
When this checksum is between used entryes... his length is 32 bytes (it "steals" the area of one entry)
When this checksum is between used entryes... his length is 32 bytes (it "steals" the area of one entry)
Line 104: Line 174:
! Entry Nº !! Offset !! Length !! Name !! Example !! Notes
! Entry Nº !! Offset !! Length !! Name !! Example !! Notes
|-
|-
| rowspan="5" style="background-color:#DDDDDD;" | 1 || 0x00 || 4 bytes (0x04) || '''file_offset''' || 0 || file offset from start of .iso root (for the first entry is always 0)
| rowspan="5" style="background-color:#DDDDDD;" | 1 || 0x00 || 0x04 (4 bytes) || '''file_offset''' || 0 || file offset from start of .iso root (for the first entry is always 0)
|-
|-
| 0x04 || 2 bytes (0x02) || '''file_size''' || variable || this size determines the displacement of the next file (in the next entry)
| 0x04 || 0x02 (2 bytes) || '''file_size''' || variable || this size determines the displacement of the next file (in the next entry)
|-
|-
| 0x06 || 2 bytes (0x02) || '''file_type ?''' || 01 00 || usually 1... and 0 for the last entry
| 0x06 || 0x02 (2 bytes) || '''file_type ?''' || 01 00 || usually 1... and 0 for the last entry
|-
|-
| 0x08 || 16 bytes (0x10) || '''file_checksum ?''' || variable || unknown
| 0x08 || 0x10 (16 bytes) || '''file_checksum''' || variable || First 16 bytes of the sha1 of the uncompressed data
|-
|-
| 0x18 || 8 bytes (0x08) || ''padding'' || ||
| 0x18 || 0x08 (8 bytes) || ''padding'' || ||
|-
|-
| style="background-color:#DDDDDD;" | Up to 32256 || || || || || same structure than the previous entry
| style="background-color:#DDDDDD;" | Up to 32256 || || || || || same structure than the previous entry
|-
|}
|}


===iso.bin Common Disc table===
====Common Disc table====
Composed by a variable number of entries (depends of the number of files/folders inside the discs), 12 bytes each entry
Composed by a variable number of entries (depends of the number of files/folders inside the discs), 12 bytes each entry


Line 125: Line 194:
! Entry Nº !! Offset !! Length !! Name !! Example !! Notes
! Entry Nº !! Offset !! Length !! Name !! Example !! Notes
|-
|-
| rowspan="4" style="background-color:#DDDDDD;" | 1 || 0x00 || 4 bytes (0x04) || '''file_offset ?''' || 0 || always increases
| rowspan="4" style="background-color:#DDDDDD;" | 1 || 0x00 || 0x04 (4 bytes) || '''file_offset ?''' || 0 || always increases
|-
|-
| 0x04 || 2 bytes (0x02) || '''file_type ?''' || 01 01 || always 01 01
| 0x04 || 0x02 (2 bytes) || '''file_type ?''' || 01 01 || always 01 01
|-
|-
| 0x06 || 3 bytes (0x03) || '''counter 1''' || || some kind of counter, in decimal, always increases <-------- related with "sectors" inside the .iso ?
| 0x06 || 0x03 (3 bytes) || '''counter 1''' || || some kind of counter, in decimal, always increases <-------- related with "sectors" inside the .iso ?
|-
|-
| 0x09 || 3 bytes (0x03) || '''counter 2''' || || another counter, in decimal, always increases, its in relationship with the previous counter (this one is always 200 bytes bigger than the previous one)
| 0x09 || 0x03 (3 bytes) || '''counter 2''' || || another counter, in decimal, always increases, its in relationship with the previous counter (this one is always 200 bytes bigger than the previous one)
|-
|-
| style="background-color:#DDDDDD;" | Up to ? || || || || || same structure than the previous entry
|}
|}


There are 2 "special" entries to mark the "start of a disc" (FFFFFFFF 00000000 FFFFFFFF), and the "end of a disc" (FFFFFFFF FFFFFFFF FFFFFFFF). Between the start and the end, there are a variable number of entries.
====Subchannel data====
This is data stored in separate .pgd in psar (0xED4 [0x12D4] in ISO header point to it if available), should be required only for games that use libcrypt protection (LC2 and higher).
Header of decrypted file is FFFFFFFF 00000000 FFFFFFFF, end of file is marked by FFFFFFFF FFFFFFFF FFFFFFFF.
Values are always 150 sectors lower than real disc sector (pregap?). Values are in little endian (sector only actually, others are 1 byte values). See section below for example code on how to generate this table.


There is also an added string at the end of the last disc (after the last FFFFFFFF FFFFFFFF FFFFFFFF entry)... is a 40 bytes unknown area (in my example my game had 4 discs so maybe this area is divided in chunks of 10 bytes for each disc)
{| class="wikitable"
|-
! Entry Nº !! Name !! Offset !! Size (bytes) !! Example !! Notes
|-
|-
| rowspan="9" style="background-color:#DDDDDD;" | 1 or 2? || Sector || 0x00 || 4 || || Sector number - 150
|-
| Track Number || 0x04 || 1 || 0x01 || Always 0x01
|-
| Index || 0x05  || 1 || 0x01 || Always 0x01
|-
| Pmin(relative) || 0x06 || 1 || ||
|-
| Psec(relative) || 0x07 || 1 || ||
|-
| Pframe(relative) || 0x08 || 1 || ||
|-
| Amin (Absolute) || 0x09 || 1 || ||
|-
| Asec (Absolute) || 0x0A || 1 || ||
|-
| Aframe (Absolute) || 0x0B || 1 || ||
|-
| style="background-color:#DDDDDD;" | Up to 1024 || || || || || or up to 1022? (minus header/footer) same structure than the previous entry
|-
|}
*More info: https://www.psx-place.com/threads/ps1-libcrypt-support-on-ps3-official-emus-research-thread.35836/page-13#post-318506
*Unpacker able to extract that data: [[PS1_Emulation#PSone_Classic_Tools|PSone Classic Tools]]
 
== Minis ISO.BIN structure ==


So as an example... for a game with 4 discs this table is:
=== Header ===
* first entry of disc 1 ---> FFFFFFFF 00000000 FFFFFFFF (start of disc 1)
 
* next entries of disc 1 --> data from disc.... the number is variable
{| class="wikitable sortable"
* last entry of disc 1 ---> FFFFFFFF FFFFFFFF FFFFFFFF (end of disc 1)
|-
* first entry of disc 2 ---> FFFFFFFF 00000000 FFFFFFFF (start of disc 2)
! Name !! Offset !! Size !! Example !! Remark
* next entries of disc 2 --> data from disc.... the number is variable
|-
* last entry of disc 2 ---> FFFFFFFF FFFFFFFF FFFFFFFF (end of disc 2)
| Magic! || 0x0 || 0x8 || NPUMDIMG ||
* first entry of disc 3 ---> FFFFFFFF 00000000 FFFFFFFF (start of disc 3)
|-
* next entries of disc 3 --> data from disc.... the number is variable
| unk1 || 0x8 || 0x4 || N.A || (be)
* last entry of disc 3 ---> FFFFFFFF FFFFFFFF FFFFFFFF (end of disc 3)
|-
* first entry of disc 4 ---> FFFFFFFF 00000000 FFFFFFFF (start of disc 4)
| Block Size || 0xC || 0x4 || N.A || (be)
* next entries of disc 4 --> data from disc.... the number is variable
|-
* last entry of disc 4 ---> FFFFFFFF FFFFFFFF FFFFFFFF (end of disc 4)
| ContentID || 0x10 || 0x24 || UP4123-NPUZ00119_00-ANGRYBIRDSGAME01 ||
* unknown area of 40 bytes (10 bytes for each disc ?)
|-
| Padding1 || 0x34 || 0xC || ({0x0}filled)||
|-
| Common1 || 0x40 || 0x4 || 0x00 0x08 0x00 0xE0 ||
|-
| Padding2 || 0x44 || 0x4 || ({0x0}filled) ||
|-
| unk2 || 0x48 || 0x4 || N.A || (be)
|-
| Padding3 || 0x4c || 0x8 || ({0x0}filled) ||
|-
| LBA Start || 0x54 || 0x4 || N.A || (be)
|-
| Padding4 || 0x58 || 0x4 || ({0x0}filled) ||
|-
| unk3 || 0x5C || 0x4 || N.A || (be)
|-
| Padding5 || 0x60 || 0x4 || ({0x0}filled) ||
|-
| LBA End || 0x64 || 0x4 || N.A || (be)
|-
| unk4 || 0x68 || 0x4 || N.A || (be)
|-
| Np_Table Offset || 0x6C || 0x4 || N.A || (be)
|-
| GameID || 0x70 || 0xA || NPUZ-00119 ||
|-
| Common2 || 0x7A || 0x26 || N.A ||
|-
| Header Key || 0xA0 || 0x10 || N.A. ||
|-
| Padding6 || 0xB0 || 0x50 || N.A({0x0} filled) ||
|-
|}
 
=== Iso Block Table (1st decrypted but compressed block)===
 
{| class="wikitable sortable"
|-
! Name !! Offset !! Size !! Example !! Remark
|-
| Block MAC || 0x100 || 0x10 || N.A ||
|-
| Block Offset || 0x110 || 0x4 || N.A || (be)
|-
| Block Size || 0x114 || 0x4 || N.A || (be)
|-
| Padding || 0x118 || 0x8 || 00000000 ||
|}
 
Until X blocks where X is the block number
 
== Minis MINIS.BIN structure ==
 
=== Header ===
 
{| class="wikitable sortable"
|-
! Name !! Offset !! Size !! Example !! Remark
|-
| Magic! || 0x0 || 0x8 || NPUMDIMG ||
|-
| unk1(be) || 0x8 || 0x4 || N.A ||
|-
| Block Size(be) || 0xC || 0x4 || N.A ||
|-
| ContentID || 0x10 || 0x24 || UP4123-NPUZ00119_00-ANGRYBIRDSGAME01 ||
|-
| Padding || 0x34 || 0x8 ||({0x0} filled) ||
|-
| Encrypted Version Key || 0x40 || 0x10 || N.A || AES-CBC Encrypted
|-  
|}
 
=== Notes ===
 
* You can decrypt any eboot.pbp from a mini OR pspremaster OR psn paid eboot(?) with npdpc
* You can use any header on an iso.bin, and the ps3 won't even try to check it
* (be) means that the generated table values will have to be endian swapped when using npdpc (now possible thanks to arnold)
* [[http://www.ps3hax.net/showthread.php?p=569948#post569948 arnold's code]]
* [[https://mega.co.nz/#!45tiWALS!XyiDIm00rYdHMs0vNyOpYzUAIBAG_dLuZmwjP0FslCA kirk lib]]


==Decrypting owned ISO.BIN.EDATs and MINIS.EDATs==
==Decrypting owned ISO.BIN.EDATs and MINIS.EDATs==
QUESTION: Am I allowed to post binaries compiled with the SCE SDK?<br>
{{warning|content='''These source codes won't work without further modification!'''
You can use this code snippet, which is based on a sdk sample, in your program to decrypt EDATs you have activated on your system:
}}
These examples work with every EDAT type.
===Decrypting with SCE SDK===
<!--// CELL_FS_  CELL_FS //-->
<pre>
<pre>
#define PSP_EMULATOR_KLIC {0x2A,0x6A,0xFB,0xCF,0x43,0xD1,0x57,0x9F,0x7D,0x73,0x87,0x41,0xA1,0x3B,0xD4,0x2E}
#define PSP_EMULATOR_KLIC {{0x2A, 0x6A, 0xFB, 0xCF, 0x43, 0xD1, 0x57, 0x9F, 0x7D, 0x73, 0x87, 0x41, 0xA1, 0x3B, 0xD4, 0x2E}}
#define BUF_SIZE      (16*1024)
#define BUF_SIZE      (16*1024)
#define NP_POOL_SIZE  (128*1024)
#define NP_POOL_SIZE  (128*1024)
Line 164: Line 349:
#include <np.h>
#include <np.h>
#include <np/drm.h>
#include <np/drm.h>
#include <stdio.h>
#include <cell/cell_fs.h>
#include <cell/sysmodule.h>


int main ()
{
uint8_t np_pool[NP_POOL_SIZE];
uint8_t np_pool[NP_POOL_SIZE];
uint8_t read_buf[BUF_SIZE];
uint8_t read_buf[BUF_SIZE];
Line 182: Line 372:
ret = sceNpDrmIsAvailable2(&k_licensee, edata_file);
ret = sceNpDrmIsAvailable2(&k_licensee, edata_file);
if (ret != CELL_OK) {
if (ret != CELL_OK) {
printf("EDAT not activated\n", ret);
printf("EDAT not activated\n");
return ret;
return ret;
}
}
Line 189: Line 379:
ret = cellFsOpen(edata_file, CELL_FS_O_RDONLY, &fd1, &arg, sizeof(arg));
ret = cellFsOpen(edata_file, CELL_FS_O_RDONLY, &fd1, &arg, sizeof(arg));
if (ret != CELL_FS_OK) {
if (ret != CELL_FS_OK) {
printf("Error opening for reading\n", ret);
printf("Error opening for reading\n");
return ret;
return ret;
}
}
Line 195: Line 385:
ret = cellFsOpen(raw_file, CELL_FS_O_RDWR|CELL_FS_O_CREAT, &fd2, NULL, 0);
ret = cellFsOpen(raw_file, CELL_FS_O_RDWR|CELL_FS_O_CREAT, &fd2, NULL, 0);
if (ret != CELL_FS_OK) {
if (ret != CELL_FS_OK) {
printf("Error opening file\n", ret);
printf("Error opening file\n");
cellFsClose(fd2);
cellFsClose(fd2);
return ret;
return ret;
Line 232: Line 422:
ret = cellSysmoduleUnloadModule(CELL_SYSMODULE_SYSUTIL_NP);
ret = cellSysmoduleUnloadModule(CELL_SYSMODULE_SYSUTIL_NP);
ret = cellSysmoduleUnloadModule(CELL_SYSMODULE_FS);
ret = cellSysmoduleUnloadModule(CELL_SYSMODULE_FS);
return ret;
}
</pre>
</pre>


=Decrypted Content=
=== Decrypting with PSL1GHT ===
Please help with your own uploads to better understand the structure.
 
==Links to Samples of Decrypted ISO.BIN.EDATs==
* broken github: https://github.com/euss/psp_edat_decryptor (git'ed by euss for convenience)
<pre>
* broken mirrors: [http://mir.cr/0XXBT99Z], [http://mir.cr/1SNVEH2D], [http://mir.cr/ZKZJFPET]
Angry Birds(USA) http://www.multiupload.nl/UM81ZBTR8E
 
</pre>
=== Generate the subchannel blob ===
==Links to Samples of Decrypted MINIS.EDATs==
Python code to generate the subchannel blob:
<pre>
Angry Birds(USA) http://www.multiupload.nl/6PJP0E6JHH
</pre>
==Links to Samples of Decrypted MINIS2.EDATs==
<pre>
<pre>
def generate_subchannels(magic_word):
    def generate_subchannel(sector, is_corrupt):
        def bcd(i):
            return int(i % 10) + 16 * (int(i / 10) % 10)
        sc = bytearray(12)
        s = sector - 150
        struct.pack_into('<I', sc, 0, s)
        struct.pack_into('<B', sc, 4, 1)
        struct.pack_into('<B', sc, 5, 1)
        if is_corrupt:
            s = s - 1
        struct.pack_into('<B', sc, 8, bcd(s % 75))
        s = s - (s % 75)
        s = int(s / 75)
        struct.pack_into('<B', sc, 7, bcd(s % 60))
        struct.pack_into('<B', sc, 6, bcd(int(s / 60)))
        s = sector
        if is_corrupt:
            s = s - 1
        struct.pack_into('<B', sc, 11, bcd(s % 75))
        s = s - (s % 75)
        s = int(s / 75)
        struct.pack_into('<B', sc, 10, bcd(s % 60))
        struct.pack_into('<B', sc, 9, bcd(int(s / 60)))
        return sc
    sector_pairs = {
        15: [14105,14110],
        14: [14231,14236],
        13: [14485,14490],
        12: [14579,14584],
        11: [14649,14654],
        10: [14899,14904],
        9: [15056,15061],
        8: [15130,15135],
        7: [15242,15247],
        6: [15312,15317],
        5: [15378,15383],
        4: [15628,15633],
        3: [15919,15924],
        2: [16031,16036],
        1: [16101,16106],
        0: [16167,16172]
        }
    scd = bytes(0)
    scd = scd + bytes([0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff])
    for i in range(15, -1, -1):
        scd = scd + generate_subchannel(sector_pairs[i][0], magic_word & (1<<i))
        scd = scd + generate_subchannel(sector_pairs[i][1], magic_word & (1<<i))
    scd = scd + bytes([0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff])
    print('Generate subchannel data for 0x%04x' % magic_word)
    s = scd
    while s:
        print(struct.unpack_from('<I', s, 0)[0], s[:12].hex())
        s = s[12:]
    return scd
</pre>
</pre>
==About PS2 Classics==
There are some new formats present in PS2 Classics. The first one is ISO.BIN.ENC, the second one is .dxt, which is inside CONTENT folder and there's also a single file named CONFIG. You can see more about this when you first install a PS2 Classic. There's also a  problem with the Data while trying to execute the instalable file. The message Unsupported Data appears on the screen when highliting the file and the error 80028F14 is shown while trying to start.<br>
This was made with the Max Payne game. There could probably be other formats present aswell
===ISO.BIN.EDAT===
For PSN PS2-Classics Games ISO.BIN.EDAT only contains the Title Id of the disc. Example:
<pre>SLES-12345</pre>
{{File Formats}}<noinclude>[[Category:Main]]</noinclude>

Latest revision as of 19:22, 25 August 2023

ISO.BIN.EDAT[edit | edit source]

ISO.BIN.EDAT is an encryted container format. First step to work with it is to decrypt it

After decryption, we should refer to ISO.BIN.EDAT as ISO.BIN.DAT (without the "E"... so the EDAT became a DAT).

ISO.BIN.DAT (decrypted)[edit | edit source]

This can be considered an intermediate container composed by the ISO.BIN + a 40 bytes signature at bottom
For the purpose of this wiki page and the concept of extracting data from layers like an onion we need to delete the last 40 bytes to convert a ISO.BIN.DAT into a ISO.BIN
The signature is intended as a sanity check to the ISO.BIN data. In other words if you are going to modify the ISO.BIN you will need to generate a new signature for it when rebuilding it
Example source-code to generate the 40 byte signature can be found in sign3.py which is part of pop-fe.

ISO.BIN structure[edit | edit source]

All offsets are in little endian (except in the last table where there are two counters in decimal)

1 block = 1024 bytes (0x400)
1 cluster = 16 blocks = 1024*16 bytes =16384 bytes (0x4000)
disc_starts ----------> 0x000400 (disc1), 0x100400 (disc2), 0x200400 (disc3), 0x300400 (disc4), etc...
disc_tocs -----------> 0x000C00 (disc1), 0x100C00 (disc2), 0x200C00 (disc3), 0x300C00 (disc4), etc...
disc_map_tables ----> 0x004400 (disc1), 0x104400 (disc2), 0x204400 (disc3), 0x304400 (disc4), etc...

Header (optional)[edit | edit source]

1 block = 1024 bytes (0x400)

Always exists in PS1 classic multidiscs (the example below is from ff8), in the official PS1 classics single disc doesnt exists, but the custom PS1 classics single discs can use it (there are custom tools that adds it in all cases)

Block Nº Offset Length Name Example Description
0
common_header
0x0000 0x10 (16 bytes) magic PSTITLEIMG000000
0x0010 0x1F0 (496 bytes) padding
0x0200 0x64 (100 bytes) discs_start_offsets 00 04 00 00 25 chunks of 4 bytes ... each chunk = start position of each disc, in games with only 1 disc only the first 4 bytes are used
0x0264 0x10 (16 bytes) game_id _SLES_12345 common identifyer for all discs
0x0274 0x18C (396 bytes) padding

Section[edit | edit source]

64 clusters, 1024 blocks, 10485576 bytes (0x100000)

This structure is repeated one time for every disc of the game all them joined together consecutivelys (the example below is from ff8), the whole space is reserved even when there is no data used

Cluster Nº Block Nº Offset Length Name Example Notes
0
Disc map header
1 0x0000 0x00C (12 bytes) magic PSISOIMG0000 In "PSP Minis" It's NPUMDIMG (NP UMD Image) ..... probably another for "ps2 classics" (speculation)
0x000C 0x004 (4 bytes) section size Offset from the start of the PSISOIMG section to the next section
For uncompressed images this is usually 0x100000 + size of iso-image padded to 0x9300
If the disc contains CD-DA tracks then this number will also include all the ATRACK encoded audio that follows after the disk image.
0x0010 0x3F0 (1008 bytes) padding
2 0x0400 0x010 (16 bytes) disc id _SLES_12345 in games with several discs each disc has a different id
0x0410 0x14 (20 bytes) padding
0x0424 0x4 (4 bytes) Ad hoc ps1 config revision 0x12345 (bcd) Ad hoc game config revision in bcd little endian.
0x042C up to 0x40 (64 bytes) Ad hoc ps1 configs 0x01, 0x40 Ad hoc game configs in little endian. Single config is 4 bytes command and 4 bytes param for said command. Up to 8 Commands is supported. ps1_netemu only. ISO.BIN.EDAT exclusive.
0x046C 0x394 (916 bytes) padding
3 0x0800 0x3FС (1020 bytes) Disc toc table variable Table of content, like CUE sheet, supports upto 99 entries (102 entries total)
0x0BFC 0x004 (4 bytes) disc start offset 0x100000
4 0x0C00 0x400 (1024 bytes) Audio tracks table Datas of audio tracks (2-65). offset, size, and more
5 0x1000 0x220 (544 bytes) Audio tracks table Datas of audio tracks (66-99). offset, size, and more
0x12B0 0x004 (4 bytes) Libcrypt Magic Word 0x1234 Little endian. Magic word is used as an answer to COP0 BPC reads for libcrypt games.
0x12D4 0x004 (4 bytes) subchannel offset 0x100400 Offset to where subchannel data is stored. This is used with libcrypt.
0x12D8 0x004 (4 bytes) subchannel count 0x178 Number of subchannel blocks. Each block is 12 bytes.
0x12DC 0x124 (292 bytes) padding
6 0x1400 0x400 (1024 bytes) not used
7 0x1800 0x400 (1024 bytes) not used
8 0x1C00 0x400 (1024 bytes) not used
9 0x2000 0x400 (1024 bytes) not used
10 0x2400 0x400 (1024 bytes) not used
11 0x2800 0x400 (1024 bytes) not used
12 0x2C00 0x400 (1024 bytes) not used
13 0x3000 0x400 (1024 bytes) not used
14 0x3400 0x400 (1024 bytes) not used
15 0x3800 0x400 (1024 bytes) not used
16 0x3C00 0x010 (16 bytes) checksum 0x1CCE0033... It seems to be the checksum of this block, and because this block is always unused the checksum is always 1CCE003360C6E8A6B36A972D00EAFDBF
0x3C10 0x3F0 (1008 bytes) padding
1
Disc map table
17 0x4000 variable Disc map table Divided in chunks of 32 bytes
Up to 32
Up to 64
Disc map table

Disc toc table[edit | edit source]

Entry structure:

Entry Nº Offset Length Name Example Notes
1 0x00 0x01 (1 byte) TYPE 0x41/0x01 entry flags
0x01 0x01 (1 byte) TNO 00 always zero
0x02 0x01 (1 byte) POINT 0xA0/0xA1/0xA2/0x01/0x02/0x03/etc increases
0x03 0x01 (1 byte) MIN varies decimal
0x04 0x01 (1 byte) SEC varies decimal
0x05 0x01 (1 byte) FRAME varies decimal
0x06 0x01 (1 byte) ZERO 00 always zero
0x07 0x01 (1 byte) PMIN varies decimal
0x08 0x01 (1 byte) PSEC varies decimal
0x09 0x01 (1 byte) PFRAME varies decimal
Up to 102 same structure than the previous entry

Audio tracks table[edit | edit source]

Entry structure:

Entry Nº Offset Length Name Example Notes
1 0x00 0x04 (4 bytes) offset
0x04 0x04 (4 bytes) size
0x08 0x04 (4 bytes) unknown_0 always zeroed
0x0C 0x04 (4 bytes) enc_key encryption key (or 0 if not encrypted)
Up to 98 same structure than the previous entry

The audio tracks themselves are raw ATRAC3 streams without a header. One way to create such blobs is to use the atracdenc encoder and strip of the first 0x60 bytes which is the header. The resulting blob is what the Audio tracks table entries will point to.

Disc map table[edit | edit source]

The table has an area reserved of 1032192 bytes. Divided in 32256 entries, of 32 bytes each entry. The number of used entryes in the file_table can vary (seems to be dependant of the .iso contents). The number of entries availables to store data is affected by a checksum (16 bytes) that is present only in the the last block of each cluster (in block nº16 of every cluster) When this checksum is between used entryes... his length is 32 bytes (it "steals" the area of one entry) Seems to be a checksum of this block... when the block is filled with zeroes the checksum is : 1CCE0033 60C6E8A6 B36A972D 00EAFDBF

The first 4 bytes of each entry (file offset from start of .iso root) increases for each entry in a amount of bytes determined by the previous entryes.... in other words... the second file in the .iso is displaced the number of bytes used by the first file... and the third file is displaced in a amount of bytes used by the addition of the sizes of first and second file

Entry Nº Offset Length Name Example Notes
1 0x00 0x04 (4 bytes) file_offset 0 file offset from start of .iso root (for the first entry is always 0)
0x04 0x02 (2 bytes) file_size variable this size determines the displacement of the next file (in the next entry)
0x06 0x02 (2 bytes) file_type ? 01 00 usually 1... and 0 for the last entry
0x08 0x10 (16 bytes) file_checksum variable First 16 bytes of the sha1 of the uncompressed data
0x18 0x08 (8 bytes) padding
Up to 32256 same structure than the previous entry

Common Disc table[edit | edit source]

Composed by a variable number of entries (depends of the number of files/folders inside the discs), 12 bytes each entry

Entry Nº Offset Length Name Example Notes
1 0x00 0x04 (4 bytes) file_offset ? 0 always increases
0x04 0x02 (2 bytes) file_type ? 01 01 always 01 01
0x06 0x03 (3 bytes) counter 1 some kind of counter, in decimal, always increases <-------- related with "sectors" inside the .iso ?
0x09 0x03 (3 bytes) counter 2 another counter, in decimal, always increases, its in relationship with the previous counter (this one is always 200 bytes bigger than the previous one)
Up to ? same structure than the previous entry

Subchannel data[edit | edit source]

This is data stored in separate .pgd in psar (0xED4 [0x12D4] in ISO header point to it if available), should be required only for games that use libcrypt protection (LC2 and higher). Header of decrypted file is FFFFFFFF 00000000 FFFFFFFF, end of file is marked by FFFFFFFF FFFFFFFF FFFFFFFF. Values are always 150 sectors lower than real disc sector (pregap?). Values are in little endian (sector only actually, others are 1 byte values). See section below for example code on how to generate this table.

Entry Nº Name Offset Size (bytes) Example Notes
1 or 2? Sector 0x00 4 Sector number - 150
Track Number 0x04 1 0x01 Always 0x01
Index 0x05 1 0x01 Always 0x01
Pmin(relative) 0x06 1
Psec(relative) 0x07 1
Pframe(relative) 0x08 1
Amin (Absolute) 0x09 1
Asec (Absolute) 0x0A 1
Aframe (Absolute) 0x0B 1
Up to 1024 or up to 1022? (minus header/footer) same structure than the previous entry

Minis ISO.BIN structure[edit | edit source]

Header[edit | edit source]

Name Offset Size Example Remark
Magic! 0x0 0x8 NPUMDIMG
unk1 0x8 0x4 N.A (be)
Block Size 0xC 0x4 N.A (be)
ContentID 0x10 0x24 UP4123-NPUZ00119_00-ANGRYBIRDSGAME01
Padding1 0x34 0xC ({0x0}filled)
Common1 0x40 0x4 0x00 0x08 0x00 0xE0
Padding2 0x44 0x4 ({0x0}filled)
unk2 0x48 0x4 N.A (be)
Padding3 0x4c 0x8 ({0x0}filled)
LBA Start 0x54 0x4 N.A (be)
Padding4 0x58 0x4 ({0x0}filled)
unk3 0x5C 0x4 N.A (be)
Padding5 0x60 0x4 ({0x0}filled)
LBA End 0x64 0x4 N.A (be)
unk4 0x68 0x4 N.A (be)
Np_Table Offset 0x6C 0x4 N.A (be)
GameID 0x70 0xA NPUZ-00119
Common2 0x7A 0x26 N.A
Header Key 0xA0 0x10 N.A.
Padding6 0xB0 0x50 N.A({0x0} filled)

Iso Block Table (1st decrypted but compressed block)[edit | edit source]

Name Offset Size Example Remark
Block MAC 0x100 0x10 N.A
Block Offset 0x110 0x4 N.A (be)
Block Size 0x114 0x4 N.A (be)
Padding 0x118 0x8 00000000

Until X blocks where X is the block number

Minis MINIS.BIN structure[edit | edit source]

Header[edit | edit source]

Name Offset Size Example Remark
Magic! 0x0 0x8 NPUMDIMG
unk1(be) 0x8 0x4 N.A
Block Size(be) 0xC 0x4 N.A
ContentID 0x10 0x24 UP4123-NPUZ00119_00-ANGRYBIRDSGAME01
Padding 0x34 0x8 ({0x0} filled)
Encrypted Version Key 0x40 0x10 N.A AES-CBC Encrypted

Notes[edit | edit source]

  • You can decrypt any eboot.pbp from a mini OR pspremaster OR psn paid eboot(?) with npdpc
  • You can use any header on an iso.bin, and the ps3 won't even try to check it
  • (be) means that the generated table values will have to be endian swapped when using npdpc (now possible thanks to arnold)
  • [arnold's code]
  • [kirk lib]

Decrypting owned ISO.BIN.EDATs and MINIS.EDATs[edit | edit source]

Warning
These source codes won't work without further modification!

These examples work with every EDAT type.

Decrypting with SCE SDK[edit | edit source]

#define PSP_EMULATOR_KLIC {{0x2A, 0x6A, 0xFB, 0xCF, 0x43, 0xD1, 0x57, 0x9F, 0x7D, 0x73, 0x87, 0x41, 0xA1, 0x3B, 0xD4, 0x2E}}
#define BUF_SIZE      (16*1024)
#define NP_POOL_SIZE  (128*1024)

#include <np.h>
#include <np/drm.h>
#include <stdio.h>
#include <cell/cell_fs.h>
#include <cell/sysmodule.h>

int main ()
{
uint8_t np_pool[NP_POOL_SIZE];
uint8_t read_buf[BUF_SIZE];
int ret;
int fd1,fd2;
uint64_t file_size;
uint64_t sw;
char *edata_file,*raw_file; //raw_file will be created if it does not exist
SceNpDrmKey k_licensee = PSP_EMULATOR_KLIC;

ret = cellSysmoduleLoadModule(CELL_SYSMODULE_FS);
ret = cellSysmoduleLoadModule(CELL_SYSMODULE_SYSUTIL_NP);
printf("sceNpInit()\n");
ret = sceNpInit(NP_POOL_SIZE, np_pool);

printf(" Open '%s' as NPDRM file\n", edata_file);
ret = sceNpDrmIsAvailable2(&k_licensee, edata_file);
if (ret != CELL_OK) {
	printf("EDAT not activated\n");
	return ret;
}
SceNpDrmOpenArg arg;
	arg.flag = SCE_NP_DRM_OPEN_FLAG;
	ret = cellFsOpen(edata_file, CELL_FS_O_RDONLY, &fd1, &arg, sizeof(arg));
	if (ret != CELL_FS_OK) {
		printf("Error opening for reading\n");
		return ret;
	}
printf("Opening file to dump to '%s'\n", raw_file);
	ret = cellFsOpen(raw_file, CELL_FS_O_RDWR|CELL_FS_O_CREAT, &fd2, NULL, 0);
	if (ret != CELL_FS_OK) {
		printf("Error opening file\n");
		cellFsClose(fd2);
		return ret;
	}
printf("\n[ dump edata ]\n");
	for (uint64_t r = 0; r < file_size; r += BUF_SIZE) {
		uint64_t rsize;
		uint64_t remain = file_size - r;
		if (remain > BUF_SIZE) { remain = BUF_SIZE; }

		ret = cellFsRead(fd1, read_buf, remain, &rsize);
		if (ret != CELL_OK || rsize != remain) {
			printf("Read error ('%s'): ret = 0x%08x, size = %llx, %llx\n",
					edata_file, ret, remain, rsize);
			if (ret == CELL_OK) { ret = -1; }
			cellFsClose(fd1);
			cellFsClose(fd2);
			return ret;
		}

		printf("dump data: (0x%08llx - 0x%08llx)  ", r, r + remain);
		ret = cellFsWrite(fd2, (const void *)read_buf, (size_t)remain, &sw);
		if (ret != CELL_FS_OK) {
			cellFsClose(fd1);
			cellFsClose(fd2);
			printf("ERROR\n");
			return -1;
		}
		printf("OK\n");
	}

	/* file close */
ret = cellFsClose(fd1);
ret = cellFsClose(fd2);
ret = sceNpTerm();
ret = cellSysmoduleUnloadModule(CELL_SYSMODULE_SYSUTIL_NP);
ret = cellSysmoduleUnloadModule(CELL_SYSMODULE_FS);
return ret;
}

Decrypting with PSL1GHT[edit | edit source]

Generate the subchannel blob[edit | edit source]

Python code to generate the subchannel blob:

def generate_subchannels(magic_word):
    def generate_subchannel(sector, is_corrupt):
        def bcd(i):
            return int(i % 10) + 16 * (int(i / 10) % 10)

        sc = bytearray(12)
        s = sector - 150
        struct.pack_into('<I', sc, 0, s)
        struct.pack_into('<B', sc, 4, 1)
        struct.pack_into('<B', sc, 5, 1)
        if is_corrupt:
            s = s - 1
        struct.pack_into('<B', sc, 8, bcd(s % 75))
        s = s - (s % 75)
        s = int(s / 75)
        struct.pack_into('<B', sc, 7, bcd(s % 60))
        struct.pack_into('<B', sc, 6, bcd(int(s / 60)))

        s = sector
        if is_corrupt:
            s = s - 1
        struct.pack_into('<B', sc, 11, bcd(s % 75))
        s = s - (s % 75)
        s = int(s / 75)
        struct.pack_into('<B', sc, 10, bcd(s % 60))
        struct.pack_into('<B', sc, 9, bcd(int(s / 60)))

        return sc

    sector_pairs = {
        15: [14105,14110],
        14: [14231,14236],
        13: [14485,14490],
        12: [14579,14584],
        11: [14649,14654],
        10: [14899,14904],
         9: [15056,15061],
         8: [15130,15135],
         7: [15242,15247],
         6: [15312,15317],
         5: [15378,15383],
         4: [15628,15633],
         3: [15919,15924],
         2: [16031,16036],
         1: [16101,16106],
         0: [16167,16172]
        }
    scd = bytes(0)
    scd = scd + bytes([0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff])
    for i in range(15, -1, -1):
        scd = scd + generate_subchannel(sector_pairs[i][0], magic_word & (1<<i))
        scd = scd + generate_subchannel(sector_pairs[i][1], magic_word & (1<<i))
    scd = scd + bytes([0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff])

    print('Generate subchannel data for 0x%04x' % magic_word)
    s = scd
    while s:
        print(struct.unpack_from('<I', s, 0)[0], s[:12].hex())
        s = s[12:]

    return scd

About PS2 Classics[edit | edit source]

There are some new formats present in PS2 Classics. The first one is ISO.BIN.ENC, the second one is .dxt, which is inside CONTENT folder and there's also a single file named CONFIG. You can see more about this when you first install a PS2 Classic. There's also a problem with the Data while trying to execute the instalable file. The message Unsupported Data appears on the screen when highliting the file and the error 80028F14 is shown while trying to start.
This was made with the Max Payne game. There could probably be other formats present aswell

ISO.BIN.EDAT[edit | edit source]

For PSN PS2-Classics Games ISO.BIN.EDAT only contains the Title Id of the disc. Example:

SLES-12345