diff --git a/scetool.vcxproj b/scetool.vcxproj index 743ed60..9097c8d 100644 --- a/scetool.vcxproj +++ b/scetool.vcxproj @@ -44,7 +44,7 @@ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - MultiThreadedDebugDLL + MultiThreadedDebug Level3 ProgramDatabase Disabled @@ -60,7 +60,7 @@ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - MultiThreadedDLL + MultiThreaded Level3 ProgramDatabase diff --git a/src/README b/src/README index 855c5ae..e91b0c6 100644 --- a/src/README +++ b/src/README @@ -9,6 +9,7 @@ NP local license handling (C) 2012 by flatz - /data/act.dat : act.dat - /rifs/* : *.rif files - /raps/* : *.rap files + - /klics/* : *.klic files ==> Keyfile Format <== [keyname] @@ -84,6 +85,10 @@ OPTIONS Possible Values Explanation -j, --np-add-sig TRUE/FALSE(default) Whether to add a NP sig. or not. ==> History <== +Version 0.2.11 + - Added .klic files support for easy decryption of the free-license-type NPDRM selfs. + - "PS3" path environment variable will now be searched for "data", "raps" and "klics" directories. + - Enabled encryption for APP and NPDRM SPU selfs. Version 0.2.10 - Added ECDSA Signature parsing and validation. - Added klicensee parsing. diff --git a/src/config.h b/src/config.h index 7a3b166..4e1ead2 100644 --- a/src/config.h +++ b/src/config.h @@ -7,7 +7,7 @@ #define _CONFIG_H_ /*! scetool base version. */ -#define SCETOOL_VERSION_BASE "0.2.10" +#define SCETOOL_VERSION_BASE "0.2.11" /*! Private build. */ //#define CONFIG_PRIVATE_BUILD @@ -63,6 +63,8 @@ #define CONFIG_RIF_PATH "./rifs" #define CONFIG_RAP_FILE_EXT ".rap" #define CONFIG_RAP_PATH "./raps" +#define CONFIG_KLIC_FILE_EXT ".klic" +#define CONFIG_KLIC_PATH "./klics" /*! Key names. */ #define CONFIG_NP_TID_KNAME "NP_tid" diff --git a/src/keys.cpp b/src/keys.cpp index 76d4213..262bddd 100644 --- a/src/keys.cpp +++ b/src/keys.cpp @@ -462,6 +462,8 @@ static u8 *idps_load() sprintf(path, "%s/%s", ps3, CONFIG_IDPS_FILE); if(access(path, 0) != 0) sprintf(path, "%s/%s", CONFIG_IDPS_PATH, CONFIG_IDPS_FILE); + if(access(path, 0) != 0) + sprintf(path, "%s/%s/%s", ps3, CONFIG_IDPS_PATH, CONFIG_IDPS_FILE); } else sprintf(path, "%s/%s", CONFIG_IDPS_PATH, CONFIG_IDPS_FILE); @@ -495,6 +497,8 @@ static act_dat_t *act_dat_load() sprintf(path, "%s/%s", ps3, CONFIG_ACT_DAT_FILE); if(access(path, 0) != 0) sprintf(path, "%s/%s", CONFIG_ACT_DAT_PATH, CONFIG_ACT_DAT_FILE); + if(access(path, 0) != 0) + sprintf(path, "%s/%s/%s", ps3, CONFIG_ACT_DAT_PATH, CONFIG_ACT_DAT_FILE); } else sprintf(path, "%s/%s", CONFIG_ACT_DAT_PATH, CONFIG_ACT_DAT_FILE); @@ -528,6 +532,8 @@ static rif_t *rif_load(const s8 *content_id) sprintf(path, "%s/%s%s", ps3, content_id, CONFIG_RIF_FILE_EXT); if(access(path, 0) != 0) sprintf(path, "%s/%s%s", CONFIG_RIF_PATH, content_id, CONFIG_RIF_FILE_EXT); + if(access(path, 0) != 0) + sprintf(path, "%s/%s/%s%s", ps3, CONFIG_RIF_PATH, content_id, CONFIG_RIF_FILE_EXT); } else sprintf(path, "%s/%s%s", CONFIG_RIF_PATH, content_id, CONFIG_RIF_FILE_EXT); @@ -560,6 +566,8 @@ static u8 *rap_load(const s8 *content_id) sprintf(path, "%s/%s%s", ps3, content_id, CONFIG_RAP_FILE_EXT); if(access(path, 0) != 0) sprintf(path, "%s/%s%s", CONFIG_RAP_PATH, content_id, CONFIG_RAP_FILE_EXT); + if(access(path, 0) != 0) + sprintf(path, "%s/%s/%s%s", ps3, CONFIG_RAP_PATH, content_id, CONFIG_RAP_FILE_EXT); } else sprintf(path, "%s/%s%s", CONFIG_RAP_PATH, content_id, CONFIG_RAP_FILE_EXT); @@ -706,6 +714,45 @@ BOOL klicensee_by_content_id(const s8 *content_id, u8 *klicensee) return TRUE; } +BOOL dev_klicensee_by_content_id(const s8 *content_id, u8 *klicensee) +{ + + s8 *ps3 = NULL, path[256]; + u8 *klic; + u32 len = 0; + + if((ps3 = getenv(CONFIG_ENV_PS3)) != NULL) + if(access(ps3, 0) != 0) + ps3 = NULL; + + if(ps3 != NULL) + { + sprintf(path, "%s/%s%s", ps3, content_id, CONFIG_KLIC_FILE_EXT); + if(access(path, 0) != 0) + sprintf(path, "%s/%s%s", CONFIG_KLIC_PATH, content_id, CONFIG_KLIC_FILE_EXT); + if(access(path, 0) != 0) + sprintf(path, "%s/%s/%s%s", ps3, CONFIG_KLIC_PATH, content_id, CONFIG_KLIC_FILE_EXT); + } + else + sprintf(path, "%s/%s%s", CONFIG_KLIC_PATH, content_id, CONFIG_KLIC_FILE_EXT); + + klic = (u8 *)_read_buffer(path, &len); + + if(klic == NULL) + return FALSE; + + if(len != KLIC_LENGTH) + { + free(klic); + return FALSE; + } + memcpy(klicensee, klic, KLIC_LENGTH); + free(klic); + _LOG_VERBOSE("Klicensee loaded from %s.klic.\n", content_id); + + return TRUE; +} + keyset_t *keyset_from_buffer(u8 *keyset) { keyset_t *ks; diff --git a/src/keys.h b/src/keys.h index 1a12fae..ca5c06b 100644 --- a/src/keys.h +++ b/src/keys.h @@ -35,6 +35,7 @@ #define ACT_DAT_LENGTH 0x1038 #define RIF_LENGTH 0x98 #define RAP_LENGTH 0x10 +#define KLIC_LENGTH 0x10 /*! IDPS, RIF, act.dat key lengths. */ #define IDPS_KEYBITS 128 @@ -127,6 +128,7 @@ BOOL vsh_curves_load(const s8 *cfile); curve_t *vsh_curve_find(u8 ctype); BOOL klicensee_by_content_id(const s8 *content_id, u8 *klicensee); +BOOL dev_klicensee_by_content_id(const s8 *content_id, u8 *klicensee); keyset_t *keyset_from_buffer(u8 *keyset); diff --git a/src/main.cpp b/src/main.cpp index c804247..f429155 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -377,6 +377,8 @@ int main(int argc, char **argv) sprintf(path, "%s/%s", ps3, CONFIG_KEYS_FILE); if(access(path, 0) != 0) sprintf(path, "%s/%s", CONFIG_KEYS_PATH, CONFIG_KEYS_FILE); + if(access(path, 0) != 0) + sprintf(path, "%s/%s/%s", ps3, CONFIG_KEYS_PATH, CONFIG_KEYS_FILE); } else sprintf(path, "%s/%s", CONFIG_KEYS_PATH, CONFIG_KEYS_FILE); @@ -399,6 +401,8 @@ int main(int argc, char **argv) sprintf(path, "%s/%s", ps3, CONFIG_CURVES_FILE); if(access(path, 0) != 0) sprintf(path, "%s/%s", CONFIG_CURVES_PATH, CONFIG_CURVES_FILE); + if(access(path, 0) != 0) + sprintf(path, "%s/%s/%s", ps3, CONFIG_CURVES_PATH, CONFIG_CURVES_FILE); } else sprintf(path, "%s/%s", CONFIG_CURVES_PATH, CONFIG_CURVES_FILE); @@ -413,6 +417,8 @@ int main(int argc, char **argv) sprintf(path, "%s/%s", ps3, CONFIG_VSH_CURVES_FILE); if(access(path, 0) != 0) sprintf(path, "%s/%s", CONFIG_VSH_CURVES_PATH, CONFIG_VSH_CURVES_FILE); + if(access(path, 0) != 0) + sprintf(path, "%s/%s/%s", ps3, CONFIG_VSH_CURVES_PATH, CONFIG_VSH_CURVES_FILE); } else sprintf(path, "%s/%s", CONFIG_VSH_CURVES_PATH, CONFIG_VSH_CURVES_FILE); diff --git a/src/np.cpp b/src/np.cpp index 6dc425e..b2b463e 100644 --- a/src/np.cpp +++ b/src/np.cpp @@ -49,11 +49,13 @@ void np_set_klicensee(u8 *klicensee) BOOL np_decrypt_npdrm(sce_buffer_ctxt_t *ctxt) { aes_context aes_ctxt; - keyset_t *ks_np_klic_free, *ks_klic_key; + ci_data_npdrm_t *np; + keyset_t *ks_np_klic_free, *ks_klic_key, *ks_np_ci; + u8 hash_check[0x10], ci_key[0x10]; u8 npdrm_key[0x10]; u8 npdrm_iv[0x10]; - ci_data_npdrm_t *np; - + int i; + if((np = _sce_find_ci_npdrm(ctxt)) == NULL) return FALSE; @@ -66,9 +68,23 @@ BOOL np_decrypt_npdrm(sce_buffer_ctxt_t *ctxt) else if(_ES32(np->license_type) == NP_LICENSE_FREE) { ks_np_klic_free = keyset_find_by_name(CONFIG_NP_KLIC_FREE_KNAME); - if(ks_np_klic_free == NULL) + ks_np_ci = keyset_find_by_name(CONFIG_NP_CI_KNAME); + if(ks_np_ci == NULL) return FALSE; - memcpy(npdrm_key, ks_np_klic_free->erk, 0x10); + + //Generate control info hash key. + for(i = 0; i < 0x10; i++) + ci_key[i] = ks_np_ci->erk[i] ^ ks_np_klic_free->erk[i]; + + //Check header for control info hash and try to load appropriate klicensee key. + aes_omac1(hash_check, (u8 *)_sce_find_ci_npdrm(ctxt), 0x60, ci_key, KEYBITS(0x10)); + if (memcmp(hash_check, np->hash_ci, 0x10) != 0) + { + if((dev_klicensee_by_content_id((s8 *)np->content_id, npdrm_key)) == FALSE) + return FALSE; + } + else + memcpy(npdrm_key, ks_np_klic_free->erk, 0x10); } else if(_ES32(np->license_type) == NP_LICENSE_LOCAL) { @@ -80,12 +96,9 @@ BOOL np_decrypt_npdrm(sce_buffer_ctxt_t *ctxt) if(_raw == TRUE) { - printf("[*] Klicensee: "); - int i; - for(i = 0; i < 0x10; i++) - printf("%02X ", npdrm_key[i]); - printf("\n"); + _hexdump(stdout, "[*] Klicensee:", 0, npdrm_key, sizeof(npdrm_key), FALSE); } + aes_setkey_dec(&aes_ctxt, ks_klic_key->erk, METADATA_INFO_KEYBITS); aes_crypt_ecb(&aes_ctxt, AES_DECRYPT, npdrm_key, npdrm_key); @@ -151,7 +164,7 @@ BOOL np_create_ci(npdrm_config_t *npconf, ci_data_npdrm_t *cinp) if(ks_np_tid == NULL || ks_np_ci == NULL) return FALSE; - //Can only create NPDRM SELF with local and free license. + //Can only create NPDRM SELF with "local" and free license. if(_klicensee_key != NULL) memcpy(npdrm_key, _klicensee_key, 0x10); else if(npconf->license_type == NP_LICENSE_FREE) diff --git a/src/self.cpp b/src/self.cpp index 3f12a37..76b6fed 100644 --- a/src/self.cpp +++ b/src/self.cpp @@ -916,7 +916,7 @@ static BOOL _build_self_32(sce_buffer_ctxt_t *ctxt, self_config_t *sconf) _es_elf32_ehdr(ehdr); //Copy program headers. - ctxt->makeself->phdrs = (Elf32_Phdr *)_memdup(ctxt->makeself->elf + ehdr->e_phoff, sizeof(Elf32_Phdr) * ehdr->e_phnum); + ctxt->makeself->phdrs = (Elf32_Phdr *)_memdup(ctxt->makeself->elf + ehdr->e_phoff , sizeof(Elf32_Phdr) * ehdr->e_phnum); ctxt->makeself->phsize = sizeof(Elf32_Phdr) * ehdr->e_phnum; phdrs = (Elf32_Phdr *)_memdup(ctxt->makeself->elf + ehdr->e_phoff, sizeof(Elf32_Phdr) * ehdr->e_phnum); @@ -1043,7 +1043,7 @@ static BOOL _build_self_64(sce_buffer_ctxt_t *ctxt, self_config_t *sconf) BOOL self_build_self(sce_buffer_ctxt_t *ctxt, self_config_t *sconf) { - //const u8 *eident; + const u8 *eident; //Fill config values. ctxt->sceh->key_revision = _ES16(sconf->key_revision); @@ -1075,8 +1075,8 @@ BOOL self_build_self(sce_buffer_ctxt_t *ctxt, self_config_t *sconf) _fill_sce_version(ctxt); //Check for 32 bit or 64 bit ELF. - //eident = (const u8*)ctxt->makeself->elf; - if(sconf->self_type == SELF_TYPE_LDR || sconf->self_type == SELF_TYPE_ISO /*|| eident[EI_CLASS] == ELFCLASS32*/) + eident = (const u8*)ctxt->makeself->elf; + if(sconf->self_type == SELF_TYPE_LDR || sconf->self_type == SELF_TYPE_ISO || eident[EI_CLASS] == ELFCLASS32) return _build_self_32(ctxt, sconf); return _build_self_64(ctxt, sconf); }