/* * Copyright (c) 2011-2013 by naehrwert * This file is released under the GPLv2. */ #include #include #include "types.h" #include "config.h" #include "util.h" #include "sce.h" #include "sce_inlines.h" #include "self.h" #include "elf.h" #include "elf_inlines.h" #include "tables.h" #include "sha1.h" #include "np.h" static void _get_shdr_flags(s8 *str, u64 flags) { memset(str, '-', 3); str[3] = 0; if(flags & SHF_WRITE) str[0] = 'W'; if(flags & SHF_ALLOC) str[1] = 'A'; if(flags & SHF_EXECINSTR) str[2] = 'E'; } static void _get_phdr_flags(s8 *str, u64 flags) { memset(str, '-', 3); str[3] = 0; if(flags & PF_X) str[0] = 'X'; if(flags & PF_W) str[1] = 'W'; if(flags & PF_R) str[2] = 'R'; } void _print_self_header(FILE *fp, self_header_t *h) { fprintf(fp, "[*] SELF Header:\n"); fprintf(fp, " Header Type 0x%016llX\n", h->header_type); fprintf(fp, " App Info Offset 0x%016llX\n", h->app_info_offset); fprintf(fp, " ELF Offset 0x%016llX\n", h->elf_offset); fprintf(fp, " PH Offset 0x%016llX\n", h->phdr_offset); fprintf(fp, " SH Offset 0x%016llX\n", h->shdr_offset); fprintf(fp, " Section Info Offset 0x%016llX\n", h->section_info_offset); fprintf(fp, " SCE Version Offset 0x%016llX\n", h->sce_version_offset); fprintf(fp, " Control Info Offset 0x%016llX\n", h->control_info_offset); fprintf(fp, " Control Info Size 0x%016llX\n", h->control_info_size); //fprintf(fp, " padding 0x%016llX\n", h->padding); } void _print_app_info(FILE *fp, app_info_t *ai) { const s8 *name; fprintf(fp, "[*] Application Info:\n"); name = _get_name(_auth_ids, ai->auth_id); if(name != NULL) { fprintf(fp, " Auth-ID "); _PRINT_RAW(fp, "0x%016llX ", ai->auth_id); fprintf(fp, "[%s]\n", name); } else fprintf(fp, " Auth-ID 0x%016llX\n", ai->auth_id); name = _get_name(_vendor_ids, ai->vendor_id); if(name != NULL) { fprintf(fp, " Vendor-ID "); _PRINT_RAW(fp, "0x%08X ", ai->vendor_id); fprintf(fp, "[%s]\n", name); } else fprintf(fp, " Vendor-ID 0x%08X\n", ai->vendor_id); name = _get_name(_self_types, ai->self_type); if(name != NULL) fprintf(fp, " SELF-Type [%s]\n", name); else fprintf(fp, " SELF-Type 0x%08X\n", ai->self_type); fprintf(fp, " Version %s\n", sce_version_to_str(ai->version)); //fprintf(fp, " padding 0x%016llX\n", ai->padding); } void _print_section_info_header(FILE *fp) { fprintf(fp, "[*] Section Infos:\n"); fprintf(fp, " Idx Offset Size Compressed unk0 unk1 Encrypted\n"); } void _print_section_info(FILE *fp, section_info_t *si, u32 idx) { fprintf(fp, " %03d %08X %08X %s %08X %08X %s\n", idx, (u32)si->offset, (u32)si->size, si->compressed == 2 ? "[YES]" : "[NO ]", si->unknown_0, si->unknown_1, si->encrypted == 1 ? "[YES]" : "[NO ]"); } void _print_sce_version(FILE *fp, sce_version_t *sv) { fprintf(fp, "[*] SCE Version:\n"); fprintf(fp, " Header Type 0x%08X\n", sv->header_type); fprintf(fp, " Present [%s]\n", sv->present == SCE_VERSION_PRESENT ? "TRUE" : "FALSE"); fprintf(fp, " Size 0x%08X\n", sv->size); fprintf(fp, " unknown_3 0x%08X\n", sv->unknown_3); } void _print_control_info(FILE *fp, control_info_t *ci) { const s8 *name; fprintf(fp, "[*] Control Info\n"); name = _get_name(_control_info_types, ci->type); if(name != NULL) fprintf(fp, " Type %s\n", name); else fprintf(fp, " Type 0x%08X\n", ci->type); fprintf(fp, " Size 0x%08X\n", ci->size); fprintf(fp, " Next [%s]\n", ci->next == 1 ? "TRUE" : "FALSE"); switch(ci->type) { case CONTROL_INFO_TYPE_FLAGS: _hexdump(fp, " Flags", 0, (u8 *)ci + sizeof(control_info_t), ci->size - sizeof(control_info_t), FALSE); break; case CONTROL_INFO_TYPE_DIGEST: if(ci->size == 0x30) { ci_data_digest_30_t *dig = (ci_data_digest_30_t *)((u8 *)ci + sizeof(control_info_t)); _hexdump(fp, " Digest", 0, dig->digest, 20, FALSE); } else if(ci->size == 0x40) { ci_data_digest_40_t *dig = (ci_data_digest_40_t *)((u8 *)ci + sizeof(control_info_t)); _es_ci_data_digest_40(dig); _hexdump(fp, " Digest 1 ", 0, dig->digest1, 20, FALSE); _hexdump(fp, " Digest 2 ", 0, dig->digest2, 20, FALSE); if(dig->fw_version != 0) fprintf(fp, " FW Version %d [%02d.%02d]\n", (u32)dig->fw_version, ((u32)dig->fw_version)/10000, (((u32)dig->fw_version)%10000)/100); } break; case CONTROL_INFO_TYPE_NPDRM: { 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", np->magic, (np->magic == NP_CI_MAGIC ? "OK" : "ERROR")); fprintf(fp, " unknown_0 0x%08X\n", np->unknown_0); fprintf(fp, " Licence Type 0x%08X\n", np->license_type); fprintf(fp, " App Type 0x%08X\n", 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", np->unknown_1); fprintf(fp, " unknown_2 0x%016llX\n", np->unknown_2); } break; } } static void _print_cap_flags_flags(FILE *fp, oh_data_cap_flags_t *cf) { if(cf->flags & 0x01) fprintf(fp, "0x01 "); if(cf->flags & 0x02) fprintf(fp, "0x02 "); if(cf->flags & 0x04) fprintf(fp, "0x04 "); if(cf->flags & CAP_FLAG_REFTOOL) fprintf(fp, "REFTOOL "); if(cf->flags & CAP_FLAG_DEBUG) fprintf(fp, "DEBUG "); if(cf->flags & CAP_FLAG_RETAIL) fprintf(fp, "RETAIL "); if(cf->flags & CAP_FLAG_SYSDBG) fprintf(fp, "SYSDBG "); } void _print_opt_header(FILE *fp, opt_header_t *oh) { const s8 *name; fprintf(fp, "[*] Optional Header\n"); name = _get_name(_optional_header_types, oh->type); if(name != NULL) fprintf(fp, " Type %s\n", name); else fprintf(fp, " Type 0x%08X\n", oh->type); fprintf(fp, " Size 0x%08X\n", oh->size); fprintf(fp, " Next [%s]\n", oh->next == 1 ? "TRUE" : "FALSE"); switch(oh->type) { case OPT_HEADER_TYPE_CAP_FLAGS: { oh_data_cap_flags_t *cf = (oh_data_cap_flags_t *)((u8 *)oh + sizeof(opt_header_t)); _IF_RAW(_hexdump(fp, " Flags", 0, (u8 *)cf, sizeof(oh_data_cap_flags_t), FALSE)); _es_oh_data_cap_flags(cf); fprintf(fp, " unknown_3 0x%016llX\n", cf->unk3); fprintf(fp, " unknown_4 0x%016llX\n", cf->unk4); 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); } break; #ifdef CONFIG_DUMP_INDIV_SEED case OPT_HEADER_TYPE_INDIV_SEED: { u8 *is = (u8 *)oh + sizeof(opt_header_t); _hexdump(fp, " Seed", 0, is, oh->size - sizeof(opt_header_t), TRUE); } break; #endif } } void _print_elf32_ehdr(FILE *fp, Elf32_Ehdr *h) { const s8 *name; fprintf(fp, "[*] ELF32 Header:\n"); name = _get_name(_e_types, h->e_type); if(name != NULL) fprintf(fp, " Type [%s]\n", name); else fprintf(fp, " Type 0x%04X\n", h->e_type); name = _get_name(_e_machines, h->e_machine); if(name != NULL) fprintf(fp, " Machine [%s]\n", name); else fprintf(fp, " Machine 0x%04X\n", h->e_machine); fprintf(fp, " Version 0x%08X\n", h->e_version); fprintf(fp, " Entry 0x%08X\n", h->e_entry); fprintf(fp, " Program Headers Offset 0x%08X\n", h->e_phoff); fprintf(fp, " Section Headers Offset 0x%08X\n", h->e_shoff); fprintf(fp, " Flags 0x%08X\n", h->e_flags); fprintf(fp, " Program Headers Count %04d\n", h->e_phnum); fprintf(fp, " Section Headers Count %04d\n", h->e_shnum); fprintf(fp, " SH String Index %04d\n", h->e_shstrndx); } void _print_elf64_ehdr(FILE *fp, Elf64_Ehdr *h) { const s8 *name; fprintf(fp, "[*] ELF64 Header:\n"); name = _get_name(_e_types, h->e_type); if(name != NULL) fprintf(fp, " Type [%s]\n", name); else fprintf(fp, " Type 0x%04X\n", h->e_type); name = _get_name(_e_machines, h->e_machine); if(name != NULL) fprintf(fp, " Machine [%s]\n", name); else fprintf(fp, " Machine 0x%04X\n", h->e_machine); fprintf(fp, " Version 0x%08X\n", h->e_version); fprintf(fp, " Entry 0x%016llX\n", h->e_entry); fprintf(fp, " Program Headers Offset 0x%016llX\n", h->e_phoff); fprintf(fp, " Section Headers Offset 0x%016llX\n", h->e_shoff); fprintf(fp, " Flags 0x%08X\n", h->e_flags); fprintf(fp, " Program Headers Count %04d\n", h->e_phnum); fprintf(fp, " Section Headers Count %04d\n", h->e_shnum); fprintf(fp, " SH String Index %04d\n", h->e_shstrndx); } void _print_elf32_shdr_header(FILE *fp) { fprintf(fp, "[*] ELF32 Section Headers:\n"); fprintf(fp, " Idx Name Type Flags Address Offset Size ES Align LK\n"); } void _print_elf32_shdr(FILE *fp, Elf32_Shdr *h, u32 idx) { const s8 *name; s8 flags[4]; _get_shdr_flags(flags, h->sh_flags); fprintf(fp, " %03d %04X ", idx, h->sh_name); name = _get_name(_sh_types, h->sh_type); if(name != NULL) fprintf(fp, "%-13s ", name); else fprintf(fp, "%08X ", h->sh_type); fprintf(fp, "%s %05X %05X %05X %02X %05X %03d\n", flags, h->sh_addr, h->sh_offset, h->sh_size, h->sh_entsize, h->sh_addralign, h->sh_link); } void _print_elf64_shdr_header(FILE *fp) { fprintf(fp, "[*] ELF64 Section Headers:\n"); fprintf(fp, " Idx Name Type Flags Address Offset Size ES Align LK\n"); } void _print_elf64_shdr(FILE *fp, Elf64_Shdr *h, u32 idx) { const s8 *name; s8 flags[4]; _get_shdr_flags(flags, h->sh_flags); fprintf(fp, " %03d %04X ", idx, h->sh_name); name = _get_name(_sh_types, h->sh_type); if(name != NULL) fprintf(fp, "%-13s ", name); else fprintf(fp, "%08X ", h->sh_type); fprintf(fp, "%s %08X %08X %08X %04X %08X %03d\n", flags, (u32)h->sh_addr, (u32)h->sh_offset, (u32)h->sh_size, (u32)h->sh_entsize, (u32)h->sh_addralign, h->sh_link); } void _print_elf32_phdr_header(FILE *fp) { fprintf(fp, "[*] ELF32 Program Headers:\n"); fprintf(fp, " Idx Type Offset VAddr PAddr FileSize MemSize Flags Align\n"); } void _print_elf32_phdr(FILE *fp, Elf32_Phdr *h, u32 idx) { const s8 *name; s8 flags[4]; _get_phdr_flags(flags, h->p_flags); fprintf(fp, " %03d ", idx); name = _get_name(_ph_types, h->p_type); if(name != NULL) fprintf(fp, "%-7s ", name); else fprintf(fp, "0x%08X ", h->p_type); fprintf(fp, "%05X %05X %05X %05X %05X %s %05X\n", h->p_offset, h->p_vaddr, h->p_paddr, h->p_filesz, h->p_memsz, flags, h->p_align); } void _print_elf64_phdr_header(FILE *fp) { fprintf(fp, "[*] ELF64 Program Headers:\n"); fprintf(fp, " Idx Type Offset VAddr PAddr FileSize MemSize PPU SPU RSX Align\n"); } void _print_elf64_phdr(FILE *fp, Elf64_Phdr *h, u32 idx) { const s8 *name; s8 ppu[4], spu[4], rsx[4]; _get_phdr_flags(ppu, h->p_flags); _get_phdr_flags(spu, h->p_flags >> 20); _get_phdr_flags(rsx, h->p_flags >> 24); fprintf(fp, " %03d ", idx); name = _get_name(_ph_types, h->p_type); if(name != NULL) fprintf(fp, "%-8s ", name); else fprintf(fp, "%08X ", h->p_type); fprintf(fp, "%08X %08X %08X %08X %08X %s %s %s %08X\n", (u32)h->p_offset, (u32)h->p_vaddr, (u32)h->p_paddr, (u32)h->p_filesz, (u32)h->p_memsz, ppu, spu, rsx, (u32)h->p_align); } BOOL self_print_info(FILE *fp, sce_buffer_ctxt_t *ctxt) { u32 i, self_type; const u8 *eident; //Check for SELF. if(ctxt->sceh->header_type != SCE_HEADER_TYPE_SELF) return FALSE; //Print SELF infos. _print_self_header(fp, ctxt->self.selfh); _print_app_info(fp, ctxt->self.ai); if(ctxt->self.sv != NULL) _print_sce_version(fp, ctxt->self.sv); //Print control infos. if(ctxt->self.cis != NULL) LIST_FOREACH(iter, ctxt->self.cis) _print_control_info(fp, (control_info_t *)iter->value); //Print optional headers. if(ctxt->mdec == TRUE) { LIST_FOREACH(iter, ctxt->self.ohs) { #ifndef CONFIG_DUMP_INDIV_SEED if(((opt_header_t *)iter->value)->type != OPT_HEADER_TYPE_INDIV_SEED) _print_opt_header(fp, (opt_header_t *)iter->value); #else _print_opt_header(fp, (opt_header_t *)iter->value); #endif } } self_type = ctxt->self.ai->self_type; eident = ctxt->scebuffer + ctxt->self.selfh->elf_offset; //SPU is 32 bit. if(self_type == SELF_TYPE_LDR || self_type == SELF_TYPE_ISO || eident[EI_CLASS] == ELFCLASS32) { //32 bit ELF. Elf32_Ehdr *eh = (Elf32_Ehdr *)(ctxt->scebuffer + ctxt->self.selfh->elf_offset); _es_elf32_ehdr(eh); //Print section infos. _print_section_info_header(fp); for(i = 0; i < eh->e_phnum; i++) { _es_section_info(&ctxt->self.si[i]); _print_section_info(fp, &ctxt->self.si[i], i); } //Print ELF header. _print_elf32_ehdr(fp, eh); Elf32_Phdr *ph = (Elf32_Phdr *)(ctxt->scebuffer + ctxt->self.selfh->phdr_offset); //Print program headers. _print_elf32_phdr_header(fp); for(i = 0; i < eh->e_phnum; i++) { _es_elf32_phdr(&ph[i]); _print_elf32_phdr(fp, &ph[i], i); } if(eh->e_shnum > 0) { Elf32_Shdr *sh = (Elf32_Shdr *)(ctxt->scebuffer + ctxt->self.selfh->shdr_offset); //Print section headers. _print_elf32_shdr_header(fp); for(i = 0; i < eh->e_shnum; i++) { _es_elf32_shdr(&sh[i]); _print_elf32_shdr(fp, &sh[i], i); } } } else { //64 bit ELF. Elf64_Ehdr *eh = (Elf64_Ehdr *)(ctxt->scebuffer + ctxt->self.selfh->elf_offset); _es_elf64_ehdr(eh); //Print section infos. _print_section_info_header(fp); for(i = 0; i < eh->e_phnum; i++) { _es_section_info(&ctxt->self.si[i]); _print_section_info(fp, &ctxt->self.si[i], i); } //Print ELF header. _print_elf64_ehdr(stdout, eh); Elf64_Phdr *ph = (Elf64_Phdr *)(ctxt->scebuffer + ctxt->self.selfh->phdr_offset); //Print program headers. _print_elf64_phdr_header(fp); for(i = 0; i < eh->e_phnum; i++) { _es_elf64_phdr(&ph[i]); _print_elf64_phdr(fp, &ph[i], i); } if(eh->e_shnum > 0) { Elf64_Shdr *sh = (Elf64_Shdr *)(ctxt->scebuffer + ctxt->self.selfh->shdr_offset); //Print section headers. _print_elf64_shdr_header(fp); for(i = 0; i < eh->e_shnum; i++) { _es_elf64_shdr(&sh[i]); _print_elf64_shdr(fp, &sh[i], i); } } } return TRUE; } //TODO: maybe implement better. BOOL self_write_to_elf(sce_buffer_ctxt_t *ctxt, const s8 *elf_out) { FILE *fp; u32 i, self_type; const u8 *eident; //Check for SELF. if(ctxt->sceh->header_type != SCE_HEADER_TYPE_SELF) return FALSE; if((fp = fopen(elf_out, "wb")) == NULL) return FALSE; self_type = ctxt->self.ai->self_type; eident = ctxt->scebuffer + ctxt->self.selfh->elf_offset; //SPU is 32 bit. if(self_type == SELF_TYPE_LDR || self_type == SELF_TYPE_ISO || eident[EI_CLASS] == ELFCLASS32) { #ifdef CONFIG_DUMP_INDIV_SEED /* //Print individuals seed. if(self_type == SELF_TYPE_ISO) { u8 *indiv_seed = (u8 *)ctxt->self.ish + sizeof(iseed_header_t); s8 ifile[256]; sprintf(ifile, "%s.indiv_seed.bin", elf_out); FILE *ifp = fopen(ifile, "wb"); fwrite(indiv_seed, sizeof(u8), ctxt->self.ish->size - sizeof(iseed_header_t), ifp); fclose(ifp); } */ #endif //32 bit ELF. Elf32_Ehdr ceh, *eh = (Elf32_Ehdr *)(ctxt->scebuffer + ctxt->self.selfh->elf_offset); _copy_es_elf32_ehdr(&ceh, eh); //Write ELF header. fwrite(eh, sizeof(Elf32_Ehdr), 1, fp); //Write program headers. Elf32_Phdr *ph = (Elf32_Phdr *)(ctxt->scebuffer + ctxt->self.selfh->phdr_offset); fwrite(ph, sizeof(Elf32_Phdr), ceh.e_phnum, fp); //Write program data. metadata_section_header_t *msh = ctxt->metash; for(i = 0; i < ctxt->metah->section_count; i++) { if(msh[i].type == METADATA_SECTION_TYPE_PHDR) { _es_elf32_phdr(&ph[msh[i].index]); fseek(fp, ph[msh[i].index].p_offset, SEEK_SET); fwrite(ctxt->scebuffer + msh[i].data_offset, sizeof(u8), msh[i].data_size, fp); } } //Write section headers. if(ctxt->self.selfh->shdr_offset != 0) { Elf32_Shdr *sh = (Elf32_Shdr *)(ctxt->scebuffer + ctxt->self.selfh->shdr_offset); fseek(fp, ceh.e_shoff, SEEK_SET); fwrite(sh, sizeof(Elf32_Shdr), ceh.e_shnum, fp); } } else { //64 bit ELF. Elf64_Ehdr ceh, *eh = (Elf64_Ehdr *)(ctxt->scebuffer + ctxt->self.selfh->elf_offset); _copy_es_elf64_ehdr(&ceh, eh); //Write ELF header. fwrite(eh, sizeof(Elf64_Ehdr), 1, fp); //Write program headers. Elf64_Phdr *ph = (Elf64_Phdr *)(ctxt->scebuffer + ctxt->self.selfh->phdr_offset); fwrite(ph, sizeof(Elf64_Phdr), ceh.e_phnum, fp); //Write program data. metadata_section_header_t *msh = ctxt->metash; for(i = 0; i < ctxt->metah->section_count; i++) { if(msh[i].type == METADATA_SECTION_TYPE_PHDR) { if(msh[i].compressed == METADATA_SECTION_COMPRESSED) { _es_elf64_phdr(&ph[msh[i].index]); u8 *data = (u8 *)malloc(ph[msh[i].index].p_filesz); _zlib_inflate(ctxt->scebuffer + msh[i].data_offset, msh[i].data_size, data, ph[msh[i].index].p_filesz); fseek(fp, ph[msh[i].index].p_offset, SEEK_SET); fwrite(data, sizeof(u8), ph[msh[i].index].p_filesz, fp); free(data); } else { _es_elf64_phdr(&ph[msh[i].index]); fseek(fp, ph[msh[i].index].p_offset, SEEK_SET); fwrite(ctxt->scebuffer + msh[i].data_offset, sizeof(u8), msh[i].data_size, fp); } } } //Write section headers. if(ctxt->self.selfh->shdr_offset != 0) { Elf64_Shdr *sh = (Elf64_Shdr *)(ctxt->scebuffer + ctxt->self.selfh->shdr_offset); fseek(fp, ceh.e_shoff, SEEK_SET); fwrite(sh, sizeof(Elf64_Shdr), ceh.e_shnum, fp); } } fclose(fp); return TRUE; } /*! Static zero control flags. */ static u8 _static_control_flags[0x20] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /*! Static control digest1. */ static u8 _static_control_digest[0x14] = { 0x62, 0x7C, 0xB1, 0x80, 0x8A, 0xB9, 0x38, 0xE3, 0x2C, 0x8C, 0x09, 0x17, 0x08, 0x72, 0x6A, 0x57, 0x9E, 0x25, 0x86, 0xE4 }; static BOOL _create_control_infos(sce_buffer_ctxt_t *ctxt, self_config_t *sconf) { control_info_t *ci; u32 self_type = ctxt->self.ai->self_type; //Step 1. switch(self_type) { case SELF_TYPE_LV0: case SELF_TYPE_LV1: case SELF_TYPE_LV2: case SELF_TYPE_APP: case SELF_TYPE_ISO: case SELF_TYPE_LDR: case SELF_TYPE_NPDRM: //TODO: <-- figure more out. { //Add control flags. ci = (control_info_t *)malloc(sizeof(control_info_t) + sizeof(ci_data_flags_t)); ci->type = CONTROL_INFO_TYPE_FLAGS; ci->size = sizeof(control_info_t) + sizeof(ci_data_flags_t); ci->next = 1; ci_data_flags_t *cif = (ci_data_flags_t *)((u8 *)ci + sizeof(control_info_t)); //Add default flags. if(sconf->ctrl_flags == NULL) memcpy(cif->data, _static_control_flags, 0x20); else memcpy(cif->data, sconf->ctrl_flags, 0x20); list_add_back(ctxt->self.cis, ci); } break; } //Step 2. switch(self_type) { case SELF_TYPE_LV0: case SELF_TYPE_LV1: case SELF_TYPE_LV2: case SELF_TYPE_APP: case SELF_TYPE_ISO: case SELF_TYPE_LDR: case SELF_TYPE_NPDRM: { //Add digest 0x40. ci = (control_info_t *)malloc(sizeof(control_info_t) + sizeof(ci_data_digest_40_t)); ci->type = CONTROL_INFO_TYPE_DIGEST; ci->size = sizeof(control_info_t) + sizeof(ci_data_digest_40_t); if(self_type == SELF_TYPE_NPDRM) ci->next = 1; else ci->next = 0; ci_data_digest_40_t *cid = (ci_data_digest_40_t *)((u8 *)ci + sizeof(control_info_t)); memcpy(cid->digest1, _static_control_digest, 0x14); memset(cid->digest2, 0, 0x14); sha1(ctxt->makeself->elf, ctxt->makeself->elf_len, cid->digest2); //TODO: check that. if(self_type == SELF_TYPE_NPDRM) cid->fw_version = sce_hexver_to_decver(sconf->fw_version); else cid->fw_version = 0; //Fixup. _es_ci_data_digest_40(cid); list_add_back(ctxt->self.cis, ci); } break; } //Step 3. switch(self_type) { case SELF_TYPE_NPDRM: { //Add NPDRM control info. if(sconf->npdrm_config == NULL) return FALSE; ci = (control_info_t *)malloc(sizeof(control_info_t) + sizeof(ci_data_npdrm_t)); ci->type = CONTROL_INFO_TYPE_NPDRM; ci->size = sizeof(control_info_t) + sizeof(ci_data_npdrm_t); ci->next = 0; ci_data_npdrm_t *cinp = (ci_data_npdrm_t *)((u8 *)ci + sizeof(control_info_t)); //Create NPDRM control info. if(np_create_ci(sconf->npdrm_config, cinp) == FALSE) { free(ci); return FALSE; } list_add_back(ctxt->self.cis, ci); } break; } return TRUE; } static void _set_cap_flags(u32 self_type, oh_data_cap_flags_t *capf) { switch(self_type) { case SELF_TYPE_LV0: capf->flags = CAP_FLAG_SYSDBG | CAP_FLAG_RETAIL | CAP_FLAG_DEBUG | CAP_FLAG_REFTOOL | 0x3; //0x7B; capf->unk6 = 1; break; case SELF_TYPE_LV1: capf->flags = CAP_FLAG_SYSDBG | CAP_FLAG_RETAIL | CAP_FLAG_DEBUG | CAP_FLAG_REFTOOL | 0x3; //0x7B; capf->unk6 = 1; break; case SELF_TYPE_LV2: capf->flags = CAP_FLAG_SYSDBG | CAP_FLAG_RETAIL | CAP_FLAG_DEBUG | CAP_FLAG_REFTOOL | 0x3; //0x7B; capf->unk6 = 1; break; case SELF_TYPE_APP: capf->flags = CAP_FLAG_SYSDBG | CAP_FLAG_RETAIL | CAP_FLAG_DEBUG | CAP_FLAG_REFTOOL | 0x3; //0x7B; capf->unk6 = 1; capf->unk7 = 0x20000; break; case SELF_TYPE_ISO: capf->flags = CAP_FLAG_SYSDBG | CAP_FLAG_RETAIL | CAP_FLAG_DEBUG | CAP_FLAG_REFTOOL; //0x78; break; case SELF_TYPE_LDR: capf->flags = CAP_FLAG_SYSDBG | CAP_FLAG_RETAIL | CAP_FLAG_DEBUG | CAP_FLAG_REFTOOL; //0x78; break; case SELF_TYPE_NPDRM: capf->flags = CAP_FLAG_RETAIL | CAP_FLAG_DEBUG | CAP_FLAG_REFTOOL | 0x3; //0x3B; capf->unk6 = 1; capf->unk7 = 0x2000; break; } _es_oh_data_cap_flags(capf); } static BOOL _create_optional_headers(sce_buffer_ctxt_t *ctxt, self_config_t *sconf) { opt_header_t *oh; u32 self_type = ctxt->self.ai->self_type; //Step 1. switch(self_type) { case SELF_TYPE_LV0: case SELF_TYPE_LV1: case SELF_TYPE_LV2: case SELF_TYPE_APP: case SELF_TYPE_ISO: case SELF_TYPE_LDR: case SELF_TYPE_NPDRM: { //Add capability flags. oh = (opt_header_t *)malloc(sizeof(opt_header_t) + sizeof(oh_data_cap_flags_t)); oh->type = OPT_HEADER_TYPE_CAP_FLAGS; oh->size = sizeof(opt_header_t) + sizeof(oh_data_cap_flags_t); if(self_type == SELF_TYPE_ISO) oh->next = 1; else oh->next = 0; oh_data_cap_flags_t *capf = (oh_data_cap_flags_t *)((u8 *)oh + sizeof(opt_header_t)); //Add default flags. if(sconf->cap_flags == NULL) _set_cap_flags(self_type, capf); else memcpy(capf, sconf->cap_flags, 0x20); list_add_back(ctxt->self.ohs, oh); } break; } //Step 2. switch(self_type) { case SELF_TYPE_ISO: { //Add individuals seed. oh = (opt_header_t *)malloc(sizeof(opt_header_t) + 0x100); oh->type = OPT_HEADER_TYPE_INDIV_SEED; oh->size = sizeof(opt_header_t) + 0x100; oh->next = 0; u8 *is = (u8 *)oh + sizeof(opt_header_t); memset(is, 0, 0x100); #ifdef CONFIG_CUSTOM_INDIV_SEED if(sconf->indiv_seed != NULL) memcpy(is, sconf->indiv_seed, sconf->indiv_seed_size); #endif list_add_back(ctxt->self.ohs, oh); } break; } return TRUE; } static void _fill_sce_version(sce_buffer_ctxt_t *ctxt) { ctxt->self.sv->header_type = SUB_HEADER_TYPE_SCEVERSION; ctxt->self.sv->present = SCE_VERSION_NOT_PRESENT; ctxt->self.sv->size = sizeof(sce_version_t); ctxt->self.sv->unknown_3 = 0x00000000; } static void _add_phdr_section(sce_buffer_ctxt_t *ctxt, u32 p_type, u32 size, u32 idx) { //Offset gets set later. ctxt->self.si[idx].offset = 0; ctxt->self.si[idx].size = size; if(p_type == PT_LOAD || p_type == PT_PS3_PRX_RELOC || p_type == 0x700000A8) ctxt->self.si[idx].encrypted = 1; //Encrypted LOAD (?). else ctxt->self.si[idx].encrypted = 0; //No LOAD (?). ctxt->self.si[idx].compressed = SECTION_INFO_NOT_COMPRESSED; ctxt->self.si[idx].unknown_0 = 0; //Unknown. ctxt->self.si[idx].unknown_1 = 0; //Unknown. } static BOOL _add_shdrs_section(sce_buffer_ctxt_t *ctxt, u32 idx) { //Add a section for the section headers. if(ctxt->makeself->shdrs != NULL) { u32 shsize = ctxt->makeself->shsize; void *sec = _memdup(ctxt->makeself->shdrs, shsize); sce_add_data_section(ctxt, sec, shsize, FALSE); //Fill metadata section header. sce_set_metash(ctxt, METADATA_SECTION_TYPE_SHDR, FALSE, idx); return TRUE; } return FALSE; } static BOOL _build_self_32(sce_buffer_ctxt_t *ctxt, self_config_t *sconf) { u32 i; Elf32_Ehdr *ehdr; Elf32_Phdr *phdrs; //Elf32_Shdr *shdrs; //Copy ELF header. ctxt->makeself->ehdr = (Elf32_Ehdr *)_memdup(ctxt->makeself->elf, sizeof(Elf32_Ehdr)); ctxt->makeself->ehsize = sizeof(Elf32_Ehdr); ehdr = (Elf32_Ehdr *)_memdup(ctxt->makeself->elf, sizeof(Elf32_Ehdr)); _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->phsize = sizeof(Elf32_Phdr) * ehdr->e_phnum; phdrs = (Elf32_Phdr *)_memdup(ctxt->makeself->elf + ehdr->e_phoff, sizeof(Elf32_Phdr) * ehdr->e_phnum); //Copy section headers. if(ehdr->e_shnum != 0) { ctxt->makeself->shdrs = (Elf32_Shdr *)_memdup(ctxt->makeself->elf + ehdr->e_shoff, sizeof(Elf32_Shdr) * ehdr->e_shnum); ctxt->makeself->shsize = sizeof(Elf32_Shdr) * ehdr->e_shnum; //shdrs = (Elf32_Shdr *)_memdup(ctxt->makeself->elf + ehdr->e_shoff, sizeof(Elf32_Shdr) * ehdr->e_shnum); } //Allocate metadata section headers (one for each program header and one for the section headers). ctxt->metash = (metadata_section_header_t *)malloc(sizeof(metadata_section_header_t) * (ehdr->e_phnum + 1)); //Copy sections, fill section infos and metadata section headers. ctxt->self.si = (section_info_t *)malloc(sizeof(section_info_t) * ehdr->e_phnum); 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); } //Section info count. ctxt->makeself->si_cnt = ehdr->e_phnum; //Number of section infos that are present as data sections. ctxt->makeself->si_sec_cnt = ehdr->e_phnum; //Add a section for the section headers. if(sconf->add_shdrs == TRUE) if(_add_shdrs_section(ctxt, i) == TRUE) i++; //Metadata. ctxt->metah->section_count = i; return TRUE; } static BOOL _build_self_64(sce_buffer_ctxt_t *ctxt, self_config_t *sconf) { u32 i; Elf64_Ehdr *ehdr; Elf64_Phdr *phdrs; //Elf64_Shdr *shdrs; //Copy ELF header. ctxt->makeself->ehdr = (Elf64_Ehdr *)_memdup(ctxt->makeself->elf, sizeof(Elf64_Ehdr)); ctxt->makeself->ehsize = sizeof(Elf64_Ehdr); ehdr = (Elf64_Ehdr *)_memdup(ctxt->makeself->elf, sizeof(Elf64_Ehdr)); _es_elf64_ehdr(ehdr); //Copy program headers. ctxt->makeself->phdrs = (Elf64_Phdr *)_memdup(ctxt->makeself->elf + ehdr->e_phoff, sizeof(Elf64_Phdr) * ehdr->e_phnum); ctxt->makeself->phsize = sizeof(Elf64_Phdr) * ehdr->e_phnum; phdrs = (Elf64_Phdr *)_memdup(ctxt->makeself->elf + ehdr->e_phoff, sizeof(Elf64_Phdr) * ehdr->e_phnum); //Copy section headers. if(ehdr->e_shnum != 0) { ctxt->makeself->shdrs = (Elf64_Shdr *)_memdup(ctxt->makeself->elf + ehdr->e_shoff, sizeof(Elf64_Shdr) * ehdr->e_shnum); ctxt->makeself->shsize = sizeof(Elf64_Shdr) * ehdr->e_shnum; //shdrs = (Elf64_Shdr *)_memdup(ctxt->makeself->elf + ehdr->e_shoff, sizeof(Elf64_Shdr) * ehdr->e_shnum); } //Allocate metadata section headers (one for each program header and one for the section headers). ctxt->metash = (metadata_section_header_t *)malloc(sizeof(metadata_section_header_t) * (ehdr->e_phnum + 1)); //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_elf64_phdr(&phdrs[i]); //Add section info. _add_phdr_section(ctxt, phdrs[i].p_type, phdrs[i].p_filesz, i); //TODO: what if the size differs, why skip other program headers? //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); //PPU 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. ctxt->makeself->si_cnt = ehdr->e_phnum; //Number of section infos that are present as data sections. ctxt->makeself->si_sec_cnt = i - skip; //Add a section for the section headers. if(sconf->add_shdrs == TRUE) if(_add_shdrs_section(ctxt, i - skip) == TRUE) i++; //Metadata. i -= skip; ctxt->metah->section_count = i; return TRUE; } BOOL self_build_self(sce_buffer_ctxt_t *ctxt, self_config_t *sconf) { //const u8 *eident; //Fill config values. ctxt->sceh->key_revision = sconf->key_revision; ctxt->self.ai->auth_id = sconf->auth_id; ctxt->self.ai->vendor_id = sconf->vendor_id; ctxt->self.ai->self_type = sconf->self_type; ctxt->self.ai->version = sconf->app_version; //Create control infos. if(_create_control_infos(ctxt, sconf) == FALSE) { printf("[*] Error: Could not create SELF control infos.\n"); return FALSE; } #ifdef CONFIG_CUSTOM_INDIV_SEED if(sconf->indiv_seed != NULL && sconf->self_type != SELF_TYPE_ISO) printf("[*] Warning: Skipping individuals seed for non-ISO SELF.\n"); #endif //Create optional headers. if(_create_optional_headers(ctxt, sconf) == FALSE) { printf("[*] Error: Could not create SELF optional headers.\n"); return FALSE; } //Set SCE version. _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*/) return _build_self_32(ctxt, sconf); return _build_self_64(ctxt, sconf); }