From 0e84db7cd95472de0096ddc6047d135bc80b87b9 Mon Sep 17 00:00:00 2001 From: roblabla Date: Tue, 7 Apr 2020 14:27:20 +0000 Subject: [PATCH 1/6] chore: Rename sections to segments when relevant --- src/format/nxo.rs | 146 ++++++++++++++++++++++---------------------- src/format/utils.rs | 2 +- 2 files changed, 74 insertions(+), 74 deletions(-) diff --git a/src/format/nxo.rs b/src/format/nxo.rs index 6dd9d21..2922c49 100644 --- a/src/format/nxo.rs +++ b/src/format/nxo.rs @@ -15,10 +15,10 @@ use std::convert::TryFrom; pub struct NxoFile { file: File, machine: Machine, - text_section: ProgramHeader, - rodata_section: ProgramHeader, - data_section: ProgramHeader, - bss_section: Option, + text_segment: ProgramHeader, + rodata_segment: ProgramHeader, + data_segment: ProgramHeader, + bss_segment: Option, build_id: Option>, } @@ -34,13 +34,13 @@ pub struct KipNpdm { kernel_capabilities: Vec, } -fn pad_segment(previous_segment_data: &mut Vec, offset: usize, section: &ProgramHeader) { - let section_vaddr = section.vaddr as usize; - let section_supposed_start = previous_segment_data.len() + offset; +fn pad_segment(previous_segment_data: &mut Vec, offset: usize, segment: &ProgramHeader) { + let segment_vaddr = segment.vaddr as usize; + let segment_supposed_start = previous_segment_data.len() + offset; - if section_vaddr > section_supposed_start { + if segment_vaddr > segment_supposed_start { let real_size = previous_segment_data.len(); - previous_segment_data.resize(real_size + (section_vaddr - section_supposed_start), 0); + previous_segment_data.resize(real_size + (segment_vaddr - segment_supposed_start), 0); } } @@ -82,22 +82,22 @@ impl NxoFile { let sections = &elf_file.sections; let phdrs: Vec = elf_file.phdrs.to_vec(); - let text_section = phdrs.get(0).unwrap_or_else(|| { + let text_segment = phdrs.get(0).unwrap_or_else(|| { println!("Error: .text not found in ELF file"); process::exit(1) }); - let rodata_section = phdrs.get(1).unwrap_or_else(|| { + let rodata_segment = phdrs.get(1).unwrap_or_else(|| { println!("Error: .rodata not found in ELF file"); process::exit(1) }); - let data_section = phdrs.get(2).unwrap_or_else(|| { + let data_segment = phdrs.get(2).unwrap_or_else(|| { println!("Error: .data not found in ELF file"); process::exit(1) }); - let bss_section = match phdrs.get(3) { + let bss_segment = match phdrs.get(3) { Some(s) => { if s.progtype == PT_LOAD { Some(*s) @@ -128,10 +128,10 @@ impl NxoFile { Ok(NxoFile { file, machine: elf_file.ehdr.machine, - text_section: *text_section, - rodata_section: *rodata_section, - data_section: *data_section, - bss_section, + text_segment: *text_segment, + rodata_segment: *rodata_segment, + data_segment: *data_segment, + bss_segment, build_id, }) } @@ -140,14 +140,14 @@ impl NxoFile { where T: Write, { - let text_section = &self.text_section; - let rodata_section = &self.rodata_section; - let data_section = &self.data_section; + let text_segment = &self.text_segment; + let rodata_segment = &self.rodata_segment; + let data_segment = &self.data_segment; // Get segments data - let mut code = utils::get_section_data(&mut self.file, text_section)?; - let mut rodata = utils::get_section_data(&mut self.file, rodata_section)?; - let mut data = utils::get_section_data(&mut self.file, data_section)?; + let mut code = utils::get_segment_data(&mut self.file, text_segment)?; + let mut rodata = utils::get_segment_data(&mut self.file, rodata_segment)?; + let mut data = utils::get_segment_data(&mut self.file, data_segment)?; // First correctly align to be conform to the NRO standard utils::add_padding(&mut code, 0xFFF); @@ -155,11 +155,11 @@ impl NxoFile { utils::add_padding(&mut data, 0xFFF); // Finally fix possible misalign of vaddr because NRO only have one base - pad_segment(&mut code, 0, rodata_section); - pad_segment(&mut rodata, code.len(), data_section); + pad_segment(&mut code, 0, rodata_segment); + pad_segment(&mut rodata, code.len(), data_segment); - if let Some(section) = self.bss_section { - pad_segment(&mut data, code.len() + rodata.len(), §ion); + if let Some(segment) = self.bss_segment { + pad_segment(&mut data, code.len() + rodata.len(), &segment); } let total_len: u32 = (code.len() + rodata.len() + data.len()) as u32; @@ -198,21 +198,21 @@ impl NxoFile { file_offset += data_size; // BSS size - match self.bss_section { - Some(section) => { - if section.vaddr != u64::from(file_offset) { + match self.bss_segment { + Some(segment) => { + if segment.vaddr != u64::from(file_offset) { println!( "Warning: possible misalign bss\n.bss addr: 0x{:x}\nexpected offset: 0x{:x}", - section.vaddr, file_offset); + segment.vaddr, file_offset); } output_writter - .write_u32::(((section.memsz + 0xFFF) & !0xFFF) as u32)?; + .write_u32::(((segment.memsz + 0xFFF) & !0xFFF) as u32)?; } _ => { // in this case the bss is missing or is embedeed in .data. libnx does that, let's support it - let data_section_size = (data_section.filesz + 0xFFF) & !0xFFF; - let bss_size = if data_section.memsz > data_section_size { - (((data_section.memsz - data_section_size) + 0xFFF) & !0xFFF) as u32 + let data_segment_size = (data_segment.filesz + 0xFFF) & !0xFFF; + let bss_size = if data_segment.memsz > data_segment_size { + (((data_segment.memsz - data_segment_size) + 0xFFF) & !0xFFF) as u32 } else { 0 }; @@ -236,7 +236,7 @@ impl NxoFile { output_writter.write_all(&rodata)?; output_writter.write_all(&data)?; - // Early return if there's no need for an ASET section. + // Early return if there's no need for an ASET segment. if let (None, None, None) = (&icon, &romfs, &nacp) { return Ok(()) } @@ -301,13 +301,13 @@ impl NxoFile { where T: Write, { - let text_section = &self.text_section; - let rodata_section = &self.rodata_section; - let data_section = &self.data_section; + let text_segment = &self.text_segment; + let rodata_segment = &self.rodata_segment; + let data_segment = &self.data_segment; - let mut code = utils::get_section_data(&mut self.file, text_section)?; - let mut rodata = utils::get_section_data(&mut self.file, rodata_section)?; - let mut data = utils::get_section_data(&mut self.file, data_section)?; + let mut code = utils::get_segment_data(&mut self.file, text_segment)?; + let mut rodata = utils::get_segment_data(&mut self.file, rodata_segment)?; + let mut data = utils::get_segment_data(&mut self.file, data_segment)?; // First correctly align to avoid possible compression issues utils::add_padding(&mut code, 0xFFF); @@ -315,8 +315,8 @@ impl NxoFile { utils::add_padding(&mut data, 0xFFF); // Because bss doesn't have it's own segment in NSO, we need to pad .data to the .bss vaddr - if let Some(section) = self.bss_section { - pad_segment(&mut data, data_section.vaddr as usize, §ion); + if let Some(segment) = self.bss_segment { + pad_segment(&mut data, data_segment.vaddr as usize, &segment); } // NSO magic @@ -337,7 +337,7 @@ impl NxoFile { let compressed_code = utils::compress_lz4(&mut code)?; let compressed_code_size = compressed_code.len() as u32; output_writter.write_u32::(file_offset as u32)?; - output_writter.write_u32::(text_section.vaddr as u32)?; + output_writter.write_u32::(text_segment.vaddr as u32)?; output_writter.write_u32::(code_size as u32)?; // Module offset (TODO: SUPPORT THAT) @@ -350,7 +350,7 @@ impl NxoFile { let compressed_rodata = utils::compress_lz4(&mut rodata)?; let compressed_rodata_size = compressed_rodata.len() as u32; output_writter.write_u32::(file_offset as u32)?; - output_writter.write_u32::(rodata_section.vaddr as u32)?; + output_writter.write_u32::(rodata_segment.vaddr as u32)?; output_writter.write_u32::(rodata_size as u32)?; // Module file size (TODO: SUPPORT THAT) @@ -364,26 +364,26 @@ impl NxoFile { let compressed_data_size = compressed_data.len() as u32; let uncompressed_data_size = data.len() as u64; output_writter.write_u32::(file_offset as u32)?; - output_writter.write_u32::(data_section.vaddr as u32)?; + output_writter.write_u32::(data_segment.vaddr as u32)?; output_writter.write_u32::(data_size as u32)?; // BSS size - match self.bss_section { - Some(section) => { - let memory_offset = data_section.vaddr + uncompressed_data_size; - if section.vaddr != memory_offset { + match self.bss_segment { + Some(segment) => { + let memory_offset = data_segment.vaddr + uncompressed_data_size; + if segment.vaddr != memory_offset { println!( "Warning: possible misalign bss\n.bss addr: 0x{:x}\nexpected offset: 0x{:x}", - section.vaddr, memory_offset); + segment.vaddr, memory_offset); } // (bss_segment['p_memsz'] + 0xFFF) & ~0xFFF output_writter - .write_u32::(((section.memsz + 0xFFF) & !0xFFF) as u32)?; + .write_u32::(((segment.memsz + 0xFFF) & !0xFFF) as u32)?; } _ => { // in this case the bss is missing or is embedeed in .data. libnx does that, let's support it output_writter - .write_u32::((data_section.memsz - data_section.filesz) as u32)?; + .write_u32::((data_segment.memsz - data_segment.filesz) as u32)?; } } @@ -449,29 +449,29 @@ impl NxoFile { unimplemented!("Unknown machine type"); } - let mut section_data = utils::get_section_data(&mut self.file, &self.text_section)?; - let text_data = utils::compress_blz(&mut section_data).unwrap(); - let mut section_data = utils::get_section_data(&mut self.file, &self.rodata_section)?; - let rodata_data = utils::compress_blz(&mut section_data).unwrap(); - let mut section_data = utils::get_section_data(&mut self.file, &self.data_section)?; - let data_data = utils::compress_blz(&mut section_data).unwrap(); + let mut segment_data = utils::get_segment_data(&mut self.file, &self.text_segment)?; + let text_data = utils::compress_blz(&mut segment_data).unwrap(); + let mut segment_data = utils::get_segment_data(&mut self.file, &self.rodata_segment)?; + let rodata_data = utils::compress_blz(&mut segment_data).unwrap(); + let mut segment_data = utils::get_segment_data(&mut self.file, &self.data_segment)?; + let data_data = utils::compress_blz(&mut segment_data).unwrap(); - write_kip_section_header(output_writer, &self.text_section, 0, text_data.len() as u32)?; - write_kip_section_header(output_writer, &self.rodata_section, u32::try_from(npdm.main_thread_stack_size.0).expect("Exected main_thread_stack_size to be an u32"), rodata_data.len() as u32)?; - write_kip_section_header(output_writer, &self.data_section, 0, data_data.len() as u32)?; + write_kip_segment_header(output_writer, &self.text_segment, 0, text_data.len() as u32)?; + write_kip_segment_header(output_writer, &self.rodata_segment, u32::try_from(npdm.main_thread_stack_size.0).expect("Exected main_thread_stack_size to be an u32"), rodata_data.len() as u32)?; + write_kip_segment_header(output_writer, &self.data_segment, 0, data_data.len() as u32)?; - if let Some(section) = self.bss_section { - output_writer.write_u32::(u32::try_from(section.vaddr).expect("BSS vaddr too big"))?; - output_writer.write_u32::(u32::try_from(section.memsz).expect("BSS memsize too big"))?; + if let Some(segment) = self.bss_segment { + output_writer.write_u32::(u32::try_from(segment.vaddr).expect("BSS vaddr too big"))?; + output_writer.write_u32::(u32::try_from(segment.memsz).expect("BSS memsize too big"))?; } else { // in this case the bss is missing or is embedeed in .data. libnx does that, let's support it - let data_section_size = (self.data_section.filesz + 0xFFF) & !0xFFF; - let bss_size = if self.data_section.memsz > data_section_size { - (((self.data_section.memsz - data_section_size) + 0xFFF) & !0xFFF) as u32 + let data_segment_size = (self.data_segment.filesz + 0xFFF) & !0xFFF; + let bss_size = if self.data_segment.memsz > data_segment_size { + (((self.data_segment.memsz - data_segment_size) + 0xFFF) & !0xFFF) as u32 } else { 0 }; - output_writer.write_u32::(u32::try_from(self.data_section.vaddr + data_section_size).unwrap())?; + output_writer.write_u32::(u32::try_from(self.data_segment.vaddr + data_segment_size).unwrap())?; output_writer.write_u32::(bss_size)?; } output_writer.write_u32::(0)?; @@ -509,12 +509,12 @@ impl NxoFile { } } -pub fn write_kip_section_header(output_writer: &mut T, section: &ProgramHeader, attributes: u32, compressed_size: u32) -> std::io::Result<()> +pub fn write_kip_segment_header(output_writer: &mut T, segment: &ProgramHeader, attributes: u32, compressed_size: u32) -> std::io::Result<()> where T: Write, { - output_writer.write_u32::(u32::try_from(section.vaddr).expect("vaddr too big"))?; - output_writer.write_u32::(u32::try_from(section.filesz).expect("memsz too big"))?; + output_writer.write_u32::(u32::try_from(segment.vaddr).expect("vaddr too big"))?; + output_writer.write_u32::(u32::try_from(segment.filesz).expect("memsz too big"))?; output_writer.write_u32::(u32::try_from(compressed_size).expect("Compressed size too big"))?; output_writer.write_u32::(attributes)?; diff --git a/src/format/utils.rs b/src/format/utils.rs index 94246ad..acdc791 100644 --- a/src/format/utils.rs +++ b/src/format/utils.rs @@ -24,7 +24,7 @@ pub fn check_string_or_truncate(string: &mut String, name: &str, size: usize) { } } -pub fn get_section_data( +pub fn get_segment_data( file: &mut File, header: &elf::types::ProgramHeader, ) -> std::io::Result> { From c32c582d8097563e9084dcf3127fb10832627d40 Mon Sep 17 00:00:00 2001 From: roblabla Date: Tue, 7 Apr 2020 18:18:14 +0000 Subject: [PATCH 2/6] Update PKI with new keys, add dev keys --- src/bin/linkle_clap.rs | 8 ++- src/pki.rs | 155 +++++++++++++++++++++++++++++++++++++---- 2 files changed, 148 insertions(+), 15 deletions(-) diff --git a/src/bin/linkle_clap.rs b/src/bin/linkle_clap.rs index 843a0cb..ca0f669 100644 --- a/src/bin/linkle_clap.rs +++ b/src/bin/linkle_clap.rs @@ -134,7 +134,7 @@ fn create_kip(input_file: &str, npdm_file: &str, output_file: &str) -> Result<() let mut option = OpenOptions::new(); let output_option = option.write(true).create(true).truncate(true); output_option.open(output_file)?; - + nxo.write_kip1(&mut output_option.open(output_file).map_err(|err| (err, output_file))?, &npdm).map_err(|err| (err, output_file))?; Ok(()) } @@ -187,7 +187,11 @@ fn create_romfs(input_directory: &Path, output_file: &Path) -> Result<(), linkle } fn print_keys(is_dev: bool, key_path: Option<&Path>) -> Result<(), linkle::error::Error> { - let keys = linkle::pki::Keys::new_retail(key_path).unwrap(); + let keys = if is_dev { + linkle::pki::Keys::new_retail(key_path).unwrap() + } else { + linkle::pki::Keys::new_dev(key_path).unwrap() + }; keys.write(&mut std::io::stdout()).unwrap(); Ok(()) diff --git a/src/pki.rs b/src/pki.rs index fbc8d2d..de5b1b2 100644 --- a/src/pki.rs +++ b/src/pki.rs @@ -146,7 +146,7 @@ pub struct Keys { keyblobs: [Option; 0x20], keyblob_key_sources: [Option; 0x20], keyblob_mac_key_source: Option, - tsec_root_key: Option, + tsec_root_key: [Option; 0x20], master_kek_sources: [Option; 0x20], master_keks: [Option; 0x20], master_key_source: Option, @@ -174,8 +174,8 @@ pub struct Keys { key_area_key_system: [Option; 0x20], sd_card_save_key: Option, sd_card_nca_key: Option, - nca_hdr_fixed_key_modulus: Option, - acid_fixed_key_modulus: Option, + nca_hdr_fixed_key_modulus: [Option; 2], + acid_fixed_key_modulus: [Option; 2], package2_fixed_key_modulus: Option, } @@ -312,11 +312,13 @@ fn generate_kek(src: &Aes128Key, master_key: &Aes128Key, kek_seed: &Aes128Key, k impl Keys { #[allow(clippy::new_ret_no_self)] - fn new(key_path: Option<&Path>, default_key_name: &Path, modulus: (Modulus, Modulus, Modulus)) -> Result { + fn new(key_path: Option<&Path>, default_key_name: &Path, modulus: ([Modulus; 2], [Modulus; 2], Modulus)) -> Result { let (modulus0, modulus1, modulus2) = modulus; + let [modulus00, modulus01] = modulus0; + let [modulus10, modulus11] = modulus1; let mut keys = Keys { - nca_hdr_fixed_key_modulus: Some(modulus0), - acid_fixed_key_modulus: Some(modulus1), + nca_hdr_fixed_key_modulus: [Some(modulus00), Some(modulus01)], + acid_fixed_key_modulus: [Some(modulus10), Some(modulus11)], package2_fixed_key_modulus: Some(modulus2), ..Default::default() }; @@ -356,7 +358,7 @@ impl Keys { pub fn new_retail(key_path: Option<&Path>) -> Result { Keys::new(key_path, Path::new("prod.keys"), ( - /* nca_hdr_fixed_key_modulus: */ Modulus([ + /* nca_hdr_fixed_key_modulus: */ [Modulus([ 0xBF, 0xBE, 0x40, 0x6C, 0xF4, 0xA7, 0x80, 0xE9, 0xF0, 0x7D, 0x0C, 0x99, 0x61, 0x1D, 0x77, 0x2F, 0x96, 0xBC, 0x4B, 0x9E, 0x58, 0x38, 0x1B, 0x03, 0xAB, 0xB1, 0x75, 0x49, 0x9F, 0x2B, 0x4D, 0x58, 0x34, 0xB0, 0x05, 0xA3, 0x75, 0x22, 0xBE, 0x1A, 0x3F, 0x03, 0x73, 0xAC, 0x70, 0x68, 0xD1, 0x16, @@ -373,8 +375,25 @@ impl Keys { 0x02, 0x79, 0xEA, 0xD2, 0xA7, 0xAF, 0x35, 0x28, 0x32, 0x1C, 0x7B, 0xE6, 0x2F, 0x1A, 0xAA, 0x40, 0x7E, 0x32, 0x8C, 0x27, 0x42, 0xFE, 0x82, 0x78, 0xEC, 0x0D, 0xEB, 0xE6, 0x83, 0x4B, 0x6D, 0x81, 0x04, 0x40, 0x1A, 0x9E, 0x9A, 0x67, 0xF6, 0x72, 0x29, 0xFA, 0x04, 0xF0, 0x9D, 0xE4, 0xF4, 0x03 - ]), - /* acid_fixed_key_modulus: */ Modulus([ + ]), Modulus([ + 0xAD, 0xE3, 0xE1, 0xFA, 0x04, 0x35, 0xE5, 0xB6, 0xDD, 0x49, 0xEA, 0x89, 0x29, 0xB1, 0xFF, 0xB6, + 0x43, 0xDF, 0xCA, 0x96, 0xA0, 0x4A, 0x13, 0xDF, 0x43, 0xD9, 0x94, 0x97, 0x96, 0x43, 0x65, 0x48, + 0x70, 0x58, 0x33, 0xA2, 0x7D, 0x35, 0x7B, 0x96, 0x74, 0x5E, 0x0B, 0x5C, 0x32, 0x18, 0x14, 0x24, + 0xC2, 0x58, 0xB3, 0x6C, 0x22, 0x7A, 0xA1, 0xB7, 0xCB, 0x90, 0xA7, 0xA3, 0xF9, 0x7D, 0x45, 0x16, + 0xA5, 0xC8, 0xED, 0x8F, 0xAD, 0x39, 0x5E, 0x9E, 0x4B, 0x51, 0x68, 0x7D, 0xF8, 0x0C, 0x35, 0xC6, + 0x3F, 0x91, 0xAE, 0x44, 0xA5, 0x92, 0x30, 0x0D, 0x46, 0xF8, 0x40, 0xFF, 0xD0, 0xFF, 0x06, 0xD2, + 0x1C, 0x7F, 0x96, 0x18, 0xDC, 0xB7, 0x1D, 0x66, 0x3E, 0xD1, 0x73, 0xBC, 0x15, 0x8A, 0x2F, 0x94, + 0xF3, 0x00, 0xC1, 0x83, 0xF1, 0xCD, 0xD7, 0x81, 0x88, 0xAB, 0xDF, 0x8C, 0xEF, 0x97, 0xDD, 0x1B, + 0x17, 0x5F, 0x58, 0xF6, 0x9A, 0xE9, 0xE8, 0xC2, 0x2F, 0x38, 0x15, 0xF5, 0x21, 0x07, 0xF8, 0x37, + 0x90, 0x5D, 0x2E, 0x02, 0x40, 0x24, 0x15, 0x0D, 0x25, 0xB7, 0x26, 0x5D, 0x09, 0xCC, 0x4C, 0xF4, + 0xF2, 0x1B, 0x94, 0x70, 0x5A, 0x9E, 0xEE, 0xED, 0x77, 0x77, 0xD4, 0x51, 0x99, 0xF5, 0xDC, 0x76, + 0x1E, 0xE3, 0x6C, 0x8C, 0xD1, 0x12, 0xD4, 0x57, 0xD1, 0xB6, 0x83, 0xE4, 0xE4, 0xFE, 0xDA, 0xE9, + 0xB4, 0x3B, 0x33, 0xE5, 0x37, 0x8A, 0xDF, 0xB5, 0x7F, 0x89, 0xF1, 0x9B, 0x9E, 0xB0, 0x15, 0xB2, + 0x3A, 0xFE, 0xEA, 0x61, 0x84, 0x5B, 0x7D, 0x4B, 0x23, 0x12, 0x0B, 0x83, 0x12, 0xF2, 0x22, 0x6B, + 0xB9, 0x22, 0x96, 0x4B, 0x26, 0x0B, 0x63, 0x5E, 0x96, 0x57, 0x52, 0xA3, 0x67, 0x64, 0x22, 0xCA, + 0xD0, 0x56, 0x3E, 0x74, 0xB5, 0x98, 0x1F, 0x0D, 0xF8, 0xB3, 0x34, 0xE6, 0x98, 0x68, 0x5A, 0xAD, + ])], + /* acid_fixed_key_modulus: */ [Modulus([ 0xDD, 0xC8, 0xDD, 0xF2, 0x4E, 0x6D, 0xF0, 0xCA, 0x9E, 0xC7, 0x5D, 0xC7, 0x7B, 0xAD, 0xFE, 0x7D, 0x23, 0x89, 0x69, 0xB6, 0xF2, 0x06, 0xA2, 0x02, 0x88, 0xE1, 0x55, 0x91, 0xAB, 0xCB, 0x4D, 0x50, 0x2E, 0xFC, 0x9D, 0x94, 0x76, 0xD6, 0x4C, 0xD8, 0xFF, 0x10, 0xFA, 0x5E, 0x93, 0x0A, 0xB4, 0x57, @@ -391,7 +410,24 @@ impl Keys { 0xB7, 0x88, 0x4A, 0x14, 0x84, 0x80, 0x33, 0x3C, 0x9D, 0x44, 0xB7, 0x3F, 0x4C, 0xE1, 0x75, 0xEA, 0x37, 0xEA, 0xE8, 0x1E, 0x7C, 0x77, 0xB7, 0xC6, 0x1A, 0xA2, 0xF0, 0x9F, 0x10, 0x61, 0xCD, 0x7B, 0x5B, 0x32, 0x4C, 0x37, 0xEF, 0xB1, 0x71, 0x68, 0x53, 0x0A, 0xED, 0x51, 0x7D, 0x35, 0x22, 0xFD - ]), + ]), Modulus([ + 0xE7, 0xAA, 0x25, 0xC8, 0x01, 0xA5, 0x14, 0x6B, 0x01, 0x60, 0x3E, 0xD9, 0x96, 0x5A, 0xBF, 0x90, + 0xAC, 0xA7, 0xFD, 0x9B, 0x5B, 0xBD, 0x8A, 0x26, 0xB0, 0xCB, 0x20, 0x28, 0x9A, 0x72, 0x12, 0xF5, + 0x20, 0x65, 0xB3, 0xB9, 0x84, 0x58, 0x1F, 0x27, 0xBC, 0x7C, 0xA2, 0xC9, 0x9E, 0x18, 0x95, 0xCF, + 0xC2, 0x73, 0x2E, 0x74, 0x8C, 0x66, 0xE5, 0x9E, 0x79, 0x2B, 0xB8, 0x07, 0x0C, 0xB0, 0x4E, 0x8E, + 0xAB, 0x85, 0x21, 0x42, 0xC4, 0xC5, 0x6D, 0x88, 0x9C, 0xDB, 0x15, 0x95, 0x3F, 0x80, 0xDB, 0x7A, + 0x9A, 0x7D, 0x41, 0x56, 0x25, 0x17, 0x18, 0x42, 0x4D, 0x8C, 0xAC, 0xA5, 0x7B, 0xDB, 0x42, 0x5D, + 0x59, 0x35, 0x45, 0x5D, 0x8A, 0x02, 0xB5, 0x70, 0xC0, 0x72, 0x35, 0x46, 0xD0, 0x1D, 0x60, 0x01, + 0x4A, 0xCC, 0x1C, 0x46, 0xD3, 0xD6, 0x35, 0x52, 0xD6, 0xE1, 0xF8, 0x3B, 0x5D, 0xEA, 0xDD, 0xB8, + 0xFE, 0x7D, 0x50, 0xCB, 0x35, 0x23, 0x67, 0x8B, 0xB6, 0xE4, 0x74, 0xD2, 0x60, 0xFC, 0xFD, 0x43, + 0xBF, 0x91, 0x08, 0x81, 0xC5, 0x4F, 0x5D, 0x16, 0x9A, 0xC4, 0x9A, 0xC6, 0xF6, 0xF3, 0xE1, 0xF6, + 0x5C, 0x07, 0xAA, 0x71, 0x6C, 0x13, 0xA4, 0xB1, 0xB3, 0x66, 0xBF, 0x90, 0x4C, 0x3D, 0xA2, 0xC4, + 0x0B, 0xB8, 0x3D, 0x7A, 0x8C, 0x19, 0xFA, 0xFF, 0x6B, 0xB9, 0x1F, 0x02, 0xCC, 0xB6, 0xD3, 0x0C, + 0x7D, 0x19, 0x1F, 0x47, 0xF9, 0xC7, 0x40, 0x01, 0xFA, 0x46, 0xEA, 0x0B, 0xD4, 0x02, 0xE0, 0x3D, + 0x30, 0x9A, 0x1A, 0x0F, 0xEA, 0xA7, 0x66, 0x55, 0xF7, 0xCB, 0x28, 0xE2, 0xBB, 0x99, 0xE4, 0x83, + 0xC3, 0x43, 0x03, 0xEE, 0xDC, 0x1F, 0x02, 0x23, 0xDD, 0xD1, 0x2D, 0x39, 0xA4, 0x65, 0x75, 0x03, + 0xEF, 0x37, 0x9C, 0x06, 0xD6, 0xFA, 0xA1, 0x15, 0xF0, 0xDB, 0x17, 0x47, 0x26, 0x4F, 0x49, 0x03 + ])], /* package2_fixed_key_modulus: */ Modulus([ 0x8D, 0x13, 0xA7, 0x77, 0x6A, 0xE5, 0xDC, 0xC0, 0x3B, 0x25, 0xD0, 0x58, 0xE4, 0x20, 0x69, 0x59, 0x55, 0x4B, 0xAB, 0x70, 0x40, 0x08, 0x28, 0x07, 0xA8, 0xA7, 0xFD, 0x0F, 0x31, 0x2E, 0x11, 0xFE, @@ -413,6 +449,99 @@ impl Keys { )) } + pub fn new_dev(key_path: Option<&Path>) -> Result { + Keys::new(key_path, Path::new("dev.keys"), ( + /* nca_hdr_fixed_key_modulus: */ [Modulus([ + 0xD8, 0xF1, 0x18, 0xEF, 0x32, 0x72, 0x4C, 0xA7, 0x47, 0x4C, 0xB9, 0xEA, 0xB3, 0x04, 0xA8, 0xA4, + 0xAC, 0x99, 0x08, 0x08, 0x04, 0xBF, 0x68, 0x57, 0xB8, 0x43, 0x94, 0x2B, 0xC7, 0xB9, 0x66, 0x49, + 0x85, 0xE5, 0x8A, 0x9B, 0xC1, 0x00, 0x9A, 0x6A, 0x8D, 0xD0, 0xEF, 0xCE, 0xFF, 0x86, 0xC8, 0x5C, + 0x5D, 0xE9, 0x53, 0x7B, 0x19, 0x2A, 0xA8, 0xC0, 0x22, 0xD1, 0xF3, 0x22, 0x0A, 0x50, 0xF2, 0x2B, + 0x65, 0x05, 0x1B, 0x9E, 0xEC, 0x61, 0xB5, 0x63, 0xA3, 0x6F, 0x3B, 0xBA, 0x63, 0x3A, 0x53, 0xF4, + 0x49, 0x2F, 0xCF, 0x03, 0xCC, 0xD7, 0x50, 0x82, 0x1B, 0x29, 0x4F, 0x08, 0xDE, 0x1B, 0x6D, 0x47, + 0x4F, 0xA8, 0xB6, 0x6A, 0x26, 0xA0, 0x83, 0x3F, 0x1A, 0xAF, 0x83, 0x8F, 0x0E, 0x17, 0x3F, 0xFE, + 0x44, 0x1C, 0x56, 0x94, 0x2E, 0x49, 0x83, 0x83, 0x03, 0xE9, 0xB6, 0xAD, 0xD5, 0xDE, 0xE3, 0x2D, + 0xA1, 0xD9, 0x66, 0x20, 0x5D, 0x1F, 0x5E, 0x96, 0x5D, 0x5B, 0x55, 0x0D, 0xD4, 0xB4, 0x77, 0x6E, + 0xAE, 0x1B, 0x69, 0xF3, 0xA6, 0x61, 0x0E, 0x51, 0x62, 0x39, 0x28, 0x63, 0x75, 0x76, 0xBF, 0xB0, + 0xD2, 0x22, 0xEF, 0x98, 0x25, 0x02, 0x05, 0xC0, 0xD7, 0x6A, 0x06, 0x2C, 0xA5, 0xD8, 0x5A, 0x9D, + 0x7A, 0xA4, 0x21, 0x55, 0x9F, 0xF9, 0x3E, 0xBF, 0x16, 0xF6, 0x07, 0xC2, 0xB9, 0x6E, 0x87, 0x9E, + 0xB5, 0x1C, 0xBE, 0x97, 0xFA, 0x82, 0x7E, 0xED, 0x30, 0xD4, 0x66, 0x3F, 0xDE, 0xD8, 0x1B, 0x4B, + 0x15, 0xD9, 0xFB, 0x2F, 0x50, 0xF0, 0x9D, 0x1D, 0x52, 0x4C, 0x1C, 0x4D, 0x8D, 0xAE, 0x85, 0x1E, + 0xEA, 0x7F, 0x86, 0xF3, 0x0B, 0x7B, 0x87, 0x81, 0x98, 0x23, 0x80, 0x63, 0x4F, 0x2F, 0xB0, 0x62, + 0xCC, 0x6E, 0xD2, 0x46, 0x13, 0x65, 0x2B, 0xD6, 0x44, 0x33, 0x59, 0xB5, 0x8F, 0xB9, 0x4A, 0xA9, + ]), Modulus([ + 0x9A, 0xBC, 0x88, 0xBD, 0x0A, 0xBE, 0xD7, 0x0C, 0x9B, 0x42, 0x75, 0x65, 0x38, 0x5E, 0xD1, 0x01, + 0xCD, 0x12, 0xAE, 0xEA, 0xE9, 0x4B, 0xDB, 0xB4, 0x5E, 0x36, 0x10, 0x96, 0xDA, 0x3D, 0x2E, 0x66, + 0xD3, 0x99, 0x13, 0x8A, 0xBE, 0x67, 0x41, 0xC8, 0x93, 0xD9, 0x3E, 0x42, 0xCE, 0x34, 0xCE, 0x96, + 0xFA, 0x0B, 0x23, 0xCC, 0x2C, 0xDF, 0x07, 0x3F, 0x3B, 0x24, 0x4B, 0x12, 0x67, 0x3A, 0x29, 0x36, + 0xA3, 0xAA, 0x06, 0xF0, 0x65, 0xA5, 0x85, 0xBA, 0xFD, 0x12, 0xEC, 0xF1, 0x60, 0x67, 0xF0, 0x8F, + 0xD3, 0x5B, 0x01, 0x1B, 0x1E, 0x84, 0xA3, 0x5C, 0x65, 0x36, 0xF9, 0x23, 0x7E, 0xF3, 0x26, 0x38, + 0x64, 0x98, 0xBA, 0xE4, 0x19, 0x91, 0x4C, 0x02, 0xCF, 0xC9, 0x6D, 0x86, 0xEC, 0x1D, 0x41, 0x69, + 0xDD, 0x56, 0xEA, 0x5C, 0xA3, 0x2A, 0x58, 0xB4, 0x39, 0xCC, 0x40, 0x31, 0xFD, 0xFB, 0x42, 0x74, + 0xF8, 0xEC, 0xEA, 0x00, 0xF0, 0xD9, 0x28, 0xEA, 0xFA, 0x2D, 0x00, 0xE1, 0x43, 0x53, 0xC6, 0x32, + 0xF4, 0xA2, 0x07, 0xD4, 0x5F, 0xD4, 0xCB, 0xAC, 0xCA, 0xFF, 0xDF, 0x84, 0xD2, 0x86, 0x14, 0x3C, + 0xDE, 0x22, 0x75, 0xA5, 0x73, 0xFF, 0x68, 0x07, 0x4A, 0xF9, 0x7C, 0x2C, 0xCC, 0xDE, 0x45, 0xB6, + 0x54, 0x82, 0x90, 0x36, 0x1F, 0x2C, 0x51, 0x96, 0xC5, 0x0A, 0x53, 0x5B, 0xF0, 0x8B, 0x4A, 0xAA, + 0x3B, 0x68, 0x97, 0x19, 0x17, 0x1F, 0x01, 0xB8, 0xED, 0xB9, 0x9A, 0x5E, 0x08, 0xC5, 0x20, 0x1E, + 0x6A, 0x09, 0xF0, 0xE9, 0x73, 0xA3, 0xBE, 0x10, 0x06, 0x02, 0xE9, 0xFB, 0x85, 0xFA, 0x5F, 0x01, + 0xAC, 0x60, 0xE0, 0xED, 0x7D, 0xB9, 0x49, 0xA8, 0x9E, 0x98, 0x7D, 0x91, 0x40, 0x05, 0xCF, 0xF9, + 0x1A, 0xFC, 0x40, 0x22, 0xA8, 0x96, 0x5B, 0xB0, 0xDC, 0x7A, 0xF5, 0xB7, 0xE9, 0x91, 0x4C, 0x49, + ])], + /* acid_fixed_key_modulus: */ [Modulus([ + 0xD6, 0x34, 0xA5, 0x78, 0x6C, 0x68, 0xCE, 0x5A, 0xC2, 0x37, 0x17, 0xF3, 0x82, 0x45, 0xC6, 0x89, + 0xE1, 0x2D, 0x06, 0x67, 0xBF, 0xB4, 0x06, 0x19, 0x55, 0x6B, 0x27, 0x66, 0x0C, 0xA4, 0xB5, 0x87, + 0x81, 0x25, 0xF4, 0x30, 0xBC, 0x53, 0x08, 0x68, 0xA2, 0x48, 0x49, 0x8C, 0x3F, 0x38, 0x40, 0x9C, + 0xC4, 0x26, 0xF4, 0x79, 0xE2, 0xA1, 0x85, 0xF5, 0x5C, 0x7F, 0x58, 0xBA, 0xA6, 0x1C, 0xA0, 0x8B, + 0x84, 0x16, 0x14, 0x6F, 0x85, 0xD9, 0x7C, 0xE1, 0x3C, 0x67, 0x22, 0x1E, 0xFB, 0xD8, 0xA7, 0xA5, + 0x9A, 0xBF, 0xEC, 0x0E, 0xCF, 0x96, 0x7E, 0x85, 0xC2, 0x1D, 0x49, 0x5D, 0x54, 0x26, 0xCB, 0x32, + 0x7C, 0xF6, 0xBB, 0x58, 0x03, 0x80, 0x2B, 0x5D, 0xF7, 0xFB, 0xD1, 0x9D, 0xC7, 0xC6, 0x2E, 0x53, + 0xC0, 0x6F, 0x39, 0x2C, 0x1F, 0xA9, 0x92, 0xF2, 0x4D, 0x7D, 0x4E, 0x74, 0xFF, 0xE4, 0xEF, 0xE4, + 0x7C, 0x3D, 0x34, 0x2A, 0x71, 0xA4, 0x97, 0x59, 0xFF, 0x4F, 0xA2, 0xF4, 0x66, 0x78, 0xD8, 0xBA, + 0x99, 0xE3, 0xE6, 0xDB, 0x54, 0xB9, 0xE9, 0x54, 0xA1, 0x70, 0xFC, 0x05, 0x1F, 0x11, 0x67, 0x4B, + 0x26, 0x8C, 0x0C, 0x3E, 0x03, 0xD2, 0xA3, 0x55, 0x5C, 0x7D, 0xC0, 0x5D, 0x9D, 0xFF, 0x13, 0x2F, + 0xFD, 0x19, 0xBF, 0xED, 0x44, 0xC3, 0x8C, 0xA7, 0x28, 0xCB, 0xE5, 0xE0, 0xB1, 0xA7, 0x9C, 0x33, + 0x8D, 0xB8, 0x6E, 0xDE, 0x87, 0x18, 0x22, 0x60, 0xC4, 0xAE, 0xF2, 0x87, 0x9F, 0xCE, 0x09, 0x5C, + 0xB5, 0x99, 0xA5, 0x9F, 0x49, 0xF2, 0xD7, 0x58, 0xFA, 0xF9, 0xC0, 0x25, 0x7D, 0xD6, 0xCB, 0xF3, + 0xD8, 0x6C, 0xA2, 0x69, 0x91, 0x68, 0x73, 0xB1, 0x94, 0x6F, 0xA3, 0xF3, 0xB9, 0x7D, 0xF8, 0xE0, + 0x72, 0x9E, 0x93, 0x7B, 0x7A, 0xA2, 0x57, 0x60, 0xB7, 0x5B, 0xA9, 0x84, 0xAE, 0x64, 0x88, 0x69 + ]), Modulus([ + 0xBC, 0xA5, 0x6A, 0x7E, 0xEA, 0x38, 0x34, 0x62, 0xA6, 0x10, 0x18, 0x3C, 0xE1, 0x63, 0x7B, 0xF0, + 0xD3, 0x08, 0x8C, 0xF5, 0xC5, 0xC4, 0xC7, 0x93, 0xE9, 0xD9, 0xE6, 0x32, 0xF3, 0xA0, 0xF6, 0x6E, + 0x8A, 0x98, 0x76, 0x47, 0x33, 0x47, 0x65, 0x02, 0x70, 0xDC, 0x86, 0x5F, 0x3D, 0x61, 0x5A, 0x70, + 0xBC, 0x5A, 0xCA, 0xCA, 0x50, 0xAD, 0x61, 0x7E, 0xC9, 0xEC, 0x27, 0xFF, 0xE8, 0x64, 0x42, 0x9A, + 0xEE, 0xBE, 0xC3, 0xD1, 0x0B, 0xC0, 0xE9, 0xBF, 0x83, 0x8D, 0xC0, 0x0C, 0xD8, 0x00, 0x5B, 0x76, + 0x90, 0xD2, 0x4B, 0x30, 0x84, 0x35, 0x8B, 0x1E, 0x20, 0xB7, 0xE4, 0xDC, 0x63, 0xE5, 0xDF, 0xCD, + 0x00, 0x5F, 0x81, 0x5F, 0x67, 0xC5, 0x8B, 0xDF, 0xFC, 0xE1, 0x37, 0x5F, 0x07, 0xD9, 0xDE, 0x4F, + 0xE6, 0x7B, 0xF1, 0xFB, 0xA1, 0x5A, 0x71, 0x40, 0xFE, 0xBA, 0x1E, 0xAE, 0x13, 0x22, 0xD2, 0xFE, + 0x37, 0xA2, 0xB6, 0x8B, 0xAB, 0xEB, 0x84, 0x81, 0x4E, 0x7C, 0x1E, 0x02, 0xD1, 0xFB, 0xD7, 0x5D, + 0x11, 0x84, 0x64, 0xD2, 0x4D, 0xBB, 0x50, 0x00, 0x67, 0x54, 0xE2, 0x77, 0x89, 0xBA, 0x0B, 0xE7, + 0x05, 0x57, 0x9A, 0x22, 0x5A, 0xEC, 0x76, 0x1C, 0xFD, 0xE8, 0xA8, 0x18, 0x16, 0x41, 0x65, 0x03, + 0xFA, 0xC4, 0xA6, 0x31, 0x5C, 0x1A, 0x7F, 0xAB, 0x11, 0xC8, 0x4A, 0x99, 0xB9, 0xE6, 0xCF, 0x62, + 0x21, 0xA6, 0x72, 0x47, 0xDB, 0xBA, 0x96, 0x26, 0x4E, 0x2E, 0xD4, 0x8C, 0x46, 0xD6, 0xA7, 0x1A, + 0x6C, 0x32, 0xA7, 0xDF, 0x85, 0x1C, 0x03, 0xC3, 0x6D, 0xA9, 0xE9, 0x68, 0xF4, 0x17, 0x1E, 0xB2, + 0x70, 0x2A, 0xA1, 0xE5, 0xE1, 0xF3, 0x8F, 0x6F, 0x63, 0xAC, 0xEB, 0x72, 0x0B, 0x4C, 0x4A, 0x36, + 0x3C, 0x60, 0x91, 0x9F, 0x6E, 0x1C, 0x71, 0xEA, 0xD0, 0x78, 0x78, 0xA0, 0x2E, 0xC6, 0x32, 0x6B + ])], + /* package2_fixed_key_modulus: */ Modulus([ + 0xB3, 0x65, 0x54, 0xFB, 0x0A, 0xB0, 0x1E, 0x85, 0xA7, 0xF6, 0xCF, 0x91, 0x8E, 0xBA, 0x96, 0x99, + 0x0D, 0x8B, 0x91, 0x69, 0x2A, 0xEE, 0x01, 0x20, 0x4F, 0x34, 0x5C, 0x2C, 0x4F, 0x4E, 0x37, 0xC7, + 0xF1, 0x0B, 0xD4, 0xCD, 0xA1, 0x7F, 0x93, 0xF1, 0x33, 0x59, 0xCE, 0xB1, 0xE9, 0xDD, 0x26, 0xE6, + 0xF3, 0xBB, 0x77, 0x87, 0x46, 0x7A, 0xD6, 0x4E, 0x47, 0x4A, 0xD1, 0x41, 0xB7, 0x79, 0x4A, 0x38, + 0x06, 0x6E, 0xCF, 0x61, 0x8F, 0xCD, 0xC1, 0x40, 0x0B, 0xFA, 0x26, 0xDC, 0xC0, 0x34, 0x51, 0x83, + 0xD9, 0x3B, 0x11, 0x54, 0x3B, 0x96, 0x27, 0x32, 0x9A, 0x95, 0xBE, 0x1E, 0x68, 0x11, 0x50, 0xA0, + 0x6B, 0x10, 0xA8, 0x83, 0x8B, 0xF5, 0xFC, 0xBC, 0x90, 0x84, 0x7A, 0x5A, 0x5C, 0x43, 0x52, 0xE6, + 0xC8, 0x26, 0xE9, 0xFE, 0x06, 0xA0, 0x8B, 0x53, 0x0F, 0xAF, 0x1E, 0xC4, 0x1C, 0x0B, 0xCF, 0x50, + 0x1A, 0xA4, 0xF3, 0x5C, 0xFB, 0xF0, 0x97, 0xE4, 0xDE, 0x32, 0x0A, 0x9F, 0xE3, 0x5A, 0xAA, 0xB7, + 0x44, 0x7F, 0x5C, 0x33, 0x60, 0xB9, 0x0F, 0x22, 0x2D, 0x33, 0x2A, 0xE9, 0x69, 0x79, 0x31, 0x42, + 0x8F, 0xE4, 0x3A, 0x13, 0x8B, 0xE7, 0x26, 0xBD, 0x08, 0x87, 0x6C, 0xA6, 0xF2, 0x73, 0xF6, 0x8E, + 0xA7, 0xF2, 0xFE, 0xFB, 0x6C, 0x28, 0x66, 0x0D, 0xBD, 0xD7, 0xEB, 0x42, 0xA8, 0x78, 0xE6, 0xB8, + 0x6B, 0xAE, 0xC7, 0xA9, 0xE2, 0x40, 0x6E, 0x89, 0x20, 0x82, 0x25, 0x8E, 0x3C, 0x6A, 0x60, 0xD7, + 0xF3, 0x56, 0x8E, 0xEC, 0x8D, 0x51, 0x8A, 0x63, 0x3C, 0x04, 0x78, 0x23, 0x0E, 0x90, 0x0C, 0xB4, + 0xE7, 0x86, 0x3B, 0x4F, 0x8E, 0x13, 0x09, 0x47, 0x32, 0x0E, 0x04, 0xB8, 0x4D, 0x5B, 0xB0, 0x46, + 0x71, 0xB0, 0x5C, 0xF4, 0xAD, 0x63, 0x4F, 0xC5, 0xE2, 0xAC, 0x1E, 0xC4, 0x33, 0x96, 0x09, 0x7B + ]) + )) + } + fn read_from_ini(&mut self, mut file: File) -> Result<(), Error> { let config = ini::Ini::read_from(&mut file)?; let section = config.general_section(); @@ -426,7 +555,7 @@ impl Keys { multi_encrypted_keyblob!(encrypted_keyblobs); multi_keyblob!(keyblobs); single_key!(keyblob_mac_key_source); - single_key!(tsec_root_key); + multi_key!(tsec_root_key); multi_key!(master_kek_sources); multi_key!(master_keks); single_key!(master_key_source); @@ -467,7 +596,7 @@ impl Keys { multi_encrypted_keyblob!(encrypted_keyblobs); multi_keyblob!(keyblobs); single_key!(keyblob_mac_key_source); - single_key!(tsec_root_key); + multi_key!(tsec_root_key); multi_key!(master_kek_sources); multi_key!(master_keks); single_key!(master_key_source); @@ -542,7 +671,7 @@ impl Keys { } for i in 6..0x20 { /* Do keygen for 6.2.0+ */ - match (&self.tsec_root_key, &self.master_kek_sources[i]) { + match (&self.tsec_root_key[i - 6], &self.master_kek_sources[i]) { (Some(tsec_root_key), Some(master_kek_source)) => { self.master_keks[i] = Some(tsec_root_key.derive_key(&master_kek_source.0)?); }, From 70bb43e0a4c7681df63f5e920933e2d30d5724d0 Mon Sep 17 00:00:00 2001 From: roblabla Date: Tue, 7 Apr 2020 18:19:14 +0000 Subject: [PATCH 3/6] Add MOD0 generation and dynstr/dynsym information to NROs --- src/format/nxo.rs | 178 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 135 insertions(+), 43 deletions(-) diff --git a/src/format/nxo.rs b/src/format/nxo.rs index 2922c49..ee7a573 100644 --- a/src/format/nxo.rs +++ b/src/format/nxo.rs @@ -1,6 +1,6 @@ use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use elf; -use elf::types::{EM_ARM, EM_AARCH64, ProgramHeader, PT_LOAD, SHT_NOTE, Machine}; +use elf::types::{EM_ARM, EM_AARCH64, ProgramHeader, PT_LOAD, SHT_NOTE, Machine, SectionHeader}; use crate::format::{utils, romfs::RomFs, nacp::NacpFile, npdm::KernelCapability}; use std; use std::fs::File; @@ -9,7 +9,7 @@ use std::path::{Path, PathBuf}; use std::process; use serde_derive::{Serialize, Deserialize}; use crate::format::utils::HexOrNum; -use std::convert::TryFrom; +use std::convert::{TryFrom, TryInto}; // TODO: Support switchbrew's embedded files for NRO pub struct NxoFile { @@ -19,6 +19,10 @@ pub struct NxoFile { rodata_segment: ProgramHeader, data_segment: ProgramHeader, bss_segment: Option, + eh_frame_hdr_section: Option, + dynamic_section: Option, + dynstr_section: Option, + dynsym_section: Option, build_id: Option>, } @@ -68,6 +72,32 @@ where Ok(()) } +fn write_mod0(nxo_file: &NxoFile, output_writter: &mut T, bss_addr: u32, bss_size: u32) -> std::io::Result<()> +where + T: Write, +{ + // MOD magic + output_writter.write_all(b"MOD0")?; + // Dynamic Offset + output_writter.write_u32::(nxo_file.dynamic_section.as_ref().map(|v| v.addr as u32).unwrap_or(0))?; + + // BSS Start Offset + output_writter.write_u32::(bss_addr)?; + // BSS End Offset + output_writter.write_u32::(bss_addr + bss_size)?; + + let (eh_frame_hdr_addr, eh_frame_hdr_size) = nxo_file.eh_frame_hdr_section.as_ref().map(|v| (v.addr, v.size)).unwrap_or((0, 0)); + // EH Frame Header Start + output_writter.write_u32::(eh_frame_hdr_addr as u32)?; + // EH Frame Header End + output_writter.write_u32::(eh_frame_hdr_addr as u32 + eh_frame_hdr_size as u32)?; + + // RTLD ptr - written at runtime by RTLD + output_writter.write_u32::(0)?; + + Ok(()) +} + impl NxoFile { pub fn from_elf(input: &str) -> std::io::Result { let path = PathBuf::from(input); @@ -107,23 +137,33 @@ impl NxoFile { } None => None, }; - let build_id = sections - .into_iter() - .filter(|&x| { - if x.shdr.shtype == SHT_NOTE { - let mut data = Cursor::new(x.data.clone()); - // Ignore the two first offset of nhdr32 - data.seek(SeekFrom::Start(0x8)).unwrap(); - let n_type = data.read_u32::().unwrap(); - - // BUILD_ID - n_type == 0x3 - } else { - false + + let mut build_id = None; + let mut dynamic_section = None; + let mut dynstr_section = None; + let mut dynsym_section = None; + let mut eh_frame_hdr_section = None; + + for section in sections { + if section.shdr.shtype == SHT_NOTE { + let mut data = Cursor::new(section.data.clone()); + // Ignore the two first offset of nhdr32 + data.seek(SeekFrom::Start(0x8)).unwrap(); + let n_type = data.read_u32::().unwrap(); + + // BUILD_ID + if n_type == 0x3 { + build_id = Some(data.into_inner()); } - }) - .map(|section| section.data.clone()) - .next(); + } + match &*section.shdr.name { + ".dynamic" => dynamic_section = Some(section.shdr.clone()), + ".dynstr" => dynstr_section = Some(section.shdr.clone()), + ".dynsym" => dynsym_section = Some(section.shdr.clone()), + ".eh_frame_hdr" => eh_frame_hdr_section = Some(section.shdr.clone()), + _ => () + } + } Ok(NxoFile { file, @@ -133,6 +173,10 @@ impl NxoFile { data_segment: *data_segment, bss_segment, build_id, + dynamic_section, + dynstr_section, + dynsym_section, + eh_frame_hdr_section }) } @@ -169,11 +213,11 @@ impl NxoFile { // NRO magic output_writter.write_all(b"NRO0")?; - // Unknown + // Version output_writter.write_u32::(0)?; // Total size output_writter.write_u32::(total_len)?; - // Unknown + // Flags output_writter.write_u32::(0)?; // Segment Header (3 entries) @@ -186,19 +230,21 @@ impl NxoFile { file_offset += code_size; // .rodata segment + let rodata_offset = file_offset; let rodata_size = rodata.len() as u32; output_writter.write_u32::(file_offset)?; output_writter.write_u32::(rodata_size)?; file_offset += rodata_size; // .data segment + let data_offset = file_offset; let data_size = data.len() as u32; output_writter.write_u32::(file_offset)?; output_writter.write_u32::(data_size)?; file_offset += data_size; // BSS size - match self.bss_segment { + let (bss_start, bss_size) = match self.bss_segment { Some(segment) => { if segment.vaddr != u64::from(file_offset) { println!( @@ -207,6 +253,7 @@ impl NxoFile { } output_writter .write_u32::(((segment.memsz + 0xFFF) & !0xFFF) as u32)?; + (segment.vaddr as u32, ((segment.memsz + 0xFFF) & !0xFFF) as u32) } _ => { // in this case the bss is missing or is embedeed in .data. libnx does that, let's support it @@ -217,24 +264,65 @@ impl NxoFile { 0 }; output_writter.write_u32::(bss_size)?; + (data_segment.vaddr as u32 + data_segment.memsz as u32, bss_size) } - } - // Unknown + }; + + // Reserved output_writter.write_u32::(0)?; write_build_id(&self.build_id, output_writter)?; - // Padding - output_writter.write_u64::(0)?; - output_writter.write_u64::(0)?; + // TODO: DSO Module Offset (unused) + output_writter.write_u32::(0)?; + // Reserved (unused) + output_writter.write_u32::(0)?; - // Unknown - output_writter.write_u64::(0)?; + // TODO: apiInfo output_writter.write_u64::(0)?; - output_writter.write_all(&code[0x80..])?; - output_writter.write_all(&rodata)?; - output_writter.write_all(&data)?; + // .dynstr section info + output_writter.write_u32::(self.dynstr_section.as_ref().map(|v| u32::try_from(v.addr).unwrap()).unwrap_or(0))?; + output_writter.write_u32::(self.dynstr_section.as_ref().map(|v| u32::try_from(v.size).unwrap()).unwrap_or(0))?; + + // .dynsym section info + output_writter.write_u32::(self.dynsym_section.as_ref().map(|v| u32::try_from(v.addr).unwrap()).unwrap_or(0))?; + output_writter.write_u32::(self.dynsym_section.as_ref().map(|v| u32::try_from(v.size).unwrap()).unwrap_or(0))?; + + let module_offset = u32::from_le_bytes(code[4..8].try_into().unwrap()) as usize; + if module_offset != 0 && !( + (0x80..code_size).contains(&(module_offset as u32)) || + (rodata_offset..data_offset).contains(&(module_offset as u32)) || + (data_offset..file_offset).contains(&(module_offset as u32))) + { + panic!("Invalid module offset {}", module_offset) + } + + if (0x80..code_size).contains(&(module_offset as u32)) && &code[module_offset..module_offset + 4] != b"MOD0" { + output_writter.write_all(&code[0x80..module_offset])?; + write_mod0(self, output_writter, bss_start, bss_size)?; + output_writter.write_all(&code[module_offset + 0x18..])?; + } else { + output_writter.write_all(&code[0x80..])?; + } + + if (rodata_offset..data_offset).contains(&(module_offset as u32)) && &rodata[module_offset - rodata_offset as usize..module_offset - rodata_offset as usize+ 4] == b"MOD0" { + let module_offset = module_offset - rodata_offset as usize; + output_writter.write_all(&rodata[..module_offset])?; + write_mod0(self, output_writter, bss_start, bss_size)?; + output_writter.write_all(&rodata[module_offset + 0x18..])?; + } else { + output_writter.write_all(&rodata)?; + } + + if (data_offset..file_offset).contains(&(module_offset as u32)) && &data[module_offset - data_offset as usize..module_offset - data_offset as usize + 4] == b"MOD0" { + let module_offset = module_offset - data_offset as usize; + output_writter.write_all(&data[..module_offset])?; + write_mod0(self, output_writter, bss_start, bss_size)?; + output_writter.write_all(&data[module_offset + 0x18..])?; + } else { + output_writter.write_all(&data)?; + } // Early return if there's no need for an ASET segment. if let (None, None, None) = (&icon, &romfs, &nacp) { @@ -321,9 +409,9 @@ impl NxoFile { // NSO magic output_writter.write_all(b"NSO0")?; - // Unknown + // Version output_writter.write_u32::(0)?; - // Unknown + // Reserved output_writter.write_u32::(0)?; // Flags, set compression + sum check @@ -340,7 +428,7 @@ impl NxoFile { output_writter.write_u32::(text_segment.vaddr as u32)?; output_writter.write_u32::(code_size as u32)?; - // Module offset (TODO: SUPPORT THAT) + // TODO: Module Name Offset output_writter.write_u32::(0)?; file_offset += compressed_code_size; @@ -353,7 +441,7 @@ impl NxoFile { output_writter.write_u32::(rodata_segment.vaddr as u32)?; output_writter.write_u32::(rodata_size as u32)?; - // Module file size (TODO: SUPPORT THAT) + // TODO: Module Name Size output_writter.write_u32::(0)?; file_offset += compressed_rodata_size; @@ -394,16 +482,20 @@ impl NxoFile { output_writter.write_u32::(compressed_rodata_size)?; output_writter.write_u32::(compressed_data_size)?; - // Padding (0x24) - output_writter.write_u64::(0)?; + // Reserved (0x1C) + output_writter.write_u32::(0)?; output_writter.write_u64::(0)?; output_writter.write_u64::(0)?; output_writter.write_u64::(0)?; - output_writter.write_u32::(0)?; - // Unknown - output_writter.write_u64::(0)?; + // TODO: SegmentHeaderRelative for .api_info output_writter.write_u64::(0)?; + // SegmentHeaderRelative for .dynstr + output_writter.write_u32::(self.dynstr_section.as_ref().map(|v| u32::try_from(v.addr).unwrap()).unwrap_or(0))?; + output_writter.write_u32::(self.dynstr_section.as_ref().map(|v| u32::try_from(v.size).unwrap()).unwrap_or(0))?; + // SegmentHeaderRelative for .dynsym + output_writter.write_u32::(self.dynsym_section.as_ref().map(|v| u32::try_from(v.addr).unwrap()).unwrap_or(0))?; + output_writter.write_u32::(self.dynsym_section.as_ref().map(|v| u32::try_from(v.size).unwrap()).unwrap_or(0))?; // .text sha256 let text_sum = utils::calculate_sha256(&code)?; @@ -501,9 +593,9 @@ impl NxoFile { output_writer.write_all(&vec![0xFF; (0x20 - caps.len()) * 4])?; // Section data - output_writer.write_all(&text_data); - output_writer.write_all(&rodata_data); - output_writer.write_all(&data_data); + output_writer.write_all(&text_data)?; + output_writer.write_all(&rodata_data)?; + output_writer.write_all(&data_data)?; Ok(()) } From e3b2833dcecb81b15aa161dc5ba20aa935b71bbd Mon Sep 17 00:00:00 2001 From: roblabla Date: Tue, 7 Apr 2020 19:05:14 +0000 Subject: [PATCH 4/6] Properly use offset when writing mod0, fix mod0 presence check --- src/format/nxo.rs | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/format/nxo.rs b/src/format/nxo.rs index ee7a573..323d8d1 100644 --- a/src/format/nxo.rs +++ b/src/format/nxo.rs @@ -72,25 +72,25 @@ where Ok(()) } -fn write_mod0(nxo_file: &NxoFile, output_writter: &mut T, bss_addr: u32, bss_size: u32) -> std::io::Result<()> +fn write_mod0(nxo_file: &NxoFile, offset: u32, output_writter: &mut T, bss_addr: u32, bss_size: u32) -> std::io::Result<()> where T: Write, { // MOD magic output_writter.write_all(b"MOD0")?; // Dynamic Offset - output_writter.write_u32::(nxo_file.dynamic_section.as_ref().map(|v| v.addr as u32).unwrap_or(0))?; + output_writter.write_u32::(nxo_file.dynamic_section.as_ref().map(|v| v.addr as u32 - offset).unwrap_or(0))?; // BSS Start Offset - output_writter.write_u32::(bss_addr)?; + output_writter.write_u32::(bss_addr - offset)?; // BSS End Offset - output_writter.write_u32::(bss_addr + bss_size)?; + output_writter.write_u32::(bss_addr + bss_size - offset)?; let (eh_frame_hdr_addr, eh_frame_hdr_size) = nxo_file.eh_frame_hdr_section.as_ref().map(|v| (v.addr, v.size)).unwrap_or((0, 0)); // EH Frame Header Start - output_writter.write_u32::(eh_frame_hdr_addr as u32)?; + output_writter.write_u32::(eh_frame_hdr_addr as u32 - offset)?; // EH Frame Header End - output_writter.write_u32::(eh_frame_hdr_addr as u32 + eh_frame_hdr_size as u32)?; + output_writter.write_u32::(eh_frame_hdr_addr as u32 + eh_frame_hdr_size as u32 - offset)?; // RTLD ptr - written at runtime by RTLD output_writter.write_u32::(0)?; @@ -300,26 +300,26 @@ impl NxoFile { if (0x80..code_size).contains(&(module_offset as u32)) && &code[module_offset..module_offset + 4] != b"MOD0" { output_writter.write_all(&code[0x80..module_offset])?; - write_mod0(self, output_writter, bss_start, bss_size)?; - output_writter.write_all(&code[module_offset + 0x18..])?; + write_mod0(self, module_offset as u32, output_writter, bss_start, bss_size)?; + output_writter.write_all(&code[module_offset + 0x1C..])?; } else { output_writter.write_all(&code[0x80..])?; } - if (rodata_offset..data_offset).contains(&(module_offset as u32)) && &rodata[module_offset - rodata_offset as usize..module_offset - rodata_offset as usize+ 4] == b"MOD0" { - let module_offset = module_offset - rodata_offset as usize; - output_writter.write_all(&rodata[..module_offset])?; - write_mod0(self, output_writter, bss_start, bss_size)?; - output_writter.write_all(&rodata[module_offset + 0x18..])?; + if (rodata_offset..data_offset).contains(&(module_offset as u32)) && &rodata[module_offset - rodata_offset as usize..module_offset - rodata_offset as usize+ 4] != b"MOD0" { + let rodata_module_offset = module_offset - rodata_offset as usize; + output_writter.write_all(&rodata[..rodata_module_offset])?; + write_mod0(self, module_offset as u32, output_writter, bss_start, bss_size)?; + output_writter.write_all(&rodata[rodata_module_offset + 0x1C..])?; } else { output_writter.write_all(&rodata)?; } - if (data_offset..file_offset).contains(&(module_offset as u32)) && &data[module_offset - data_offset as usize..module_offset - data_offset as usize + 4] == b"MOD0" { - let module_offset = module_offset - data_offset as usize; - output_writter.write_all(&data[..module_offset])?; - write_mod0(self, output_writter, bss_start, bss_size)?; - output_writter.write_all(&data[module_offset + 0x18..])?; + if (data_offset..file_offset).contains(&(module_offset as u32)) && &data[module_offset - data_offset as usize..module_offset - data_offset as usize + 4] != b"MOD0" { + let data_module_offset = module_offset - data_offset as usize; + output_writter.write_all(&data[..data_module_offset])?; + write_mod0(self, module_offset as u32, output_writter, bss_start, bss_size)?; + output_writter.write_all(&data[data_module_offset + 0x1C..])?; } else { output_writter.write_all(&data)?; } From fdf9abdac354bb6f4af44365328e3084f1023e2d Mon Sep 17 00:00:00 2001 From: roblabla Date: Tue, 7 Apr 2020 23:31:21 +0000 Subject: [PATCH 5/6] Attempt 1 at supporting cdylibs --- src/bin/cargo-nro.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/cargo-nro.rs b/src/bin/cargo-nro.rs index 163f1ab..7019d41 100644 --- a/src/bin/cargo-nro.rs +++ b/src/bin/cargo-nro.rs @@ -252,7 +252,7 @@ fn main() { let iter = cargo_metadata::parse_message_stream(command.stdout.unwrap()); for message in iter { match message { - Ok(Message::CompilerArtifact(ref artifact)) if artifact.target.kind[0] == "bin" => { + Ok(Message::CompilerArtifact(ref artifact)) if artifact.target.kind.contains("bin") || artifact.target.kind.contains("cdylib") => { // Find the artifact's source. This is not going to be pretty. // For whatever reason, cargo thought it'd be a *great idea* to make file URLs use // the non-standard "path+file:///" scheme, instead of, y'know, the ""file:///" everyone From a9b8732d8062610689247bab4790b16862b063ae Mon Sep 17 00:00:00 2001 From: roblabla Date: Tue, 7 Apr 2020 23:33:44 +0000 Subject: [PATCH 6/6] Attempt 2 at adding cdylib support to cargo-nro --- src/bin/cargo-nro.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/cargo-nro.rs b/src/bin/cargo-nro.rs index 7019d41..d9fa9f2 100644 --- a/src/bin/cargo-nro.rs +++ b/src/bin/cargo-nro.rs @@ -252,7 +252,7 @@ fn main() { let iter = cargo_metadata::parse_message_stream(command.stdout.unwrap()); for message in iter { match message { - Ok(Message::CompilerArtifact(ref artifact)) if artifact.target.kind.contains("bin") || artifact.target.kind.contains("cdylib") => { + Ok(Message::CompilerArtifact(ref artifact)) if artifact.target.kind.contains(&"bin".into()) || artifact.target.kind.contains(&"cdylib".into()) => { // Find the artifact's source. This is not going to be pretty. // For whatever reason, cargo thought it'd be a *great idea* to make file URLs use // the non-standard "path+file:///" scheme, instead of, y'know, the ""file:///" everyone