diff --git a/docs.py b/docs.py index 021435c..59982ea 100644 --- a/docs.py +++ b/docs.py @@ -49,14 +49,15 @@ SEGA_CONTENTS = { "software": ("Software", { "pcp": ("PCP", {"libpcp.html": "libpcp"}), "drivers": ("Device drivers", None), - "security": ("Security", { - "game.html": "Game encryption", - }), + "security.html": "Security", "groovemaster.html": "GrooveMaster.ini", }), # "network": ("Networking", { # "allnet.html": "ALL.Net" # }), + "misc": ("Misc", { + "partition.html": "SEGA Partition Structure" + }), } CONTENTS = { "": EAMUSE_CONTENTS, diff --git a/images/ftk.png b/images/ftk.png new file mode 100644 index 0000000..54bb034 Binary files /dev/null and b/images/ftk.png differ diff --git a/static/keys/SystemKeyFile b/static/keys/SystemKeyFile new file mode 100644 index 0000000..c5a2fee --- /dev/null +++ b/static/keys/SystemKeyFile @@ -0,0 +1 @@ +adsaf21519189aq1g56161asdff19as1f9:PF:CA[][_159191wef \ No newline at end of file diff --git a/static/keys/UpdateKeyFile b/static/keys/UpdateKeyFile new file mode 100644 index 0000000..42d6c60 --- /dev/null +++ b/static/keys/UpdateKeyFile @@ -0,0 +1,2 @@ + +GkN#l \ No newline at end of file diff --git a/styles.css b/styles.css index 6faeef6..3d5fccc 100644 --- a/styles.css +++ b/styles.css @@ -294,6 +294,18 @@ mark { } } + +.ata-bad { + color: #f5417d; +} +.ata-good { + color: #4df541; +} +.ata-ignore { + color: #f5ad41; +} + + @media (prefers-color-scheme: dark) { body { background-color: #000; diff --git a/templates/pages/sega/partition.html b/templates/pages/sega/misc/partition.html similarity index 100% rename from templates/pages/sega/partition.html rename to templates/pages/sega/misc/partition.html diff --git a/templates/pages/sega/software/security.html b/templates/pages/sega/software/security.html new file mode 100644 index 0000000..4c27b22 --- /dev/null +++ b/templates/pages/sega/software/security.html @@ -0,0 +1,526 @@ +{% extends "sega.html" %} +{% block title %}{% endblock %} +{% block body %} +

System Security

+

The Ring* series have a number of security measures in place, some easy to bypass, others requiring more work. They + are listed here in, roughly, the order in which each layer is applied.

+ +

Drive ATA Password

+

The SSD contained within the system has an ATA password set. The system BIOS contains a password derivation function + that derives the specific password for that drive based on its serial number.

+

This can be bypassed either by extracting the password used, or by first powering on the Ring* system with the drive + connected, then hotplugging the SATA data cable on the drive while keeping the drive powered.

+ +
+ Why does this work? +

The following is the sequence of possible security modes for an ATA drive:

+ + + + + + + + + + + + + + + + + + + + + + SEC0 + + + + + Power: off + + + Security: No + + + + + + Power on + + + + + Freeze + + + + + HW Reset + + + + + + + + + + SEC1 + + + + + Security: No + + + Frozen: No + + + + + + + + SEC2 + + + + + Security: No + + + Frozen: Yes + + + + + + + + SEC5 + + + + + Security: Yes + + + Unlocked: Yes + + + Frozen: No + + + + + + + + SEC4 + + + + + Security: Yes + + + Unlocked: No + + + Frozen: No + + + + + + + + SEC6 + + + + + Security: Yes + + + Unlocked: Yes + + + Frozen: Yes + + + + + + Power on + + + + + HW reset + + + + + + + Unlock + + + + + + Freeze + + + + + + + + SEC3 + + + + + Power: off + + + Security: Yes + + + +

When the drive has a password set, it initially starts in SEC3. The RingEdge then transitions the drive to SEC5 + then SEC6. Importantly, however, as long as power is never lost, the drive will remain in SEC6 mode, even if we + connect it to a different system.

+

This allows us full read-write access to the drive without ever knowing the password!

+
+ +

Windows Password

+

It seems silly to mention, but it's worth noting. AppUser will automatically log in, but if you need to + log back in, or wish to login as SystemUser, you'll need the passwords.

+

AppUser's password is segahard.

+

SystemUser's password is <6/=U=#tpe!$*3!5. NOTE: if a debugger is attached to + mxprestartup, Miflac=Ifme9Jfp0 will be attempted as the password for + SystemUser instead. This is not the correct password for a production unit. +

+ +
+ Finding SystemUser's password + +

When AppUser logs in, mxprestartup is executed. This binary constructs SystemUser's password then elevates + permissions. When no debugger is present, the following steps are performed:

+ + + +

If a debugger is present, a similar process is performed:

+ + + +

Why is the process for a debugged process more elaborate? I'm not sure.

+
+ +

System binaries encryption

+

The system binaries, normally located on S:, are a TrueCrypt partition. The partition file can be found + at C:\System\Execute\System. It has password segahardpassword, and used the alternate data + stream loated at + C:\System\Execute\DLL:SystemKeyFile as a keyfile. +

+

C:\System\Execute\DLL:UpdateKeyFile is also present here, which is used for encryption of update + data (but is not utilised in the process of mounting S:).

+ +
+ What's an Alternate Data Stream? +

An alternate data stream, or ADS for short, is a feature of the NTFS filesystem where additional data can be + stored alongside a file or directory. On modern Windows systems, they can be shown using dir /R. If + you are performing analysis on the system using digital forensics software, which you probably should be, all + major packages will show these streams clearly.

+ +
+ +
The alternate data streams, in FTK Imager
+
+ +

The SANS Institude + website is a great resource for more information and links.

+
+
+ Finding this information + +

The decryption of the system partition is the responsibility of mxstartup. This file contains pairs + of hex strings which sum to produce the paths to the alternate data streams, and the volume password.

+
+ +

Keyfile downloads

+ + +

Keychip

+

This is the first point during the boot process where a physical keychip is required in order to continue the system + boot process.

+

With the exception of mxkeychip, processes do not + directly communicate with the keychip. Instead, they communicate with mxkeychip via a PCP. mxkeychip itself is then responsible for + communicating with the keychip. These communications are AES encrypted with keys agreed during the initial + handshake.

+ +

The keychip is responsible for a number of functions:

+ + +

This security layer can be bypassed by replacing the mxkeychip.exe binary with a custom binary, + eliminating the need to emulate the physical parallel device, and its encryption.

+ +

Game data encryption

+

Once the system has verified it is allowed to continue booting, it proceeds to decrypt the game partition. This is + done by performing a keychip.decrypt request.

+

The specific key used varies by game. The easiest way to retrieve this key is to, well, ask the keychip for it. We + can first start a listener on port 40106 to retrieve the value that the boot process is passing. + Following that, we can start the real mxkeychip, and request the same decryption. It will then provide us with the + key to be used for the game encryption!

+

TODO: Some proper digging into the mx binaries to determine exactly where it pulls the encrypted string in the + request

+

The value we have now should be 16 bytes, and is the contents for a keyfile.

+

Like the S: drive, game data is a TrueCrypt partition. Check the SEGA partition description to determine which partition contains + the game data. If in doubt, just try they all until one works :).

