Talk:SELF - SPRX

From PS3 Developer wiki
Revision as of 10:47, 6 October 2011 by Euss (talk | contribs) (→‎VSH)
Jump to navigation Jump to search


To be merged with SELF File Format and Decryption


NPDRM Header

typedef struct 
{	
u32 block_type;  // this is 3(NPDRM)	
u32 block_size;  // this is 0x90(sizeof(Self_NPDRM))	
u32 unknown1; //So far always 0	
u32 unknown2; //So far always 0	
u32 magic;       // 0x4E504400(NPD)	
u32 unknown3;    // So far always 1	
u32 license;    // 1 Network License, 2 Local License, 3 Free	
u32 type;    // 1 Executable, 21 Update for Disc Based Game	
u8 titleid[0x30];	
u8 hash_unknown[0x10];	
u8 hash1[0x10];	
u8 hash2[0x10];	
u8 padding[0x10];	
} Self_NPDRM

Located after the Self Control Info.





App Info header:

Aligned to 0x10 bytes.

field offset type notes
authid 0x00 u64
unknown 0x08 u32
app_type 0x0c u32
  • 1 -- level 0
  • 2 -- level 1
  • 3 -- level 2
  • 4 -- application
  • 5 -- isolated SPU module
  • 6 -- secure loader
  • 8 -- NP-DRM application
app_version 0x10 u64

Encrypted phdr offset entry

There is one of these entries for each phdr entry in the elf file so that the ps3 knows where to decrypt the data from. (because it might also be compressed.)

field offset type notes
Encrypted Data Offset 0x00 u64
Encrypted Data Size 0x08 u64
unknown 0x10 u32 This has been 1 in all the examples I have seen.
unknown 0x14 u32 Always 0, as far as I know.
unknown 0x18 u32 Always 0, as far as I know.
unknown 0x1c u32 This is 2 for loadable segment types, and 0 for other types.



field offset type notes
Magic 0x0 u32 Must be "SCE\0"
version 0x4 u32 This must be 2 or the Self loader will abort
flags 0x8 u16
  • 0: retail type 0
  • 1: retail
  • 2: retail type 1
  • 0x8000: devkit
  • 4: unknown, games that require 3.42.
  • 7: unknown, all games that require 3.50 have that flag.
0001: FW 1.00 (app version 1.0.0)
...
0001: FW 3.15 (app version 3.15.0)
0001: FW 3.20 (app version 3.20.0)
0001: FW 3.21 (app version 3.21.0)
0001: FW 3.30 (app version 3.30.0)
0004: FW 3.40 (app version 3.40.0)
0004: FW 3.41 (app version 3.40.0)
0004: FW 3.42 (app version 3.40.0)
0007: FW 3.50 (app version 3.55.0)
000a: FW 3.55 (app version 3.55.0)
000d: FW 3.56 (app version 3.56.0)
0010: FW 3.60 (app version 3.60.0)
0010: FW 3.61 (app version 3.61.0)
0013: FW 3.65 (app version 3.65.0)
0013: FW 3.66 (app version 3.66.0)
0016: FW 3.70 (app version 3.70.0)
0016: FW 3.72 (app version 3.70.0)



NPDRM Self algorithm

THIS DOES NOT ALLOW TO OBTAIN 3.60+ keys, nor piracy as you require the rif, act.dat and IDPS

On NPDRM self decryption all the security levels of the PS3 are involved: user space (vsh), kernel space(lv2), hypervisor( lv1) and isolated SPU (metldr + appldr)

The process start on vsh.elf...

VSH

Once the vsh detects that user is trying to start a self, it looks for the appinfo header type. If the type is 8, then the control digest element type 3 (NPD element) is located. From this NPD header the vsh gets the license type (free, local or network license).

If a free content(type 3) is detected then a generic klicense will be use for further steps (go to LV2). That klicensee is already public (see geohot npdrm_omac_key_1).

  npdrm_omac_key1  :   72F990788F9CFF745725F08E4C128387        # ps3publictools/include/oddkeys.h
  npdrm_omac_key2  :   6BA52976EFDA16EF3C339FB2971E256B        # ...
  npdrm_omac_key3  :   9B515FEACF75064981AA604D91A54E97        # ...

However if a paid content is to be loaded the vsh loads the act.dat and the rif associated to the content (if local it will locate a file with the same titleid on NPD element, if remote it will download to vsh process memory)

Then the signature is checked (last 0x28 bytes of both RIF and act.dat). The curves used are on vsh.self. It is a 3 element table, having the first curve nulled. The curve index for rif/act is 2. The curve values are negated as in the apploader and has the following structure

struct curve {
uint8_t p[0x14];
uint8_t a[0x14];
uint8_t b[0x14];
uint8_t N[0x14];
uint8_t Gx[0x14];
uint8_t Gy[0x14];
}

If the curve checks then vsh will process the rif:

struct rif {
uint8_t unk1[0x10]; //version, license type and user number
uint8_t titleid[0x30]; //Content ID
uint8 padding[0xC]; //Padding for randomness
uint32_t actDatIndex; //Key index on act.dat between 0x00 and 0x7F
uint8 key[0x10]; //encrypted klicensee
uint64_t unk2; //timestamp??
uint64_t unk3; //Always 0
uint8_t rs[0x28];
};
struct ACTDAT {
uint8_t unk1[0x10]; //Version, User number
uint8_t keyTable[0x800]; //Key Table
......
uint8_t signature[0x28];
}

Using the RIF_KEY it will obtain the actdatIndex:

