某ゲームのセーブデータのスクランブルを解除するプログラム
このプログラムを使うとセーブデータのスクランブルを解除し、以下のようなファイルを得ることができます。

これに関連するTODOは以下の通り
- スクランブルをかける方のプログラムも書く
- チェックサムを直すプログラムも書く
- セーブデータの各領域が何を意味しているかはROMの中のあるファイルに従えばわかるので、それを使って人間に見やすく表示するプログラムを書く
以下はRustで書かれたプログラムです。
カレントディレクトリのファイルscrambled.bin (32640バイトのもの)を読み込み、スクランブルを解除し、ファイルunscrambled.binに出力します。
use std::fs::File; use std::io::{self, Read, Write}; fn unscramble(binary : &mut Vec<u8>) { let mut random_bytes = [0; 3 * 4]; let mut random = [0; 3]; let mut random_pool: [u16; 256] = [0; 256]; let size = binary.len() - 12; let a = size / 16; let b = if a == 0 { 0xB5BDCF5A_u32 >> 0x10 } else { (a as u32) * (0xB5BDCF5A_u32 >> 0x10) >> 0x10 } as usize; let index = b + 0x20; let mut binary_index = index; let mut seed = 0xB5BDCF5A_u32; for i in 0..12 { seed = 0x5D588B65_u32.wrapping_mul(seed).wrapping_add(0x269EC3_u32); let value = if a == 0 { seed >> 16 } else { (seed >> 16) * (a as u32) >> 0x10 }; binary_index += (value as usize) + 2; random_bytes[i] = binary[binary_index]; binary[binary_index] = binary[size + i]; } for i in 0..3 { random[i] = u32::from_le_bytes(random_bytes[i * 4..i * 4 + 4].try_into().unwrap()); } for i in 0..256 { random[0] = 0x5D588B65_u32.wrapping_mul(random[0]).wrapping_add(0x269EC3); random_pool[i] = (random[0] >> 0x10) as u16; } for i in 0..size { let rem = (i + (size * (random_pool[i % 256] as usize)) / 0x10000) % size; if ((i < 4) || (19 < i)) && ((rem < 4) || (19 < rem)) { binary.swap(i, rem); } } for i in 0..size { random[1] = 0x5D588B65_u32.wrapping_mul(random[1]).wrapping_add(0x269EC3_u32); if i < 4 || 19 < i { binary[i] ^= (random[1] >> 24) as u8; } } for i in 0..size { random[2] = 0x5D588B65_u32.wrapping_mul(random[2]).wrapping_add(0x269EC3_u32); if i < 4 || 19 < i { let shift = ((random[2] >> 0x10) << 3) >> 0x10; binary[i] = (((binary[i] as u16) << 8 | (binary[i] as u16)) >> shift) as u8; } } } fn main() -> io::Result<()> { let file_path: &str = "scrambled.bin"; let mut file = File::open(file_path)?; let mut binary = Vec::new(); file.read_to_end(&mut binary)?; unscramble(&mut binary); let file_path = "unscrambled.bin"; let mut file = File::create(file_path)?; file.write(&binary)?; Ok(()) }