ScePfsMgr
Module
Version | World | Privilege |
---|---|---|
0.990.030-3.740.011 | Non-secure | Kernel |
Libraries
Known NIDs
Version | Name | World | Visibility | NID |
---|---|---|---|---|
0.990.030-3.740.011 | ScePfsMgrForKernel | Non-secure | Kernel | 0xA067B56F |
0.931.010-1.69 | ScePfsFacadeForKernel | Non-secure | Kernel | not present |
1.800.071-3.740.011 | ScePfsFacadeForKernel | Non-secure | Kernel | 0xC26DC7BD |
PFS implementation
files.db
files.db is a file that stores as a binary search tree all the directories and files names included in the PFS image. If a directory or file in the tree does not conform to strict weak ordering, it will be recognized by ScePfsMgr as a non-existent entry.
Sw Version | Version | Description | Example titleid |
---|---|---|---|
1.03 | 3 | - | NPXS10007 |
1.50 | 4 | Terminal index (~0) added to end of block. Added filedb seed. | PCSI00009 |
? | 5 | root icv hash changed to entire block | PCSG90096 |
If the icv is unicv.db, there is a strictly determined version connection.
If a version of unicv.db that does not match these is used, ScePfsMgr returns error code 0x80140E15. The error code ultimately translates to 0x8001002F.
files.db version | unicv.db version |
---|---|
0 | 0 |
1 | 1 |
2 | 1 |
3 | 1 |
4 | 1 |
5 | 2 |
icv.db
icv.db is the folder that stores ${ENTRY_ID}.icv files. ${ENTRY_ID}.icv files store page hash info included in read/write PFS images.
unicv (SCEIFTBL)
unicv.db stores page hash info included in read-only PFS images.
Sw Version | Version | Description | Example titleid |
---|---|---|---|
1.03 | 1 | - | PCSI00009 |
2.00 | 2 | header size to 0x48 bytes from 0x20 bytes. | PCSG90096 |
PFS image type
Image Type | RSA verify | Description |
---|---|---|
0 | no | Redirect |
1 | yes | Read Only GD/SD |
2 | no | Read Write GD/SD |
3 | no | Additional content (addcont0:) |
4 | yes | unknown |
0xFFFF | - | Invalid image |
Pmi flags
value | Description |
---|---|
1 | no klicensee |
2 | gd secret (?) |
4 | pmi is active |
8 | System Is not DevelopmentMode |
0x10 | force unmount |
0x20 | PFS mode is 3 |
0x40 | PFS mode is 10. And something. |
0x1000 | - |
0x2000 | - |
Pfs mount mode
Mode | Vfs | Image | IsGameData | Feature | Example path | Description |
---|---|---|---|---|---|---|
0 | Redirect Pseudo Drive | 0 | no | redirect-rw | N/A | - |
1 | - | 0xFFFF | no | - | N/A | 0x80142109 |
2 | Gamedata/Savedata Pseudo Drive | 1 | yes | gd-gd_secret-ro-unicv-no_write-no_sync | ux0:/temp/fakepkg/expand/PCSG90096 ux0:/app/PCSI00009 ux0:/patch/PCSI00009 |
- |
3 | Gamedata/Savedata Pseudo Drive | 1 | yes | gd-gd_secret-ro-unicv-no_write | N/A | - |
4 | AC Pseudo Drive | 3 | no | acid-sd_secret-rw-icv | N/A | used by appmgr addcont mount for non gro0:. |
5 | Gamedata/Savedata Pseudo Drive | 2 | no | sd-sd_secret-rw-icv | ux0:/user/00/savedata/PCSG90096 ux0:appmeta/new ux0:/appmeta/PCSI00009 ux0:/user/00/savedata/PCSI00009 |
- |
6 | Gamedata/Savedata Pseudo Drive | 2 | no | sd-sd_secret-rw-icv | ur0:/user/00/trophy/data/sce_trop ur0:/user/00/trophy/data/NPWR02174_00 |
- |
7 | Gamedata/Savedata Pseudo Drive | 2 | no | sd-sd_secret-rw-icv | N/A | - |
8 | AC Pseudo Drive | 3 | no | acid-sd_secret-rw-icv | N/A | - |
9 | Gamedata/Savedata Pseudo Drive | 2 | no | sd-sd_secret-rw-icv | N/A | - |
0xA | Gamedata/Savedata Pseudo Drive | 1 | yes | gd-gd_secret-rw-unicv | N/A | - |
0xB | - | 4 | yes | gd-gd_secret-rw-unicv | N/A | 0x80142109 |
0xC | AC Pseudo Drive | 3 | no | sd-sd_secret-ro-icv-no_sync | N/A | used by appmgr addcont mount for gro0:. |
0xD | - | 0xFFFF | no | - | N/A | 0x80142109 |
0xE | - | 0xFFFF | no | - | N/A | 0x80142109 |
0xF | - | 0xFFFF | no | - | N/A | 0x80142109 |
0x10 | - | 0xFFFF | no | - | N/A | 0x80142109 |
0x11 | - | 0xFFFF | no | - | N/A | 0x80142109 |
0x12 | - | 0xFFFF | no | - | N/A | 0x80142109 |
0x13 | - | 0xFFFF | no | - | N/A | 0x80142109 |
0x14 | Redirect Pseudo Drive | 0 | no | redirect-ro-no_sync | vs0:/app/NPXS10027 vs0:/sys/external vs0:/data/external ux0:/data/pkg |
- |
0x15 | Redirect Pseudo Drive | 0 | no | redirect-rw | ur0:/user/00/savedata/NPXS10027 ux0:/cache/PCSI00009 ux0:/pspemu |
- |
0x16 | Redirect Pseudo Drive | 0 | no | redirect-rw | ux0:/picture ux0:/music ur0:/user/00/psnfriend |
- |
0x17 | Redirect Pseudo Drive | 0 | no | redirect-rw | N/A | - |
0x18 | - | 0xFFFF | no | - | N/A | 0x80142109 |
0x19 | - | 0xFFFF | no | - | N/A | 0x80142109 |
0x1A | - | 0xFFFF | no | - | N/A | 0x80142109 |
0x1B | - | 0xFFFF | no | - | N/A | 0x80142109 |
0x1C | - | 0xFFFF | no | - | N/A | 0x80142109 |
0x1D | - | 0xFFFF | no | - | N/A | 0x80142109 |
0x1E | - | 0xFFFF | no | - | N/A | 0x80142109 |
0x1F | - | 0xFFFF | no | - | N/A | 0x80142109 |
0x20 | - | 4 | yes | ac-gd_secret-ro-unicv-no_sync | N/A | unknown |
0x21 | - | 4 | yes | ac-gd_secret-ro-unicv-no_sync | N/A | unknown |
Types
typedef char[0x10] ScePfsRndDriveId; typedef struct pmi_blc_subctx { pmi_blc_subctx *subctx0; pmi_blc_subctx *subctx4; SceUInt64 auth_ids[16]; vfs_block_dev_info block_dev; SceUInt32 auth_ids_num; } pmi_blc_subctx; union pfs_pmi_buffer_list_ctx_u0 { buffer_list *blist; int some_flags; }; typedef struct pfs_pmi_buffer_list_ctx { // size is 0x228-bytes pfs_pmi_buffer_list_ctx_u0 unk_0; uint32_t unk_4; SceUID ScePfsPmi_mutex_id; // 0x08 char original_path[0x40]; // 0xC char rnd_drive_id1[0x22]; // 0x4C - "/%s" char rnd_drive_id2[0x24]; // 0x6E - "%s0:" - used for pfs_pmi_buffer_list_ctx lookup on mount uint16_t mode_index; // 0x92 uint16_t crypto_engine_flag; // 0x94 = 0 char klicensee[0x10]; // 0x96 uint16_t key_id; uint32_t files_salt; uint32_t unk_AC; // = 0 SceUID ScePfsFilesDb_mutex_id; // 0xB0 char unk_data1[0xBC]; // 0xB4 pmi_blc_subctx subctx; // further fields are unknown } pfs_pmi_buffer_list_ctx; typedef struct buffer_list { SceUID mutex_id; uint32_t unk_4; uint32_t unk_8; uint32_t unk_C; uint32_t unk_10; void* blc; // 0x14 - one of versions is pfs_pmi_buffer_list_ctx } buffer_list; typedef struct CryptEngineData { // size is 0x60 uint32_t unk_0; uint32_t unk_4; uint32_t unk_8; uint16_t unk_C; uint16_t flag; // 0xE - flag that selects decryption type ? uint16_t key_id; // 0x10 uint16_t seed1_base; // iv seed uint32_t unk_14; uint32_t unk_18; uint32_t unk_1C; uint32_t unk_20; uint32_t unk_24; uint32_t size1; char key[0x10]; // 0x2C char iv_xor_key[0x10]; // 0x3C char hmac_key[0x14]; // 0x4C } CryptEngineData; typedef struct CryptEngineSubctx { // size is 0x58 uint32_t unk_0; uint32_t unk_4; uint32_t opt_code; // 0x8 - if 3 then decrypt, if 4 then encrypt, if 2 then encrypt CryptEngineData* data; // 0xC uint32_t unk_10; uint32_t source; // 0x14 uint32_t unk_18; uint32_t unk_1C; uint32_t unk_20; uint32_t unk_24; uint32_t size2; // 0x28 uint32_t nDigests; // 0x2C - also digest table index uint32_t unk_30; uint32_t seed0_base; // 0x34 uint32_t dest_offset; // 0x38 uint32_t size0; // 0x3C uint32_t size1; uint32_t unk_44; uint32_t size3; // 0x48 char* hmac_sha1_digest; // digest to verify (possibly table) void* buffer0; // 0x50 void* buffer1; // 0x54 } CryptEngineSubctx; typedef struct CryptEngineWorkCtx { // size is 0x18 void* unk_0; // pointer to data 0x140 + 0x18 ? void* unk_4; // pointer to data 0x140 + 0x18 ? CryptEngineSubctx* subctx; // 0x8 uint32_t error; // set to 0 or error code after executing crypto task SceUID threadId; // Set with sceKernelGetThreadIdForDriver. Used with sceKernelSignalCondToForDriver. uint32_t unk_14; } CryptEngineWorkCtx; typedef _ScePfsModeSetting { // size is 0x28-bytes SceUInt32 unk_0x00; SceUInt32 is_icv; // 0: unicv (RO) | 1: icv (RW) | 2: redirect SceUInt32 unk_0x08; int files_db_open_flag; int icv_open_flag; int create_mode; SceUInt32 unk_0x18; SceBool no_write; SceBool no_sync; SceBool gd_secret; } ScePfsModeSetting;
Data segment layout
Address | Size | Description |
---|---|---|
0x0000 | 0x20 | vfs_add_data PFS_REDIRECT_INF node (Redirect Pseudo Drive. )
|
0x0020 | 0x20 | vfs_add_data PFS_GDSD_INF node (Gamedata/Savedata Pseudo Drive. )
|
0x0040 | 0x20 | vfs_add_data PFS_AC_INF node (AC Pseudo Drive. )
|
0x0060 | 0x20 | unknown |
0x0080 | 0x4 | mutex SceUID ScePfsFiBufferList
|
0x0084 | 0x4 | memblock SceUID ScePfsFiBufferList
|
0x0088 | 0x4 | char* ScePfsFiBufferList
|
0x008C | 0x4 | some offset or size |
0x0090 | 0x4 | some offset or size |
0x0094 | 0x4 | void* |
0x0098 | 0x4 | mutex SceUID ScePfsVdBufferList
|
0x009C | 0x4 | memblock SceUID ScePfsVdBufferList
|
0x00A0 | 0x4 | char* ScePfsVdBufferList
|
0x00A4 | 0x4 | some offset or size |
0x00A8 | 0x4 | some offset or size |
0x00AC | 0x4 | void* |
0x00B0 | 0x4 | mutex SceUID ScePfsLruPoolBufferList
|
0x00B4 | 0x4 | memblock SceUID ScePfsLruPoolBufferList
|
0x00B8 | 0x4 | char* ScePfsLruPoolBufferList
|
0x00BC | 0x4 | some offset or size |
0x00C0 | 0x4 | some offset or size |
0x00C4 | 0x4 | void* |
0x00C8 | 0x4 | mutex SceUID ScePfsLruTblHdrBufferList
|
0x00CC | 0x4 | memblock SceUID ScePfsLruTblHdrBufferList
|
0x00D0 | 0x4 | char* ScePfsLruTblHdrBufferList
|
0x00D4 | 0x4 | some offset or size |
0x00D8 | 0x4 | some offset or size |
0x00DC | 0x4 | void* |
0x00E0 | 0x20 | unknown |
0x0100 | 0x10 | CMAC buffer used in ScePfsCryptEngineThread subroutines |
0x0110 | 0x4 | mutex SceUID ScePfsThePmi
|
0x0114 | 0x4 | unknown |
0x0118 | 0x4 | pfs_pmi_buffer_list_ctx* root |
0x011C | 0x4 | unknown |
0x0120 | 0x4 | buffer_list* with mutex SceUID ScePfsPmiBufferList
|
0x0124 | 0x4 | memblock SceUID ScePfsPmiBufferList
|
0x0128 | 0x4 | char* ScePfsPmiBufferList
|
0x012C | 0x4 | some offset or size |
0x0130 | 0x4 | some offset or size |
0x0134 | 0x4 | void* |
0x0138 | 0x4 | unknown |
0x013C | 0x4 | unknown |
0x0140 | 0x4 | 0 |
0x0144 | 0x4 | thread SceUID ScePfsCryptEngineThread
|
0x0148 | 0x4 | mutex SceUID ScePfsCryptEngineTodoMtx
|
0x014C | 0x4 | cond SceUID ScePfsCryptEngineTodoCnd
|
0x0150 | 0x4 | mutex SceUID ScePfsCryptEngineDoneMtx
|
0x0154 | 0x4 | cond SceUID ScePfsCryptEngineDoneCnd
|
0x0158 | 0x4 | pointer to 0x158 |
0x015C | 0x4 | pointer to 0x158 |
0x0160 | 0x4 | pointer to 0x160 |
0x0164 | 0x4 | pointer to 0x160 |
0x0168 | 0x9D8 | unknown |
0x0B40 | 0xC0 | data chunk of size 0xC0 |
0x0C00 | 180 | unknown |
0x0D80 | 0x4 | mutex SceUID ScePfsCryptBufMutexVC
|
0x0D84 | 0x4 | mutex SceUID ScePfsCryptBufMutexRM
|
0x0D88 | 0x4 | mutex SceUID ScePfsCryptBufMutexEMMC
|
0x0D8C | 0x4 | memblock SceUID ScePfsCryptBufVC - size 0x40000
|
0x0D90 | 0x4 | memblock SceUID ScePfsCryptBufVCForShared
|
0x0D94 | 0x4 | memblock base of ScePfsCryptBufVC
|
0x0D98 | 0x4 | memblock base of ScePfsCryptBufVCForShared
|
0x0D9C | 0x4 | 0x000000FF |
0x0DA0 | 0x4 | memblock SceUID ScePfsCryptBufRM - size 0x40000
|
0x0DA4 | 0x4 | memblock SceUID ScePfsCryptBufRMForShared
|
0x0DA8 | 0x4 | memblock base of ScePfsCryptBufRM
|
0x0DAC | 0x4 | memblock base of ScePfsCryptBufRMForShared
|
0x0DB0 | 0x4 | 0x000000FF |
0x0DB4 | 0x4 | memblock SceUID ScePfsCryptBufEMM - size 0x40000
|
0x0DB8 | 0x4 | memblock SceUID ScePfsCryptBufEMMCForShared
|
0x0DBC | 0x4 | memblock base of ScePfsCryptBufEMM
|
0x0DC0 | 0x4 | memblock base of ScePfsCryptBufEMMCForShared
|
0x0DC4 | 0x4 | 0x000000FF |
0x0DC8 | 0x4 | cond SceUID ScePfsCryptBufCondVarVC
|
0x0DCC | 0x4 | cond SceUID ScePfsCryptBufCondVarRM
|
0x0DD0 | 0x4 | cond SceUID ScePfsCryptBufCondVarEMMC
|
Decryption process
Crypto engine
ScePfsMgr
heavily uses crypto API from SceSblSsMgrForDriver.
There is a separate thread in ScePfsMgr
that is called ScePfsCryptEngineThread
.
Almost all calls to the crypto API are done from this single thread.
ScePfsMgr
uses a crypto task dispatch mechanism based on mutexes and conditions.
It uses a CryptEngineWorkCtx
structure for dispatching the task.
Pointer to that structure is written at offset 0x158 of data section (this needs confirmation).
For dispatching the task ScePfsMgr
uses subroutine located at offset 0xBD88.
When task is dispatched ScePfsCryptEngineTodoMtx
mutex is locked, ScePfsCryptEngineTodoCnd
condition is signaled, ScePfsCryptEngineTodoMtx
is unlocked.
For waiting till task is completed ScePfsMgr
uses subroutine located at offset 0xBEA0.
Then ScePfsCryptEngineDoneMtx
mutex is locked, wait happens on ScePfsCryptEngineDoneCnd
condition, ScePfsCryptEngineDoneMtx
mutex is unlocked.
Meanwhile ScePfsCryptEngineThread
runs.
It locks ScePfsCryptEngineTodoMtx
mutex, waits for ScePfsCryptEngineTodoCnd
condition, unlocks ScePfsCryptEngineTodoMtx
mutex.
When task is finished ScePfsCryptEngineThread
locks ScePfsCryptEngineDoneCnd
mutex, signals ScePfsCryptEngineDoneCnd
to specific thread, unlocks ScePfsCryptEngineDoneCnd
mutex.
Thread id for signaling ScePfsCryptEngineDoneCnd
is stored in CryptEngineWorkCtx
.
VFS node functions
Dispatching mechanism is used only by VFS node functions.
Nodes that are used:
- PFS_GDSD_INF
- PFS_AC_INF
Node functions that are used:
- 5 - sceIoReadForDriver
- 6 - sceIoWriteForDriver
- 16 - sceIoChstatForDriver
- 19 - sceIoPreadForDriver
- 20 - sceIoPwriteForDriver
- 26 - sceIoChstatByFdForDriver
Notes
Debug PFS is prohibited on CEX: PFS mounting fails with error code 0x80010016.
ScePfsMgrForKernel
scePfsMountForKernel
Version | NID |
---|---|
0.990.030-3.740.011 | 0xA772209C |
int scePfsMountForKernel(const char *path, const ScePfsRndDriveId *rnd_drive_id, SceUInt64 program_authority_id, void *klicensee, SceUInt16 mode_index);
scePfsMount2ForKernel
Version | NID |
---|---|
0.990.030-3.740.011 | 0x2D48AEA2 |
int scePfsMount2ForKernel(const char *path, const ScePfsRndDriveId *rnd_drive_id, const void *klicensee, uint16_t mode_index);
scePfsUnmountForKernel
Version | NID |
---|---|
0.990.030-3.740.011 | 0x680BC384 |
int scePfsUnmountForKernel(const ScePfsRndDriveId *rnd_drive_id);
scePfsApproveForKernel
Version | NID |
---|---|
0.990.030-3.740.011 | 0xD8D0FEE5 |
- find pfs_pmi_buffer_list_ctx* by mount_point
- check program authority ID
- set unk_94 flag
int scePfsApproveForKernel(const ScePfsRndDriveId *rnd_drive_id, SceUInt64 program_authority_id);
scePfsDisapproveForKernel
Version | NID |
---|---|
0.990.030-3.740.011 | 0x2D67D8CA |
int scePfsDisapproveForKernel(ScePfsRndDriveId *rnd_drive_id, SceUInt64 program_authority_id);
scePfsAcidDirMountForKernel
Version | NID |
---|---|
0.990.030-3.740.011 | 0x4A4A8243 |
- open mountpoint/dlc_folder directory
- execute ioctl command 0x4402 with klicensee input
- close mountpoint/dlc_folder directory
int scePfsAcidDirMountForKernel(const char *mountpoint, const char *dlc_folder, const void *klicensee);
scePfsAcidDirUnmountForKernel
Version | NID |
---|---|
0.990.030-3.740.011 | 0x00C8AF80 |
- open mountpoint/dlc_folder directory
- execute ioctl command 0x4404
- close mountpoint/dlc_folder directory
int scePfsAcidDirUnmountForKernel(const char *mountpoint, const char *dlc_folder);
scePfsAcidDirApproveForKernel
Version | NID |
---|---|
0.990.030-3.740.011 | 0x8CDA249A |
- open mountpoint/dlc_folder directory
- execute ioctl command 0x4403
- close mountpoint/dlc_folder directory
int scePfsAcidDirApproveForKernel(const char *mountpoint, const char *dlc_folder);
scePfsAcidDirSetForKernel
Version | NID |
---|---|
0.990.030-3.740.011 | 0xB0CC0A1A |
ScePfsMgrForKernel_27FB7618
Version | NID |
---|---|
0.996.090-3.740.011 | 0x27FB7618 |
Executes 0x4410 command on <device_name>0:. Gets 8 bytes of result.
int ScePfsMgrForKernel_27FB7618(const char *device_name, int *ioctl0_res, int *ioctl1_res);
ScePfsMgrForKernel_806D2EA1
Version | NID |
---|---|
0.996.090-3.740.011 | 0x806D2EA1 |
ScePfsMgrForKernel_4C148288
Version | NID |
---|---|
0.931.010-1.06 | not present |
1.500.151-3.740.011 | 0x4C148288 |
ScePfsMgrForKernel_7E4B76E6
Version | NID |
---|---|
0.931.010-1.69 | not present |
1.800.071-3.740.011 | 0x7E4B76E6 |
ScePfsMgrForKernel_E9D672AB
Version | NID |
---|---|
0.931.010-2.060.011 | not present |
2.100.081-3.740.011 | 0xE9D672AB |
ScePfsFacadeForKernel
t_scePfsFacadeReadForDriver
Version | NID |
---|---|
0.931.010-1.69 | not present |
1.800.071-3.740.011 | 0xBD5B21F6 |
This is a thread callback used by SceIofilemgr
This function is not implemented and throws 0x8014231C
error
int t_scePfsFacadeReadForDriver(sceIoReadForDriver_args *args);
t_scePfsFacadeWriteForDriver
Version | NID |
---|---|
0.931.010-1.69 | not present |
1.800.071-3.740.011 | 0xCB622FFE |
This is a thread callback used by SceIofilemgr
int t_scePfsFacadeWriteForDriver(sceIoWriteForDriver_args *args);
t_scePfsFacadePreadForDriver
Version | NID |
---|---|
0.931.010-1.69 | not present |
1.800.071-3.740.011 | 0x4238D2D2 |
This is a thread callback used by SceIofilemgr
int t_scePfsFacadePreadForDriver(sceIoPreadForDriver_args *args);
t_scePfsFacadePwriteForDriver
Version | NID |
---|---|
0.931.010-1.69 | not present |
1.800.071-3.740.011 | 0x58E643C5 |
This is a thread callback used by SceIofilemgr
int t_scePfsFacadePwriteForDriver(sceIoPwriteForDriver_args *args);
ScePfsFacadeForKernel_04352D52
Version | NID |
---|---|
0.931.010-1.69 | not present |
1.800.071-3.740.011 | 0x04352D52 |
ScePfsFacadeForKernel_7F9F4E49
Version | NID |
---|---|
0.931.010-1.69 | not present |
1.800.071-3.740.011 | 0x7F9F4E49 |