ScePfsMgr

From Vita Development Wiki
Jump to navigation Jump to search

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

pfs can be mounted if it is an exfat filesystem, but if the mount point is other than Internal (0x100) / Game_Card (0x201) / Removable (0x202), calling sceIoRead etc. will result in an error of 0x80010016.

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