Difference between revisions of "SceNpDrm"
CelesteBlue (talk | contribs) (→RIF) |
|||
(38 intermediate revisions by 2 users not shown) | |||
Line 39: | Line 39: | ||
| 0x0008 || 0x8 || unknown | | 0x0008 || 0x8 || unknown | ||
|- | |- | ||
− | | 0x0010 || 0xC0 || | + | | 0x0010 || 0xC0 || Static keys decrypted with [[SceSblAuthMgr#sceSblAuthMgrGetEKc|sceSblAuthMgrGetEKcForDriver]] key 0. |
First 0x10 bytes are reencrypted with [[SceSblSsMgr#sceSblSsMgrGetConsoleIdForDriver|ConsoleId]]. | First 0x10 bytes are reencrypted with [[SceSblSsMgr#sceSblSsMgrGetConsoleIdForDriver|ConsoleId]]. | ||
Line 61: | Line 61: | ||
| 0x2240 || 0x10 || [[SceSblSsMgr#sceKernelGetOpenPsIdForDriver|OpenPsId]] | | 0x2240 || 0x10 || [[SceSblSsMgr#sceKernelGetOpenPsIdForDriver|OpenPsId]] | ||
− | This data is compared against OpenPsId | + | This data is compared against OpenPsId in act.dat and under some conditions in .rif at offset 0xC0. |
− | |||
− | |||
|- | |- | ||
| 0x2250 || 0x4 || act data Is Valid flag | | 0x2250 || 0x4 || act data Is Valid flag | ||
Line 75: | Line 73: | ||
| 0x2264 || 0x4 || /CONFIG/NP/debug_upgradable registry key | | 0x2264 || 0x4 || /CONFIG/NP/debug_upgradable registry key | ||
|- | |- | ||
− | | 0x2268 || 0x20 || | + | | 0x2268 || 0x20 || sha256 digest of [[SceSblGcAuthMgr#get_act_data|get_act_data]] |
|- | |- | ||
− | | 0x2288 || 0x20 || hmac | + | | 0x2288 || 0x20 || hmac-sha256 digest of [[SceSblGcAuthMgr#get_act_data|get_act_data]] |
|- | |- | ||
| 0x22A8 || 0x8 || unknown | | 0x22A8 || 0x8 || unknown | ||
Line 83: | Line 81: | ||
| 0x22B0 || 0x8 || account_id | | 0x22B0 || 0x8 || account_id | ||
|- | |- | ||
− | | 0x22B8 || 0x8 || | + | | 0x22B8 || 0x8 || PSM activation start date |
|- | |- | ||
− | | 0x22C0 || 0x8 || | + | | 0x22C0 || 0x8 || PSM activation end date |
|- | |- | ||
| 0x22C8 || 0x20 || some key decrypted with 0x2288 | | 0x22C8 || 0x20 || some key decrypted with 0x2288 | ||
− | |||
|} | |} | ||
== Obtaining klicensee == | == Obtaining klicensee == | ||
− | 1. Get the | + | Initialization steps (common): |
+ | |||
+ | 1. Get the hardcoded encrypted EKc (0xC0 bytes). (on FW 3.60, 0xC0 bytes from SceNpDrm code segment at offset 0x111D0) | ||
+ | |||
+ | 2. Decrypt the hardcoded encrypted EKc using [[SceSblAuthMgr#sceSblAuthMgrGetEKcForDriver|sceSblAuthMgrGetEKcForDriver]] with key revision 0 (?or 1 or 2?). | ||
− | + | Initialization steps (per-console): | |
− | 3. Get 0x10 bytes | + | 3. Get ConsoleId (0x10 bytes) using [[SceSblSsMgr#sceSblSsMgrGetConsoleIdForDriver|sceSblSsMgrGetConsoleIdForDriver]]. |
− | 4. | + | 4. Decrypt using AES128ECB first 0x10 bytes of EKc with ConsoleId as key. |
− | 5. Read 0x800 bytes of Primary Key Table from act.dat | + | 5. Read 0x800 bytes of the encrypted Primary Key Table from act.dat file. |
6. Decrypt 0x800 bytes of Primary Key Table with reencrypted static key using AES (need to figure out which AES exactly). | 6. Decrypt 0x800 bytes of Primary Key Table with reencrypted static key using AES (need to figure out which AES exactly). | ||
− | 7. Get | + | Initialization steps (per-content): |
+ | |||
+ | 7. Get 0x98 / 0x200 bytes of RIF data from the content's .rif file and select one of the 5 scenarios for decrypting RIF Key into klicensee based on License flags (need to figure out). In most cases only the first 0x70 bytes are needed for klicensee derivation because at 0x70 is the ECDSA signature which is not used for derivation, and after 0x98 is data only used for some PS Vita contents (maybe only PS Vita cartridges require a 0x200-byte RIF). | ||
=== Scenario 1 - maybe DRM Free === | === Scenario 1 - maybe DRM Free === | ||
Line 115: | Line 118: | ||
Take first 0x70 bytes of RIF data. | Take first 0x70 bytes of RIF data. | ||
− | Use [[SceSblAuthMgr# | + | Use [[SceSblAuthMgr#sceSblAuthMgrDecBindDataForDriver]] to decrypt RIF key 2 and obtain klicensee. |
=== Scenario 2 === | === Scenario 2 === | ||
Line 125: | Line 128: | ||
Take first 0x70 bytes of RIF data. | Take first 0x70 bytes of RIF data. | ||
− | Use [[SceSblAuthMgr# | + | Use [[SceSblAuthMgr#sceSblAuthMgrDecBindDataForDriver]] to decrypt RIF key 2 and obtain klicensee. |
=== Scenario 3 - Game Cartridge === | === Scenario 3 - Game Cartridge === | ||
Line 135: | Line 138: | ||
Take first 0x70 bytes of RIF data. | Take first 0x70 bytes of RIF data. | ||
− | Use [[SceSblAuthMgr# | + | Use [[SceSblAuthMgr#sceSblAuthMgrDecBindDataForDriver]] to decrypt RIF key 2 and obtain klicensee. |
=== Scenario 4 - Game Cartridge === | === Scenario 4 - Game Cartridge === | ||
Line 147: | Line 150: | ||
Erase RIF Key 1 from RIF data. | Erase RIF Key 1 from RIF data. | ||
− | Use [[SceSblAuthMgr# | + | Use [[SceSblAuthMgr#sceSblAuthMgrDecBindDataForDriver]] to decrypt RIF key 1 and obtain klicensee. |
=== Scenario 5 === | === Scenario 5 === | ||
+ | |||
+ | Take RIF Key 1. | ||
Decrypt Primary Table Key index from RIF data with static key 2 using AES (need to figure out which AES exactly). | Decrypt Primary Table Key index from RIF data with static key 2 using AES (need to figure out which AES exactly). | ||
Line 197: | Line 202: | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
− | | 1.69 | + | | 1.69-3.60 || 0x4458812B |
− | |||
− | |||
|} | |} | ||
Line 212: | Line 215: | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
− | | 1.69 | + | | 1.69-3.60 || 0x507D06A6 |
− | |||
− | |||
|} | |} | ||
Line 255: | Line 256: | ||
<source lang="C"> | <source lang="C"> | ||
− | typedef struct rif_info //size is 0x70 | + | typedef struct rif_info { //size is 0x70 |
− | |||
char content_id[0x30]; | char content_id[0x30]; | ||
− | char version_number[ | + | char version_number[4]; |
− | char rif_lic_flags[ | + | char rif_lic_flags[4]; |
− | char | + | char drm_type0[4]; // DRM type related |
− | char | + | char drm_type1[4]; // DRM type related |
− | char account_id[ | + | char account_id[8]; |
− | char | + | char rif_data_0x98[8]; |
− | + | uint64_t lic_start_time; | |
− | + | uint64_t lic_exp_time; | |
− | char | + | char klicensee[0x10]; |
− | }rif_info | + | } rif_info; |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | // | + | typedef struct _sceNpDrmGetRifInfo_opt { //size is 0x28 |
+ | void* content_id; | ||
+ | void* account_id; | ||
+ | void* version_number; | ||
+ | void* rif_lic_flags; | ||
+ | void* lic_type0; // DRM type related | ||
+ | void* lic_type1; // DRM type related | ||
+ | void* lic_start_time; | ||
+ | void* lic_exp_time; | ||
+ | void* rif_data_0x98; | ||
+ | } _sceNpDrmGetRifInfo_opt; | ||
+ | // rif data is of size 0x200 | ||
int _sceNpDrmGetRifInfo(void* rif_data, int rif_size, int num, _sceNpDrmGetRifInfo_opt* opt); | int _sceNpDrmGetRifInfo(void* rif_data, int rif_size, int num, _sceNpDrmGetRifInfo_opt* opt); | ||
− | |||
</source> | </source> | ||
Line 307: | Line 304: | ||
<source lang="C"> | <source lang="C"> | ||
− | //opt is of size 0x10 | + | // opt is of size 0x10 |
int _sceNpDrmCheckActData(int unk0, int unk1, int unk2, void* opt); | int _sceNpDrmCheckActData(int unk0, int unk1, int unk2, void* opt); | ||
</source> | </source> | ||
Line 320: | Line 317: | ||
<source lang="C"> | <source lang="C"> | ||
− | //rif data is of size 0x200 | + | // rif data is of size 0x200 |
int _sceNpDrmPresetRifProvisionalFlag(void* rif_data); | int _sceNpDrmPresetRifProvisionalFlag(void* rif_data); | ||
</source> | </source> | ||
Line 335: | Line 332: | ||
<source lang="C"> | <source lang="C"> | ||
− | // | + | // content_id size is 0x30 |
− | int sceNpDrmGetRifInfoForDriver(void* | + | int sceNpDrmGetRifInfoForDriver(const void *license, SceSize license_size, int check_sign, char *content_id, SceUInt64 *pAccountId, int *pLicenseVersion, int *pLicenseFlags, int *flags, int *sku_flags, SceInt64 *lic_start_time, SceInt64 *lic_exp_time, SceUInt64 *flags2); |
</source> | </source> | ||
Line 358: | Line 355: | ||
<source lang="C"> | <source lang="C"> | ||
− | //name is of size 0x30 | + | // name is of size 0x30 |
− | int sceNpDrmGetFixedRifNameForDriver(char *name, | + | int sceNpDrmGetFixedRifNameForDriver(char *name, SceUInt64 aid); |
</source> | </source> | ||
Line 371: | Line 368: | ||
<source lang="C"> | <source lang="C"> | ||
− | //name is of size 0x30 | + | // name is of size 0x30 |
− | int sceNpDrmGetRifNameForDriver(char *name, | + | int sceNpDrmGetRifNameForDriver(char *name, SceUInt64 aid); |
</source> | </source> | ||
Line 384: | Line 381: | ||
<source lang="C"> | <source lang="C"> | ||
− | //name is of size 0x30 | + | // name is of size 0x30 |
− | // | + | // if not_use_content_id is zero, use license content id |
− | int sceNpDrmGetRifNameForInstallForDriver(char *name, void * | + | int sceNpDrmGetRifNameForInstallForDriver(char *name, const void *license, int not_use_content_id); |
</source> | </source> | ||
Line 396: | Line 393: | ||
| 3.60 || 0xC070FE89 | | 3.60 || 0xC070FE89 | ||
|} | |} | ||
+ | |||
+ | Updating license data. | ||
<source lang="C"> | <source lang="C"> | ||
− | + | int sceNpDrmPresetRifProvisionalFlagForDriver(void *license, int unk2); | |
− | int sceNpDrmPresetRifProvisionalFlagForDriver(void* | ||
</source> | </source> | ||
Line 410: | Line 408: | ||
|} | |} | ||
− | + | get </code>tm0:/npdrm/act.dat</code> info | |
<source lang="C"> | <source lang="C"> | ||
//size of act data is 0x1040 | //size of act data is 0x1040 | ||
− | + | int sceNpDrmCheckActDataForDriver(int *act_type, int *unk2, SceUInt64 *pAccountId, SceInt64 *act_start_time, SceInt64 *act_exp_time); | |
− | int sceNpDrmCheckActDataForDriver(int | ||
</source> | </source> | ||
Line 426: | Line 423: | ||
|} | |} | ||
− | + | Remove tm0:/npdrm/act.dat | |
− | <source lang="C">int sceNpDrmRemoveActDataForDriver( | + | <source lang="C"> |
+ | // pAccountId of deleted tm0:/npdrm/act.dat | ||
+ | int sceNpDrmRemoveActDataForDriver(SceUInt64 *pAccountId); | ||
+ | </source> | ||
=== sceNpDrmUpdateAccountIdForDriver === | === sceNpDrmUpdateAccountIdForDriver === | ||
Line 438: | Line 438: | ||
|} | |} | ||
− | <source lang="C">int sceNpDrmUpdateAccountIdForDriver( | + | <source lang="C">int sceNpDrmUpdateAccountIdForDriver(SceUInt64 account_id);</source> |
=== sceNpDrmEbootSigGenMultiDiscForDriver === | === sceNpDrmEbootSigGenMultiDiscForDriver === | ||
Line 448: | Line 448: | ||
|} | |} | ||
− | <source lang="C">int sceNpDrmEbootSigGenMultiDiscForDriver( | + | <source lang="C"> |
+ | // dst size is 0x200 | ||
+ | int sceNpDrmEbootSigGenMultiDiscForDriver(const char *path, const void *some_sig, void *dst, SceUInt32 systemSwVersion); | ||
+ | </source> | ||
=== sceNpDrmEbootSigGenPs1ForDriver === | === sceNpDrmEbootSigGenPs1ForDriver === | ||
Line 458: | Line 461: | ||
|} | |} | ||
− | <source lang="C">int sceNpDrmEbootSigGenPs1ForDriver( | + | <source lang="C"> |
+ | // dst size is 0x200 | ||
+ | int sceNpDrmEbootSigGenPs1ForDriver(const char *path, const void *hash_sha256, void *dst, SceUInt32 systemSwVersion); | ||
+ | </source> | ||
=== sceNpDrmGetLegacyDocKeyForDriver === | === sceNpDrmGetLegacyDocKeyForDriver === | ||
Line 467: | Line 473: | ||
| 3.60 || 0x4E321BDE | | 3.60 || 0x4E321BDE | ||
|} | |} | ||
+ | |||
+ | Gets klicensee to decrypt encrypted DOCUMENT.DAT. | ||
<source lang="C"> | <source lang="C"> | ||
− | // | + | // pLegacyDocKey size is 0x10 bytes |
− | + | int sceNpDrmGetLegacyDocKeyForDriver(void *pRif, void *pDocEdat, SceSize docEdatSize, void *pLegacyDocKey); | |
− | int sceNpDrmGetLegacyDocKeyForDriver(void * | ||
</source> | </source> | ||
Line 494: | Line 501: | ||
|} | |} | ||
− | <source lang="C">int sceNpDrmEbootSigGenPspForDriver( | + | <source lang="C"> |
+ | // dst size is 0x200 | ||
+ | int sceNpDrmEbootSigGenPspForDriver(const char *path, const void *hash_sha256, void *dst, SceUInt32 systemSwVersion); | ||
+ | </source> | ||
=== sceNpDrmEbootSigConvertForDriver === | === sceNpDrmEbootSigConvertForDriver === | ||
Line 504: | Line 514: | ||
|} | |} | ||
− | <source lang="C">int sceNpDrmEbootSigConvertForDriver( | + | <source lang="C"> |
+ | // dst size is 0x200 | ||
+ | int sceNpDrmEbootSigConvertForDriver(const char *path, const void *some_sig, void *dst); | ||
+ | </source> | ||
=== sceNpDrmPspEbootVerifyForDriver === | === sceNpDrmPspEbootVerifyForDriver === | ||
Line 514: | Line 527: | ||
|} | |} | ||
− | <source lang="C">int sceNpDrmPspEbootVerifyForDriver( | + | <source lang="C">int sceNpDrmPspEbootVerifyForDriver(const char *path, const void *some_sig);</source> |
=== sceNpDrmPspEbootSigGenForDriver === | === sceNpDrmPspEbootSigGenForDriver === | ||
Line 524: | Line 537: | ||
|} | |} | ||
− | <source lang="C">int sceNpDrmPspEbootSigGenForDriver( | + | <source lang="C"> |
+ | // dst size is 0x100 | ||
+ | int sceNpDrmPspEbootSigGenForDriver(const char *path, const void *hash_sha256, void *dst); | ||
+ | </source> | ||
=== sceNpDrmIsLooseAccountBindForDriver === | === sceNpDrmIsLooseAccountBindForDriver === | ||
Line 546: | Line 562: | ||
checks /CONFIG/NP debug_upgradable and /CONFIG/NP2 debug_drm_loose_bind registry values | checks /CONFIG/NP debug_upgradable and /CONFIG/NP2 debug_drm_loose_bind registry values | ||
− | <source lang="C">int sceNpDrmUpdateDebugSettingsForDriver();</source> | + | <source lang="C">int sceNpDrmUpdateDebugSettingsForDriver(void);</source> |
=== sceNpDrmGetRifPspKeyForDriver === | === sceNpDrmGetRifPspKeyForDriver === | ||
Line 556: | Line 572: | ||
|} | |} | ||
− | <source lang="C"> | + | <source lang="C">int sceNpDrmGetRifPspKeyForDriver(const void *license, void *klicensee, int *flags, SceUInt64 *lic_start_time, SceUInt64 *lic_exp_time);</source> |
− | |||
− | |||
− | int sceNpDrmGetRifPspKeyForDriver(void * | ||
=== sceNpDrmGetRifVitaKeyForDriver === | === sceNpDrmGetRifVitaKeyForDriver === | ||
Line 569: | Line 582: | ||
|} | |} | ||
− | + | It uses [[#sceNpDrmGetRifInfoForDriver]] to get required fields. | |
− | <source lang="C"> | + | <source lang="C">int sceNpDrmGetRifVitaKeyForDriver(const void *license, void *klicensee, int *flags, int *sku_flags, SceUInt64 *lic_start_time, SceUInt64 *lic_exp_time);</source> |
− | int sceNpDrmGetRifVitaKeyForDriver(void * | ||
− | </source> | ||
− | === | + | === sceNpDrmWriteActDataForDriver === |
{| class="wikitable" | {| class="wikitable" | ||
|- | |- | ||
Line 583: | Line 594: | ||
|} | |} | ||
− | Related to _sceSblGcAuthMgrPcactActivation. | + | Related to [[SceSblGcAuthMgr#_sceSblGcAuthMgrPcactActivation]]. |
decrypts act_data with aes_dec_key and stores it to data segment | decrypts act_data with aes_dec_key and stores it to data segment | ||
Line 603: | Line 614: | ||
<source lang="C"> | <source lang="C"> | ||
// act_data is of size 0x1040 | // act_data is of size 0x1040 | ||
− | int | + | int sceNpDrmWriteActDataForDriver(void *act_data, const char *aes_dec_key); |
</source> | </source> | ||
− | === | + | === sceNpDrmReadActDataForDriver === |
{| class="wikitable" | {| class="wikitable" | ||
|- | |- | ||
Line 619: | Line 630: | ||
<source lang="C"> | <source lang="C"> | ||
− | //act_data is of size 0x1038 | + | // act_data is of size 0x1038 |
− | int | + | int sceNpDrmReadActDataForDriver(void *act_data); |
</source> | </source> | ||
− | === | + | === sceNpDrmVerifyRifForDriver === |
{| class="wikitable" | {| class="wikitable" | ||
|- | |- | ||
Line 634: | Line 645: | ||
<source lang="C"> | <source lang="C"> | ||
− | //rif_data max size is 0x200 | + | // rif_data max size is 0x200 |
− | int | + | int sceNpDrmVerifyRifForDriver(void *rif_data, SceSize rif_size); |
</source> | </source> | ||
Line 654: | Line 665: | ||
<source lang="C"> | <source lang="C"> | ||
// rif data size is unknown but at least 0xF8 | // rif data size is unknown but at least 0xF8 | ||
− | int sceNpDrmVerifyRifFullForDriver(void* rif_data); | + | int sceNpDrmVerifyRifFullForDriver(void *rif_data); |
</source> | </source> | ||
− | === | + | === sceNpDrmUpdateActDataForDriver === |
{| class="wikitable" | {| class="wikitable" | ||
|- | |- | ||
Line 667: | Line 678: | ||
reads tm0:/npdrm/act.dat | reads tm0:/npdrm/act.dat | ||
− | verifies sha1 | + | verifies ECDSA with sha1 and RSA with sha256 |
checks Loose Account Bind flag | checks Loose Account Bind flag | ||
Line 677: | Line 688: | ||
decrypts Primary Key Table | decrypts Primary Key Table | ||
− | <source lang="C"> | + | <source lang="C">int sceNpDrmUpdateActDataForDriver(void);</source> |
− | int | ||
− | </source> | ||
== SceNpDrmPackage == | == SceNpDrmPackage == | ||
Line 688: | Line 697: | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
− | | 1.69 | + | | 1.69-3.60 || 0x0567DCA1 |
− | |||
− | |||
|} | |} | ||
<source lang="C"> | <source lang="C"> | ||
− | //opt is of size 0x28 | + | // opt is of size 0x28 |
int _sceNpDrmPackageTransform(int unk0, int unk1, void* opt, int unk3); | int _sceNpDrmPackageTransform(int unk0, int unk1, void* opt, int unk3); | ||
</source> | </source> | ||
Line 703: | Line 710: | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
− | | 1.69 | + | | 1.69-3.60 || 0x6896EAF2 |
− | |||
− | |||
|} | |} | ||
<source lang="C"> | <source lang="C"> | ||
− | //opt is of size 0x8 | + | // opt is of size 0x8 |
int _sceNpDrmPackageInstallFinished(int unk0, int unk1, int unk2, void* opt); | int _sceNpDrmPackageInstallFinished(int unk0, int unk1, int unk2, void* opt); | ||
</source> | </source> | ||
Line 718: | Line 723: | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
− | | 1.69 | + | | 1.69-3.60 || 0xA1D885FA |
− | |||
− | |||
|} | |} | ||
− | <source lang="C"> | + | <source lang="C">int _sceNpDrmPackageCheck(const void *buffer1, SceSize size, void *buffer2, SceUInt32 identifier);</source> |
− | int _sceNpDrmPackageCheck(const void *buffer1, SceSize size, void *buffer2, | ||
− | </source> | ||
=== sceNpDrmPackageIsGameExist === | === sceNpDrmPackageIsGameExist === | ||
Line 732: | Line 733: | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
− | | 1.69 | + | | 1.69-3.60 || 0xB9337914 |
− | |||
− | |||
|} | |} | ||
Line 744: | Line 743: | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
− | | 1.69 | + | | 1.69-3.60 || 0xCEC18DA4 |
− | |||
− | |||
|} | |} | ||
Line 759: | Line 756: | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
− | | 1.69 | + | | 1.69-3.60 || 0xD6F05ACC |
− | |||
− | |||
|} | |} | ||
<source lang="C"> | <source lang="C"> | ||
− | typedef struct _sceNpDrmPackageDecrypt //size is 0x10 | + | typedef struct _sceNpDrmPackageDecrypt { //size is 0x10 |
− | |||
SceOff offset; //The offset in the encrypted data | SceOff offset; //The offset in the encrypted data | ||
unsigned int identifier; | unsigned int identifier; | ||
Line 780: | Line 774: | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
− | | 1.69 | + | | 1.69-3.60 || 0xED0471FE |
− | |||
− | |||
|} | |} | ||
Line 796: | Line 788: | ||
<source lang="C"> | <source lang="C"> | ||
− | //opt is of size 0x8 | + | // opt is of size 0x8 |
int _sceNpDrmPackageUninstallFinished(int unk0, int unk1, int unk2, void* opt); | int _sceNpDrmPackageUninstallFinished(int unk0, int unk1, int unk2, void* opt); | ||
</source> | </source> | ||
Line 842: | Line 834: | ||
<source lang="C"> | <source lang="C"> | ||
− | //opt is of size 0x10 | + | // opt is of size 0x10 |
int unk_4665E75A(int unk0, int unk1, int unk2, void *opt); | int unk_4665E75A(int unk0, int unk1, int unk2, void *opt); | ||
</source> | </source> | ||
Line 891: | Line 883: | ||
<source lang="C"> | <source lang="C"> | ||
− | //opt is of size 0x8 | + | // opt is of size 0x8 |
int unk_C75A775B(int unk0, int unk1, int unk2, void *opt); | int unk_C75A775B(int unk0, int unk1, int unk2, void *opt); | ||
</source> | </source> | ||
Line 906: | Line 898: | ||
<source lang="C"> | <source lang="C"> | ||
− | //some data is of size 0x400 and contains rif data | + | // some data is of size 0x400 and contains rif data |
int get_rif_name(char *rif_name, void *some_data); | int get_rif_name(char *rif_name, void *some_data); | ||
</source> | </source> | ||
Line 944: | Line 936: | ||
* klicensee size 0x200 | * klicensee size 0x200 | ||
**/ | **/ | ||
− | int scePsmDrmGetRifKey(SceNpDrmLicense * rif_data , uint8_t *klicensee, uint32_t *flags, uint64_t *start_time, uint64_t *expiration_time); | + | int scePsmDrmGetRifKey(SceNpDrmLicense *rif_data, uint8_t *klicensee, uint32_t *flags, uint64_t *start_time, uint64_t *expiration_time); |
</source> | </source> | ||
Line 1,031: | Line 1,023: | ||
decrypts psm_act_data with aes_dec_key | decrypts psm_act_data with aes_dec_key | ||
− | creates tm0:/psmdrm if | + | creates tm0:/psmdrm if necessary |
writes tm0:/psmdrm/act.dat | writes tm0:/psmdrm/act.dat | ||
Line 1,075: | Line 1,067: | ||
== Package integrity checks == | == Package integrity checks == | ||
+ | |||
=== Disable hash/signature verification === | === Disable hash/signature verification === | ||
+ | |||
To find the function responsible for package verification search for immediate 0x7F504B47 ('.PKG'). Inside it does a lot of stuff including determining the function that will do signature checks. Find the condition that looks like <code>if ( (v62 & 7) == 3 )</code>; below you will see the assignment <code>check_func = &off_81009CFC;</code>. To bypass signature checks you need to patch two functions located at this offset and offset+4, making them behave as "return 1" is enough. For reference, on 1.60 the functions are sub_81000310 and sub_81000AA4. sub_81000310 is the only function in this module that calls SceSblGcAuthMgrPkgForDriver_E459A9A8_imp. | To find the function responsible for package verification search for immediate 0x7F504B47 ('.PKG'). Inside it does a lot of stuff including determining the function that will do signature checks. Find the condition that looks like <code>if ( (v62 & 7) == 3 )</code>; below you will see the assignment <code>check_func = &off_81009CFC;</code>. To bypass signature checks you need to patch two functions located at this offset and offset+4, making them behave as "return 1" is enough. For reference, on 1.60 the functions are sub_81000310 and sub_81000AA4. sub_81000310 is the only function in this module that calls SceSblGcAuthMgrPkgForDriver_E459A9A8_imp. | ||
Line 1,081: | Line 1,075: | ||
=== Allow debug packages to be installed === | === Allow debug packages to be installed === | ||
− | Find the function that calls [[SceSysmem#sceSblAIMgrIsCEXForDriver|sceSblAIMgrIsCEXForDriver]]. Patch it to always return 1. On 1.60 it | + | |
+ | Find the function that calls [[SceSysmem#sceSblAIMgrIsCEXForDriver|sceSblAIMgrIsCEXForDriver]]. Patch it to always return 1. On FW 1.60 it is at 0x81002d64. | ||
Search for immediate 0x80870003, there should be two matches. Replace both with "MOV Reg, #0". On 1.60 the locations are 0x810035fe and 0x81004856. | Search for immediate 0x80870003, there should be two matches. Replace both with "MOV Reg, #0". On 1.60 the locations are 0x810035fe and 0x81004856. | ||
Line 1,087: | Line 1,082: | ||
== RIF == | == RIF == | ||
− | The | + | The RIF file holds the klicensee for NPDRM contents. The RIF files are used as DRM licenses. For each installed PKG and Game Card you have a unique RIF file with proper information that is used when you open the game to verify if you own the game (or PKG). The RIF files holds important information as PSN Account ID, the key used to decrypt one of the SELF encryption layers. |
− | + | PS Vita supports two different RIF file formats. The first format version (v0) is used by RIF files with 0x98 bytes size and the second version (v1) is used by RIF files with 0x200 bytes size. The difference between these formats is just the signature and some data used by PS Vita only. RIF version 0 only uses ECDSA Signature only whilst RIF Version 1 uses the ECDSA Signature and an extra RSA Signature. | |
− | |||
− | |||
{| class='wikitable' | {| class='wikitable' | ||
Line 1,101: | Line 1,094: | ||
| Version Flag || 0x2 || 0x2 || 0 or 1 | | Version Flag || 0x2 || 0x2 || 0 or 1 | ||
|- | |- | ||
− | | | + | | DRM Type || 0x4 || 0x2 || |
|- | |- | ||
− | | License Flags || 0x6 || 0x2 || | + | | License Flags || 0x6 || 0x2 || 2: per-content, 0xD: PSP2 DRM Free, 0x400: PSP2 GameCard |
|- | |- | ||
− | | | + | | NP Account ID || 0x8 || 0x8 || NP Account ID (in little-endian) for Network and Local DRM, 8 first bytes of sha-1 of some key for Free DRM. |
|- | |- | ||
| Content ID || 0x10 || 0x30 || [https://www.psdevwiki.com/ps3/PARAM.SFO#CONTENT_ID CONTENT_ID] | | Content ID || 0x10 || 0x30 || [https://www.psdevwiki.com/ps3/PARAM.SFO#CONTENT_ID CONTENT_ID] | ||
|- | |- | ||
− | | | + | | Encrypted account keyring index || 0x40 || 0x10 || Encrypted account keyring index for Network and Local DRM, 12 last bytes of sha-1 of some key + 4 bytes of zeroes for Free DRM. |
|- | |- | ||
− | | RIF Key | + | | Encrypted RIF Key || 0x50 || 0x10 || Used to get klicensee to decrypt NPDRM SELF/SPRX/EDAT/PFS files. |
|- | |- | ||
| License start time || 0x60 || 0x8 || For human readable, convert to decimal and use an Epoch-Unix converter time format online. | | License start time || 0x60 || 0x8 || For human readable, convert to decimal and use an Epoch-Unix converter time format online. | ||
Line 1,117: | Line 1,110: | ||
| License expiration time || 0x68 || 0x8 || If zeroed, there is no time limit. Used for PS+ time-limited content for example. | | License expiration time || 0x68 || 0x8 || If zeroed, there is no time limit. Used for PS+ time-limited content for example. | ||
|- | |- | ||
− | | ECDSA Signature || 0x70 || 0x28 || Patched in most PS3 CFWs to allow unsigned. See Rif_Junk on Rap2Rif by Flatz | + | | ECDSA Signature || 0x70 || 0x28 || Patched in most PS3 CFWs to allow unsigned RIF. See Rif_Junk on Rap2Rif by Flatz. Params are same as for act.dat. |
|- | |- | ||
− | | Some Flag || 0x98 || | + | | Some Flag || 0x98 || 0x4 || Used by PS Vita only, not PSP nor PS3. |
|- | |- | ||
− | | | + | | Some Flag || 0x9C || 0x4 || Used by PS Vita only, not PSP nor PS3. ex: ?0x400?. |
|- | |- | ||
− | | | + | | Encrypted RIF Key 2 || 0xA0 || 0x10 || Used by PS Vita only, not PSP nor PS3. Used to get klicensee to decrypt NPDRM SELF/SPRX/EDAT/PFS files. |
|- | |- | ||
− | | | + | | Unknown_B0 || 0xB0 || 0x10 || Used by PS Vita only, not PSP nor PS3. |
|- | |- | ||
− | | | + | | [[SceSblSsMgr#sceKernelGetOpenPsIdForDriver|OpenPsId]] || 0xC0 || 0x10 || Used by PS Vita only, not PSP nor PS3. Checked only if License Flag 0x100 is set. |
|- | |- | ||
− | | | + | | Unknown_D0 || 0xD0 || 0x10 || Used by PS Vita only, not PSP nor PS3. |
|- | |- | ||
− | | | + | | [[SceSblGcAuthMgr#memcmp_safe_5018|CMD56 handshake part]] || 0xE0 || 0x14 || Used by PS Vita only, not PSP nor PS3. Checked only if License Flag 0x400 is set. |
|- | |- | ||
− | | | + | | Unknown_F4 || 0xF4 || 0x4 || Used by PS Vita only, not PSP nor PS3. Some flag related to debug_upgradable. ex: 0 (default), 1 (seen on a PSP2 gamecard). |
|- | |- | ||
− | | | + | | Unknown_F8 || 0xF8 || 0x4 || Used by PS Vita only, not PSP nor PS3. |
|- | |- | ||
− | | RSA Signature || 0x100 || 0x100 || | + | | SKU flag || 0xFC || 0x4 || Used by PS Vita only, not PSP nor PS3. Some flag related to debug_upgradable. |
+ | |- | ||
+ | | RSA Signature || 0x100 || 0x100 || Used by PS Vita only, not PSP nor PS3. | ||
|} | |} | ||
== PSM-ACT == | == PSM-ACT == | ||
+ | |||
PSM Activation file | PSM Activation file | ||
Line 1,147: | Line 1,143: | ||
! Name !! Offset !! Size !! Example !! Remark | ! Name !! Offset !! Size !! Example !! Remark | ||
|- | |- | ||
− | | Magic || | + | | Magic || 0x0 || 0x8 || "PSM-ACT" || |
|- | |- | ||
− | | Unknown1 || | + | | Unknown1 || 0x8 || 0x8 || 00 00 00 00 00 00 00 00 || |
|- | |- | ||
| Account Id || 0x10 || 0x8 || 91 78 34 02 01 EF CD AB || PSN account ID (little endian) | | Account Id || 0x10 || 0x8 || 91 78 34 02 01 EF CD AB || PSN account ID (little endian) | ||
Line 1,171: | Line 1,167: | ||
== PSM-RIF == | == PSM-RIF == | ||
+ | |||
PSM RIF file | PSM RIF file | ||
Line 1,177: | Line 1,174: | ||
! Name !! Offset !! Size !! Example !! Remark | ! Name !! Offset !! Size !! Example !! Remark | ||
|- | |- | ||
− | | Magic | + | | Magic || 0x0 || 0x8 || "PSM-RIF" || |
|- | |- | ||
− | | Unknown1 || | + | | Unknown1 || 0x8 || 0x4 || 00 00 00 01 || Maybe Version and Version Flag? |
|- | |- | ||
− | | Unknown2 || | + | | Unknown2 || 0xC || 0x4 || 00 00 00 00 || Maybe DRM Type and License Flags? |
|- | |- | ||
| Account ID || 0x10 || 0x8 || 91 78 34 02 01 EF CD AB || PSN account ID (little endian) | | Account ID || 0x10 || 0x8 || 91 78 34 02 01 EF CD AB || PSN account ID (little endian) | ||
|- | |- | ||
− | | Unknown3 || | + | | Unknown3 || 0x18 || 0x4 || 00 00 00 00 || Must be 0 |
|- | |- | ||
− | | Unknown4 || | + | | Unknown4 || 0x1C || 0x4 || 00 00 00 00 || Must be 0 |
|- | |- | ||
| Activation start time || 0x20 || 0x8 || 00 00 01 4C 16 4D 83 A8 || | | Activation start time || 0x20 || 0x8 || 00 00 01 4C 16 4D 83 A8 || |
Revision as of 13:13, 10 October 2022
Module
Version | World | Privilege |
---|---|---|
1.69-3.73 | Non-secure | Kernel |
Libraries
Known NIDs
Version | Name | World | Visibility | NID |
---|---|---|---|---|
1.69-3.60 | SceNpDrm | Non-secure | User | 0xF2799B1B |
1.69-3.60 | SceNpDrmForDriver | Non-secure | Kernel | 0xD84DC44A |
1.69-3.60 | SceNpDrmPackage | Non-secure | User | 0x88514DB2 |
3.60 | ScePsmDrm | Non-secure | User | 0x3F2B0888 |
3.60 | ScePsmDrmForDriver | Non-secure | Kernel | 0x9F4924F2 |
Data segment layout
Address | Size | Description |
---|---|---|
0x0000 | 0x4 | SceNpDrm mutex SceUID |
0x0004 | 0x4 | ScePsmDrm mutex SceUID |
0x0008 | 0x8 | unknown |
0x0010 | 0xC0 | Static keys decrypted with sceSblAuthMgrGetEKcForDriver key 0.
First 0x10 bytes are reencrypted with ConsoleId. First 0x10 bytes are aes_key used to decrypt 0x800 bytes of Primary Key Table from act.dat. Second 0x10 bytes are aes_key used to decrypt Primary Key Table index from rif. |
0x00D0 | 0xCF8 | unknown |
0x0DC8 | 0x4 | Game Exist flag |
0x0DCC | 0x4 | Is DEX flag or Is Tool flag |
0x0DD0 | 0x30 | unknown |
0x0E00 | 0x1040 | tm0:/npdrm/act.dat data |
0x1E40 | 0x400 | tm0:/psmdrm/act.dat data |
0x2240 | 0x10 | OpenPsId
This data is compared against OpenPsId in act.dat and under some conditions in .rif at offset 0xC0. |
0x2250 | 0x4 | act data Is Valid flag |
0x2254 | 0x4 | unknown |
0x2258 | 0x8 | /CONFIG/NP/account_id registry key |
0x2260 | 0x4 | Loose Account Bind flag |
0x2264 | 0x4 | /CONFIG/NP/debug_upgradable registry key |
0x2268 | 0x20 | sha256 digest of get_act_data |
0x2288 | 0x20 | hmac-sha256 digest of get_act_data |
0x22A8 | 0x8 | unknown |
0x22B0 | 0x8 | account_id |
0x22B8 | 0x8 | PSM activation start date |
0x22C0 | 0x8 | PSM activation end date |
0x22C8 | 0x20 | some key decrypted with 0x2288 |
Obtaining klicensee
Initialization steps (common):
1. Get the hardcoded encrypted EKc (0xC0 bytes). (on FW 3.60, 0xC0 bytes from SceNpDrm code segment at offset 0x111D0)
2. Decrypt the hardcoded encrypted EKc using sceSblAuthMgrGetEKcForDriver with key revision 0 (?or 1 or 2?).
Initialization steps (per-console):
3. Get ConsoleId (0x10 bytes) using sceSblSsMgrGetConsoleIdForDriver.
4. Decrypt using AES128ECB first 0x10 bytes of EKc with ConsoleId as key.
5. Read 0x800 bytes of the encrypted Primary Key Table from act.dat file.
6. Decrypt 0x800 bytes of Primary Key Table with reencrypted static key using AES (need to figure out which AES exactly).
Initialization steps (per-content):
7. Get 0x98 / 0x200 bytes of RIF data from the content's .rif file and select one of the 5 scenarios for decrypting RIF Key into klicensee based on License flags (need to figure out). In most cases only the first 0x70 bytes are needed for klicensee derivation because at 0x70 is the ECDSA signature which is not used for derivation, and after 0x98 is data only used for some PS Vita contents (maybe only PS Vita cartridges require a 0x200-byte RIF).
Scenario 1 - maybe DRM Free
Take RIF Key 2.
Take static keys 3, 4.
Take first 0x70 bytes of RIF data.
Use SceSblAuthMgr#sceSblAuthMgrDecBindDataForDriver to decrypt RIF key 2 and obtain klicensee.
Scenario 2
Take RIF Key 2.
Take primary keys 1, 2.
Take first 0x70 bytes of RIF data.
Use SceSblAuthMgr#sceSblAuthMgrDecBindDataForDriver to decrypt RIF key 2 and obtain klicensee.
Scenario 3 - Game Cartridge
Take RIF Key 2.
Take cmd56 handshake keys with get_5018_data.
Take first 0x70 bytes of RIF data.
Use SceSblAuthMgr#sceSblAuthMgrDecBindDataForDriver to decrypt RIF key 2 and obtain klicensee.
Scenario 4 - Game Cartridge
Take RIF Key 1.
Take cmd56 handshake keys with get_5018_data.
Take first 0x70 bytes of RIF data.
Erase RIF Key 1 from RIF data.
Use SceSblAuthMgr#sceSblAuthMgrDecBindDataForDriver to decrypt RIF key 1 and obtain klicensee.
Scenario 5
Take RIF Key 1.
Decrypt Primary Table Key index from RIF data with static key 2 using AES (need to figure out which AES exactly).
Take primary key using decrypted index.
Decrypt RIF key 1 with obtained primary key using AES (need to figure out which AES exactly).
Get rif name algorithm
uint8_t rif_name_keys[0x10] = {
0x19, 0xDD, 0x4F, 0xB9, 0x89, 0x48, 0x2B, 0xD4,
0xCB, 0x9E, 0xC9, 0xC7, 0x9A, 0x2E, 0xFB, 0xD0
};
int aes_encrypt(const void *buf, int size, uint8_t *keys) {
AES_ctx ctx;
AES_set_key(&ctx, rif_name_keys, 0x80);
int i;
for (i = 0; i < size; i += 0x10) {
AES_encrypt(&ctx, buf+i, buf+i);
}
}
typedef struct {
uint64_t mode; // 0: bounded, 1: fixed
uint64_t aid;
} SceNpDrmRifName;
int getRifName(char *name, int length, uint64_t aid, uint64_t mode) {
SceNpDrmRifName rif_name;
rif_name.mode = mode;
rif_name.aid = aid;
aes_encrypt(&rif_name, sizeof(SceNpDrmRifName), rif_name_keys);
snprintf(name, length, "%016llx%016llx.rif", __builtin_bswap64(((uint64_t *)&rif_name)[0]), __builtin_bswap64(((uint64_t *)&rif_name)[1]));
}
SceNpDrm
_sceNpDrmCheckDrmReset
Version | NID |
---|---|
1.69-3.60 | 0x4458812B |
//opt is of size 0x18
int _sceNpDrmCheckDrmReset(int unk0, int unk1, void *opt);
_sceNpDrmRemoveActData
Version | NID |
---|---|
1.69-3.60 | 0x507D06A6 |
//opt is of size 0x8
int _sceNpDrmRemoveActData(int unk0, void* opt);
_sceNpDrmGetRifName
Version | NID |
---|---|
1.69-3.60 | 0xB8C5DA7C |
int _sceNpDrmGetRifName(char *name, uint64_t aid);
_sceNpDrmGetRifNameForInstall
Version | NID |
---|---|
1.69-3.60 | 0xD312424D |
//name is of size 0x30
//rif_data is of size 0x200
int _sceNpDrmGetRifNameForInstall(char *name, void *rif_data, int num);
_sceNpDrmGetRifInfo
Version | NID |
---|---|
1.69-3.60 | 0xE8343660 |
typedef struct rif_info { //size is 0x70
char content_id[0x30];
char version_number[4];
char rif_lic_flags[4];
char drm_type0[4]; // DRM type related
char drm_type1[4]; // DRM type related
char account_id[8];
char rif_data_0x98[8];
uint64_t lic_start_time;
uint64_t lic_exp_time;
char klicensee[0x10];
} rif_info;
typedef struct _sceNpDrmGetRifInfo_opt { //size is 0x28
void* content_id;
void* account_id;
void* version_number;
void* rif_lic_flags;
void* lic_type0; // DRM type related
void* lic_type1; // DRM type related
void* lic_start_time;
void* lic_exp_time;
void* rif_data_0x98;
} _sceNpDrmGetRifInfo_opt;
// rif data is of size 0x200
int _sceNpDrmGetRifInfo(void* rif_data, int rif_size, int num, _sceNpDrmGetRifInfo_opt* opt);
_sceNpDrmGetFixedRifName
Version | NID |
---|---|
1.69-3.60 | 0xE935B0FC |
int _sceNpDrmGetFixedRifName(char *name, uint64_t aid);
_sceNpDrmCheckActData
Version | NID |
---|---|
1.69-3.60 | 0xFEEBCD62 |
// opt is of size 0x10
int _sceNpDrmCheckActData(int unk0, int unk1, int unk2, void* opt);
_sceNpDrmPresetRifProvisionalFlag
Version | NID |
---|---|
3.60 | 0x2523F57F |
// rif data is of size 0x200
int _sceNpDrmPresetRifProvisionalFlag(void* rif_data);
SceNpDrmForDriver
sceNpDrmGetRifInfoForDriver
Version | NID |
---|---|
3.60 | 0xDB406EAE |
// content_id size is 0x30
int sceNpDrmGetRifInfoForDriver(const void *license, SceSize license_size, int check_sign, char *content_id, SceUInt64 *pAccountId, int *pLicenseVersion, int *pLicenseFlags, int *flags, int *sku_flags, SceInt64 *lic_start_time, SceInt64 *lic_exp_time, SceUInt64 *flags2);
sceNpDrmPackageSetGameExistForDriver
Version | NID |
---|---|
3.60 | 0x3BFD2850 |
int sceNpDrmPackageSetGameExistForDriver(int value);
sceNpDrmGetFixedRifNameForDriver
Version | NID |
---|---|
3.60 | 0x5D73448C |
// name is of size 0x30
int sceNpDrmGetFixedRifNameForDriver(char *name, SceUInt64 aid);
sceNpDrmGetRifNameForDriver
Version | NID |
---|---|
3.60 | 0xDF62F3B8 |
// name is of size 0x30
int sceNpDrmGetRifNameForDriver(char *name, SceUInt64 aid);
sceNpDrmGetRifNameForInstallForDriver
Version | NID |
---|---|
3.60 | 0x17573133 |
// name is of size 0x30
// if not_use_content_id is zero, use license content id
int sceNpDrmGetRifNameForInstallForDriver(char *name, const void *license, int not_use_content_id);
sceNpDrmPresetRifProvisionalFlagForDriver
Version | NID |
---|---|
3.60 | 0xC070FE89 |
Updating license data.
int sceNpDrmPresetRifProvisionalFlagForDriver(void *license, int unk2);
sceNpDrmCheckActDataForDriver
Version | NID |
---|---|
3.60 | 0x9265B350 |
get tm0:/npdrm/act.dat info
//size of act data is 0x1040
int sceNpDrmCheckActDataForDriver(int *act_type, int *unk2, SceUInt64 *pAccountId, SceInt64 *act_start_time, SceInt64 *act_exp_time);
sceNpDrmRemoveActDataForDriver
Version | NID |
---|---|
3.60 | 0x8B85A509 |
Remove tm0:/npdrm/act.dat
// pAccountId of deleted tm0:/npdrm/act.dat
int sceNpDrmRemoveActDataForDriver(SceUInt64 *pAccountId);
sceNpDrmUpdateAccountIdForDriver
Version | NID |
---|---|
3.60 | 0x116FC0D6 |
int sceNpDrmUpdateAccountIdForDriver(SceUInt64 account_id);
sceNpDrmEbootSigGenMultiDiscForDriver
Version | NID |
---|---|
3.60 | 0x39A7A666 |
// dst size is 0x200
int sceNpDrmEbootSigGenMultiDiscForDriver(const char *path, const void *some_sig, void *dst, SceUInt32 systemSwVersion);
sceNpDrmEbootSigGenPs1ForDriver
Version | NID |
---|---|
3.60 | 0x6D9223E1 |
// dst size is 0x200
int sceNpDrmEbootSigGenPs1ForDriver(const char *path, const void *hash_sha256, void *dst, SceUInt32 systemSwVersion);
sceNpDrmGetLegacyDocKeyForDriver
Version | NID |
---|---|
3.60 | 0x4E321BDE |
Gets klicensee to decrypt encrypted DOCUMENT.DAT.
// pLegacyDocKey size is 0x10 bytes
int sceNpDrmGetLegacyDocKeyForDriver(void *pRif, void *pDocEdat, SceSize docEdatSize, void *pLegacyDocKey);
sceNpDrmEbootSigVerifyForDriver
Version | NID |
---|---|
3.60 | 0x7A319692 |
drm_data - __sce_ebootpbp or license data, size is 0x200.
int sceNpDrmEbootSigVerifyForDriver(const char *path, void *drm_data);
sceNpDrmEbootSigGenPspForDriver
Version | NID |
---|---|
3.60 | 0x90B1A6D3 |
// dst size is 0x200
int sceNpDrmEbootSigGenPspForDriver(const char *path, const void *hash_sha256, void *dst, SceUInt32 systemSwVersion);
sceNpDrmEbootSigConvertForDriver
Version | NID |
---|---|
3.60 | 0xA29B75F9 |
// dst size is 0x200
int sceNpDrmEbootSigConvertForDriver(const char *path, const void *some_sig, void *dst);
sceNpDrmPspEbootVerifyForDriver
Version | NID |
---|---|
3.60 | 0xB6CA3A2C |
int sceNpDrmPspEbootVerifyForDriver(const char *path, const void *some_sig);
sceNpDrmPspEbootSigGenForDriver
Version | NID |
---|---|
3.60 | 0xEF387FC4 |
// dst size is 0x100
int sceNpDrmPspEbootSigGenForDriver(const char *path, const void *hash_sha256, void *dst);
sceNpDrmIsLooseAccountBindForDriver
Version | NID |
---|---|
3.60 | 0xFC84CA1A |
int sceNpDrmIsLooseAccountBindForDriver(void);
sceNpDrmUpdateDebugSettingsForDriver
Version | NID |
---|---|
3.60 | 0xA91C7443 |
checks /CONFIG/NP debug_upgradable and /CONFIG/NP2 debug_drm_loose_bind registry values
int sceNpDrmUpdateDebugSettingsForDriver(void);
sceNpDrmGetRifPspKeyForDriver
Version | NID |
---|---|
3.60 | 0xDACB71F4 |
int sceNpDrmGetRifPspKeyForDriver(const void *license, void *klicensee, int *flags, SceUInt64 *lic_start_time, SceUInt64 *lic_exp_time);
sceNpDrmGetRifVitaKeyForDriver
Version | NID |
---|---|
3.60 | 0x723322B5 |
It uses #sceNpDrmGetRifInfoForDriver to get required fields.
int sceNpDrmGetRifVitaKeyForDriver(const void *license, void *klicensee, int *flags, int *sku_flags, SceUInt64 *lic_start_time, SceUInt64 *lic_exp_time);
sceNpDrmWriteActDataForDriver
Version | NID |
---|---|
0.990-3.60 | 0x742EBAF4 |
Related to SceSblGcAuthMgr#_sceSblGcAuthMgrPcactActivation.
decrypts act_data with aes_dec_key and stores it to data segment
verifies sha1 - ecdsa or sha256 - RSA
checks Loose Account Bind flag
verifies OpenPsId
creates tm0:/npdrm folder
writes tm0:/npdrm/act.dat file
repeats all verification steps
decrypts Primary Key Table
// act_data is of size 0x1040
int sceNpDrmWriteActDataForDriver(void *act_data, const char *aes_dec_key);
sceNpDrmReadActDataForDriver
Version | NID |
---|---|
3.60 | 0xD91C3BCE |
Related to sceSblGcAuthMgrPcactGetChallenge
reads 0x1038 bytes of tm0:/npdrm/act.dat data
// act_data is of size 0x1038
int sceNpDrmReadActDataForDriver(void *act_data);
sceNpDrmVerifyRifForDriver
Version | NID |
---|---|
3.60 | 0xFE7B17B6 |
verify ECDSA - SHA1 pair or RSA - SHA256 pair
// rif_data max size is 0x200
int sceNpDrmVerifyRifForDriver(void *rif_data, SceSize rif_size);
sceNpDrmVerifyRifFullForDriver
Version | NID |
---|---|
3.60 | 0xFF63672D |
check OpenPsId
check cmd56 handshake part
perform steps to get decrypted rif key
// rif data size is unknown but at least 0xF8
int sceNpDrmVerifyRifFullForDriver(void *rif_data);
sceNpDrmUpdateActDataForDriver
Version | NID |
---|---|
3.60 | 0x77926F5 |
reads tm0:/npdrm/act.dat
verifies ECDSA with sha1 and RSA with sha256
checks Loose Account Bind flag
verifies OpenPsId
clears Secondary Table, RSA Signature, Unknown Sig, ECDSA Signature
decrypts Primary Key Table
int sceNpDrmUpdateActDataForDriver(void);
SceNpDrmPackage
_sceNpDrmPackageTransform
Version | NID |
---|---|
1.69-3.60 | 0x0567DCA1 |
// opt is of size 0x28
int _sceNpDrmPackageTransform(int unk0, int unk1, void* opt, int unk3);
_sceNpDrmPackageInstallFinished
Version | NID |
---|---|
1.69-3.60 | 0x6896EAF2 |
// opt is of size 0x8
int _sceNpDrmPackageInstallFinished(int unk0, int unk1, int unk2, void* opt);
_sceNpDrmPackageCheck
Version | NID |
---|---|
1.69-3.60 | 0xA1D885FA |
int _sceNpDrmPackageCheck(const void *buffer1, SceSize size, void *buffer2, SceUInt32 identifier);
sceNpDrmPackageIsGameExist
Version | NID |
---|---|
1.69-3.60 | 0xB9337914 |
int sceNpDrmPackageIsGameExist();
_sceNpDrmPackageInstallStarted
Version | NID |
---|---|
1.69-3.60 | 0xCEC18DA4 |
//opt is of size 0x10
int _sceNpDrmPackageInstallStarted(int unk0, int unk1, int unk2, void* opt);
_sceNpDrmPackageDecrypt
Version | NID |
---|---|
1.69-3.60 | 0xD6F05ACC |
typedef struct _sceNpDrmPackageDecrypt { //size is 0x10
SceOff offset; //The offset in the encrypted data
unsigned int identifier;
uint32_t unk_C;
} _sceNpDrmPackageDecrypt_opt;
int _sceNpDrmPackageDecrypt(void * buffer, SceSize size, _sceNpDrmPackageDecrypt_opt * opt);
sceNpDrmPackageInstallOngoing
Version | NID |
---|---|
1.69-3.60 | 0xED0471FE |
int sceNpDrmPackageInstallOngoing(int unk0, int unk1);
_sceNpDrmPackageUninstallFinished
Version | NID |
---|---|
3.60 | 0x23A28861 |
// opt is of size 0x8
int _sceNpDrmPackageUninstallFinished(int unk0, int unk1, int unk2, void* opt);
_sceNpDrmPackageUninstallStarted
Version | NID |
---|---|
3.60 | 0x4901C3E6 |
//opt is of size 0x10
int _sceNpDrmPackageUninstallStarted(int unk0, int unk1, int unk2, void* opt);
sceNpDrmPackageUninstallOngoing
Version | NID |
---|---|
3.60 | 0xF1FF6193 |
int sceNpDrmPackageUninstallOngoing(int unk0, int unk1);
unk_200D2DE4
Version | NID |
---|---|
3.60 | 0x200D2DE4 |
int unk_200D2DE4(int unk0, int unk1);
unk_4665E75A
Version | NID |
---|---|
3.60 | 0x4665E75A |
// opt is of size 0x10
int unk_4665E75A(int unk0, int unk1, int unk2, void *opt);
unk_640C1724
Version | NID |
---|---|
3.60 | 0x640C1724 |
//opt is of size 0x8
int unk_640C1724(int unk0, int unk1, int unk2, void *opt);
unk_97BB85BD
Version | NID |
---|---|
3.60 | 0x97BB85BD |
//opt is of size 0x10
int unk_97BB85BD(int unk0, int unk1, int unk2, void *opt)
unk_A5E0F38C
Version | NID |
---|---|
3.60 | 0xA5E0F38C |
int unk_A5E0F38C(int unk0, int unk1);
unk_C75A775B
Version | NID |
---|---|
3.60 | 0xC75A775B |
// opt is of size 0x8
int unk_C75A775B(int unk0, int unk1, int unk2, void *opt);
ScePsmDrm
get_rif_name
Version | NID |
---|---|
3.60 | 0x0D6470DA |
// some data is of size 0x400 and contains rif data
int get_rif_name(char *rif_name, void *some_data);
_get_info
Version | NID |
---|---|
3.60 | 0xE31A6220 |
typedef struct get_info_opt //size is 0x10
{
void* out2;
void* out3;
uint32_t unk_8;
uint32_t unk_C;
}get_info_opt
int _get_info(void *some_data, void *out0, void *out1, get_info_opt *opt);
scePsmDrmGetRifKey
Version | NID |
---|---|
3.60 | 0x207A2C53 |
/**
* rif_data size 0x400
* klicensee size 0x200
**/
int scePsmDrmGetRifKey(SceNpDrmLicense *rif_data, uint8_t *klicensee, uint32_t *flags, uint64_t *start_time, uint64_t *expiration_time);
unk_E193CBB
Version | NID |
---|---|
3.60 | 0xE193CBB |
int unk_E193CBB(int unk0);
unk_3E881391
Version | NID |
---|---|
3.60 | 0x3E881391 |
int unk_3E881391(int unk0);
unk_A89653B3
Version | NID |
---|---|
3.60 | 0xA89653B3 |
//opt is of size 0x10
int unk_A89653B3(int unk0, int unk1, int unk2, void *opt);
ScePsmDrmForDriver
scePsmDrmGetRifInfoForDriver
Version | NID |
---|---|
3.60 | 0x984F9017 |
This function is named after sceNpDrmGetRifInfoForDriver since arguments are very similar.
//license_buf is of size 0x400
//content_id is of size 0x30
//account_id is of size 0x8
//start_time is of size 0x8
//expiration_time is of size 0x8
int scePsmDrmGetRifInfoForDriver(ScePsmDrmLicense *license_buf, char *content_id, uint64_t *account_id, uint64_t *start_time, uint64_t *expiration_time);
get_info_2_for_driver
Version | NID |
---|---|
3.60 | 0x8C8CFD01 |
this function is named after sceNpDrmGetRifInfoForDriver since arguments are very similar
//data is of size 0x400
//out0 is of size 0x200
//out1 is of size 0x4
//out2 is of size 0x8
//out3 is of size 0x8
int get_info_2_for_driver(void *data, void *out0, void *out1, void *out2, int out3);
set_psm_act_data
Version | NID |
---|---|
3.60 | 0xCB73E9D3 |
decrypts psm_act_data with aes_dec_key
creates tm0:/psmdrm if necessary
writes tm0:/psmdrm/act.dat
verifies sha256 - rca
//data is of size 0x400
int set_psm_act_data(void *psm_act_data, const char *aes_dec_key);
unk_4CD5375C
Version | NID |
---|---|
3.60 | 0x4CD5375C |
Deletes psmact.dat.
int unk_4CD5375C(int unk);
unk_791198CE
Version | NID |
---|---|
3.60 | 0x791198CE |
int unk_791198CE();
unk_B09003A7
Version | NID |
---|---|
3.60 | 0xB09003A7 |
int unk_B09003A7(int unk0, int unk1, int unk2, int unk3, int arg_0);
Package integrity checks
Disable hash/signature verification
To find the function responsible for package verification search for immediate 0x7F504B47 ('.PKG'). Inside it does a lot of stuff including determining the function that will do signature checks. Find the condition that looks like if ( (v62 & 7) == 3 )
; below you will see the assignment check_func = &off_81009CFC;
. To bypass signature checks you need to patch two functions located at this offset and offset+4, making them behave as "return 1" is enough. For reference, on 1.60 the functions are sub_81000310 and sub_81000AA4. sub_81000310 is the only function in this module that calls SceSblGcAuthMgrPkgForDriver_E459A9A8_imp.
Note that on 1.60 this module sometimes is loaded at different addresses between reboots.
Allow debug packages to be installed
Find the function that calls sceSblAIMgrIsCEXForDriver. Patch it to always return 1. On FW 1.60 it is at 0x81002d64.
Search for immediate 0x80870003, there should be two matches. Replace both with "MOV Reg, #0". On 1.60 the locations are 0x810035fe and 0x81004856.
RIF
The RIF file holds the klicensee for NPDRM contents. The RIF files are used as DRM licenses. For each installed PKG and Game Card you have a unique RIF file with proper information that is used when you open the game to verify if you own the game (or PKG). The RIF files holds important information as PSN Account ID, the key used to decrypt one of the SELF encryption layers.
PS Vita supports two different RIF file formats. The first format version (v0) is used by RIF files with 0x98 bytes size and the second version (v1) is used by RIF files with 0x200 bytes size. The difference between these formats is just the signature and some data used by PS Vita only. RIF version 0 only uses ECDSA Signature only whilst RIF Version 1 uses the ECDSA Signature and an extra RSA Signature.
Name | Offset | Size | Remarks |
---|---|---|---|
Version | 0x0 | 0x2 | |
Version Flag | 0x2 | 0x2 | 0 or 1 |
DRM Type | 0x4 | 0x2 | |
License Flags | 0x6 | 0x2 | 2: per-content, 0xD: PSP2 DRM Free, 0x400: PSP2 GameCard |
NP Account ID | 0x8 | 0x8 | NP Account ID (in little-endian) for Network and Local DRM, 8 first bytes of sha-1 of some key for Free DRM. |
Content ID | 0x10 | 0x30 | CONTENT_ID |
Encrypted account keyring index | 0x40 | 0x10 | Encrypted account keyring index for Network and Local DRM, 12 last bytes of sha-1 of some key + 4 bytes of zeroes for Free DRM. |
Encrypted RIF Key | 0x50 | 0x10 | Used to get klicensee to decrypt NPDRM SELF/SPRX/EDAT/PFS files. |
License start time | 0x60 | 0x8 | For human readable, convert to decimal and use an Epoch-Unix converter time format online. |
License expiration time | 0x68 | 0x8 | If zeroed, there is no time limit. Used for PS+ time-limited content for example. |
ECDSA Signature | 0x70 | 0x28 | Patched in most PS3 CFWs to allow unsigned RIF. See Rif_Junk on Rap2Rif by Flatz. Params are same as for act.dat. |
Some Flag | 0x98 | 0x4 | Used by PS Vita only, not PSP nor PS3. |
Some Flag | 0x9C | 0x4 | Used by PS Vita only, not PSP nor PS3. ex: ?0x400?. |
Encrypted RIF Key 2 | 0xA0 | 0x10 | Used by PS Vita only, not PSP nor PS3. Used to get klicensee to decrypt NPDRM SELF/SPRX/EDAT/PFS files. |
Unknown_B0 | 0xB0 | 0x10 | Used by PS Vita only, not PSP nor PS3. |
OpenPsId | 0xC0 | 0x10 | Used by PS Vita only, not PSP nor PS3. Checked only if License Flag 0x100 is set. |
Unknown_D0 | 0xD0 | 0x10 | Used by PS Vita only, not PSP nor PS3. |
CMD56 handshake part | 0xE0 | 0x14 | Used by PS Vita only, not PSP nor PS3. Checked only if License Flag 0x400 is set. |
Unknown_F4 | 0xF4 | 0x4 | Used by PS Vita only, not PSP nor PS3. Some flag related to debug_upgradable. ex: 0 (default), 1 (seen on a PSP2 gamecard). |
Unknown_F8 | 0xF8 | 0x4 | Used by PS Vita only, not PSP nor PS3. |
SKU flag | 0xFC | 0x4 | Used by PS Vita only, not PSP nor PS3. Some flag related to debug_upgradable. |
RSA Signature | 0x100 | 0x100 | Used by PS Vita only, not PSP nor PS3. |
PSM-ACT
PSM Activation file
Name | Offset | Size | Example | Remark |
---|---|---|---|---|
Magic | 0x0 | 0x8 | "PSM-ACT" | |
Unknown1 | 0x8 | 0x8 | 00 00 00 00 00 00 00 00 | |
Account Id | 0x10 | 0x8 | 91 78 34 02 01 EF CD AB | PSN account ID (little endian) |
Unknown2 | 0x18 | 0x4 | 00 00 00 00 | Must be 0 |
Unknown3 | 0x1C | 0x4 | 00 00 00 00 | Must be 0 |
Activation start time | 0x20 | 0x8 | 00 00 01 4C 16 4D 83 A8 | |
Activation expiration time | 0x28 | 0x8 | 00 00 04 2A D4 3D 3E 68 | |
SHA256 from act.dat | 0x30 | 0x20 | SHA256 digest of get_act_data (0x39222A58) | |
Unknown4 | 0x50 | 0xB0 | Zeros | |
Unknown5 | 0x100 | 0x200 | KEY saved at 0x22C8 - Decrypted with 0x2288 | |
RSA signature | 0x300 | 0x100 |
PSM-RIF
PSM RIF file
Name | Offset | Size | Example | Remark |
---|---|---|---|---|
Magic | 0x0 | 0x8 | "PSM-RIF" | |
Unknown1 | 0x8 | 0x4 | 00 00 00 01 | Maybe Version and Version Flag? |
Unknown2 | 0xC | 0x4 | 00 00 00 00 | Maybe DRM Type and License Flags? |
Account ID | 0x10 | 0x8 | 91 78 34 02 01 EF CD AB | PSN account ID (little endian) |
Unknown3 | 0x18 | 0x4 | 00 00 00 00 | Must be 0 |
Unknown4 | 0x1C | 0x4 | 00 00 00 00 | Must be 0 |
Activation start time | 0x20 | 0x8 | 00 00 01 4C 16 4D 83 A8 | |
Activation expiration time | 0x28 | 0x8 | 7F FF FF FF FF FF FF FF | Max Value |
SHA256 from act.dat | 0x30 | 0x20 | SHA256 digest of get_act_data (0x39222A58) | |
Content ID | 0x50 | 0x30 | EM0041-NPOA00013_00-0000000000000000 | |
Unknown5 | 0x80 | 0x80 | Zeros | |
Unknown6 | 0x100 | 0x200 | Key saved at 0x1F40. First 0x200 bytes are decrypted with 0x22C8 and then only the first 0x20 bytes are again decrypted with 0x2288 | |
RSA signature | 0x300 | 0x100 |