AES_KEY rifKey;
int result = AES_set_decrypt_key(RIF_KEY, 0x80, &rifKey);
AES_decrypt(&rif->padding, &rif->padding, &rifKey);

And finally having the actDat key index the execution pass to LV2 syscall 471

LV2

Lv2 is accessed using syscall471 which haves the following syntax:

int syscall_471(uint32_t type, char* titleID, void* klicensee, uint8_t* actdat, uint8_t* rif, int32_t licenseType, uint8_t* magicVersion);

The function has different parameters depending if the content is debug, free or paid:

FREE: syscall471(npd.type, &npd.titleID, freeklicensee, NULL, NULL, npd.license, &npd);
PAID: syscall471(npd.type, &npd.titleID, NULL, &actdat.keyTable[rif.actDatIndex], &rif.key, npd.license, &npd);

The lv2 keeps a memory table with contentID and the associated key. When it receives a free content (r5 is not null) then copies the titleID and the klicensee to the table. For a paid content the rif.key is converted to the klicensee using:

AES_KEY IDPSKey, ConstKey, ActDatKey;
uint8_t encrConst[0x10];
uint8_t decryptedActDat[0x10];
uint8_t klicensee[0x10];
int result = AES_set_encrypt_key(&IDPSVariation, 0x80, &IDPSKey);
AES_encrypt(&CONSTACTDAT, &encrConst, &IDPSKey);
result = AES_set_decrypt_key(&encrConst,0x80,&ConstKey);
AES_decrypt(actDat,&decryptedActDat,&ConstKey);
result = AES_set_decrypt_key(&decryptedActDat,0x80,&ActDatKey);
AES_decrypt(rif,&klicensee,&ActDatKey);

where CONSTACTDAT is a constant value on lv2, IDPSVaritaion appears to be IDPS (not checked but DRM_Manager_initialize (see graf_chokolo's "bible") to something with the same structure), actdat are the 0x10bytes selected by rif keyIndex, and rif is rif.key (bytes 0x50-0x5f).

Once transformed it is stored on memory table...

I haven't check further steps on vsh nor lv2 so perhaps there are further transformations on the paid case (NOT FOR THE FREE AS I HAVE DECRYPTED THOSE) so we are jumping directly to the appldr

AppLdr

As you can see from graf_chokolo payloads a parameter is passed on spu_args.field60. That parameter is the previously stored klicensee.

However this key must be transformed (again) even for the free case. The transformation is:

uint8_t decryptedKLicensee[0x10]
uint8_t KLicenseeDecryptKey[] = {0xf2, 0xfb, 0xca, 0x7a, 0x75, 0xb0, 0x4e, 0xdc, 0x13, 0x90, 0x63, 0x8c, 0xcd, 0xfd, 0xd1, 0xee};
AES_KEY KLicenseeKey
int result = AES_set_decrypt_key(KLicenseeDecryptKey,0x80,&KLICENSEEKEY);
AES_decrypt(klicensee,&decryptedKLicensee,&KLicenseeKey);
EY is another key located inside the apploader and klicensee is the parameter.

Then we can finally remove the NPDRM layer using:

AES_KEY key;
uint8_t iv[0x10];
memset(&iv[0],0,0x10);
int result = AES_set_decrypt_key(&KLicenseeDecryptKey,0x80,&key);
AES_cbc_encrypt(self + self->metaoffset + 0x20, self + self->metaoffset + 0x20,0x40,&key,&iv,0);

Observe the above code in action at [1]

Once that layer is removed we proceed as normal:

  • Decrypt using AESCBC256 with the NPDRM keys to obtain the metadata keys
  • Decrypt using AESCTR128 the data sha,hmac,iv keys
  • Decrypt the data.

Source: http://www.ps3hax.net/showpost.php?p=259713&postcount=1 JuanNadie

Footnote: KLicenseeDecryptKey is located in appldr twice, e.g.

1.00:

  Offset(h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
     
  000187C0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  000187D0  F2 FB CA 7A 75 B0 4E DC 13 90 63 8C CD FD D1 EE  òûÊzu°NÜ..cŒÍýÑî
  000187E0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  000187F0  F2 FB CA 7A 75 B0 4E DC 13 90 63 8C CD FD D1 EE  òûÊzu°NÜ..cŒÍýÑî

3.15:

  Offset(h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
     
  00018EB0  F2 FB CA 7A 75 B0 4E DC 13 90 63 8C CD FD D1 EE  òûÊzu°NÜ..cŒÍýÑî
  00018EC0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  00018ED0  F2 FB CA 7A 75 B0 4E DC 13 90 63 8C CD FD D1 EE  òûÊzu°NÜ..cŒÍýÑî
  00018EE0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................

3.55:

  Offset(h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
     
  00019730  F2 FB CA 7A 75 B0 4E DC 13 90 63 8C CD FD D1 EE  òûÊzu°NÜ..cŒÍýÑî
  00019740  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  00019750  F2 FB CA 7A 75 B0 4E DC 13 90 63 8C CD FD D1 EE  òûÊzu°NÜ..cŒÍýÑî
  00019760  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................

3.56:

  Offset(h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
     
  0001F920  F2 FB CA 7A 75 B0 4E DC 13 90 63 8C CD FD D1 EE  òûÊzu°NÜ..cŒÍýÑî
  0001F930  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  0001F940  F2 FB CA 7A 75 B0 4E DC 13 90 63 8C CD FD D1 EE  òûÊzu°NÜ..cŒÍýÑî
  0001F950  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................