Undid README.technical to MD
This commit is contained in:
parent
8a9e221b33
commit
4b039f9ba9
1 changed files with 0 additions and 0 deletions
223
docs/README.technical
Normal file
223
docs/README.technical
Normal file
|
@ -0,0 +1,223 @@
|
|||
FriiDump Techincal info
|
||||
===============================================================================
|
||||
|
||||
This document is a reworking and unification of information found all over the net, regarding the structure of Nintendo Gamecube/Wii Optical Discs and how to read them on an ordinary DVD-ROM drive. All the due credits can be found in the AUTHORS file.
|
||||
|
||||
Nintendo Gamecube/Wii Optical Disc (GOD/WOD) structure
|
||||
===============================================================================
|
||||
|
||||
In order to understand how a Gamecube or WII Optical Disk is made, let us first take a look at a standard DVD-ROM. The complete standard is explained in the ECMA-267 Standard.
|
||||
|
||||
The user data stored on the DVD is divided in blocks, each 2048 bytes long. Each 2048-byte block is then encapsulated in a 2064-byte structure, adding some other data needed for error-correction and head positioning. A 2064-byte block is called a "Data frame", and its logical layout is as follows:
|
||||
|
||||
| 4 bytes | 2 bytes | 6 bytes | 2048 bytes | 4 bytes |
|
||||
| ------- | ------- | ------- | --------------- | ------- |
|
||||
| ID | IED | CPR_MAI | User Data Frame | EDC |
|
||||
|
||||
- Identification Data (ID): Contains the PSN (Physical Sector Number), info
|
||||
about the sector itself, like the layer, reflectivity, zone, etc.
|
||||
- ID Error Detection Code (IED)
|
||||
- Copyright Management Information (CPR_MAI): Its use is application-specific,
|
||||
for instance it can be used to store a sector key in videos that use CSS, or
|
||||
a scrambling key in the XBox and XBox360 Security Sectors.
|
||||
- User Data: This is the data available for the end user.
|
||||
- Error Detection Code (EDC): It is the checksum data for all the fields above,
|
||||
its polinomial is x^32 + x^31 + x^4 + 1.
|
||||
|
||||
For various reasons (not related to copy protection), the User Data Frame is
|
||||
XOR'ed with a stream cipher generated by an 15bits LFSR (Linear Feedback Shift
|
||||
Register), with bits 10 and 14 used as taps. The seeds are obtained from a
|
||||
table of the ECMA-267 standard, the index of the seed is the 4 MSB of the last
|
||||
byte of the "ID" field of the Data Frame. The same stream cipher is then used
|
||||
by 16 consecutive Data Frames: for this and other reasons (again related to
|
||||
error correction), data from the DVD are always read in 16-data frame blocks.
|
||||
|
||||
4bytes 2bytes 6bytes 2048bytes 4bytes
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
| ID | IED | CPR_MAI | User Data Frame | EDC |
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
^ | 2048bytes cipher stream |
|
||||
^ - - - - - - - - - -
|
||||
Scrambling
|
||||
seed index
|
||||
|
||||
Now, the first problem when dealing with Gamecube/Wii Optical Discs is that
|
||||
they use a different (and yet unknown) set of seeds. This means that when an
|
||||
ordinary DVD-ROM drive tries to read a GOD/WOD disc, it will unscramble the
|
||||
User Data Frame with the wrong seed, causing the EDC check to fail and a read
|
||||
error to be reported to the operating system, which means the inability to read
|
||||
the disc.
|
||||
|
||||
Furthermore, Gamecube/Wii Optical Disks use a slightly different structure for
|
||||
the Data Frame, as shown in the following figure:
|
||||
|
||||
4bytes 2bytes 2048bytes 6bytes 4bytes
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
| ID | IED | User Data Frame | CPR_MAI | EDC |
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
| 2048bytes cipher stream |
|
||||
- - - - - - - - - -
|
||||
|
||||
Basically, the User Data Frame and the CPR_MAI fields are swapped, while the
|
||||
scrambled bytes remain the same.
|
||||
|
||||
|
||||
===============================================================================
|
||||
Tricks used to read a GOD/WOD on a standard DVD-ROM drive.
|
||||
===============================================================================
|
||||
To cope with the above-mentioned problems, some methods have been suggested by
|
||||
many people on the net. They vary in performance, but the basic idea is always
|
||||
the same:
|
||||
|
||||
1. Issue a read command for the sector of interest (this is actually a
|
||||
16-sector block, not a single sector, as stated above).
|
||||
2. Let the read return failure.
|
||||
3. At this moment, the DVD-ROM drive must have cached the data read from the
|
||||
disc somewhere in its internal memory, to be able to unscramble them and to
|
||||
check the EDC. So, we can dump the data from the drive's internal RAM.
|
||||
|
||||
Unfortunately, this is not as easy as it seems, due to the fact that there is
|
||||
no standard "Dump drive memory" command. This is probably implemented in many
|
||||
drives for firmware debugging purposes, but, as such, it is a vendor-specific
|
||||
command, which are usually undocumented and vary from vendor to vendor (or even
|
||||
from drive model to drive model).
|
||||
|
||||
This is where the work that many hackers around the world have done, in order
|
||||
to crack the Microsoft XBox360 console, becomes useful. They needed some way to
|
||||
read and write data to the XBox360 drive's internal memory, so they
|
||||
disassembled the drive's firmware and patiently tried to understand what each
|
||||
of the vendor-specific commands did. This way, they discovered that a certain
|
||||
command could be used to read an arbitrary portion of the drive's internal RAM.
|
||||
They also managed to map the RAM addresses, so that it is known where data
|
||||
read from the disc are temporarily stored.
|
||||
|
||||
Fortunately, the XBox360 drive is not too different from some retail DVD-ROM
|
||||
drives, namely some models from LG, which means that the discovered command
|
||||
works on them as well. Hence, we now have some sort of access to the disc data.
|
||||
|
||||
Although, this comes at the price of speed: dumping the drive's internal memory
|
||||
is a slow process, as it uses Programmed I/O (PIO) instead of Direct Memory
|
||||
Access (DMA) to transfer data from the drive to the computer's memory. For this
|
||||
reason, some have proposed the use of the "streaming read" command: it is a
|
||||
standard command thought for those applications where the constant flow of data
|
||||
is more important than its absolute correctness, such as audio or video
|
||||
applications. Thus, this command does not perform the EDC on the data read from
|
||||
the disc, but returns it immediately. Anyway, the command will only return the
|
||||
User Data Frame, which means that only a portion of the data will be read this
|
||||
way, while the rest (i.e.: the first 12 and the last 4 bytes) will have to be
|
||||
read using the memory dump method. Nevertheless, this combined method will be
|
||||
faster overall, as only some dozens of bytes have to be transfered through PIO,
|
||||
instead of the whole sectors.
|
||||
|
||||
We still have to cope with the unknown seeds. This problem can be easily solved
|
||||
through the use of brute force: as there are only 15 bits to try (and commonly
|
||||
only 17 seeds per GOD/WOD), this approach only takes about 30 seconds. The
|
||||
bruteforce process is very simple: the LFSR is seeded from 0 to 7FFFh and for
|
||||
each seed the corresponding stream cipher is generated and XOR'ed with the
|
||||
proper section of the Data Frame and the EDC is computed. If the EDC is the same
|
||||
as the one in the EDC field then we have the correct seed.
|
||||
|
||||
|
||||
===============================================================================
|
||||
The FriiDump approach
|
||||
===============================================================================
|
||||
FriiDump can use four different disc dump methods. They have been developed
|
||||
gradually, empirically and heuristically, by experimenting with the PLScsi tool
|
||||
and comparing the retrieved data with a known-good dump. In this section the
|
||||
inner working of every dump method will be described. The code implementing the
|
||||
different methods can be found in the "disc_read_sector_X" functions of disc.c.
|
||||
|
||||
Please note that the desibed behaviour is that of my LG GDR8164B drive, which I
|
||||
assume to be shared by similar drives. Other, more different drives, might
|
||||
behave differently and require totally different methods.
|
||||
|
||||
Also note that all of the methods read 16-sector blocks.
|
||||
|
||||
|
||||
Method 1
|
||||
|
||||
This method is very slow. So slow that I have never dumped a whole disc with
|
||||
it. Although, it served me to prove that I was going in the right direction and
|
||||
that my efforts could eventually come to a working end. It also showed me that
|
||||
the first versions of RawDump create bad dumps, sometimes.
|
||||
|
||||
Basically this method is the same used by those early versions of RawDump,
|
||||
which took 50+ hours to dump a whole disc. It works like this:
|
||||
|
||||
1. Issue a read command for the required sector. This will cause the 16-sector
|
||||
block to which the sector belongs to be placed at the beginning of the
|
||||
drive's cache memory. Do not even bother to see what the read command
|
||||
returns, as it will surely be a data read error.
|
||||
2. Dump the 16-sector block.
|
||||
|
||||
|
||||
Method 2
|
||||
|
||||
Method 2 is similar to method 1, but uses the above-mentioned "streaming read"
|
||||
method, which somehow allows us to dump 5 blocks at a time.
|
||||
|
||||
1. Issue a "streaming read" command for the required sector. This will cause
|
||||
the 16-sector block to which the sector belongs to be placed at the
|
||||
beginning of the drive's cache memory, together with the 4 following
|
||||
16-sector blocks. Do not bother to see what the read command returns.
|
||||
2. Dump the 5 16-sector blocks.
|
||||
|
||||
|
||||
Method 3
|
||||
|
||||
This is similar to the previous method, but instead of dumping the whole
|
||||
sectors from memory, it uses the (not EDC checked) data returned by the
|
||||
"streaming read" command. and completes it dumping only the missing bits from
|
||||
memory.
|
||||
|
||||
1. Issue a "streaming read" command for the required sector. This will cause
|
||||
the 16-sector block to which the sector belongs to be placed at the
|
||||
beginning of the drive's cache memory, together with the 4 following
|
||||
16-sector blocks.
|
||||
2. For each sector of each block, reconstruct the whole Data Frame, as follows:
|
||||
- Dump 12 bytes from memory.
|
||||
- Use 2048 bytes returned by the read command.
|
||||
- Dump 4 more bytes from memory.
|
||||
|
||||
Note that this method has a small issue, as sometimes the beginning of the
|
||||
cache will be dirty and contain invalid data, needing the sector to be read
|
||||
again. As this seems to happen quite often, we always read a dummy sector
|
||||
before the requested sector.
|
||||
|
||||
|
||||
Method 4
|
||||
|
||||
Method 4 is just method 3 with a trick to use a single dump command for every
|
||||
sector that has to be reconstructed, instead of two. It is the faster dump
|
||||
method currently supported and, as such, the default one.
|
||||
|
||||
1. Issue a "streaming read" command for the required sector. This will cause
|
||||
the 16-sector block to which the sector belongs to be placed at the
|
||||
beginning of the drive's cache memory, together with the 4 following
|
||||
16-sector blocks.
|
||||
2. For each sector of each block, reconstruct the whole Data Frame, as follows:
|
||||
- If this is the first sector of a block, dump 12 bytes from memory.
|
||||
Otherwise, use the last 12 bytes of the preceding dump.
|
||||
- Use 2048 bytes returned by the read command.
|
||||
- Dump 16 bytes from memory, and use the first 4. This leaves 12 bytes to be
|
||||
used for the reconstruction of the next sector.
|
||||
|
||||
Note that the issue of method 3 applies to this method, too.
|
||||
|
||||
|
||||
===============================================================================
|
||||
How to add support for a new drive
|
||||
===============================================================================
|
||||
If you read all the above stuff, it should be clear that, in order to add
|
||||
support for a new DVD-ROM drive, all that is needed is a way to dump the
|
||||
drive's internal memory, in particular the portion where the data read from the
|
||||
disc is cached. As explained above, this function might not be present in all
|
||||
drives, and might not be easy to find or to use. In case you manage to discover
|
||||
it, just copy the file "hitachi.c" to a new one, and modify it opportunely.
|
||||
|
||||
Some modifications will also be needed in "dvd_drive.c", in order to add
|
||||
autodetection for the new drive, in the "dvd_assign_functions" function.
|
||||
|
||||
Apart from this, the cache behaviour of the new drive might not be the same
|
||||
as that of the currently supported models, so the program architecture might
|
||||
need radical changes. In this case, please report.
|
Loading…
Add table
Add a link
Reference in a new issue