+ +

Game-keychip handshake

+

There is one final security step present, however I believe this to only be present in some games.

+

When the game boots, it makes requests to keychip.ssd.proof and keychip.ds.compute. These + are challenge-response queries, which the keychip will internally look up in a large table of possible values.

+

While we could dump the EEPROM chip located on the keychip, there is no need for this. As the game also needs a copy + of the responses to validate against, we can just grab that file, as we have already decrypted the game partition by + this point. The file will likely be named [game ID]_Table.dat.

+ +

I'll flush this out later, but for now, here's the structure of that file:

+
{% highlight "c" %}
+struct {
+    struct {
+        char challenge[7];
+        char responses[4][20];
+    } ds[10000];
+    struct {
+        char challenge[16];
+        char response[16];
+    } ssd[10000];
+}
+{% endhighlight %}
+ +

The responses are scrambled as described below:

+

DS Scramble:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Output index012345678910111213141516171819
Input index155131410121116741812630178199
+

SSD Scramble:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Output index0123456789101112131415
Input index6841271311023111415059
+ +

NOTE: The following information may only be true for MaiMai FiNALE! I have not yet verified this on other + games! +
+ In dev mode, the game will only ever request a single string as the challenge. +

+

This string is 2CFECBC71CF1E4, and its corresponding four response pages are (not scrambled):

+
    +
  1. ca6ed736401682dd4411a27d2440ac4b478bad8b
  2. +
  3. 4ac606302ce5ef51abb3df2dc46c863b3c06aa2c
  4. +
  5. 2aaf35b2aba4c6840bdb7bd40ecbce2cca934795
  6. +
  7. 2f6d713dabde3c43df818491ab9467ba8ba0fed4
  8. +
+

+ NOTE: The following information is super un-verified!
+ Occasionally the game will make a query to the DS table that is not present in the table. In this instance, the + keychip responds with the entry at index n, where n is a counter that increments every time a + keychip.ds.compute query is performed, modulo 100. +

+

It should be noted that if the keychip binary imemdiatly terminates the connection, rather than sending a + known-incorrect response (such as if the challenge matches none in the known tables), the game will re-attempt the + query, and this query will, with a high likelyhood, be different.

+ +

It should additionally be noted that this whole process can be skipped by returning code=54 rather than + a valid response.

+ +{% endblock %} \ No newline at end of file diff --git a/templates/pages/sega/software/security/game.html b/templates/pages/sega/software/security/game.html deleted file mode 100644 index e68cb98..0000000 --- a/templates/pages/sega/software/security/game.html +++ /dev/null @@ -1,6 +0,0 @@ -{% extends "sega.html" %} -{% block title %}{% endblock %} -{% block body %} -

Game Encryption

-

Games are encrypted with CrackProof encryption.

-{% endblock %} \ No newline at end of file