Join Us and become a Member for a Verified Badge to access private areas with the latest PS4 PKGs.
Status
Not open for further replies.
Today PlayStation 4 developer @zecoxao shared a Python Script (hdd_script.py with updated revisions below) via Twitter from 'the usual suspect' that converts the wrapped key blobs stored in sflash0 into eap_hdd_key, which can then be used to retrieve data from any PS4 console (DevKit, Retail, TestKit) with an SFlash dump! šŸ˜

Download: hdd_script.py (5.29 KB) / hdd_script.py (v2) (5.36 KB - outputs the keys to a file called keys.bin, to be used on Linux with Cryptmount) / hdd_script.py (v2) Mirror / hdd_script.py (v3) (5.57 KB - error handling on sflash0 size and on magic check, in order for the hdd script to work, the dump of sflash0 must have EXACTLY 32MB - 0x2000000 bytes): hdd_script.py (v3) Mirror / Mounting PS4 HDD on WSL2 (Windows Subsystem for Linux 2) Guide with PS4 HDD Script by Anonymous (hdd_script.zip - 2.11 KB - includes hdd_script.py) and WSL2_UFS_Support_Read_Only.rar (2.83 GB - WSL2 UFS RO Kernel)
Code:
#!/usr/bin/env python

from binascii import hexlify as hx
from pathlib import Path

import sys, os, struct
import hashlib, hmac

from Crypto.Cipher import AES
from Crypto.Util import Counter

def aes_encrypt_ecb(key, data):
    crypto = AES.new(key, AES.MODE_ECB)
    return crypto.encrypt(data)

def aes_decrypt_ecb(key, data):
    crypto = AES.new(key, AES.MODE_ECB)
    return crypto.decrypt(data)

def aes_encrypt_cbc(key, iv, data):
    crypto = AES.new(key, AES.MODE_CBC, iv)
    return crypto.encrypt(data)

def aes_decrypt_cbc(key, iv, data):
    crypto = AES.new(key, AES.MODE_CBC, iv)
    return crypto.decrypt(data)

def hmac_sha256(key, data):
    return hmac.new(key=key, msg=data, digestmod=hashlib.sha256).digest()

portability_seed_key = 'E973A44C578757A73492625D2CE2D76B'.decode('hex')
portability_seed = 'DF0C2552DFC7F4F089B9D52DAA0E572A'.decode('hex')

# generate portability key
portability_key = aes_encrypt_ecb(portability_seed_key, portability_seed)

# generate keys from seeds
eap_hdd_key_blob_key1_seed = '7A49D928D2243C9C4D6E1EA8F5B4E229317E0DCAD2ABE5C56D2540572FB4B6E3'.decode('hex')
eap_hdd_key_blob_key2_seed = '921CE9C8184C5DD476F4B5D3981F7E2F468193ED071E19FFFD66B693534689D6'.decode('hex')

eap_hdd_key_blob_key1 = aes_encrypt_ecb(portability_key, eap_hdd_key_blob_key1_seed)
eap_hdd_key_blob_key2 = aes_encrypt_ecb(portability_key, eap_hdd_key_blob_key2_seed)

use_new_blob = False

SFLASH0 = open('sflash0', 'rb')
length = Path('sflash0').stat().st_size
if length != 0x2000000:
    raise SystemExit("not correct size! leaving...")
data = SFLASH0.read()

# ICC NVS: block #4, offset 0x200, size 0x40/0x60, magic 0xE5E5E501 (big endian)
#eap_hdd_wrapped_key = <PASTE KEY HERE>.decode('hex')

print('[DEBUG] ' + hx(data[0x1C91FC:0x1C9200]))

if data[0x1C91FC:0x1C9200] == '\xE5\xE5\xE5\x01':
    print('[DEBUG] ' + hx(data[0x1C9240:0x1C9250]))
else:
    raise SystemExit("not correct magic! leaving...")

if data[0x1C9240:0x1C9250] == '\xFF' * 16:
    eap_hdd_wrapped_key = data[0x1C9200:0x1C9240]
    print('[DEBUG] LEN 40 | ' + hx(eap_hdd_wrapped_key))
else:
    eap_hdd_wrapped_key = data[0x1C9200:0x1C9260]
    print('[DEBUG] LEN 60 | ' + hx(eap_hdd_wrapped_key))

# ICC NVS: block #4, offset 0x60, size 0x4
#smi_version = 0x03700000
#smi_version = 0x03150000

print('[DEBUG] ' + hx(data[0x1C9060:0x1C9064]))

smi_version = struct.unpack('<i',data[0x1C9060:0x1C9064])[0]



# verify and decrypt eap key blob
if use_new_blob:
    eap_hdd_key_blob_enc = 'CFFDCB6ECAE612B7A30A9EDBD8F77E261D629DE5E6CA3F22F439211AC033884F4B5D7D16D0A6F65D3173A2586CF819C7C6F437444C1D9499F6EBC4145E0BBAABC1DE7C63ED1F5A1E1946358C7F181B1FAB6DAB31195D8E611A1CB81B9ACF8B38FF21029FAB568C7A1BCC3E2FBEB25B13F1AFD6A3599EEF09EAEBE32684FDDA29'.decode('hex')
    eap_hdd_key_blob_sig = '4798B78DD422601F26A32A1FEC5CAB8B256E50958E0B11A31D77DEE201D4D00E'.decode('hex')
    eap_hdd_key_blob_iv = '462500ECC487F0A8C2F39511E020CC59'.decode('hex')
