SceNpDrm: Difference between revisions
CelesteBlue (talk | contribs) |
|||
(57 intermediate revisions by 2 users not shown) | |||
Line 5: | Line 5: | ||
! Version !! World !! Privilege | ! Version !! World !! Privilege | ||
|- | |- | ||
| | | 0.990.000-3.740.011 || Non-secure || Kernel | ||
|} | |} | ||
Line 16: | Line 16: | ||
! Version !! Name !! World !! Visibility !! NID | ! Version !! Name !! World !! Visibility !! NID | ||
|- | |- | ||
| 1. | | 1.000.071-3.740.011 || [[SceNpDrm#SceNpDrm|SceNpDrm]] || Non-secure || User || 0xF2799B1B | ||
|- | |- | ||
| | | 0.990.000-3.740.011 || [[SceNpDrm#SceNpDrmForDriver|SceNpDrmForDriver]] || Non-secure || Kernel || 0xD84DC44A | ||
|- | |- | ||
| 1. | | 1.000.071-3.740.011 || [[SceNpDrm#SceNpDrmPackage|SceNpDrmPackage]] || Non-secure || User || 0x88514DB2 | ||
|- | |- | ||
| 3. | | 1.800.071-3.570.011 || [[SceNpDrm#ScePsmDrm|ScePsmDrm]] || Non-secure || User || 0x3F2B0888 | ||
|- | |- | ||
| 3. | | 1.800.071-3.740.011 || [[SceNpDrm#ScePsmDrmForDriver|ScePsmDrmForDriver]] || Non-secure || Kernel || 0x9F4924F2 | ||
|} | |} | ||
Line 39: | Line 39: | ||
| 0x0008 || 0x8 || unknown | | 0x0008 || 0x8 || unknown | ||
|- | |- | ||
| 0x0010 || 0xC0 || | | 0x0010 || 0xC0 || Static keys decrypted with [[SceSblAuthMgr#sceSblAuthMgrGetEKcForDriver|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#sceSblAimgrGetConsoleIdForDriver|sceSblAimgrGetConsoleIdForDriver]]. | ||
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 from the content's .rif file and select one of the 5 scenarios for decrypting RIF Key into klicensee based on DRM Type (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 are data only used for some PS Vita contents (maybe only PS Vita gamecards require a 0x200-byte RIF). | |||
=== Scenario 1 - maybe DRM Free === | === Scenario 1 - maybe DRM Free === | ||
Line 113: | Line 116: | ||
Take static keys 3, 4. | Take static keys 3, 4. | ||
Take first 0x70 bytes of RIF | Take first 0x70 bytes of RIF. | ||
Use [[SceSblAuthMgr# | Use [[SceSblAuthMgr#sceSblAuthMgrDecBindDataForDriver]] to decrypt RIF key 2 and obtain klicensee. | ||
=== Scenario 2 === | === Scenario 2 === | ||
Line 123: | Line 126: | ||
Take primary keys 1, 2. | Take primary keys 1, 2. | ||
Take first 0x70 bytes of RIF | Take first 0x70 bytes of RIF. | ||
Use [[SceSblAuthMgr# | Use [[SceSblAuthMgr#sceSblAuthMgrDecBindDataForDriver]] to decrypt RIF key 2 and obtain klicensee. | ||
=== Scenario 3 - Game Cartridge === | === Scenario 3 - Game Cartridge === | ||
Line 133: | Line 136: | ||
Take cmd56 handshake keys with [[SceSblGcAuthMgr#get_5018_data|get_5018_data]]. | Take cmd56 handshake keys with [[SceSblGcAuthMgr#get_5018_data|get_5018_data]]. | ||
Take first 0x70 bytes of RIF | Take first 0x70 bytes of RIF. | ||
Use [[SceSblAuthMgr# | Use [[SceSblAuthMgr#sceSblAuthMgrDecBindDataForDriver]] to decrypt RIF key 2 and obtain klicensee. | ||
=== Scenario 4 - Game Cartridge === | === Scenario 4 - Game Cartridge === | ||
Line 143: | Line 146: | ||
Take cmd56 handshake keys with [[SceSblGcAuthMgr#get_5018_data|get_5018_data]]. | Take cmd56 handshake keys with [[SceSblGcAuthMgr#get_5018_data|get_5018_data]]. | ||
Take first 0x70 bytes of RIF | Take first 0x70 bytes of RIF. | ||
Erase RIF Key 1 from RIF | Erase RIF Key 1 from RIF. | ||
Use [[SceSblAuthMgr# | Use [[SceSblAuthMgr#sceSblAuthMgrDecBindDataForDriver]] to decrypt RIF key 1 and obtain klicensee. | ||
=== Scenario 5 === | === Scenario 5 === | ||
Decrypt Primary Table Key index from RIF | Take RIF Key 1. | ||
Decrypt Primary Table Key index from RIF with static key 2 using AES (need to figure out which AES exactly). | |||
Take primary key using decrypted index. | Take primary key using decrypted index. | ||
Line 157: | Line 162: | ||
Decrypt RIF key 1 with obtained primary key using AES (need to figure out which AES exactly). | Decrypt RIF key 1 with obtained primary key using AES (need to figure out which AES exactly). | ||
== | == RIF Name Generation == | ||
<source lang="C"> | <source lang="C"> | ||
Line 168: | Line 173: | ||
AES_ctx ctx; | AES_ctx ctx; | ||
AES_set_key(&ctx, rif_name_keys, 0x80); | AES_set_key(&ctx, rif_name_keys, 0x80); | ||
for (int i = 0; i < size; i += 0x10) AES_encrypt(&ctx, buf+i, buf+i); | |||
for (i = 0; i < size; i += 0x10) | |||
} | } | ||
typedef struct { | typedef struct SceNpDrmRifNameWork { // size is 0x10 | ||
SceBool is_fixed; | |||
SceUInt32 reserved; | |||
} | SceUInt64 account_id; | ||
} SceNpDrmRifNameWork; | |||
void getRifName(char *rif_name, SceSize length, SceUInt64 account_id, SceBool is_fixed) { | |||
SceNpDrmRifNameWork rif_name_work; | |||
rif_name_work.is_fixed = is_fixed; | |||
rif_name_work.account_id = account_id; | |||
aes_encrypt(& | aes_encrypt(&rif_name_work, sizeof(SceNpDrmRifName), rif_name_keys); | ||
snprintf(rif_name, length, "%016llx%016llx.rif", __builtin_bswap64(((SceUInt64 *)&rif_name_work)[0]), __builtin_bswap64(((SceUInt64 *)&rif_name_work)[1])); | |||
snprintf( | |||
} | } | ||
</source> | </source> | ||
Line 197: | Line 198: | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
| 1. | | 1.000.071-3.740.011 || 0x4458812B | ||
|} | |} | ||
<source lang="C"> | <source lang="C"> | ||
// | typedef struct SceNpDrmCheckDrmResetOpt { // size is 0x18 | ||
int _sceNpDrmCheckDrmReset( | SceUInt64 account_id; | ||
SceBool *pReset; // Set to SCE_TRUE if act.dat was reset during the function call | |||
SceSize in_size; // in_size must not exceed 0x40 | |||
SceUInt64 reserved; | |||
} SceNpDrmCheckDrmResetOpt; | |||
// in_addr byte 0 must not be 0 | |||
// in_addr byte 1 contains flags: 0x40, 0x80 | |||
// size must not exceed 0x40 | |||
int _sceNpDrmCheckDrmReset(const void *in_addr, SceSize size, SceNpDrmCheckDrmResetOpt *pOpt); | |||
</source> | </source> | ||
Line 212: | Line 220: | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
| 1. | | 1.000.071-3.740.011 || 0x507D06A6 | ||
|} | |} | ||
Removes NPDRM per-console activation data at tm0:/npdrm/act.dat. | |||
<source lang="C"> | <source lang="C"> | ||
// | // pAccountId of removed tm0:/npdrm/act.dat | ||
int _sceNpDrmRemoveActData( | >int _sceNpDrmRemoveActData(SceUInt64 *pAccountId); | ||
</source> | </source> | ||
Line 227: | Line 235: | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
| 1. | | 1.000.071-3.740.011 || 0xB8C5DA7C | ||
|} | |} | ||
<source lang="C">int _sceNpDrmGetRifName(char * | Calls [[#sceNpDrmGetRifNameForDriver]]. | ||
<source lang="C">int _sceNpDrmGetRifName(char *rif_name, SceUInt64 account_id);</source> | |||
=== _sceNpDrmGetRifNameForInstall === | === _sceNpDrmGetRifNameForInstall === | ||
Line 237: | Line 247: | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
| 1. | | 1.000.071-3.740.011 || 0xD312424D | ||
|} | |} | ||
Calls [[#sceNpDrmGetRifNameForInstallForDriver]]. | |||
<source lang="C"> | <source lang="C"> | ||
// | // rif_name is of size 0x30 | ||
// | // license is of size 0x200 | ||
int _sceNpDrmGetRifNameForInstall(char * | int _sceNpDrmGetRifNameForInstall(char *rif_name, const void *license, SceBool is_fixed); | ||
</source> | </source> | ||
Line 251: | Line 263: | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
| 1. | | 1.000.071-3.740.011 || 0xE8343660 | ||
|} | |} | ||
<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 | char license_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]; | ||
SceUInt64 lic_start_time; | |||
SceUInt64 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* license_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; | |||
// license is of size 0x200 | |||
int _sceNpDrmGetRifInfo(void *license, SceSize rif_size, SceUInt32 num, _sceNpDrmGetRifInfo_opt* pOpt); | |||
</source> | </source> | ||
Line 293: | Line 301: | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
| 1. | | 1.000.071-3.740.011 || 0xE935B0FC | ||
|} | |} | ||
<source lang="C">int _sceNpDrmGetFixedRifName(char * | <source lang="C">int _sceNpDrmGetFixedRifName(char *rif_name, SceUInt64 account_id);</source> | ||
=== _sceNpDrmCheckActData === | === _sceNpDrmCheckActData === | ||
Line 303: | Line 311: | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
| 1. | | 1.000.071-3.740.011 || 0xFEEBCD62 | ||
|} | |} | ||
Calls [[#sceNpDrmCheckActDataForDriver]]. | |||
<source lang="C"> | <source lang="C"> | ||
// | typedef struct SceNpDrmCheckActDataOpt { // size is 0x10 | ||
int _sceNpDrmCheckActData( | SceUInt64 act_start_time; | ||
SceUInt64 act_exp_time; | |||
} SceNpDrmCheckActDataOpt; | |||
int _sceNpDrmCheckActData(SceUInt32 *act_type, SceUInt32 *unk2, SceUInt64 *pAccountId, SceNpDrmCheckActDataOpt *pOpt); | |||
</source> | </source> | ||
Line 316: | Line 330: | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
| 3. | | 0.931.010-1.692.000 || not present | ||
|- | |||
| 1.800.071-3.740.011 || 0x2523F57F | |||
|} | |} | ||
Calls [[#sceNpDrmPresetRifProvisionalFlagForDriver]](license, SCE_TRUE). | |||
<source lang="C"> | <source lang="C"> | ||
// | // license is of size 0x200 | ||
int _sceNpDrmPresetRifProvisionalFlag(void* | int _sceNpDrmPresetRifProvisionalFlag(void *license); | ||
</source> | </source> | ||
Line 331: | Line 349: | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
| 3. | | 0.990.000-3.740.011 || 0xDB406EAE | ||
|} | |} | ||
<source lang="C"> | <source lang="C"> | ||
// | // pContentId is of size 0x30 | ||
int sceNpDrmGetRifInfoForDriver(void* | int sceNpDrmGetRifInfoForDriver(const void *license, SceSize license_size, int check_sign, char *pContentId, SceUInt64 *pAccountId, int *pLicenseVersion, int *pDrmType, int *pFlags, int *pSkuFlags, SceUInt64 *pLicStartTime, SceUInt64 *pLicExpTime, SceUInt64 *pFlags2); | ||
</source> | </source> | ||
Line 344: | Line 362: | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
| 3. | | 1.500.151-3.740.011 || 0x3BFD2850 | ||
|} | |} | ||
Line 354: | Line 372: | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
| 3. | | 0.990.000-3.740.011 || 0x5D73448C | ||
|} | |} | ||
<source lang="C"> | <source lang="C"> | ||
// | // rif_name is of size 0x30 | ||
int sceNpDrmGetFixedRifNameForDriver(char * | int sceNpDrmGetFixedRifNameForDriver(char *rif_name, SceUInt64 account_id); | ||
</source> | </source> | ||
Line 367: | Line 385: | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
| 3. | | 0.990.000-3.740.011 || 0xDF62F3B8 | ||
|} | |} | ||
Gets the RIF name for the provided NP Account ID, in order to read the license file from the good path. | |||
<source lang="C"> | <source lang="C"> | ||
// | // rif_name is of size 0x30 | ||
int sceNpDrmGetRifNameForDriver(char * | int sceNpDrmGetRifNameForDriver(char *rif_name, SceUInt64 account_id); | ||
</source> | </source> | ||
Line 380: | Line 400: | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
| 3. | | 0.990.000-3.740.011 || 0x17573133 | ||
|} | |} | ||
Gets the RIF name for the provided license, in order to install (write) this license file to the good path. | |||
<source lang="C"> | <source lang="C"> | ||
// | // rif_name is of size 0x30 | ||
// | // if is_fixed is set, the Content ID is not used to generate the RIF name | ||
int sceNpDrmGetRifNameForInstallForDriver(char * | int sceNpDrmGetRifNameForInstallForDriver(char *rif_name, const void *license, SceBool is_fixed); | ||
</source> | </source> | ||
Line 394: | Line 416: | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
| 3. | | 0.931.010-1.692.000 || not present | ||
|- | |||
| 1.800.071-3.740.011 || 0xC070FE89 | |||
|} | |} | ||
Updates license buffer by setting or unsetting the provisional flag. This way, the license RSA signature becomes invalid altough the ECDSA signature should remain valid. | |||
<source lang="C"> | <source lang="C"> | ||
int sceNpDrmPresetRifProvisionalFlagForDriver(void *license, SceBool enable); | |||
int sceNpDrmPresetRifProvisionalFlagForDriver(void* | |||
</source> | </source> | ||
Line 407: | Line 432: | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
| 3. | | 0.990.000-3.740.011 || 0x9265B350 | ||
|} | |} | ||
Gets information about NPDRM per-console activation data at tm0:/npdrm/act.dat. | |||
int sceNpDrmCheckActDataForDriver( | <source lang="C">int sceNpDrmCheckActDataForDriver(SceUInt32 *act_type, SceUInt32 *unk2, SceUInt64 *pAccountId, SceUInt64 *act_start_time, SceUInt64 *act_exp_time);</source> | ||
</source> | |||
=== sceNpDrmRemoveActDataForDriver === | === sceNpDrmRemoveActDataForDriver === | ||
Line 423: | Line 444: | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
| 3. | | 0.990.000-3.740.011 || 0x8B85A509 | ||
|} | |} | ||
Removes NPDRM per-console activation data at tm0:/npdrm/act.dat. | |||
<source lang="C">int sceNpDrmRemoveActDataForDriver( | <source lang="C"> | ||
// pAccountId of removed tm0:/npdrm/act.dat | |||
int sceNpDrmRemoveActDataForDriver(SceUInt64 *pAccountId); | |||
</source> | |||
=== sceNpDrmUpdateAccountIdForDriver === | === sceNpDrmUpdateAccountIdForDriver === | ||
Line 435: | Line 459: | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
| 3. | | 2.100.081-3.740.011 || 0x116FC0D6 | ||
|} | |} | ||
<source lang="C">int sceNpDrmUpdateAccountIdForDriver( | <source lang="C">int sceNpDrmUpdateAccountIdForDriver(SceUInt64 account_id);</source> | ||
=== | === sceNpDrmPspEbootSigGenForDriver === | ||
{| class="wikitable" | {| class="wikitable" | ||
|- | |- | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
| 3. | | 0.931.010-1.06 || not present | ||
|- | |||
| 1.500.151-3.740.011 || 0xEF387FC4 | |||
|} | |} | ||
<source lang="C">int | <source lang="C"> | ||
// npumdsig is of size 0x100 | |||
int sceNpDrmPspEbootSigGenForDriver(const char *eboot_path, const void *hash_sha256, void *npumdsig); | |||
</source> | |||
=== | === sceNpDrmPspEbootVerifyForDriver === | ||
{| class="wikitable" | {| class="wikitable" | ||
|- | |- | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
| 3. | | 0.931.010-1.06 || not present | ||
|- | |||
| 1.500.151-3.740.011 || 0xB6CA3A2C | |||
|} | |} | ||
<source lang="C">int | <source lang="C">int sceNpDrmPspEbootVerifyForDriver(const char *eboot_path, const void *npumdsig);</source> | ||
=== | === sceNpDrmEbootSigGenPspForDriver === | ||
{| class="wikitable" | {| class="wikitable" | ||
|- | |- | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
| 3. | | 0.931.010-1.692.000 || not present | ||
|- | |||
| 1.800.071-3.740.011 || 0x90B1A6D3 | |||
|} | |} | ||
<source lang="C"> | <source lang="C"> | ||
// | // npumdsig is of size 0x200 | ||
int sceNpDrmEbootSigGenPspForDriver(const char *eboot_path, const void *hash_sha256, void *npumdsig, SceUInt32 systemSwVersion); | |||
int | |||
</source> | </source> | ||
=== | === sceNpDrmEbootSigGenPs1ForDriver === | ||
{| class="wikitable" | {| class="wikitable" | ||
|- | |- | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
| 3. | | 0.931.010-1.692.000 || not present | ||
|- | |||
| 1.800.071-3.740.011 || 0x6D9223E1 | |||
|} | |} | ||
<source lang="C"> | |||
// npumdsig is of size 0x200 | |||
int sceNpDrmEbootSigGenPs1ForDriver(const char *eboot_path, const void *hash_sha256, void *npumdsig, SceUInt32 systemSwVersion); | |||
</source> | |||
=== sceNpDrmEbootSigGenMultiDiscForDriver === | |||
== | |||
{| class="wikitable" | {| class="wikitable" | ||
|- | |- | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
| 3. | | 0.931.010-1.692.000 || not present | ||
|- | |||
| 1.800.071-3.740.011 || 0x39A7A666 | |||
|} | |} | ||
<source lang="C">int | <source lang="C"> | ||
// multidisc_ctx is of size 0xC8 at least | |||
// npumdsig is of size 0x200 | |||
int sceNpDrmEbootSigGenMultiDiscForDriver(const char *eboot_path, const void *multidisc_ctx, void *npumdsig, SceUInt32 systemSwVersion); | |||
</source> | |||
=== | === sceNpDrmEbootSigVerifyForDriver === | ||
{| class="wikitable" | {| class="wikitable" | ||
|- | |- | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
| 3. | | 0.931.010-1.692.000 || not present | ||
|- | |||
| 1.800.071-3.740.011 || 0x7A319692 | |||
|} | |} | ||
<source lang="C">int | <source lang="C"> | ||
// npumdsig is of size 0x200 | |||
int sceNpDrmEbootSigVerifyForDriver(const char *eboot_path, const void *npumdsig); | |||
</source> | |||
=== | === sceNpDrmEbootSigConvertForDriver === | ||
{| class="wikitable" | {| class="wikitable" | ||
|- | |- | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
| 3. | | 0.931.010-1.692.000 || not present | ||
|- | |||
| 1.800.071-3.740.011 || 0xA29B75F9 | |||
|} | |} | ||
<source lang="C">int | <source lang="C"> | ||
// npumdsig is of size 0x200 | |||
// new_npumdsig is of size 0x200 | |||
int sceNpDrmEbootSigConvertForDriver(const char *eboot_path, const void *npumdsig, void *new_npumdsig); | |||
</source> | |||
=== | === sceNpDrmGetLegacyDocKeyForDriver === | ||
{| class="wikitable" | {| class="wikitable" | ||
|- | |- | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
| 3. | | 0.990.000-3.740.011 || 0x4E321BDE | ||
|} | |} | ||
<source lang="C">int | Gets klicensee to decrypt encrypted DOCUMENT.DAT. | ||
<source lang="C"> | |||
// pLegacyDocKey is of size 0x10 bytes | |||
int sceNpDrmGetLegacyDocKeyForDriver(void *pRif, void *pDocEdat, SceSize docEdatSize, void *pLegacyDocKey); | |||
</source> | |||
=== sceNpDrmIsLooseAccountBindForDriver === | === sceNpDrmIsLooseAccountBindForDriver === | ||
Line 531: | Line 588: | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
| 3. | | 0.931.010-1.692.000 || not present | ||
|- | |||
| 1.800.071-3.740.011 || 0xFC84CA1A | |||
|} | |} | ||
Line 541: | Line 600: | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
| 3. | | 0.931.010-2.06 || 0xA91C7443 | ||
|- | |||
| 2.100.081-3.740.011 || 0xA91C7443 | |||
|} | |} | ||
Updates SceNpdrm global variables based on /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 553: | Line 614: | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
| 3. | | 0.990.000-3.740.011 || 0xDACB71F4 | ||
|} | |} | ||
<source lang="C"> | <source lang="C">int sceNpDrmGetRifPspKeyForDriver(const void *license, void *klicensee, SceUInt32 *flags, SceUInt64 *lic_start_time, SceUInt64 *lic_exp_time);</source> | ||
int sceNpDrmGetRifPspKeyForDriver(void * | |||
=== sceNpDrmGetRifVitaKeyForDriver === | === sceNpDrmGetRifVitaKeyForDriver === | ||
Line 566: | Line 624: | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
| 3. | | 0.990.000-3.740.011 || 0x723322B5 | ||
|} | |} | ||
This function calls [[#sceNpDrmGetRifInfoForDriver]] to get required fields. | |||
<source lang="C"> | <source lang="C">int sceNpDrmGetRifVitaKeyForDriver(const void *license, void *klicensee, SceUInt32 *flags, SceUInt32 *sku_flags, SceUInt64 *lic_start_time, SceUInt64 *lic_exp_time);</source> | ||
int sceNpDrmGetRifVitaKeyForDriver(void * | |||
</source> | |||
=== | === sceNpDrmWriteActDataForDriver === | ||
{| class="wikitable" | {| class="wikitable" | ||
|- | |- | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
| 0.990-3. | | 0.990.000-3.740.011 || 0x742EBAF4 | ||
|} | |} | ||
Related to | Related to [[SceSblGcAuthMgr#sceSblGcAuthMgrPcactActivationForDriver]]. | ||
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 602: | Line 658: | ||
<source lang="C"> | <source lang="C"> | ||
// | // npdrm_act_data is of size 0x1040 | ||
int | int sceNpDrmWriteActDataForDriver(void *npdrm_act_data, const char *aes_dec_key); | ||
</source> | </source> | ||
=== | === sceNpDrmReadActDataForDriver === | ||
{| class="wikitable" | {| class="wikitable" | ||
|- | |- | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
| 3. | | 0.990.000-3.740.011 || 0xD91C3BCE | ||
|} | |} | ||
Related to | Related to [[SceSblGcAuthMgr#sceSblGcAuthMgrPcactGetChallengeForDriver]]. | ||
Reads 0x1038 bytes of tm0:/npdrm/act.dat. | |||
<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> | ||
Line 628: | Line 684: | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
| 3. | | 0.990.000-3.740.011 || 0xFE7B17B6 | ||
|} | |} | ||
Verifies ECDSA - SHA1 pair and/or RSA - SHA256 pair. | |||
<source lang="C"> | <source lang="C"> | ||
// | // license max size is 0x200 | ||
int sceNpDrmVerifyRifForDriver(void * | int sceNpDrmVerifyRifForDriver(const void *license, SceSize license_size); | ||
</source> | </source> | ||
Line 643: | Line 699: | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
| 3. | | 0.990.000-3.740.011 || 0xFF63672D | ||
|} | |} | ||
Line 653: | Line 709: | ||
<source lang="C"> | <source lang="C"> | ||
// | // license is of unknown size but at least 0xF8 | ||
int sceNpDrmVerifyRifFullForDriver(void * | int sceNpDrmVerifyRifFullForDriver(const void *license); | ||
</source> | </source> | ||
Line 662: | Line 718: | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
| 3. | | 0.990.000-3.740.011 || 0x077926F5 | ||
|} | |} | ||
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 733: | ||
decrypts Primary Key Table | decrypts Primary Key Table | ||
<source lang="C"> | <source lang="C">int sceNpDrmUpdateActDataForDriver(void);</source> | ||
int sceNpDrmUpdateActDataForDriver(void); | |||
</source> | |||
== SceNpDrmPackage == | == SceNpDrmPackage == | ||
Line 688: | Line 742: | ||
! 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 755: | ||
! 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 768: | ||
! 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 778: | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
| 1.69 | | 1.69-3.740.011 || 0xB9337914 | ||
|} | |} | ||
<source lang="C">int sceNpDrmPackageIsGameExist();</source> | <source lang="C">int sceNpDrmPackageIsGameExist(void);</source> | ||
=== _sceNpDrmPackageInstallStarted === | === _sceNpDrmPackageInstallStarted === | ||
Line 744: | Line 788: | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
| 1.69 | | 1.69-3.60 || 0xCEC18DA4 | ||
|} | |} | ||
<source lang="C"> | <source lang="C"> | ||
//opt is of size 0x10 | // opt is of size 0x10 | ||
int _sceNpDrmPackageInstallStarted(int unk0, int unk1, int unk2, void* opt); | int _sceNpDrmPackageInstallStarted(int unk0, int unk1, int unk2, void* opt); | ||
</source> | </source> | ||
Line 759: | Line 801: | ||
! 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; // offset in the encrypted data | |||
SceOff offset; // | SceUInt32 identifier; | ||
SceUInt32 unk_C; | |||
} _sceNpDrmPackageDecrypt_opt; | } _sceNpDrmPackageDecrypt_opt; | ||
int _sceNpDrmPackageDecrypt(void * buffer, SceSize size, _sceNpDrmPackageDecrypt_opt * | int _sceNpDrmPackageDecrypt(void *buffer, SceSize size, _sceNpDrmPackageDecrypt_opt *pOpt); | ||
</source> | </source> | ||
Line 780: | Line 819: | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
| 1.69 | | 1.69-3.60 || 0xED0471FE | ||
|} | |} | ||
Line 796: | Line 833: | ||
<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 809: | Line 846: | ||
<source lang="C"> | <source lang="C"> | ||
//opt is of size 0x10 | // opt is of size 0x10 | ||
int _sceNpDrmPackageUninstallStarted(int unk0, int unk1, int unk2, void* opt); | int _sceNpDrmPackageUninstallStarted(int unk0, int unk1, int unk2, void* opt); | ||
</source> | </source> | ||
Line 823: | Line 860: | ||
<source lang="C">int sceNpDrmPackageUninstallOngoing(int unk0, int unk1);</source> | <source lang="C">int sceNpDrmPackageUninstallOngoing(int unk0, int unk1);</source> | ||
=== | === SceNpDrmPackage_200D2DE4 === | ||
{| class="wikitable" | {| class="wikitable" | ||
|- | |- | ||
Line 831: | Line 868: | ||
|} | |} | ||
<source lang="C">int | <source lang="C">int SceNpDrmPackage_200D2DE4(int unk0, int unk1);</source> | ||
=== | === SceNpDrmPackage_4665E75A === | ||
{| class="wikitable" | {| class="wikitable" | ||
|- | |- | ||
Line 842: | Line 879: | ||
<source lang="C"> | <source lang="C"> | ||
//opt is of size 0x10 | // opt is of size 0x10 | ||
int | int SceNpDrmPackage_4665E75A(int unk0, int unk1, int unk2, void *opt); | ||
</source> | </source> | ||
=== | === SceNpDrmPackage_640C1724 === | ||
{| class="wikitable" | {| class="wikitable" | ||
|- | |- | ||
Line 855: | Line 892: | ||
<source lang="C"> | <source lang="C"> | ||
//opt is of size 0x8 | // opt is of size 0x8 | ||
int | int SceNpDrmPackage_640C1724(int unk0, int unk1, int unk2, void *opt); | ||
</source> | </source> | ||
=== | === SceNpDrmPackage_97BB85BD === | ||
{| class="wikitable" | {| class="wikitable" | ||
|- | |- | ||
Line 868: | Line 905: | ||
<source lang="C"> | <source lang="C"> | ||
//opt is of size 0x10 | // opt is of size 0x10 | ||
int | int SceNpDrmPackage_97BB85BD(int unk0, int unk1, int unk2, void *opt) | ||
</source> | </source> | ||
=== | === SceNpDrmPackage_A5E0F38C === | ||
{| class="wikitable" | {| class="wikitable" | ||
|- | |- | ||
Line 880: | Line 917: | ||
|} | |} | ||
<source lang="C">int | <source lang="C">int SceNpDrmPackage_A5E0F38C(int unk0, int unk1);</source> | ||
=== | === SceNpDrmPackage_C75A775B === | ||
{| class="wikitable" | {| class="wikitable" | ||
|- | |- | ||
Line 891: | Line 928: | ||
<source lang="C"> | <source lang="C"> | ||
//opt is of size 0x8 | // opt is of size 0x8 | ||
int | int SceNpDrmPackage_C75A775B(int unk0, int unk1, int unk2, void *opt); | ||
</source> | </source> | ||
== ScePsmDrm == | == ScePsmDrm == | ||
=== | === scePsmDrmGetRifName === | ||
{| class="wikitable" | {| class="wikitable" | ||
|- | |- | ||
Line 904: | Line 941: | ||
| 3.60 || 0x0D6470DA | | 3.60 || 0x0D6470DA | ||
|} | |} | ||
This is a guessed name. | |||
<source lang="C"> | <source lang="C"> | ||
// | // license is of size 0x400 | ||
int | int scePsmDrmGetRifName(char *rif_name, const void *license); | ||
</source> | </source> | ||
=== | === scePsmDrmGetDebugRifName === | ||
{| class="wikitable" | {| class="wikitable" | ||
|- | |- | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
| 3.60 || | | 3.60 || 0x3E881391 | ||
|} | |} | ||
This is a guessed name. | |||
int | <source lang="C">int scePsmDrmGetDebugRifName(char *rif_name);</source> | ||
</source> | |||
=== | === scePsmDrmGetRifInfo === | ||
{| class="wikitable" | {| class="wikitable" | ||
|- | |- | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
| 3.60 || | | 3.60 || 0xE31A6220 | ||
|} | |} | ||
<source lang="C"> | <source lang="C"> | ||
typedef struct ScePsmDrmGetRifInfoOpt { //size is 0x10 | |||
SceUInt64 lic_start_time; | |||
SceUInt64 lic_exp_time; | |||
} ScePsmDrmGetRifInfoOpt; | |||
int scePsmDrmGetRifInfo(void *license, char *content_id, void *account_id, ScePsmDrmGetRifInfoOpt *pOpt); | |||
int | |||
</source> | </source> | ||
=== | === scePsmDrmGetRifPsmKey === | ||
{| class="wikitable" | {| class="wikitable" | ||
|- | |- | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
| 3.60 || | | 3.60 || 0x207A2C53 | ||
|} | |} | ||
<source lang="C">int | <source lang="C"> | ||
/** | |||
* license is of size 0x400 | |||
* klicensee is of size 0x200 | |||
**/ | |||
int scePsmDrmGetRifPsmKey(void *license, void *klicensee, SceUInt32 *flags, SceUInt64 *lic_start_time, SceUInt64 *lic_exp_time); | |||
</source> | |||
=== | === scePsmDrmRemoveActData === | ||
{| class="wikitable" | {| class="wikitable" | ||
|- | |- | ||
! Version !! NID | ! Version !! NID | ||
|- | |- | ||
| 3.60 || | | 3.60 || 0x0E193CBB | ||
|} | |} | ||
<source lang="C">int | <source lang="C"> | ||
// pAccountId of removed tm0:/psmdrm/act.dat | |||
int scePsmDrmRemoveActData(SceUInt64 *pAccountId); | |||
</source> | |||
=== | === scePsmDrmCheckActData === | ||
{| class="wikitable" | {| class="wikitable" | ||
|- | |- | ||
Line 975: | Line 1,014: | ||
| 3.60 || 0xA89653B3 | | 3.60 || 0xA89653B3 | ||
|} | |} | ||
Calls [[#scePsmDrmCheckActDataForDriver]]. | |||
<source lang="C"> | <source lang="C"> | ||
// | typedef struct SceNpDrmCheckActDataOpt { // size is 0x10 | ||
int | SceUInt64 act_start_time; | ||
SceUInt64 act_exp_time; | |||
} SceNpDrmCheckActDataOpt; | |||
int scePsmDrmCheckActData(SceUInt32 *act_type, SceUInt32 *unk2, SceUInt64 *pAccountId, SceNpDrmCheckActDataOpt *pOpt); | |||
</source> | </source> | ||
Line 991: | Line 1,036: | ||
|} | |} | ||
This function is named after sceNpDrmGetRifInfoForDriver since arguments are very similar. | This function is named after [[#sceNpDrmGetRifInfoForDriver]] since arguments are very similar. | ||
<source lang="C"> | <source lang="C"> | ||
// | // license is of size 0x400 | ||
//content_id is of size 0x30 | // content_id is of size 0x30 | ||
int scePsmDrmGetRifInfoForDriver(void *license, char *content_id, SceUInt64 *account_id, SceUInt64 *lic_start_time, SceUInt64 *lic_exp_time); | |||
int scePsmDrmGetRifInfoForDriver( | |||
</source> | </source> | ||
=== | === scePsmDrmGetRifPsmKeyForDriver === | ||
{| class="wikitable" | {| class="wikitable" | ||
|- | |- | ||
Line 1,010: | Line 1,052: | ||
|} | |} | ||
This function is named after [[#sceNpDrmGetRifVitaKeyForDriver]] since arguments are very similar. | |||
<source lang="C"> | <source lang="C"> | ||
// | // license is of size 0x400 | ||
// | // klicensee is of size 0x200 | ||
int scePsmDrmGetRifPsmKeyForDriver(const void *license, void *klicensee, SceUInt32 *flags, SceUInt64 *lic_start_time, SceUInt64 *lic_exp_time); | |||
int | |||
</source> | </source> | ||
=== | === scePsmDrmWriteActDataForDriver === | ||
{| class="wikitable" | {| class="wikitable" | ||
|- | |- | ||
Line 1,031: | Line 1,070: | ||
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,038: | Line 1,077: | ||
<source lang="C"> | <source lang="C"> | ||
// | // psm_act_data is of size 0x400 | ||
int | int scePsmDrmWriteActDataForDriver(void *psm_act_data, const char *aes_dec_key); | ||
</source> | </source> | ||
=== | === scePsmDrmRemoveActDataForDriver === | ||
{| class="wikitable" | {| class="wikitable" | ||
|- | |- | ||
Line 1,050: | Line 1,089: | ||
|} | |} | ||
Removes PSM DRM per-console activation data at tm0:/psmdrm/act.dat. | |||
<source lang="C">int | <source lang="C"> | ||
// pAccountId of removed tm0:/psmdrm/act.dat | |||
int scePsmDrmRemoveActDataForDriver(SceUInt64 *pAccountId); | |||
</source> | |||
=== | === scePsmDrmUpdateActDataForDriver === | ||
{| class="wikitable" | {| class="wikitable" | ||
|- | |- | ||
Line 1,062: | Line 1,104: | ||
|} | |} | ||
reads tm0:/psmdrm/act.dat | |||
=== | verifies RSA with sha256 | ||
decrypts Primary Key Table | |||
<source lang="C">int scePsmDrmUpdateActDataForDriver(void);</source> | |||
=== scePsmDrmCheckActDataForDriver === | |||
{| class="wikitable" | {| class="wikitable" | ||
|- | |- | ||
Line 1,072: | Line 1,120: | ||
|} | |} | ||
<source lang="C">int | Gets information about currently loaded PSM act.dat. | ||
<source lang="C">int scePsmDrmCheckActDataForDriver(SceUInt32 *act_type, SceUInt32 *unk2, SceUInt64 *pAccountId, SceUInt64 *act_start_time, SceUInt64 *act_exp_time);</source> | |||
== 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,133: | ||
=== 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,140: | ||
== 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. | ||
The RIF files are used as | |||
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,097: | Line 1,148: | ||
! Name !! Offset !! Size !! Remarks | ! Name !! Offset !! Size !! Remarks | ||
|- | |- | ||
| | | Finalized Flag || 0x0 || 0x2 || ex: 0 for default, 0xFFFF (-1) for debug licenses | ||
|- | |- | ||
| Version | | Version || 0x0 || 0x2 || ex: 0, 1 | ||
|- | |- | ||
| License | | License Flags || 0x4 || 0x2 || See [https://www.psdevwiki.com/ps3/NPDRM#License_Flags]. | ||
|- | |- | ||
| | | DRM Type || 0x6 || 0x2 || See [https://www.psdevwiki.com/ps3/NPDRM#DRM_Type]. | ||
|- | |- | ||
| | | 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,168: | ||
| 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 || 0x4 || Used by PS Vita only, not PSP nor PS3. | |||
|- | |- | ||
| | | Provisional Flag || 0x9C || 0x4 || Used by PS Vita only, not PSP nor PS3. ex: 0, 1 (provisional flag). | ||
|- | |- | ||
| RIF Key 2 || 0xA0 || 0x10 || | | 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 || | | Unknown_B0 || 0xB0 || 0x10 || Used by PS Vita only, not PSP nor PS3. | ||
|- | |- | ||
| [[SceSblSsMgr#sceKernelGetOpenPsIdForDriver|OpenPsId]] || 0xC0 || 0x10 || | | [[SceSblSsMgr#sceKernelGetOpenPsIdForDriver|OpenPsId]] || 0xC0 || 0x10 || Used by PS Vita only, not PSP nor PS3. Checked only if DRM Type 0x100 is set. | ||
|- | |- | ||
| Unknown_D0 || 0xD0 || 0x10 || | | Unknown_D0 || 0xD0 || 0x10 || Used by PS Vita only, not PSP nor PS3. | ||
|- | |- | ||
| [[SceSblGcAuthMgr# | | [[SceSblGcAuthMgr#memcmp_safe_5018|CMD56 handshake part]] || 0xE0 || 0x14 || Used by PS Vita only, not PSP nor PS3. Checked only if DRM Type 0x400 is set. | ||
|- | |- | ||
| | | Unknown index || 0xF4 || 0x4 || Used by PS Vita only, not PSP nor PS3. Some index related to debug_upgradable. ex: 0 (default), 1 (seen on a PSP2 gamecard). Allowed range is 0 (default) and 1-0x20. | ||
|- | |- | ||
| Unknown_F8 || 0xF8 || 0x4 || | | Unknown_F8 || 0xF8 || 0x4 || Used by PS Vita only, not PSP nor PS3. | ||
|- | |- | ||
| SKU flag || 0xFC || 0x4 || | | SKU flag || 0xFC || 0x4 || Used by PS Vita only, not PSP nor PS3. Some flag related to debug_upgradable. | ||
|- | |- | ||
| RSA Signature || 0x100 || 0x100 || | | 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,201: | ||
! 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 || | | Account Id || 0x10 || 0x8 || 91 78 34 02 01 EF CD AB || NP Account ID (in little-endian) | ||
|- | |- | ||
| Unknown2 || 0x18 || 0x4 || 00 00 00 00 || Must be 0 | | Unknown2 || 0x18 || 0x4 || 00 00 00 00 || Must be 0 | ||
Line 1,171: | Line 1,225: | ||
== PSM-RIF == | == PSM-RIF == | ||
PSM RIF file | PSM RIF file | ||
Line 1,177: | Line 1,232: | ||
! Name !! Offset !! Size !! Example !! Remark | ! Name !! Offset !! Size !! Example !! Remark | ||
|- | |- | ||
| Magic | | Magic || 0x0 || 0x8 || "PSM-RIF" || | ||
|- | |- | ||
| | | Version || 0x8 || 0x4 || 00 00 00 01 || | ||
|- | |- | ||
| 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 || | | NP Account ID || 0x10 || 0x8 || 91 78 34 02 01 EF CD AB || NP Account ID (in little-endian) | ||
|- | |- | ||
| Unknown3 || | | Unknown3 || 0x18 || 0x4 || 00 00 00 00 || Must be 0 | ||
|- | |- | ||
| Unknown4 || | | Unknown4 || 0x1C || 0x4 || 00 00 00 00 || Must be 0 | ||
|- | |- | ||
| | | License start time || 0x20 || 0x8 || 00 00 01 4C 16 4D 83 A8 || | ||
|- | |- | ||
| | | License 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) | | SHA256 from act.dat || 0x30 || 0x20 || || SHA256 digest of get_act_data (0x39222A58) | ||
Line 1,199: | Line 1,254: | ||
| Unknown5 || 0x80 || 0x80 || || Zeros | | Unknown5 || 0x80 || 0x80 || || Zeros | ||
|- | |- | ||
| Unknown6 || 0x100 || 0x200 || || Key saved at 0x1F40. First 0x200 bytes are decrypted with 0x22C8 | | Unknown6 || 0x100 || 0x200 || || Key saved at 0x1F40. First 0x200 bytes are decrypted with 0x22C8 then only the first 0x20 bytes are again decrypted with 0x2288 | ||
|- | |- | ||
| RSA signature || 0x300 || 0x100 || || | | RSA signature || 0x300 || 0x100 || || | ||
|} | |} | ||
[[Category:ARM]] | |||
[[Category:Kernel]] | |||
[[Category:Modules]] | [[Category:Modules]] | ||
[[Category: | [[Category:Library]] |
Latest revision as of 01:42, 9 August 2023
Module
Version | World | Privilege |
---|---|---|
0.990.000-3.740.011 | Non-secure | Kernel |
Libraries
Known NIDs
Version | Name | World | Visibility | NID |
---|---|---|---|---|
1.000.071-3.740.011 | SceNpDrm | Non-secure | User | 0xF2799B1B |
0.990.000-3.740.011 | SceNpDrmForDriver | Non-secure | Kernel | 0xD84DC44A |
1.000.071-3.740.011 | SceNpDrmPackage | Non-secure | User | 0x88514DB2 |
1.800.071-3.570.011 | ScePsmDrm | Non-secure | User | 0x3F2B0888 |
1.800.071-3.740.011 | 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 sceSblAimgrGetConsoleIdForDriver.
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 from the content's .rif file and select one of the 5 scenarios for decrypting RIF Key into klicensee based on DRM Type (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 are data only used for some PS Vita contents (maybe only PS Vita gamecards 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.
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.
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.
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.
Erase RIF Key 1 from RIF.
Use SceSblAuthMgr#sceSblAuthMgrDecBindDataForDriver to decrypt RIF key 1 and obtain klicensee.
Scenario 5
Take RIF Key 1.
Decrypt Primary Table Key index from RIF 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).
RIF Name Generation
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); for (int i = 0; i < size; i += 0x10) AES_encrypt(&ctx, buf+i, buf+i); } typedef struct SceNpDrmRifNameWork { // size is 0x10 SceBool is_fixed; SceUInt32 reserved; SceUInt64 account_id; } SceNpDrmRifNameWork; void getRifName(char *rif_name, SceSize length, SceUInt64 account_id, SceBool is_fixed) { SceNpDrmRifNameWork rif_name_work; rif_name_work.is_fixed = is_fixed; rif_name_work.account_id = account_id; aes_encrypt(&rif_name_work, sizeof(SceNpDrmRifName), rif_name_keys); snprintf(rif_name, length, "%016llx%016llx.rif", __builtin_bswap64(((SceUInt64 *)&rif_name_work)[0]), __builtin_bswap64(((SceUInt64 *)&rif_name_work)[1])); }
SceNpDrm
_sceNpDrmCheckDrmReset
Version | NID |
---|---|
1.000.071-3.740.011 | 0x4458812B |
typedef struct SceNpDrmCheckDrmResetOpt { // size is 0x18 SceUInt64 account_id; SceBool *pReset; // Set to SCE_TRUE if act.dat was reset during the function call SceSize in_size; // in_size must not exceed 0x40 SceUInt64 reserved; } SceNpDrmCheckDrmResetOpt; // in_addr byte 0 must not be 0 // in_addr byte 1 contains flags: 0x40, 0x80 // size must not exceed 0x40 int _sceNpDrmCheckDrmReset(const void *in_addr, SceSize size, SceNpDrmCheckDrmResetOpt *pOpt);
_sceNpDrmRemoveActData
Version | NID |
---|---|
1.000.071-3.740.011 | 0x507D06A6 |
Removes NPDRM per-console activation data at tm0:/npdrm/act.dat.
// pAccountId of removed tm0:/npdrm/act.dat >int _sceNpDrmRemoveActData(SceUInt64 *pAccountId);
_sceNpDrmGetRifName
Version | NID |
---|---|
1.000.071-3.740.011 | 0xB8C5DA7C |
Calls #sceNpDrmGetRifNameForDriver.
int _sceNpDrmGetRifName(char *rif_name, SceUInt64 account_id);
_sceNpDrmGetRifNameForInstall
Version | NID |
---|---|
1.000.071-3.740.011 | 0xD312424D |
Calls #sceNpDrmGetRifNameForInstallForDriver.
// rif_name is of size 0x30 // license is of size 0x200 int _sceNpDrmGetRifNameForInstall(char *rif_name, const void *license, SceBool is_fixed);
_sceNpDrmGetRifInfo
Version | NID |
---|---|
1.000.071-3.740.011 | 0xE8343660 |
typedef struct rif_info { // size is 0x70 char content_id[0x30]; char version_number[4]; char license_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]; SceUInt64 lic_start_time; SceUInt64 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* license_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; // license is of size 0x200 int _sceNpDrmGetRifInfo(void *license, SceSize rif_size, SceUInt32 num, _sceNpDrmGetRifInfo_opt* pOpt);
_sceNpDrmGetFixedRifName
Version | NID |
---|---|
1.000.071-3.740.011 | 0xE935B0FC |
int _sceNpDrmGetFixedRifName(char *rif_name, SceUInt64 account_id);
_sceNpDrmCheckActData
Version | NID |
---|---|
1.000.071-3.740.011 | 0xFEEBCD62 |
Calls #sceNpDrmCheckActDataForDriver.
typedef struct SceNpDrmCheckActDataOpt { // size is 0x10 SceUInt64 act_start_time; SceUInt64 act_exp_time; } SceNpDrmCheckActDataOpt; int _sceNpDrmCheckActData(SceUInt32 *act_type, SceUInt32 *unk2, SceUInt64 *pAccountId, SceNpDrmCheckActDataOpt *pOpt);
_sceNpDrmPresetRifProvisionalFlag
Version | NID |
---|---|
0.931.010-1.692.000 | not present |
1.800.071-3.740.011 | 0x2523F57F |
Calls #sceNpDrmPresetRifProvisionalFlagForDriver(license, SCE_TRUE).
// license is of size 0x200 int _sceNpDrmPresetRifProvisionalFlag(void *license);
SceNpDrmForDriver
sceNpDrmGetRifInfoForDriver
Version | NID |
---|---|
0.990.000-3.740.011 | 0xDB406EAE |
// pContentId is of size 0x30 int sceNpDrmGetRifInfoForDriver(const void *license, SceSize license_size, int check_sign, char *pContentId, SceUInt64 *pAccountId, int *pLicenseVersion, int *pDrmType, int *pFlags, int *pSkuFlags, SceUInt64 *pLicStartTime, SceUInt64 *pLicExpTime, SceUInt64 *pFlags2);
sceNpDrmPackageSetGameExistForDriver
Version | NID |
---|---|
1.500.151-3.740.011 | 0x3BFD2850 |
int sceNpDrmPackageSetGameExistForDriver(int value);
sceNpDrmGetFixedRifNameForDriver
Version | NID |
---|---|
0.990.000-3.740.011 | 0x5D73448C |
// rif_name is of size 0x30 int sceNpDrmGetFixedRifNameForDriver(char *rif_name, SceUInt64 account_id);
sceNpDrmGetRifNameForDriver
Version | NID |
---|---|
0.990.000-3.740.011 | 0xDF62F3B8 |
Gets the RIF name for the provided NP Account ID, in order to read the license file from the good path.
// rif_name is of size 0x30 int sceNpDrmGetRifNameForDriver(char *rif_name, SceUInt64 account_id);
sceNpDrmGetRifNameForInstallForDriver
Version | NID |
---|---|
0.990.000-3.740.011 | 0x17573133 |
Gets the RIF name for the provided license, in order to install (write) this license file to the good path.
// rif_name is of size 0x30 // if is_fixed is set, the Content ID is not used to generate the RIF name int sceNpDrmGetRifNameForInstallForDriver(char *rif_name, const void *license, SceBool is_fixed);
sceNpDrmPresetRifProvisionalFlagForDriver
Version | NID |
---|---|
0.931.010-1.692.000 | not present |
1.800.071-3.740.011 | 0xC070FE89 |
Updates license buffer by setting or unsetting the provisional flag. This way, the license RSA signature becomes invalid altough the ECDSA signature should remain valid.
int sceNpDrmPresetRifProvisionalFlagForDriver(void *license, SceBool enable);
sceNpDrmCheckActDataForDriver
Version | NID |
---|---|
0.990.000-3.740.011 | 0x9265B350 |
Gets information about NPDRM per-console activation data at tm0:/npdrm/act.dat.
int sceNpDrmCheckActDataForDriver(SceUInt32 *act_type, SceUInt32 *unk2, SceUInt64 *pAccountId, SceUInt64 *act_start_time, SceUInt64 *act_exp_time);
sceNpDrmRemoveActDataForDriver
Version | NID |
---|---|
0.990.000-3.740.011 | 0x8B85A509 |
Removes NPDRM per-console activation data at tm0:/npdrm/act.dat.
// pAccountId of removed tm0:/npdrm/act.dat int sceNpDrmRemoveActDataForDriver(SceUInt64 *pAccountId);
sceNpDrmUpdateAccountIdForDriver
Version | NID |
---|---|
2.100.081-3.740.011 | 0x116FC0D6 |
int sceNpDrmUpdateAccountIdForDriver(SceUInt64 account_id);
sceNpDrmPspEbootSigGenForDriver
Version | NID |
---|---|
0.931.010-1.06 | not present |
1.500.151-3.740.011 | 0xEF387FC4 |
// npumdsig is of size 0x100 int sceNpDrmPspEbootSigGenForDriver(const char *eboot_path, const void *hash_sha256, void *npumdsig);
sceNpDrmPspEbootVerifyForDriver
Version | NID |
---|---|
0.931.010-1.06 | not present |
1.500.151-3.740.011 | 0xB6CA3A2C |
int sceNpDrmPspEbootVerifyForDriver(const char *eboot_path, const void *npumdsig);
sceNpDrmEbootSigGenPspForDriver
Version | NID |
---|---|
0.931.010-1.692.000 | not present |
1.800.071-3.740.011 | 0x90B1A6D3 |
// npumdsig is of size 0x200 int sceNpDrmEbootSigGenPspForDriver(const char *eboot_path, const void *hash_sha256, void *npumdsig, SceUInt32 systemSwVersion);
sceNpDrmEbootSigGenPs1ForDriver
Version | NID |
---|---|
0.931.010-1.692.000 | not present |
1.800.071-3.740.011 | 0x6D9223E1 |
// npumdsig is of size 0x200 int sceNpDrmEbootSigGenPs1ForDriver(const char *eboot_path, const void *hash_sha256, void *npumdsig, SceUInt32 systemSwVersion);
sceNpDrmEbootSigGenMultiDiscForDriver
Version | NID |
---|---|
0.931.010-1.692.000 | not present |
1.800.071-3.740.011 | 0x39A7A666 |
// multidisc_ctx is of size 0xC8 at least // npumdsig is of size 0x200 int sceNpDrmEbootSigGenMultiDiscForDriver(const char *eboot_path, const void *multidisc_ctx, void *npumdsig, SceUInt32 systemSwVersion);
sceNpDrmEbootSigVerifyForDriver
Version | NID |
---|---|
0.931.010-1.692.000 | not present |
1.800.071-3.740.011 | 0x7A319692 |
// npumdsig is of size 0x200 int sceNpDrmEbootSigVerifyForDriver(const char *eboot_path, const void *npumdsig);
sceNpDrmEbootSigConvertForDriver
Version | NID |
---|---|
0.931.010-1.692.000 | not present |
1.800.071-3.740.011 | 0xA29B75F9 |
// npumdsig is of size 0x200 // new_npumdsig is of size 0x200 int sceNpDrmEbootSigConvertForDriver(const char *eboot_path, const void *npumdsig, void *new_npumdsig);
sceNpDrmGetLegacyDocKeyForDriver
Version | NID |
---|---|
0.990.000-3.740.011 | 0x4E321BDE |
Gets klicensee to decrypt encrypted DOCUMENT.DAT.
// pLegacyDocKey is of size 0x10 bytes int sceNpDrmGetLegacyDocKeyForDriver(void *pRif, void *pDocEdat, SceSize docEdatSize, void *pLegacyDocKey);
sceNpDrmIsLooseAccountBindForDriver
Version | NID |
---|---|
0.931.010-1.692.000 | not present |
1.800.071-3.740.011 | 0xFC84CA1A |
int sceNpDrmIsLooseAccountBindForDriver(void);
sceNpDrmUpdateDebugSettingsForDriver
Version | NID |
---|---|
0.931.010-2.06 | 0xA91C7443 |
2.100.081-3.740.011 | 0xA91C7443 |
Updates SceNpdrm global variables based on /CONFIG/NP/debug_upgradable and /CONFIG/NP2/debug_drm_loose_bind registry values.
int sceNpDrmUpdateDebugSettingsForDriver(void);
sceNpDrmGetRifPspKeyForDriver
Version | NID |
---|---|
0.990.000-3.740.011 | 0xDACB71F4 |
int sceNpDrmGetRifPspKeyForDriver(const void *license, void *klicensee, SceUInt32 *flags, SceUInt64 *lic_start_time, SceUInt64 *lic_exp_time);
sceNpDrmGetRifVitaKeyForDriver
Version | NID |
---|---|
0.990.000-3.740.011 | 0x723322B5 |
This function calls #sceNpDrmGetRifInfoForDriver to get required fields.
int sceNpDrmGetRifVitaKeyForDriver(const void *license, void *klicensee, SceUInt32 *flags, SceUInt32 *sku_flags, SceUInt64 *lic_start_time, SceUInt64 *lic_exp_time);
sceNpDrmWriteActDataForDriver
Version | NID |
---|---|
0.990.000-3.740.011 | 0x742EBAF4 |
Related to SceSblGcAuthMgr#sceSblGcAuthMgrPcactActivationForDriver.
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
// npdrm_act_data is of size 0x1040 int sceNpDrmWriteActDataForDriver(void *npdrm_act_data, const char *aes_dec_key);
sceNpDrmReadActDataForDriver
Version | NID |
---|---|
0.990.000-3.740.011 | 0xD91C3BCE |
Related to SceSblGcAuthMgr#sceSblGcAuthMgrPcactGetChallengeForDriver.
Reads 0x1038 bytes of tm0:/npdrm/act.dat.
// act_data is of size 0x1038 int sceNpDrmReadActDataForDriver(void *act_data);
sceNpDrmVerifyRifForDriver
Version | NID |
---|---|
0.990.000-3.740.011 | 0xFE7B17B6 |
Verifies ECDSA - SHA1 pair and/or RSA - SHA256 pair.
// license max size is 0x200 int sceNpDrmVerifyRifForDriver(const void *license, SceSize license_size);
sceNpDrmVerifyRifFullForDriver
Version | NID |
---|---|
0.990.000-3.740.011 | 0xFF63672D |
check OpenPsId
check cmd56 handshake part
perform steps to get decrypted rif key
// license is of unknown size but at least 0xF8 int sceNpDrmVerifyRifFullForDriver(const void *license);
sceNpDrmUpdateActDataForDriver
Version | NID |
---|---|
0.990.000-3.740.011 | 0x077926F5 |
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.740.011 | 0xB9337914 |
int sceNpDrmPackageIsGameExist(void);
_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; // offset in the encrypted data SceUInt32 identifier; SceUInt32 unk_C; } _sceNpDrmPackageDecrypt_opt; int _sceNpDrmPackageDecrypt(void *buffer, SceSize size, _sceNpDrmPackageDecrypt_opt *pOpt);
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);
SceNpDrmPackage_200D2DE4
Version | NID |
---|---|
3.60 | 0x200D2DE4 |
int SceNpDrmPackage_200D2DE4(int unk0, int unk1);
SceNpDrmPackage_4665E75A
Version | NID |
---|---|
3.60 | 0x4665E75A |
// opt is of size 0x10 int SceNpDrmPackage_4665E75A(int unk0, int unk1, int unk2, void *opt);
SceNpDrmPackage_640C1724
Version | NID |
---|---|
3.60 | 0x640C1724 |
// opt is of size 0x8 int SceNpDrmPackage_640C1724(int unk0, int unk1, int unk2, void *opt);
SceNpDrmPackage_97BB85BD
Version | NID |
---|---|
3.60 | 0x97BB85BD |
// opt is of size 0x10 int SceNpDrmPackage_97BB85BD(int unk0, int unk1, int unk2, void *opt)
SceNpDrmPackage_A5E0F38C
Version | NID |
---|---|
3.60 | 0xA5E0F38C |
int SceNpDrmPackage_A5E0F38C(int unk0, int unk1);
SceNpDrmPackage_C75A775B
Version | NID |
---|---|
3.60 | 0xC75A775B |
// opt is of size 0x8 int SceNpDrmPackage_C75A775B(int unk0, int unk1, int unk2, void *opt);
ScePsmDrm
scePsmDrmGetRifName
Version | NID |
---|---|
3.60 | 0x0D6470DA |
This is a guessed name.
// license is of size 0x400 int scePsmDrmGetRifName(char *rif_name, const void *license);
scePsmDrmGetDebugRifName
Version | NID |
---|---|
3.60 | 0x3E881391 |
This is a guessed name.
int scePsmDrmGetDebugRifName(char *rif_name);
scePsmDrmGetRifInfo
Version | NID |
---|---|
3.60 | 0xE31A6220 |
typedef struct ScePsmDrmGetRifInfoOpt { //size is 0x10 SceUInt64 lic_start_time; SceUInt64 lic_exp_time; } ScePsmDrmGetRifInfoOpt; int scePsmDrmGetRifInfo(void *license, char *content_id, void *account_id, ScePsmDrmGetRifInfoOpt *pOpt);
scePsmDrmGetRifPsmKey
Version | NID |
---|---|
3.60 | 0x207A2C53 |
/** * license is of size 0x400 * klicensee is of size 0x200 **/ int scePsmDrmGetRifPsmKey(void *license, void *klicensee, SceUInt32 *flags, SceUInt64 *lic_start_time, SceUInt64 *lic_exp_time);
scePsmDrmRemoveActData
Version | NID |
---|---|
3.60 | 0x0E193CBB |
// pAccountId of removed tm0:/psmdrm/act.dat int scePsmDrmRemoveActData(SceUInt64 *pAccountId);
scePsmDrmCheckActData
Version | NID |
---|---|
3.60 | 0xA89653B3 |
Calls #scePsmDrmCheckActDataForDriver.
typedef struct SceNpDrmCheckActDataOpt { // size is 0x10 SceUInt64 act_start_time; SceUInt64 act_exp_time; } SceNpDrmCheckActDataOpt; int scePsmDrmCheckActData(SceUInt32 *act_type, SceUInt32 *unk2, SceUInt64 *pAccountId, SceNpDrmCheckActDataOpt *pOpt);
ScePsmDrmForDriver
scePsmDrmGetRifInfoForDriver
Version | NID |
---|---|
3.60 | 0x984F9017 |
This function is named after #sceNpDrmGetRifInfoForDriver since arguments are very similar.
// license is of size 0x400 // content_id is of size 0x30 int scePsmDrmGetRifInfoForDriver(void *license, char *content_id, SceUInt64 *account_id, SceUInt64 *lic_start_time, SceUInt64 *lic_exp_time);
scePsmDrmGetRifPsmKeyForDriver
Version | NID |
---|---|
3.60 | 0x8C8CFD01 |
This function is named after #sceNpDrmGetRifVitaKeyForDriver since arguments are very similar.
// license is of size 0x400 // klicensee is of size 0x200 int scePsmDrmGetRifPsmKeyForDriver(const void *license, void *klicensee, SceUInt32 *flags, SceUInt64 *lic_start_time, SceUInt64 *lic_exp_time);
scePsmDrmWriteActDataForDriver
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
// psm_act_data is of size 0x400 int scePsmDrmWriteActDataForDriver(void *psm_act_data, const char *aes_dec_key);
scePsmDrmRemoveActDataForDriver
Version | NID |
---|---|
3.60 | 0x4CD5375C |
Removes PSM DRM per-console activation data at tm0:/psmdrm/act.dat.
// pAccountId of removed tm0:/psmdrm/act.dat int scePsmDrmRemoveActDataForDriver(SceUInt64 *pAccountId);
scePsmDrmUpdateActDataForDriver
Version | NID |
---|---|
3.60 | 0x791198CE |
reads tm0:/psmdrm/act.dat
verifies RSA with sha256
decrypts Primary Key Table
int scePsmDrmUpdateActDataForDriver(void);
scePsmDrmCheckActDataForDriver
Version | NID |
---|---|
3.60 | 0xB09003A7 |
Gets information about currently loaded PSM act.dat.
int scePsmDrmCheckActDataForDriver(SceUInt32 *act_type, SceUInt32 *unk2, SceUInt64 *pAccountId, SceUInt64 *act_start_time, SceUInt64 *act_exp_time);
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 |
---|---|---|---|
Finalized Flag | 0x0 | 0x2 | ex: 0 for default, 0xFFFF (-1) for debug licenses |
Version | 0x0 | 0x2 | ex: 0, 1 |
License Flags | 0x4 | 0x2 | See [1]. |
DRM Type | 0x6 | 0x2 | See [2]. |
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. |
Provisional Flag | 0x9C | 0x4 | Used by PS Vita only, not PSP nor PS3. ex: 0, 1 (provisional flag). |
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 DRM Type 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 DRM Type 0x400 is set. |
Unknown index | 0xF4 | 0x4 | Used by PS Vita only, not PSP nor PS3. Some index related to debug_upgradable. ex: 0 (default), 1 (seen on a PSP2 gamecard). Allowed range is 0 (default) and 1-0x20. |
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 | NP Account ID (in 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" | |
Version | 0x8 | 0x4 | 00 00 00 01 | |
Unknown2 | 0xC | 0x4 | 00 00 00 00 | Maybe DRM Type and License Flags? |
NP Account ID | 0x10 | 0x8 | 91 78 34 02 01 EF CD AB | NP Account ID (in little-endian) |
Unknown3 | 0x18 | 0x4 | 00 00 00 00 | Must be 0 |
Unknown4 | 0x1C | 0x4 | 00 00 00 00 | Must be 0 |
License start time | 0x20 | 0x8 | 00 00 01 4C 16 4D 83 A8 | |
License 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 then only the first 0x20 bytes are again decrypted with 0x2288 | |
RSA signature | 0x300 | 0x100 |