change CIC detection method in the deployer

This commit is contained in:
Mateusz Faderewski 2023-11-29 19:37:27 +01:00
parent f9fcdf8fc8
commit 8ecbd6e401
2 changed files with 41 additions and 82 deletions

View File

@ -3,74 +3,7 @@ use super::Error;
pub const IPL3_OFFSET: u32 = 0x40;
pub const IPL3_LENGTH: usize = 0xFC0;
enum CicType {
_5101,
_6101,
_7102,
X102,
X103,
X105,
X106,
_5167,
NDXJ0,
NDDJ0,
NDDJ1,
NDDJ2,
NDDE0,
}
impl From<u32> for CicType {
fn from(value: u32) -> Self {
match value {
0x587BD543 => CicType::_5101,
0x6170A4A1 => CicType::_6101,
0x009E9EA3 => CicType::_7102,
0x90BB6CB5 => CicType::X102,
0x0B050EE0 => CicType::X103,
0x98BC2C86 => CicType::X105,
0xACC8580A => CicType::X106,
0x0E018159 => CicType::_5167,
0x10C68B18 => CicType::NDXJ0,
0xBC605D0A => CicType::NDDJ0,
0x502C4466 => CicType::NDDJ1,
0x0C965795 => CicType::NDDJ2,
0x8FEBA21E => CicType::NDDE0,
_ => CicType::X102,
}
}
}
impl From<CicType> for u8 {
fn from(value: CicType) -> Self {
match value {
CicType::_5101 => 0xAC,
CicType::_6101 => 0x3F,
CicType::_7102 => 0x3F,
CicType::X102 => 0x3F,
CicType::X103 => 0x78,
CicType::X105 => 0x91,
CicType::X106 => 0x85,
CicType::_5167 => 0xDD,
CicType::NDXJ0 => 0xDD,
CicType::NDDJ0 => 0xDD,
CicType::NDDJ1 => 0xDD,
CicType::NDDJ2 => 0xDD,
CicType::NDDE0 => 0xDE,
}
}
}
pub fn guess_ipl3_seed(ipl3: &[u8]) -> Result<u8, Error> {
if ipl3.len() < IPL3_LENGTH {
return Err(Error::new("Invalid IPL3 length provided"));
}
let cic_type: CicType = crc32fast::hash(ipl3).into();
Ok(cic_type.into())
}
pub fn calculate_ipl3_checksum(ipl3: &[u8], seed: u8) -> Result<[u8; 6], Error> {
fn calculate_ipl3_checksum(ipl3: &[u8], seed: u8) -> Result<u64, Error> {
if ipl3.len() < IPL3_LENGTH {
return Err(Error::new("Invalid IPL3 length provided"));
}
@ -209,12 +142,37 @@ pub fn calculate_ipl3_checksum(ipl3: &[u8], seed: u8) -> Result<[u8; 6], Error>
let sum = checksum(final_buffer[0], final_buffer[1], 16);
let xor = final_buffer[3] ^ final_buffer[2];
Ok([
(sum >> 8) as u8,
(sum >> 0) as u8,
(xor >> 24) as u8,
(xor >> 16) as u8,
(xor >> 8) as u8,
(xor >> 0) as u8,
])
let checksum = (((sum & 0xFFFF) as u64) << 32) | (xor as u64);
Ok(checksum)
}
pub fn sign_ipl3(ipl3: &[u8]) -> Result<(u8, u64), Error> {
let known_seed_checksum_pairs = [
(0xAC, 0x5930D81014DAu64), // 5101
(0xDD, 0x083C6C77E0B1u64), // 5167
(0x3F, 0x45CC73EE317Au64), // 6101
(0x3F, 0x44160EC5D9AFu64), // 7102
(0x3F, 0xA536C0F1D859u64), // 6102/7102
(0x78, 0x586FD4709867u64), // 6103/7103
(0x91, 0x8618A45BC2D3u64), // 6105/7105
(0x85, 0x2BBAD4E6EB74u64), // 6106/7106
(0xDD, 0x6EE8D9E84970u64), // NDXJ0
(0xDD, 0x6C216495C8B9u64), // NDDJ0
(0xDD, 0xE27F43BA93ACu64), // NDDJ1
(0xDD, 0x32B294E2AB90u64), // NDDJ2
(0xDE, 0x05BA2EF0A5F1u64), // NDDE0
];
for (seed, checksum) in known_seed_checksum_pairs {
if calculate_ipl3_checksum(ipl3, seed)? == checksum {
return Ok((seed, checksum));
}
}
// Unknown IPL3 detected, sign it with arbitrary seed (CIC6102/7101 value is used here)
const DEFAULT_SEED: u8 = 0x3F;
let checksum = calculate_ipl3_checksum(ipl3, DEFAULT_SEED)?;
Ok((DEFAULT_SEED, checksum))
}

View File

@ -18,7 +18,7 @@ pub use self::{
};
use self::{
cic::{calculate_ipl3_checksum, guess_ipl3_seed, IPL3_LENGTH, IPL3_OFFSET},
cic::{sign_ipl3, IPL3_LENGTH, IPL3_OFFSET},
link::{Command, Link},
time::{convert_from_datetime, convert_to_datetime},
types::{
@ -143,11 +143,13 @@ impl SC64 {
&mut self,
disable: bool,
seed: u8,
checksum: &[u8; 6],
checksum: u64,
) -> Result<(), Error> {
let checksum_high = ((checksum >> 32) & 0xFFFF) as u32;
let checksum_low = (checksum & 0xFFFFFFFF) as u32;
let args = [
u32::from_be_bytes([(disable as u8) << 0, seed, checksum[0], checksum[1]]),
u32::from_be_bytes([checksum[2], checksum[3], checksum[4], checksum[5]]),
((if disable { 1 } else { 0 }) << 24) | ((seed as u32) << 16) | checksum_high,
checksum_low,
];
self.link.execute_command(&Command {
id: b'B',
@ -503,8 +505,7 @@ impl SC64 {
_ => BOOTLOADER_ADDRESS,
};
let ipl3 = self.command_memory_read(address + IPL3_OFFSET, IPL3_LENGTH)?;
let seed = guess_ipl3_seed(&ipl3)?;
let checksum = &calculate_ipl3_checksum(&ipl3, seed)?;
let (seed, checksum) = sign_ipl3(&ipl3)?;
self.command_cic_params_set(false, seed, checksum)
}