else:
    eap_hdd_key_blob_enc = 'E073B691E177D39642DF2E1D583D0E9A5A49EDF72BE9412E2B433E51490CE973234B84F49E949F03727331D5456F4598F2EDE6D0C11483B84CE3283243D0DE9DC379E915301A805DFAEB292B30374C9BF1C59041509BF11D215C35D5C08E3330807C8229C930FAB88672C4CF7DACA881C323D72346CA07921DB806FC242A2ED1'.decode('hex')
    eap_hdd_key_blob_sig = 'ED4F32C095847C6D3143EFFD61E7582F75F24465855C4E94DAF34885D8D03463'.decode('hex')
    eap_hdd_key_blob_iv = '3286EA97F3E92C434E1DC170C9289003'.decode('hex')

selected_key = eap_hdd_key_blob_key1
computed_signature = hmac_sha256(selected_key[0x10:0x20], eap_hdd_key_blob_enc)
if computed_signature != eap_hdd_key_blob_sig:
    selected_key = eap_hdd_key_blob_key2
    computed_signature = hmac_sha256(selected_key[0x10:0x20], eap_hdd_key_blob_enc)
    if computed_signature != eap_hdd_key_blob_sig:
        print('error: invalid signature')
        sys.exit()
eap_hdd_key_blob = aes_decrypt_cbc(selected_key[0x00:0x10], eap_hdd_key_blob_iv, eap_hdd_key_blob_enc)
if not eap_hdd_key_blob.startswith('SCE_EAP_HDD__KEY'):
    print('error: invalid magic')
    sys.exit()

eap_hdd_key_blob = 'SCE_EAP_HDD__KEY' + \
    'BB6CD66DDC671FAC3664F7BF5049BAA8C4687904BC31CF4F2F4E9F89FA458793811745E7C7E80D460FAF2326550BD7E4D2A0A0D9729DE5D2117D70676F1D55748DC17CDF29C86A855F2AE9A1AD3E915F0000000000000000000000000000000000000000000000000000000000000000'.decode('hex')

if use_new_blob:
    eap_hdd_unwrapped_key = aes_decrypt_cbc(eap_hdd_key_blob[0x60:0x70], '\0' * 0x10, eap_hdd_wrapped_key[:0x40])
else:
    eap_hdd_unwrapped_key = aes_decrypt_cbc(eap_hdd_key_blob[0x50:0x60], '\0' * 0x10, eap_hdd_wrapped_key[:0x40])
#print('eap_hdd_unwrapped_key', eap_hdd_unwrapped_key.encode('hex').upper())

eap_hdd_key_offset = 0x10 if (smi_version == 0xFFFFFFFF or smi_version < 0x4000000) else 0x20
eap_hdd_unwrapped_key_dec = aes_decrypt_cbc(eap_hdd_key_blob[eap_hdd_key_offset:eap_hdd_key_offset + 0x10], '\0' * 0x10, eap_hdd_unwrapped_key)
if eap_hdd_unwrapped_key_dec[0x10:0x20] != '\0' * 0x10:
    eap_hdd_unwrapped_key_dec = aes_decrypt_cbc(eap_hdd_key_blob[eap_hdd_key_offset:eap_hdd_key_offset + 0x10], '\0' * 0x10, eap_hdd_wrapped_key[:0x10])

if use_new_blob:
    eap_partition_key = hmac_sha256(eap_hdd_unwrapped_key_dec[:0x10], eap_hdd_key_blob[0x40:0x50])
else:
    eap_partition_key = hmac_sha256(eap_hdd_unwrapped_key_dec[:0x10], eap_hdd_key_blob[0x30:0x40])

tweak_key = eap_partition_key[0x00:0x10]
data_key = eap_partition_key[0x10:0x20]

print('XTS data key:', data_key.encode('hex').upper())
print('XTS tweak key:', tweak_key.encode('hex').upper())

keys = open('keys.bin', 'wb')
keys.write(data_key)
keys.write(tweak_key)
As previously noted, in PS4 6.50 Firmware Sony introduced a new EAP HDD kernel... and this comes following a Guide to Obtain Your PS4 SFlash via PS4 Root FTP Server, a Decrypted EAP Partition Key Script (SAMU will decrypt the key), some PS4 EAP Kernel Dumps, a PS4 Registry Editor to examine the resulting system.eap file and a PS4 EAP Key Dumping and Decrypting Guide video tutorial.

Then came a PS4 HDD Reading Config File for Cryptmount and details on how to automatically dump the PS4 EAP Key to /etc/cryptsetp/eap_hdd_key.bin via PSXITArch Linux v2 without using OrbisMAN, SFlash0Unpack and PS4 SFlash0 Tools to unpack SFlash0 files in PS4 Flash dumps alongside a Python version, a Guide for Mounting a PS4 HDD in Linux on PC and a PS4-EAP-KEY-DUMPER-672.bin payload that dumps the PS4 EAP Key to /mnt/usb0/eap_key.bin for use with Jailbroken PS4 6.72 consoles.

