static int aice_pipe_write_mem_unit(uint32_t coreid, uint32_t addr, uint32_t size, uint32_t count, const uint8_t *buffer) { char line[AICE_PIPE_MAXLINE]; char command[AICE_PIPE_MAXLINE]; command[0] = AICE_WRITE_MEM_UNIT; set_u32(command + 1, addr); set_u32(command + 5, size); set_u32(command + 9, count); /* WRITE_MEM_UNIT|addr|size|count|data */ memcpy(command + 13, buffer, size * count); if (aice_pipe_write(command, 13 + size * count) < 0) return ERROR_FAIL; if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0) return ERROR_FAIL; if (line[0] == AICE_OK) return ERROR_OK; else return ERROR_FAIL; return ERROR_OK; }
void init_Self_Shdr(Self_Shdr* hdr) { set_u32(&(hdr->s_magic), 0x53434500); set_u32(&(hdr->s_hdrversion), 2); #ifdef SPRX // on 3.41 //set_u16(&(hdr->s_flags), 4); // on 3.55 set_u16(&(hdr->s_flags), 7); #else set_u16(&(hdr->s_flags), 1); #endif set_u16(&(hdr->s_hdrtype), 1); }
static int aice_pipe_write_mem_bulk(uint32_t coreid, uint32_t addr, uint32_t length, const uint8_t *buffer) { char line[AICE_PIPE_MAXLINE]; char command[AICE_PIPE_MAXLINE + 4]; uint32_t remain_len = length; uint32_t written_len = 0; uint32_t write_len; command[0] = AICE_WRITE_MEM_BULK; set_u32(command + 1, addr); set_u32(command + 5, length); /* Send command first */ if (aice_pipe_write(command, 9) < 0) return ERROR_FAIL; if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0) return ERROR_FAIL; if (line[0] == AICE_ERROR) return ERROR_FAIL; while (remain_len > 0) { if (remain_len > AICE_PIPE_MAXLINE) write_len = AICE_PIPE_MAXLINE; else write_len = remain_len; set_u32(command, write_len); memcpy(command + 4, buffer + written_len, write_len); /* data only */ if (aice_pipe_write(command, write_len + 4) < 0) return ERROR_FAIL; if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0) return ERROR_FAIL; if (line[0] == AICE_ERROR) return ERROR_FAIL; remain_len -= write_len; written_len += write_len; } if (line[0] == AICE_OK) return ERROR_OK; else return ERROR_FAIL; }
static int aice_pipe_read_mem_bulk(uint32_t coreid, uint32_t addr, uint32_t length, uint8_t *buffer) { char line[AICE_PIPE_MAXLINE + 1]; char command[AICE_PIPE_MAXLINE]; uint32_t remain_len = length; uint32_t prepare_len; char *received_line; uint32_t received_len; int read_len; command[0] = AICE_READ_MEM_BULK; set_u32(command + 1, addr); set_u32(command + 5, length); if (aice_pipe_write(command, 9) < 0) return ERROR_FAIL; while (remain_len > 0) { if (remain_len > AICE_PIPE_MAXLINE) prepare_len = AICE_PIPE_MAXLINE; else prepare_len = remain_len; prepare_len++; received_len = 0; received_line = line; do { read_len = aice_pipe_read(received_line, prepare_len - received_len); if (read_len < 0) return ERROR_FAIL; received_line += read_len; received_len += read_len; } while (received_len < prepare_len); if (line[0] != AICE_OK) return ERROR_FAIL; prepare_len--; memcpy(buffer, line + 1, prepare_len); remain_len -= prepare_len; buffer += prepare_len; } return ERROR_OK; }
static int aice_pipe_read_mem_unit(uint32_t coreid, uint32_t addr, uint32_t size, uint32_t count, uint8_t *buffer) { char command[AICE_PIPE_MAXLINE]; command[0] = AICE_READ_MEM_UNIT; set_u32(command + 1, addr); set_u32(command + 5, size); set_u32(command + 9, count); if (aice_pipe_write(command, 13) != 13) return ERROR_FAIL; if (aice_pipe_read(buffer, size * count) < 0) return ERROR_FAIL; return ERROR_OK; }
static int aice_pipe_cache_ctl(uint32_t coreid, uint32_t subtype, uint32_t address) { char line[AICE_PIPE_MAXLINE]; char command[AICE_PIPE_MAXLINE]; command[0] = AICE_CACHE_CTL; set_u32(command + 1, subtype); set_u32(command + 5, address); if (aice_pipe_write(command, 9) != 9) return ERROR_FAIL; if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0) return ERROR_FAIL; if (line[0] == AICE_OK) return ERROR_OK; else return ERROR_FAIL; }
static int aice_pipe_write_debug_reg(uint32_t coreid, uint32_t addr, const uint32_t val) { char line[AICE_PIPE_MAXLINE]; char command[AICE_PIPE_MAXLINE]; command[0] = AICE_WRITE_DEBUG_REG; set_u32(command + 1, addr); set_u32(command + 5, val); if (aice_pipe_write(command, 9) != 9) return ERROR_FAIL; if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0) return ERROR_FAIL; if (line[0] == AICE_OK) return ERROR_OK; else return ERROR_FAIL; }
static int aice_pipe_write_reg_64(uint32_t coreid, uint32_t num, uint64_t val) { char line[AICE_PIPE_MAXLINE]; char command[AICE_PIPE_MAXLINE]; command[0] = AICE_WRITE_REG_64; set_u32(command + 1, num); set_u32(command + 5, val & 0xFFFFFFFF); set_u32(command + 9, (val >> 32) & 0xFFFFFFFF); if (aice_pipe_write(command, 13) != 9) return ERROR_FAIL; if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0) return ERROR_FAIL; if (line[0] == AICE_OK) return ERROR_OK; else return ERROR_FAIL; }
void init_Self_NPDRM(Self_NPDRM* npdrm, char* titleid, char* filename) { set_u32(&npdrm->block_type, 3); set_u32(&npdrm->block_size, sizeof(Self_NPDRM)); set_u32(&npdrm->magic, 0x4E504400); set_u32(&npdrm->unknown3, 1); set_u32(&npdrm->unknown4, 3); set_u32(&npdrm->unknown5, 1); strncpy(npdrm->titleid, titleid, 0x30); //memcpy(npdrm->hash_unknown, npdrm_hash_unknown, sizeof(npdrm_hash_unknown)); char *true_filename = strrchr(filename,'/'); if(true_filename == NULL) { true_filename = strrchr(filename,'\\'); } if(true_filename == NULL) { true_filename = filename; } else { true_filename++; } u8 npdrm_omac_key[0x10]; int i; for(i=0;i<0x10;i++) npdrm_omac_key[i] = npdrm_omac_key1[i] ^ npdrm_omac_key2[i]; int buf_len = 0x30+strlen(true_filename); char *buf = (char*)malloc(buf_len); memcpy(buf, npdrm->titleid, 0x30); strcpy(buf+0x30, true_filename); aesOmac1Mode(npdrm->hash1, buf, buf_len, npdrm_omac_key3, sizeof(npdrm_omac_key3)*8); free(buf); aesOmac1Mode(npdrm->hash2, (u8*)&(npdrm->magic), 0x60, npdrm_omac_key, sizeof(npdrm_omac_key)*8); }
void init_Self_Ihdr(Self_Ihdr* hdr) { #ifdef NPDRM set_u64(&(hdr->i_authid), 0x1010000001000003LL); set_u32(&(hdr->i_apptype), 8); #else #ifdef SPRX set_u64(&(hdr->i_authid), 0x1070000052000001LL); #else //set_u64(&(hdr->i_authid), 0x10700003FD000001LL); set_u64(&(hdr->i_authid), 0x10700003FF000001LL); #endif set_u32(&(hdr->i_apptype), 4); #endif //set_u64(&(hdr->i_authid), 0x1070000500000001LL); set_u32(&(hdr->i_magic), 0x01000002); set_u64(&(hdr->i_version), 0x0003005500000000LL); //set_u64(&(hdr->i_version), 0x0003004000000000LL); //set_u64(&(hdr->i_version), 0x0003000000000000LL); //set_u64(&(hdr->i_version), 0x0001004000001000LL); //set_u64(&(hdr->i_version), 0x0001000000000000LL); }
void build_segment_crypt_data() { Self_Segment* segment_ptr; segment_ptr = &first_segment; while(segment_ptr != NULL) { if(segment_ptr->incrypt) { set_u32(&(segment_ptr->enc_segment.segment_sha1_index), segment_crypt_data_len/0x10); memcpy(&segment_crypt_data[segment_crypt_data_len], segment_ptr->crypt_segment.sha1, sizeof(segment_ptr->crypt_segment.sha1)); segment_crypt_data_len += sizeof(segment_ptr->crypt_segment.sha1); memcpy(&segment_crypt_data[segment_crypt_data_len], segment_ptr->crypt_segment.hmac, sizeof(segment_ptr->crypt_segment.hmac)); segment_crypt_data_len += sizeof(segment_ptr->crypt_segment.hmac); if(segment_ptr->encrypted) { set_u32(&(segment_ptr->enc_segment.segment_erk_index), segment_crypt_data_len/0x10); memcpy(&segment_crypt_data[segment_crypt_data_len], segment_ptr->crypt_segment.erk, sizeof(segment_ptr->crypt_segment.erk)); segment_crypt_data_len += sizeof(segment_ptr->crypt_segment.erk); set_u32(&(segment_ptr->enc_segment.segment_riv_index), segment_crypt_data_len/0x10); memcpy(&segment_crypt_data[segment_crypt_data_len], segment_ptr->crypt_segment.riv, sizeof(segment_ptr->crypt_segment.riv)); segment_crypt_data_len += sizeof(segment_ptr->crypt_segment.riv); } else { set_u32(&(segment_ptr->enc_segment.segment_erk_index), 0xFFFFFFFF); set_u32(&(segment_ptr->enc_segment.segment_riv_index), 0xFFFFFFFF); } } segment_ptr = segment_ptr->next_segment; } }
static int aice_pipe_read_debug_reg(uint32_t coreid, uint32_t addr, uint32_t *val) { char line[AICE_PIPE_MAXLINE]; char command[AICE_PIPE_MAXLINE]; command[0] = AICE_READ_DEBUG_REG; set_u32(command + 1, addr); if (aice_pipe_write(command, 5) != 5) return ERROR_FAIL; if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0) return ERROR_FAIL; *val = get_u32(line); return ERROR_OK; }
static int aice_pipe_read_reg_64(uint32_t coreid, uint32_t num, uint64_t *val) { char line[AICE_PIPE_MAXLINE]; char command[AICE_PIPE_MAXLINE]; command[0] = AICE_READ_REG_64; set_u32(command + 1, num); if (aice_pipe_write(command, 5) != 5) return ERROR_FAIL; if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0) return ERROR_FAIL; *val = (((uint64_t)get_u32(line + 4)) << 32) | get_u32(line); return ERROR_OK; }
static int aice_pipe_memory_mode(uint32_t coreid, enum nds_memory_select mem_select) { char line[AICE_PIPE_MAXLINE]; char command[AICE_PIPE_MAXLINE]; command[0] = AICE_MEMORY_MODE; set_u32(command + 1, mem_select); if (aice_pipe_write(command, 5) != 5) return ERROR_FAIL; if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0) return ERROR_FAIL; if (line[0] == AICE_OK) return ERROR_OK; else return ERROR_FAIL; }
static int aice_pipe_memory_access(uint32_t coreid, enum nds_memory_access access_channel) { char line[AICE_PIPE_MAXLINE]; char command[AICE_PIPE_MAXLINE]; command[0] = AICE_MEMORY_ACCESS; set_u32(command + 1, access_channel); if (aice_pipe_write(command, 5) != 5) return ERROR_FAIL; if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0) return ERROR_FAIL; if (line[0] == AICE_OK) return ERROR_OK; else return ERROR_FAIL; }
static int aice_pipe_set_jtag_clock(uint32_t a_clock) { char line[AICE_PIPE_MAXLINE]; char command[AICE_PIPE_MAXLINE]; command[0] = AICE_SET_JTAG_CLOCK; set_u32(command + 1, a_clock); if (aice_pipe_write(command, 5) != 5) return ERROR_FAIL; if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0) return ERROR_FAIL; if (line[0] == AICE_OK) return ERROR_OK; else return ERROR_FAIL; }
static int aice_pipe_read_tlb(uint32_t coreid, uint32_t virtual_address, uint32_t *physical_address) { char line[AICE_PIPE_MAXLINE]; char command[AICE_PIPE_MAXLINE]; command[0] = AICE_READ_TLB; set_u32(command + 1, virtual_address); if (aice_pipe_write(command, 5) != 5) return ERROR_FAIL; if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0) return ERROR_FAIL; if (line[0] == AICE_OK) { *physical_address = get_u32(line + 1); return ERROR_OK; } else return ERROR_FAIL; }
int main(int argc, char* argv[]) { int i; u8 ecount_buf[0x10], iv[0x10]; size_t countp; int num; if(argc < 4) { printf("usage: %s input.elf output.self keytype keysuffix\n", argv[0]); return -1; } Elf64_Ehdr input_elf_header; FILE *input_elf_file = fopen(argv[1], "rb"); fseek(input_elf_file, 0, SEEK_END); int nlen = ftell(input_elf_file); fseek(input_elf_file, 0, SEEK_SET); input_elf_data = (u8*)malloc(nlen); fread(input_elf_data, 1, nlen, input_elf_file); fclose(input_elf_file); memcpy(&input_elf_header, input_elf_data, sizeof(input_elf_header)); FILE *output_self_file = fopen(argv[2], "wb"); printf("ELF header size @ %x\n", get_u16(&(input_elf_header.e_ehsize)) ); printf("%d program headers @ %64llX\n", get_u16(&(input_elf_header.e_phnum)), get_u64(&(input_elf_header.e_phoff))); printf("%d section headers @ %64llX\n", get_u16(&(input_elf_header.e_shnum)), get_u64(&(input_elf_header.e_shoff))); Self_Shdr output_self_header; memset(&output_self_header, 0, sizeof(output_self_header)); Self_Ehdr output_extended_self_header; memset(&output_extended_self_header, 0, sizeof(output_extended_self_header)); Self_Ihdr output_self_info_header; memset(&output_self_info_header, 0, sizeof(output_self_info_header)); set_u32(&(output_self_header.s_magic), 0x53434500); set_u32(&(output_self_header.s_hdrversion), 2); set_u16(&(output_self_header.s_flags), 1); set_u16(&(output_self_header.s_hdrtype), 1); // header size and file size aren't known yet set_u64(&(output_extended_self_header.e_magic), 3); set_u64(&(output_extended_self_header.e_ihoff), sizeof(Self_Shdr)+sizeof(Self_Ehdr)); set_u64(&(output_extended_self_header.e_ehoff), sizeof(Self_Shdr)+sizeof(Self_Ehdr)+sizeof(Self_Ihdr)); set_u64(&(output_extended_self_header.e_phoff), sizeof(Self_Shdr)+sizeof(Self_Ehdr)+sizeof(Self_Ihdr)+get_u64(&(input_elf_header.e_phoff))); // section header offset unknown set_u64(&(output_self_info_header.i_authid), 0x1070000500000001LL); set_u32(&(output_self_info_header.i_magic), 0x01000002); set_u32(&(output_self_info_header.i_apptype), 4); set_u64(&(output_self_info_header.i_version), 0x0003000000000000LL); // set static data int phnum = get_u16(&(input_elf_header.e_phnum)); u32 phsize = (sizeof(Elf64_Phdr)*get_u16(&(input_elf_header.e_phnum))); Self_SDKversion sdkversion; Self_Cflags cflags; memcpy(&sdkversion, sdkversion_static, sizeof(Self_SDKversion)); memcpy(&cflags, cflags_static, sizeof(Self_Cflags)); int running_size = (sizeof(output_self_header)+sizeof(output_extended_self_header)+sizeof(output_self_info_header)+sizeof(input_elf_header)+phsize+0xF)&0xFFFFFFF0; set_u64(&(output_extended_self_header.e_pmoff), running_size); running_size += phnum*sizeof(Self_PMhdr); set_u64(&(output_extended_self_header.e_svoff), running_size); running_size += sizeof(Self_SDKversion); set_u64(&(output_extended_self_header.e_cfoff), running_size); running_size += sizeof(Self_Cflags); set_u64(&(output_extended_self_header.e_cfsize), sizeof(Self_Cflags)); set_u32(&(output_self_header.s_esize), running_size - sizeof(output_self_header)); printf("running size is %X\n", running_size); int maxsection = 6; running_size += sizeof(metadata_crypt_header)+sizeof(segment_certification_header)+maxsection*(sizeof(segment_certification_segment)+sizeof(segment_certification_crypt_encrypted))+sizeof(segment_certification_sign)+sizeof(nubpadding_static); printf("running size is %X\n", running_size); set_u64(&(output_self_header.s_shsize), running_size); // init randomness gmp_randstate_t r_state; gmp_randinit_default(r_state); gmp_randseed_ui(r_state, time(NULL)); // loop through the sections segment_certification_header segment_header; memset(&segment_header, 0, sizeof(segment_header)); Self_Section first_section; Self_Section* section_ptr = &first_section; set_u64(&(segment_header.signature_offset), running_size-sizeof(segment_certification_sign)); set_u32(&(segment_header.unknown1), 1); set_u32(&(segment_header.segment_count), phnum); set_u32(&(segment_header.crypt_len), (phnum*sizeof(segment_certification_crypt_encrypted))/0x10); Elf64_Phdr* elf_segment = (Elf64_Phdr*)(&input_elf_data[get_u64(&(input_elf_header.e_phoff))]); for(i=0;i<phnum;i++) { memset(section_ptr, 0, sizeof(Self_Section)); //set_u64(&(section_ptr->enc_segment.segment_offset), get_u64(&(elf_segment->p_vaddr))); set_u64(&(section_ptr->enc_segment.segment_offset), running_size); set_u64(&(section_ptr->enc_segment.segment_size), get_u64(&(elf_segment->p_filesz))); set_u32(&(section_ptr->enc_segment.segment_crypt_flag), 2); set_u32(&(section_ptr->enc_segment.segment_sha1_index), i*8); set_u32(&(section_ptr->enc_segment.segment_erk_index), i*8+6); set_u32(&(section_ptr->enc_segment.segment_riv_index), i*8+7); set_u32(&(section_ptr->enc_segment.segment_number), i); set_u32(&(section_ptr->enc_segment.unknown2), 2); set_u32(&(section_ptr->enc_segment.unknown3), 3); set_u32(&(section_ptr->enc_segment.unknown4), 2); set_u64(&(section_ptr->pmhdr.pm_offset), running_size); set_u64(&(section_ptr->pmhdr.pm_size), get_u64(&(elf_segment->p_filesz))); set_u32(&(section_ptr->pmhdr.pm_compressed), 1); set_u32(&(section_ptr->pmhdr.pm_encrypted), 1); mpz_t riv, erk, hmac; mpz_init(riv); mpz_init(erk); mpz_init(hmac); mpz_urandomb(erk, r_state, 128); mpz_urandomb(riv, r_state, 128); mpz_urandomb(hmac, r_state, 512); mpz_export(section_ptr->crypt_segment.erk, &countp, 1, 0x10, 1, 0, erk); mpz_export(section_ptr->crypt_segment.riv, &countp, 1, 0x10, 1, 0, riv); mpz_export(section_ptr->crypt_segment.hmac, &countp, 1, 0x40, 1, 0, hmac); section_ptr->rlen = get_u64(&(elf_segment->p_filesz)); section_ptr->len = ((section_ptr->rlen)+0xF)&0xFFFFFFF0; section_ptr->data = (u8*)malloc(section_ptr->len); u32 in_data_offset = get_u64(&(elf_segment->p_offset)); // + get_u16(&(input_elf_header.e_ehsize)) + (sizeof(Elf64_Phdr)*get_u16(&(input_elf_header.e_phnum))); u8* in_data = &input_elf_data[in_data_offset]; printf("processing segment %d with len %x offset %x\n", i, section_ptr->len, in_data_offset); //hexdump((u8*)elf_segment, sizeof(Elf64_Phdr)); /*SHA_CTX c; SHA1_ghetto_init(&c, section_ptr->crypt_segment.hmac); SHA1_Update(&c, in_data, section_ptr->rlen); SHA1_ghetto_final(section_ptr->crypt_segment.sha1, &c, section_ptr->crypt_segment.hmac);*/ sha1_hmac(section_ptr->crypt_segment.hmac, in_data, section_ptr->rlen, section_ptr->crypt_segment.sha1); memset(ecount_buf, 0, 16); num=0; AES_set_encrypt_key(section_ptr->crypt_segment.erk, 128, &aes_key); memcpy(iv, section_ptr->crypt_segment.riv, 16); #ifdef NO_CRYPT memcpy(section_ptr->data, in_data, section_ptr->len); #else //AES_ctr128_encrypt(in_data, section_ptr->data, section_ptr->len, &aes_key, iv, ecount_buf, &num); aes128ctr((u8*)&aes_key, iv, in_data, section_ptr->len, section_ptr->data); #endif running_size += section_ptr->len; // next if(i != phnum-1) { section_ptr->next_section = malloc(sizeof(Self_Section)); } elf_segment += 1; // 1 is sizeof(Elf64_Phdr) section_ptr = section_ptr->next_section; } printf("segment processing done\n"); // section table offset set_u64(&(output_extended_self_header.e_shoff), running_size); // lay out the metadata u8 metadata[0x2000]; memset(metadata, 0, 0x2000); u32 metadata_len = 0; memcpy(&metadata[metadata_len], &output_self_header, sizeof(output_self_header)); metadata_len += sizeof(output_self_header); memcpy(&metadata[metadata_len], &output_extended_self_header, sizeof(output_extended_self_header)); metadata_len += sizeof(output_extended_self_header); memcpy(&metadata[metadata_len], &output_self_info_header, sizeof(output_self_info_header)); metadata_len += sizeof(output_self_info_header); memcpy(&metadata[metadata_len], &input_elf_header, sizeof(input_elf_header)); metadata_len += sizeof(input_elf_header); memcpy(&metadata[metadata_len], &input_elf_data[get_u64(&(input_elf_header.e_phoff))], phsize); metadata_len += phsize; metadata_len = (metadata_len+0xF)&0xFFFFFFF0; section_ptr = &first_section; while(section_ptr != NULL) { memcpy(&metadata[metadata_len], &(section_ptr->pmhdr), sizeof(section_ptr->pmhdr)); metadata_len += sizeof(section_ptr->pmhdr); section_ptr = section_ptr->next_section; } memcpy(&metadata[metadata_len], &sdkversion, sizeof(sdkversion)); metadata_len += sizeof(sdkversion); memcpy(&metadata[metadata_len], &cflags, sizeof(cflags)); metadata_len += sizeof(cflags); printf("top half of metadata ready\n"); // generate metadata encryption keys mpz_t bigriv, bigerk; mpz_init(bigriv); mpz_init(bigerk); mpz_urandomb(bigerk, r_state, 128); mpz_urandomb(bigriv, r_state, 128); metadata_crypt_header md_header; mpz_export(md_header.erk, &countp, 1, 0x10, 1, 0, bigerk); mpz_export(md_header.riv, &countp, 1, 0x10, 1, 0, bigriv); memcpy(&metadata[metadata_len], &md_header, sizeof(md_header)); metadata_len += sizeof(md_header); memcpy(&metadata[metadata_len], &segment_header, sizeof(segment_header)); metadata_len += sizeof(segment_header); // copy section data int csection; csection = 0; section_ptr = &first_section; while(section_ptr != NULL) { memcpy(&metadata[metadata_len], &(section_ptr->enc_segment), sizeof(section_ptr->enc_segment)); metadata_len += sizeof(section_ptr->enc_segment); section_ptr = section_ptr->next_section; if((++csection) == maxsection) break; } csection = 0; section_ptr = &first_section; while(section_ptr != NULL) { memcpy(&metadata[metadata_len], &(section_ptr->crypt_segment), sizeof(section_ptr->crypt_segment)); metadata_len += sizeof(section_ptr->crypt_segment); section_ptr = section_ptr->next_section; if((++csection) == maxsection) break; } // nubpadding time memcpy(&metadata[metadata_len], nubpadding_static, sizeof(nubpadding_static)); metadata_len += sizeof(nubpadding_static); // sign shit u8 digest[0x14]; sha1(metadata, metadata_len, digest); printf("metadata len is %X\n", metadata_len); //hexdump(metadata, metadata_len); //hexdump_nl(digest, 0x14); segment_certification_sign all_signed; memset(&all_signed, 0, sizeof(all_signed)); #ifdef GEOHOT_SIGN mpz_t n,k,da,kinv,r,cs,z; mpz_init(n); mpz_init(k); mpz_init(da); mpz_init(r); mpz_init(cs); mpz_init(z); mpz_init(kinv); mpz_import(r, 0x14, 1, 1, 0, 0, appold_R); mpz_import(n, 0x14, 1, 1, 0, 0, appold_n); mpz_import(k, 0x14, 1, 1, 0, 0, appold_K); mpz_import(da, 0x14, 1, 1, 0, 0, appold_Da); mpz_invert(kinv, k, n); mpz_import(z, 0x14, 1, 1, 0, 0, digest); mpz_mul(cs, r, da); mpz_mod(cs, cs, n); mpz_add(cs, cs, z); mpz_mod(cs, cs, n); mpz_mul(cs, cs, kinv); mpz_mod(cs, cs, n); mpz_export(all_signed.R, &countp, 1, 0x14, 1, 0, r); mpz_export(all_signed.S, &countp, 1, 0x14, 1, 0, cs); #else get_keys(argv[3], argv[4]); //ecdsa_set_curve(appnew_ctype); //ecdsa_set_pub(appnew_pub); //ecdsa_set_priv(appnew_priv); //ecdsa_sign(digest, all_signed.R, all_signed.S); #endif memcpy(&metadata[metadata_len], &all_signed, sizeof(all_signed)); metadata_len += sizeof(all_signed); // encrypt metadata int metadata_offset = get_u32(&(output_self_header.s_esize)) + sizeof(Self_Shdr); #ifndef NO_CRYPT /*memset(ecount_buf, 0, 16); num=0; AES_set_encrypt_key(&metadata[metadata_offset], 128, &aes_key); memcpy(iv, &metadata[metadata_offset+0x20], 16); //AES_ctr128_encrypt(&metadata[0x40+metadata_offset], &metadata[0x40+metadata_offset], metadata_len-metadata_offset-0x40, &aes_key, iv, ecount_buf, &num); aes128ctr(&metadata[0x20+metadata_offset], &metadata[0x40+metadata_offset], &metadata[0x60+metadata_offset], metadata_len-metadata_offset-0x60, &metadata[0x60+metadata_offset]); printf("encrypted metadata\n"); //AES_set_encrypt_key(appold_erk, 256, &aes_key); //memcpy(iv, appold_riv, 16); AES_set_encrypt_key(appnew_erk, 256, &aes_key); memcpy(iv, appnew_riv, 16); //AES_cbc_encrypt(&metadata[metadata_offset], &metadata[metadata_offset], 0x40, &aes_key, iv, AES_ENCRYPT); aes256cbc_enc(appnew_erk, appnew_riv, &metadata[metadata_offset], 0x40, &metadata[metadata_offset]); printf("encrypted keys\n");*/ //k.key = appnew_erk; //k.iv = appnew_riv; sce_encrypt_header(metadata, &ks); #endif // write the output self fwrite(metadata, 1, metadata_len, output_self_file); csection = 0; section_ptr = &first_section; while(section_ptr != 0) { printf("writing section with size %X\n", section_ptr->len); fwrite(section_ptr->data, 1, section_ptr->len, output_self_file); section_ptr = section_ptr->next_section; if((++csection) == maxsection) break; } fwrite(&input_elf_data[get_u64(&(input_elf_header.e_shoff))], sizeof(Elf64_Shdr), get_u16(&(input_elf_header.e_shnum)), output_self_file); fclose(output_self_file); }
void enumerate_segments() { int i,num; size_t countp; u8 ecount_buf[0x10],iv[0x10]; Self_Segment* segment_ptr = &first_segment; Elf64_Phdr* elf_segment = (Elf64_Phdr*)(&input_elf_data[get_u64(&(input_elf_header->e_phoff))]); mpz_t riv, erk, hmac; mpz_init(riv); mpz_init(erk); mpz_init(hmac); for(i=0;i<get_u16(&(input_elf_header->e_phnum));i++) { memset(segment_ptr, 0, sizeof(Self_Segment)); // these are choices you can make /*segment_ptr->compressed = (i<2); segment_ptr->incrypt = (i<6); // **TESTING segment_ptr->encrypted = (i<5);*/ #ifdef NPDRM segment_ptr->encrypted = (i<5); segment_ptr->compressed = (i<4); segment_ptr->incrypt = (i<7); #else segment_ptr->encrypted = 1; segment_ptr->compressed = 1; segment_ptr->incrypt = 1; #endif set_u32(&(segment_ptr->enc_segment.segment_number), i); set_u32(&(segment_ptr->enc_segment.unknown2), 2); set_u32(&(segment_ptr->enc_segment.unknown3), 3); mpz_urandomb(hmac, r_state, 512); mpz_export(segment_ptr->crypt_segment.hmac, &countp, 1, 0x40, 1, 0, hmac); if(segment_ptr->encrypted) { mpz_urandomb(erk, r_state, 128); mpz_urandomb(riv, r_state, 128); mpz_export(segment_ptr->crypt_segment.erk, &countp, 1, 0x10, 1, 0, erk); mpz_export(segment_ptr->crypt_segment.riv, &countp, 1, 0x10, 1, 0, riv); } segment_ptr->rlen = get_u64(&(elf_segment->p_filesz)); u32 in_data_offset = get_u64(&(elf_segment->p_offset)); u8* in_data = &input_elf_data[in_data_offset]; if(segment_ptr->compressed) { int def_size = DEFLATION_BUFFER_SIZE; printf("deflated...", def(in_data, segment_ptr->rlen, def_buffer, &def_size)); fflush(stdout); segment_ptr->len = def_size; segment_ptr->data = (u8*)malloc(segment_ptr->len); memcpy(segment_ptr->data, def_buffer, def_size); } else { segment_ptr->len = segment_ptr->rlen; segment_ptr->data = (u8*)malloc(segment_ptr->len); memcpy(segment_ptr->data, in_data, segment_ptr->len); } /*if(i==0) { segment_ptr->padding = 0x26A4; } else if(i==1) { segment_ptr->padding = 0xC; } else { segment_ptr->padding = 0; }*/ segment_ptr->padding = (0x10-(segment_ptr->len&0xF))&0xF; // hacks to make it match /*if(segment_ptr->len == 0x14BCC8) { segment_ptr->padding += 0x4330; }*/ printf("processing segment %d with rlen %x len %x offset %x...", i, segment_ptr->rlen, segment_ptr->len, in_data_offset); fflush(stdout); //hexdump((u8*)elf_segment, sizeof(Elf64_Phdr)); set_u64(&(segment_ptr->enc_segment.segment_size), segment_ptr->len); set_u32(&(segment_ptr->enc_segment.segment_crypt_flag), 1+segment_ptr->encrypted); set_u32(&(segment_ptr->enc_segment.segment_compressed_flag), 1+segment_ptr->compressed); set_u64(&(segment_ptr->pmhdr.pm_size), segment_ptr->len); set_u32(&(segment_ptr->pmhdr.pm_compressed), 1+segment_ptr->compressed); set_u32(&(segment_ptr->pmhdr.pm_encrypted), segment_ptr->encrypted); // compute sha1 SHA_CTX c; SHA1_ghetto_init(&c, segment_ptr->crypt_segment.hmac); SHA1_Update(&c, segment_ptr->data, segment_ptr->len); SHA1_ghetto_final(segment_ptr->crypt_segment.sha1, &c, segment_ptr->crypt_segment.hmac); if(segment_ptr->encrypted) { printf("encrypted..."); fflush(stdout); memset(ecount_buf, 0, 16); num=0; AES_set_encrypt_key(segment_ptr->crypt_segment.erk, 128, &aes_key); memcpy(iv, segment_ptr->crypt_segment.riv, 16); #ifndef NO_CRYPT AES_ctr128_encrypt(segment_ptr->data, segment_ptr->data, segment_ptr->len, &aes_key, iv, ecount_buf, &num); #endif } if(i != get_u16(&(input_elf_header->e_phnum))-1) { segment_ptr->next_segment = malloc(sizeof(Self_Segment)); } elf_segment += 1; // 1 is sizeof(Elf64_Phdr) segment_ptr = segment_ptr->next_segment; printf("\n"); } }
int main(int argc, char* argv[]) { int i; u8 ecount_buf[0x10], iv[0x10]; size_t countp; int num; Self_Segment* segment_ptr; memset(zero_padding, 0, sizeof(zero_padding)); #ifdef NPDRM if(argc < 3) { printf("usage: %s input.elf output.self <titleid>\n", argv[0]); printf(" warning NPDRM cares about the output file name, do not rename\n"); return -1; } #else if(argc < 2) { printf("usage: %s input.elf output.self\n", argv[0]); return -1; } #endif // init randomness gmp_randinit_default(r_state); gmp_randseed_ui(r_state, time(NULL)); // read elf file read_elf_file(argv[1]); input_elf_header = (Elf64_Ehdr*)input_elf_data; printf("ELF header size @ %x\n", get_u16(&(input_elf_header->e_ehsize)) ); printf("%d program headers @ %llx\n", get_u16(&(input_elf_header->e_phnum)), get_u64(&(input_elf_header->e_phoff))); printf("%d section headers @ %llx\n", get_u16(&(input_elf_header->e_shnum)), get_u64(&(input_elf_header->e_shoff))); // loop through the segments enumerate_segments(); printf("segments enumerated\n"); // setup self headers Self_Shdr output_self_header; memset(&output_self_header, 0, sizeof(output_self_header)); Self_Ehdr output_extended_self_header; memset(&output_extended_self_header, 0, sizeof(output_extended_self_header)); Self_Ihdr output_self_info_header; memset(&output_self_info_header, 0, sizeof(output_self_info_header)); init_Self_Shdr(&output_self_header); init_Self_Ehdr(&output_extended_self_header); init_Self_Ihdr(&output_self_info_header); set_u64(&output_self_header.s_exsize, input_elf_len); // setup segment header segment_certification_header segment_header; memset(&segment_header, 0, sizeof(segment_header)); set_u32(&(segment_header.version), 1); // NPDRM #ifdef NPDRM Self_NPDRM npdrm; memset(&npdrm, 0, sizeof(npdrm)); init_Self_NPDRM(&npdrm, argv[3], argv[2]); #endif // useless bullshit Self_SDKversion sdkversion; Self_Cflags cflags; memcpy(&sdkversion, sdkversion_static, sizeof(Self_SDKversion)); memcpy(&cflags, cflags_static, sizeof(Self_Cflags)); // generate metadata encryption keys metadata_crypt_header md_header; memset(&md_header, 0, sizeof(md_header)); #ifdef NPDRM memcpy(&md_header, npdrm_keypair_d, sizeof(md_header)); #else mpz_t bigriv, bigerk; mpz_init(bigriv); mpz_init(bigerk); mpz_urandomb(bigerk, r_state, 128); mpz_urandomb(bigriv, r_state, 128); mpz_export(md_header.erk, &countp, 1, 0x10, 1, 0, bigerk); mpz_export(md_header.riv, &countp, 1, 0x10, 1, 0, bigriv); #endif // init signing shit mpz_t n,k,da,kinv,r,cs,z; mpz_init(n); mpz_init(k); mpz_init(da); mpz_init(r); mpz_init(cs); mpz_init(z); mpz_init(kinv); mpz_import(r, 0x14, 1, 1, 0, 0, KEY(R)); mpz_import(n, 0x14, 1, 1, 0, 0, KEY(n)); mpz_import(k, 0x14, 1, 1, 0, 0, KEY(K)); mpz_import(da, 0x14, 1, 1, 0, 0, KEY(Da)); mpz_invert(kinv, k, n); segment_certification_sign all_signed; memset(&all_signed, 0, sizeof(all_signed)); mpz_export(all_signed.R, &countp, 1, 0x14, 1, 0, r); // **** everything here is still length independent *** build_segment_crypt_data(); set_u32(&(segment_header.crypt_len), (segment_crypt_data_len)/0x10); set_u32(&(segment_header.unknown2), 0x30); // needed?? printf("built crypt data\n"); // start building metadata in theory, ordering is fixed now memset(&start_file, 0, sizeof(file_ll)); running_size = 0; // 0x000 -- Self_Shdr add_file_section(&output_self_header, sizeof(output_self_header)); // 0x020 -- Self_Ehdr add_file_section(&output_extended_self_header, sizeof(output_extended_self_header)); // 0x070 -- Self_Ihdr set_u64(&(output_extended_self_header.e_ihoff), running_size); add_file_section(&output_self_info_header, sizeof(output_self_info_header)); // 0x090 -- elf data set_u64(&(output_extended_self_header.e_ehoff), running_size); set_u64(&(output_extended_self_header.e_phoff), running_size+get_u64(&(input_elf_header->e_phoff))); add_file_section(input_elf_data, get_u64(&(input_elf_header->e_phoff)) + get_u16(&(input_elf_header->e_phnum)) * sizeof(Elf64_Phdr)); add_file_section(zero_padding, (0x10-(running_size&0xF))&0xF); // 0x*** -- all Self_PMhdr(including not in crypt) set_u64(&(output_extended_self_header.e_pmoff), running_size); segment_ptr = &first_segment; while(segment_ptr != NULL) { add_file_section(&(segment_ptr->pmhdr), sizeof(segment_ptr->pmhdr)); segment_ptr = segment_ptr->next_segment; } // 0x*** -- Self_SDKversion set_u64(&(output_extended_self_header.e_svoff), running_size); add_file_section(&sdkversion, sizeof(sdkversion)); // 0x*** -- ??? #ifdef NPDRM add_file_section(zero_padding, 0x20); #endif // 0x*** -- Self_Cflags set_u64(&(output_extended_self_header.e_cfoff), running_size); add_file_section(&cflags, sizeof(cflags)); #ifdef NPDRM // 0x*** -- npdrm data add_file_section(&npdrm, sizeof(npdrm)); #endif // 0x*** -- metadata_crypt_header set_u32(&(output_self_header.s_esize), running_size - sizeof(output_self_header)); add_file_section(&md_header, sizeof(md_header)); // 0x*** -- segment_certification_header add_file_section(&segment_header, sizeof(segment_header)); // 0x*** -- all segment_certification_segment incrypt int incrypt_count = 0; segment_ptr = &first_segment; while(segment_ptr != NULL) { if(segment_ptr->incrypt) { add_file_section(&(segment_ptr->enc_segment), sizeof(segment_ptr->enc_segment)); incrypt_count++; } segment_ptr = segment_ptr->next_segment; } set_u32(&(segment_header.segment_count), incrypt_count); // 0x*** -- segment_crypt_data add_file_section(segment_crypt_data, segment_crypt_data_len); // 0x*** -- nubpadding_static add_file_section(nubpadding_static, sizeof(nubpadding_static)); // 0x*** -- segment_certification_sign set_u64(&(segment_header.signature_offset), running_size); add_file_section(&all_signed, sizeof(all_signed)); // 0x*** -- data must be 0x80 aligned if((running_size%0x80) != 0) { add_file_section(zero_padding, 0x80-(running_size%0x80)); } // 0x*** -- data set_u64(&(output_self_header.s_shsize), running_size); // ...data... segment_ptr = &first_segment; while(segment_ptr != NULL) { set_u64(&(segment_ptr->enc_segment.segment_offset), running_size); set_u64(&(segment_ptr->pmhdr.pm_offset), running_size); add_file_section(segment_ptr->data, segment_ptr->len); add_file_section(zero_padding, segment_ptr->padding); segment_ptr = segment_ptr->next_segment; } // 0x*** -- section table #ifndef SPRX set_u64(&(output_extended_self_header.e_shoff), running_size); add_file_section(input_elf_data+get_u64(&(input_elf_header->e_shoff)), get_u16(&(input_elf_header->e_shnum)) * sizeof(Elf64_Shdr)); #endif // ***DONE*** printf("file built\n"); // write self file in memory <-- useful comment write_self_file_in_memory(); printf("self written in memory\n"); // sign shit u8 digest[0x14]; SHA1(output_self_data, get_u64(&(segment_header.signature_offset)), digest); mpz_import(z, 0x14, 1, 1, 0, 0, digest); mpz_mul(cs, r, da); mpz_mod(cs, cs, n); mpz_add(cs, cs, z); mpz_mod(cs, cs, n); mpz_mul(cs, cs, kinv); mpz_mod(cs, cs, n); //mpz_export(all_signed.S, &countp, 1, 0x14, 1, 0, cs); mpz_export(&output_self_data[get_u64(&output_self_data[get_u32(output_self_data+0xC)+0x60])+0x16], &countp, 1, 0x14, 1, 0, cs); // write the output self test FILE *test_self_file = fopen("test_out", "wb"); fwrite(output_self_data, 1, running_size, test_self_file); fclose(test_self_file); // encrypt metadata int metadata_offset = get_u32(&(output_self_header.s_esize)) + sizeof(Self_Shdr); #ifndef NO_CRYPT memset(ecount_buf, 0, 16); num=0; AES_set_encrypt_key(&output_self_data[metadata_offset], 128, &aes_key); memcpy(iv, &output_self_data[metadata_offset+0x20], 16); AES_ctr128_encrypt(&output_self_data[0x40+metadata_offset], &output_self_data[0x40+metadata_offset], get_u64(&(output_self_header.s_shsize))-metadata_offset-0x40, &aes_key, iv, ecount_buf, &num); printf("encrypted metadata\n"); #ifdef NPDRM memcpy(&output_self_data[metadata_offset], npdrm_keypair_e, sizeof(md_header)); #else AES_set_encrypt_key(KEY(erk), 256, &aes_key); memcpy(iv, KEY(riv), 16); AES_cbc_encrypt(&output_self_data[metadata_offset], &output_self_data[metadata_offset], 0x40, &aes_key, iv, AES_ENCRYPT); printf("encrypted keys\n"); #endif #else printf("NO_CRYPT is enabled...self is broken\n"); #endif // write the output self FILE *output_self_file = fopen(argv[2], "wb"); fwrite(output_self_data, 1, running_size, output_self_file); fclose(output_self_file); }