diff --git a/src/README b/src/README index e91b0c6..8b5c872 100644 --- a/src/README +++ b/src/README @@ -85,6 +85,9 @@ OPTIONS Possible Values Explanation -j, --np-add-sig TRUE/FALSE(default) Whether to add a NP sig. or not. ==> History <== +Version 0.2.12 + - Enabled options to compress and skip sections for SPU selfs. + - Extended information about the NPDRM selfs. 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. diff --git a/src/config.h b/src/config.h index 4e1ead2..5428c1f 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.11" +#define SCETOOL_VERSION_BASE "0.2.12" /*! Private build. */ //#define CONFIG_PRIVATE_BUILD diff --git a/src/np.cpp b/src/np.cpp index b2b463e..c87cf00 100644 --- a/src/np.cpp +++ b/src/np.cpp @@ -55,7 +55,7 @@ BOOL np_decrypt_npdrm(sce_buffer_ctxt_t *ctxt) u8 npdrm_key[0x10]; u8 npdrm_iv[0x10]; int i; - + if((np = _sce_find_ci_npdrm(ctxt)) == NULL) return FALSE; @@ -183,7 +183,7 @@ BOOL np_create_ci(npdrm_config_t *npconf, ci_data_npdrm_t *cinp) return FALSE; cinp->magic = _ES32(NP_CI_MAGIC); - cinp->unknown_0 = _ES32(1); + cinp->version = _ES32(1); cinp->license_type = _ES32(npconf->license_type); cinp->app_type = _ES32(npconf->app_type); memcpy(cinp->content_id, npconf->content_id, 0x30); @@ -193,8 +193,8 @@ BOOL np_create_ci(npdrm_config_t *npconf, ci_data_npdrm_t *cinp) //Better than boring random bytes! memcpy(cinp->rndpad, CONFIG_NPDRM_WATERMARK, 0x10); #endif - cinp->unknown_1 = _ES64(0); - cinp->unknown_2 = _ES64(0); + cinp->limited_time_start = _ES64(0); + cinp->limited_time_end = _ES64(0); //Generate control info hash key. for(i = 0; i < 0x10; i++) diff --git a/src/sce.h b/src/sce.h index e889ccc..37834e3 100644 --- a/src/sce.h +++ b/src/sce.h @@ -381,7 +381,8 @@ typedef struct _ci_data_npdrm { /*! Magic. */ u32 magic; - u32 unknown_0; + /*! Version. */ + u32 version; /*! License type. */ u32 license_type; /*! Application type. */ @@ -394,8 +395,10 @@ typedef struct _ci_data_npdrm u8 hash_cid_fname[0x10]; /*! Control info hash. */ u8 hash_ci[0x10]; - u64 unknown_1; - u64 unknown_2; + /*! Start of the Validity period. */ + u64 limited_time_start; + /*! End of the Validity period. */ + u64 limited_time_end; } ci_data_npdrm_t; /*! Optional header. */ diff --git a/src/self.cpp b/src/self.cpp index 76b6fed..a4ab484 100644 --- a/src/self.cpp +++ b/src/self.cpp @@ -5,6 +5,7 @@ #include #include +#include #include "types.h" #include "config.h" @@ -120,6 +121,8 @@ void _print_sce_version(FILE *fp, sce_version_t *sv) void _print_control_info(FILE *fp, control_info_t *ci) { const s8 *name; + time_t t; + tm* aTm; fprintf(fp, "[*] Control Info\n"); @@ -158,16 +161,63 @@ void _print_control_info(FILE *fp, control_info_t *ci) ci_data_npdrm_t *np = (ci_data_npdrm_t *)((u8 *)ci + sizeof(control_info_t)); //Was already fixed in decrypt_header. //_es_ci_data_npdrm(np); - fprintf(fp, " Magic 0x%08X [%s]\n", _ES32(np->magic), (_ES32(np->magic) == NP_CI_MAGIC ? "OK" : "ERROR")); - fprintf(fp, " unknown_0 0x%08X\n", _ES32(np->unknown_0)); - fprintf(fp, " Licence Type 0x%08X\n", _ES32(np->license_type)); - fprintf(fp, " App Type 0x%08X\n", _ES32(np->app_type)); - fprintf(fp, " ContentID %s\n", np->content_id); - _hexdump(fp, " Random Pad ", 0, np->rndpad, 0x10, FALSE); - _hexdump(fp, " CID_FN Hash ", 0, np->hash_cid_fname, 0x10, FALSE); - _hexdump(fp, " CI Hash ", 0, np->hash_ci, 0x10, FALSE); - fprintf(fp, " unknown_1 0x%016llX\n", _ES64(np->unknown_1)); - fprintf(fp, " unknown_2 0x%016llX\n", _ES64(np->unknown_2)); + fprintf(fp, " Magic 0x%08X [%s]\n", _ES32(np->magic), (_ES32(np->magic) == NP_CI_MAGIC ? "OK" : "ERROR")); + fprintf(fp, " Version 0x%08X\n", _ES32(np->version)); + + name = _get_name(_np_license_types, _ES32(np->license_type)); + if(name != NULL) + { + fprintf(fp, " Licence Type "); + _PRINT_RAW(fp, "0x%08X ", _ES32(np->license_type)); + fprintf(fp, "[%s]\n", name); + } + else + fprintf(fp, " Licence Type 0x%08X\n", _ES32(np->license_type)); + + name = _get_name(_np_app_types, _ES32(np->app_type)); + if(name != NULL) + { + fprintf(fp, " App Type "); + _PRINT_RAW(fp, "0x%08X ", _ES32(np->app_type)); + fprintf(fp, "[%s]\n", name); + } + else + fprintf(fp, " App Type 0x%08X\n", _ES32(np->app_type)); + + fprintf(fp, " ContentID %s\n", np->content_id); + _hexdump(fp, " Random Pad ", 0, np->rndpad, 0x10, FALSE); + _hexdump(fp, " CID_FN Hash ", 0, np->hash_cid_fname, 0x10, FALSE); + _hexdump(fp, " CI Hash ", 0, np->hash_ci, 0x10, FALSE); + + t = (time_t)(_ES64(np->limited_time_start) / 1000); + aTm = localtime(&t); + if(_ES64(np->limited_time_start) != 0) + { + fprintf(fp, " Validity Start "); + _PRINT_RAW(fp, "0x%016llX ", _ES64(np->limited_time_start)); + fprintf(fp, "[%04d/%02d/%02d %02d:%02d:%02d]\n",aTm->tm_year+1900, aTm->tm_mon+1, aTm->tm_mday, aTm->tm_hour, aTm->tm_min, aTm->tm_sec); + } + else + { + fprintf(fp, " Validity Start "); + _PRINT_RAW(fp, "0x%016llX ", _ES64(np->limited_time_start)); + fprintf(fp, "[Unlimited]\n"); + } + + t = (time_t)(_ES64(np->limited_time_end) / 1000); + aTm = localtime(&t); + if(_ES64(np->limited_time_end) != 0) + { + fprintf(fp, " Validity End "); + _PRINT_RAW(fp, "0x%016llX ", _ES64(np->limited_time_end)); + fprintf(fp, "[%04d/%02d/%02d %02d:%02d:%02d]\n",aTm->tm_year+1900, aTm->tm_mon+1, aTm->tm_mday, aTm->tm_hour, aTm->tm_min, aTm->tm_sec); + } + else + { + fprintf(fp, " Validity End "); + _PRINT_RAW(fp, "0x%016llX ", _ES64(np->limited_time_end)); + fprintf(fp, "[Unlimited]\n"); + } } break; } @@ -222,7 +272,7 @@ void _print_opt_header(FILE *fp, opt_header_t *oh) fprintf(fp, " Flags 0x%016llX [ ", cf->flags); _print_cap_flags_flags(fp, cf); fprintf(fp, "]\n"); - + fprintf(fp, " unknown_6 0x%08X\n", cf->unk6); fprintf(fp, " unknown_7 0x%08X\n", cf->unk7); } @@ -573,11 +623,25 @@ BOOL self_write_to_elf(sce_buffer_ctxt_t *ctxt, const s8 *elf_out) { if(_ES32(msh[i].type) == METADATA_SECTION_TYPE_PHDR) { - _es_elf32_phdr(&ph[_ES32(msh[i].index)]); - fseek(fp, ph[_ES32(msh[i].index)].p_offset, SEEK_SET); - fwrite(ctxt->scebuffer + _ES64(msh[i].data_offset), sizeof(u8), _ES64(msh[i].data_size), fp); + if(_ES32(msh[i].compressed) == METADATA_SECTION_COMPRESSED) + { + _es_elf32_phdr(&ph[_ES32(msh[i].index)]); + u8 *data = (u8 *)malloc(ph[_ES32(msh[i].index)].p_filesz); + + _zlib_inflate(ctxt->scebuffer + _ES64(msh[i].data_offset), _ES64(msh[i].data_size), data, ph[_ES32(msh[i].index)].p_filesz); + fseek(fp, ph[_ES32(msh[i].index)].p_offset, SEEK_SET); + fwrite(data, sizeof(u8), ph[_ES32(msh[i].index)].p_filesz, fp); + + free(data); + } + else + { + _es_elf32_phdr(&ph[_ES32(msh[i].index)]); + fseek(fp, ph[_ES32(msh[i].index)].p_offset, SEEK_SET); + fwrite(ctxt->scebuffer + _ES64(msh[i].data_offset), sizeof(u8), _ES64(msh[i].data_size), fp); + } } - } + } //Write section headers. if(_ES64(ctxt->self.selfh->shdr_offset) != 0) @@ -827,7 +891,7 @@ static BOOL _create_optional_headers(sce_buffer_ctxt_t *ctxt, self_config_t *sco _set_cap_flags(self_type, capf); else memcpy(capf, sconf->cap_flags, 0x20); - + list_add_back(ctxt->self.ohs, oh); } break; @@ -850,7 +914,7 @@ static BOOL _create_optional_headers(sce_buffer_ctxt_t *ctxt, self_config_t *sco if(sconf->indiv_seed != NULL) memcpy(is, sconf->indiv_seed, sconf->indiv_seed_size); #endif - + list_add_back(ctxt->self.ohs, oh); } break; @@ -916,7 +980,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); @@ -933,17 +997,33 @@ static BOOL _build_self_32(sce_buffer_ctxt_t *ctxt, self_config_t *sconf) //Copy sections, fill section infos and metadata section headers. ctxt->self.si = (section_info_t *)malloc(sizeof(section_info_t) * ehdr->e_phnum); + u32 loff = 0xFFFFFFFF, skip = 0; for(i = 0; i < ehdr->e_phnum; i++) { _es_elf32_phdr(&phdrs[i]); - void *sec = _memdup(ctxt->makeself->elf + phdrs[i].p_offset, phdrs[i].p_filesz); - //Never compress sections on SPU SELFs. - sce_add_data_section(ctxt, sec, phdrs[i].p_filesz, FALSE); //Add section info. _add_phdr_section(ctxt, phdrs[i].p_type, phdrs[i].p_filesz, i); - //Fill metadata section header. - sce_set_metash(ctxt, METADATA_SECTION_TYPE_PHDR, phdrs[i].p_type == PT_LOAD ? TRUE : FALSE, i); + + //Fill metadata section header but skip identical program header offsets. + if(sconf->skip_sections == TRUE && (phdrs[i].p_offset == loff || !(phdrs[i].p_type == PT_LOAD || phdrs[i].p_type == PT_PS3_PRX_RELOC || phdrs[i].p_type == 0x700000A8))) + { + const s8 *name = _get_name(_ph_types, phdrs[i].p_type); + if(name != NULL) + _LOG_VERBOSE("Skipped program header %-8s @ 0x%08X (0x%08X)\n", name, phdrs[i].p_offset, phdrs[i].p_filesz); + else + _LOG_VERBOSE("Skipped program header 0x%08X @ 0x%08X (0x%08X)\n", phdrs[i].p_type, phdrs[i].p_offset, phdrs[i].p_filesz); + skip++; + } + else + { + void *sec = _memdup(ctxt->makeself->elf + phdrs[i].p_offset, phdrs[i].p_filesz); + //SPU sections may be compressed. + sce_add_data_section(ctxt, sec, phdrs[i].p_filesz, TRUE); + sce_set_metash(ctxt, METADATA_SECTION_TYPE_PHDR, TRUE /*(phdrs[i].p_type == PT_LOAD || phdrs[i].p_type == PT_PS3_PRX_RELOC || phdrs[i].p_type == 0x700000A8) ? TRUE : FALSE*/, i - skip); + } + + loff = phdrs[i].p_offset; } //Section info count. @@ -953,10 +1033,11 @@ static BOOL _build_self_32(sce_buffer_ctxt_t *ctxt, self_config_t *sconf) //Add a section for the section headers. if(sconf->add_shdrs == TRUE) - if(_add_shdrs_section(ctxt, i) == TRUE) + if(_add_shdrs_section(ctxt, i - skip) == TRUE) i++; //Metadata. + i -= skip; ctxt->metah->section_count = _ES32(i); return TRUE; diff --git a/src/tables.cpp b/src/tables.cpp index f736b9c..f04fb3d 100644 --- a/src/tables.cpp +++ b/src/tables.cpp @@ -58,6 +58,15 @@ id_to_name_t _optional_header_types[] = {0, NULL} }; +/*! NPDRM license types. */ +id_to_name_t _np_license_types[] = +{ + {NP_LICENSE_NETWORK, "NETWORK"}, + {NP_LICENSE_LOCAL, "LOCAL"}, + {NP_LICENSE_FREE, "FREE"}, + {0, NULL} +}; + /*! NPDRM application types. */ id_to_name_t _np_app_types[] = { @@ -65,7 +74,7 @@ id_to_name_t _np_app_types[] = {NP_TYPE_EXEC, "EXEC"}, {NP_TYPE_USPRX, "USPRX"}, {NP_TYPE_UEXEC, "UEXEC"}, - {0, NULL}, + {0, NULL} }; /*! Auth IDs. */ diff --git a/src/tables.h b/src/tables.h index 032cefc..ce65729 100644 --- a/src/tables.h +++ b/src/tables.h @@ -21,6 +21,9 @@ extern id_to_name_t _control_info_types[]; /*! Optional header types. */ extern id_to_name_t _optional_header_types[]; +/*! NPDRM license types. */ +extern id_to_name_t _np_license_types[]; + /*! NPDRM application types. */ extern id_to_name_t _np_app_types[];