Finally, below is a brief summary by @CelesteBlue via Twitter of what's now possible with the hdd_script.py from the Tweets below to quote:
  • That means from now anyone can read his PS4 HDD/SSD data after having used a hardware flasher to dump its flash memory.
  • Before that, only exploited PS4 consoles could, by dumping running kernel memory or with kernel execution.
Summary:

As of now, to be able to access your PS4 HDD/SSD content you can do:
  • for PS4s on FWs <= 6.72: dump by software your PS4 eap_hdd_key using kernel exploit.
  • for PS4s on any FW: dump by hardware your PS4 sflash0 then run the script to convert to eap_hdd_key.
Spoiler: Related Tweets

Decided to create a repo that specializes in decryption of retail ps4 eap hdd partitions:
Credits to @rajeshca911 (Twitter) for supplying the ps4 pro dumps in order to test this.

Note that if your ps4 is a phat 1000 or 1100 model, IVOFFSET will work as 0.
How to mount EAP partitions on Windows:

Mounting PS4 HDD On Windows, Only Specific Partitions
Requirements:
  • .wslconfig (for this you also need wsl2 installed, wsl1 should work as well)
  • bzImage (this is ufs readonly! for ufs rw you need to compile your own bzImage)
Both .wslconfig are place on C:\Users\(your_username)\ (in my case it's zecoxao)

cmtab
eap key partitions (i've chosen eap_vsh, update, user)
folders (according to cmtab)
and of course, your keys

in the case of user partition the number of the partition will be 27 so you do this
subtract 27 with 1
this will give 26
then you left shift 32
this will give 111669149696

Modify .wslconfig and cmtab accordingly! (path to bzImage, directory where to mount eap partitions, keys.bin location, ivoffset, etc)

HDD_Script.py to Retrieve Data from Any PS4 Console via SFlash Dump!.jpg
 

Comments

If I understood correctly, this is big. We can dump game installed on newer firmware and backport them to play on 6.72. Finger crossed. Let's hope for the best.
 
@KCAH you cant backport games from higher firmware without the keys so if you have a game on 7.00 there is no way to backport it to 6.72 without the actual key and the key being used is different then the game key

To backport games the game itself needs to be decrypted for fpkg to work so higher firmware games wont be decrypted only drm protected by the key until the keys are found to resign the boot files its not exactly something that will work without another process
 
Hi,

I know this is probably something been asked a fair amount on here and I've done some research and understand to some extent what I need to do. Basically my internal Toshiba 1TB HDD is stuck on Option 7 in Safe Mode and I can't boot into it to retrieve my data which is not backed up on PS+. I understand I need to mount it in Linux with an EAP key, and to get that key I can either flash the PS4 (I take it that means physically take the NOR chip off the motherboard and flash it that way?) or jailbreak my PS4, and I have to run the script to get the key in Linux.

I was hoping I could speak to @Leeful as I noticed he commented on someone else's one that got resolved. Any help greatly appreciated and I'm willing to learn and get the right things to do the job if it is possible. It was working and then when resuming from rest mode it just stopped being able to boot into the system so I don't think it's majorly damaged.

Thanks!
 
Hello,
I hope someone has experience mounting the PS4's Internal hard drive on a PS4 running linux since I cannot seem to manage to do it.

I have a PS4 Slim Belize model (not sure what the exact model number is but it is a CUH-1100) running on 9.00 so it is jailbreakable and I can run Linux on it.

I have tried multiple linux loaders and none of them seem to work any different. The PS4's hard drive and all of it's partitions are visible from inside linux so I don't believe compatibility with reading the hard drive is the issue. The PS4 also seems to boot just fine so I am also confident that the hard drive is not corrupted in any way.

I use this eap dumper (HDD_Script v2) to get the keys from the sflash0 which I dump using GoldHen's built in FTP server. The sflash0 is exactly 33554432 bytes (32MB) so I also don't think it is being dumped incorrectly.

Once I run the script, it produces a file called keys.bin which should be the eap key. The script has no errors whatsoever so I don't think there is anything wrong with it. However, from this thread I also read that the key needs to be reversed so I also reversed it using HxD. I triple checked that the key is reversed properly.

However, if I try to use this key, either reversed or not, to decrypt sda27 (the user partition), I am met with this error:
Code:
[cryptmount-mount]: /ps4hdd: wrong fs type, bad option, bad superblock on /dev/mapper/user, missing codepage or helper program, or other error.
I use the cmtab from the psdevwiki, both the version with the offset and without. I placed the keys exactly as they are referenced in the cmtab. The error is the same.

What am I doing wrong? Maybe it is something as simple as a missing filesystem driver on the distro I'm using (PopOS)? Maybe the offsets from the eap key have changed since the eap dumper was made?

I can provide my sflash0 as well as the keys dumped if needed.

Thanks for any help.
 
Status
Not open for further replies.
Back
Top