improvements to roku and fix output folder issue in sony_bdp

This commit is contained in:
theubusu
2026-04-12 16:00:59 +02:00
parent 558310c36e
commit a3fbb9e76f
3 changed files with 104 additions and 49 deletions
+84 -34
View File
@@ -7,43 +7,93 @@ pub static FILE_KEY: [u8; 16] = [
pub static FILE_IV: [u8; 16] = [0x00; 16]; pub static FILE_IV: [u8; 16] = [0x00; 16];
#[derive(BinRead)] // u-boot-2011.06/include/aimage.h
pub struct ImageHeader { // (C) Copyright 2004-2008 Andre McCurdy, NXP Semiconductors
_empty: [u8; 8],
_magic_bytes: [u8; 8], //imgARMcC #[derive(Debug, BinRead)]
_target_bytes: [u8; 4], pub struct AImageHeader {
_platform_id: [u8; 4], _vector: u32, // reserved for a branch instruction (if data_start_offset and data_entry_point_offset are 0)
pub image_type: u32, _vector2: u32, // reserved for a branch instruction branch delay slot
pub size1: u32, _magic: u32, // 0x41676d69
_size2: u32, _magic2: u32, // 0x43634d52
pub data_start_offset: u32, _release_id: u32, // toplevel build / release version
_data_link_address: u32, _platform_id: u32, // target platform information
_data_entry_point_offset: u32, pub image_type: u32, // image type
pub flags: u32, pub lenght: u32, // length of entire image (header + data + trailing padding)
_timestamp: u32, _data_lenght: u32, // length of image data (ie from data_start_offset to start of trailing padding)
_build_host: [u8; 4], pub data_start_offset: u32, // 0 if header is part of data, sizeof(aimage_v1_header_t) if header is prepended to data
_unk: [u8; 4], _data_link_address: u32, // for non-pic executable images, where should the image placed in memory in order to execute
_rest_of_header: [u8; 192], _data_entry_point_offset: u32, // 0 if execution entry point is at the beginning of image data
pub flags: u32, // image flags
_build_time: u32, // if non-zero, gives time when image was created (seconds since 1970)
_build_host_offset: u32, // if non-zero, offset of a string in the image data giving build host information
_signature: [u8; 128], // 32 32bit words == 1024 bit RSA signature
_hash: [u8; 20], // raw sha1 hash (fallback if not checking signature)
_usd: u32, // "un-signed data" (treated as 0 during hash and signature verification, regardless of actual value)
_reserved: [u8; 28], // image type specific params etc (number tweaked to keep header size == 256 bytes)
/*
Note: The final 16 bytes of the header are used to form the
IV for aimage images which are encrypted with AES (ie if
IMG_FLAG_ENC RYPTED_V1 flag is set).
From a security standpoint, the IV does _not_ have to be
secret in any way, but it _should_ be unique for every
image which is encrypted with a given AES key.
*/
_iv: [u8; 16], // space reserved for random data or timestamp to ensure IV is unique for every image which is signed
} }
impl ImageHeader { impl AImageHeader {
pub fn is_encrypted(&self) -> bool { //pub fn release_id_str(&self) -> String {
self.flags == 0x80 // let release_id_major = ((self.release_id) >> 21) & 0x3FF;
// let release_id_minor = ((self.release_id) >> 15) & 0x3F;
// let release_id_build = ((self.release_id) >> 1) & 0x3FFF;
// return format!("{}.{}-{}", release_id_major, release_id_minor, release_id_build)
//}
pub fn image_type_str(&self) -> &str {
match self.image_type {
0x00 => "invalid",
0x01 => "debug_message",
0x02 => "bloader",
0x03 => "slaveloader", // [O]
0x04 => "env",
0x05 => "rbf",
0x06 => "bootdata", // [O] ROKUBOOT_TYPE_PKG
0x07 => "cexapp",
0x08 => "slaveapp",
0x09 => "zimage",
0x0A => "initfs_cramfs", // [O] cramfs image
0x0B => "initfs_zext2",
0x0C => "appfs_ext2",
0x0D => "appfs_cramfs", // [O] custom_pkg image
0x0E => "firmware_blob", // [O] ROKUBOOT_TYPE_UBOOT //main u-boot
0x0F => "bootcount",
0x10 => "bootselection",
0x11 => "gnfs_ext2",
0x12 => "eth0mac",
0x13 => "bloader_testmode",
0x14 => "bloader_dfu",
0x15 => "splashscreen",
0x16 => "custom_pkg_token", // [O]
0x17 => "initrd",
0x18 => "uimage", // [O] ROKUBOOT_TYPE_KERNEL // linux
0x19 => "uboot_mipsel",
0x1A => "uboot_mipseb",
0x1B => "initfs_squashfs",
0x101 => "cramfs_auth", // [O] merkle tree for cramfs
_ => "UNKNOWN",
}
} }
pub fn type_string(&self) -> &str {
if self.image_type == 0xa { pub fn encmode_str(&self) -> &str {
return "initfs" let encmode_flags = self.flags & (7 << 6);
} else if self.image_type == 0x18 { if (encmode_flags & (1 << 6)) != 0 { // image data is encrypted before signing: CBC mode, entire image in one pass
return "uImage" return "cbc_onepass"
} else if self.image_type == 0x3 { } else if (encmode_flags & (2 << 6)) != 0 { // image data is encrypted before signing: CBC mode, 4k byte blocks, block group iv = (iv + (first block's block offset))
return "loader" return "cbc_4kblocks"
} else if self.image_type == 0xd { } else if (encmode_flags & (3 << 6)) != 0 { // image data is encrypted before signing: CTR mode, block iv = (iv + (block offset))
return "app_cramfs" return "ctr"
} else if self.image_type == 0x6 {
return "Customization Package"
} else if self.image_type == 0xe {
return "firmware_blob"
} else { } else {
return "unknown" return "none/unknown"
} }
} }
} }
+14 -10
View File
@@ -4,7 +4,7 @@ use crate::AppContext;
use std::fs::{self, OpenOptions}; use std::fs::{self, OpenOptions};
use std::path::Path; use std::path::Path;
use std::io::{Write, Seek, Read, Cursor}; use std::io::{Cursor, Read, Seek, SeekFrom, Write};
use tar::Archive; use tar::Archive;
use binrw::BinReaderExt; use binrw::BinReaderExt;
@@ -38,6 +38,7 @@ pub fn extract_roku(app_ctx: &AppContext, _ctx: Box<dyn Any>) -> Result<(), Box<
for entry_result in tar_archive.entries_with_seek()? { for entry_result in tar_archive.entries_with_seek()? {
let mut entry = entry_result?; let mut entry = entry_result?;
let path = entry.path()?.to_path_buf(); let path = entry.path()?.to_path_buf();
if path == std::path::Path::new("manifest") { if path == std::path::Path::new("manifest") {
@@ -58,26 +59,29 @@ pub fn extract_roku(app_ctx: &AppContext, _ctx: Box<dyn Any>) -> Result<(), Box<
let mut i = 1; let mut i = 1;
while image_reader.stream_position()? < size as u64 { while image_reader.stream_position()? < size as u64 {
let image: ImageHeader = image_reader.read_le()?; let image: AImageHeader = image_reader.read_le()?;
println!("\nImage {} - Type: {:x}({}), Size: {}, Flags: {:x}{}, Data offset: {}", println!(" #{} - Type: {}(0x{:x}), Lenght: {}, encmode: {}",
i ,image.image_type, image.type_string(), image.size1, image.flags, if image.is_encrypted(){"(Encrypted)"}else{" "}, image.data_start_offset); i, image.image_type_str(), image.image_type, image.lenght, image.encmode_str());
//println!("{:?}", image);
let data = let data =
if image.data_start_offset == 0 { if image.data_start_offset == 0 { // "0 if header is part of data"
common::read_exact(&mut image_reader, image.size1 as usize - 256)? image_reader.seek(SeekFrom::Current(-256))?; //rewind header
common::read_exact(&mut image_reader, image.lenght as usize)?
} else { } else {
let _extra_data = common::read_exact(&mut image_reader, image.data_start_offset as usize - 256)?; let _skip_data = common::read_exact(&mut image_reader, image.data_start_offset as usize - 256)?;
common::read_exact(&mut image_reader, image.size1 as usize - image.data_start_offset as usize)? common::read_exact(&mut image_reader, image.lenght as usize - image.data_start_offset as usize)?
}; };
let folder_path = Path::new(&app_ctx.output_dir).join(&path); let folder_path = Path::new(&app_ctx.output_dir).join(&path);
let output_path = Path::new(&folder_path).join(format!("{}_{}.bin", i, image.type_string())); let output_path = Path::new(&folder_path).join(format!("{}_{}.bin", i, image.image_type_str()));
fs::create_dir_all(&folder_path)?; fs::create_dir_all(&folder_path)?;
let mut out_file = OpenOptions::new().write(true).create(true).open(output_path)?; let mut out_file = OpenOptions::new().write(true).create(true).open(output_path)?;
out_file.write_all(&data)?; out_file.write_all(&data)?;
println!("- Saved file!"); println!(" - Saved file!\n");
i += 1; i += 1;
} }
+6 -5
View File
@@ -36,9 +36,10 @@ pub fn extract_sony_bdp(app_ctx: &AppContext, _ctx: Box<dyn Any>) -> Result<(),
let mut last_file_path: Option<PathBuf> = None; let mut last_file_path: Option<PathBuf> = None;
let mut first_entry_offset = 0; let mut first_entry_offset = 0;
let mut i = 1; let mut i = 0;
loop { loop {
if (i != 1) && (hdr_reader.position() >= first_entry_offset) {
if (i != 0) && (hdr_reader.position() >= first_entry_offset) {
break break
} }
@@ -48,14 +49,14 @@ pub fn extract_sony_bdp(app_ctx: &AppContext, _ctx: Box<dyn Any>) -> Result<(),
} }
println!("\n#{} - Offset: {}, Size: {}", i, entry.offset, entry.size); println!("\n#{} - Offset: {}, Size: {}", i, entry.offset, entry.size);
if i == 1 { if i == 0 {
first_entry_offset = entry.offset as u64; first_entry_offset = entry.offset as u64;
} }
let obf_data = common::read_file(&file, entry.offset as u64, entry.size as usize)?; let obf_data = common::read_file(&file, entry.offset as u64, entry.size as usize)?;
let data = hex_substitute(&obf_data); let data = hex_substitute(&obf_data);
let output_path = Path::new(&app_ctx.output_dir).join(format!("{}.bin", i)); let output_path = Path::new(&app_ctx.output_dir).join(format!("{}.bin", i+1));
last_file_path = Some(output_path.clone()); last_file_path = Some(output_path.clone());
fs::create_dir_all(&app_ctx.output_dir)?; fs::create_dir_all(&app_ctx.output_dir)?;
@@ -71,7 +72,7 @@ pub fn extract_sony_bdp(app_ctx: &AppContext, _ctx: Box<dyn Any>) -> Result<(),
println!("\nChecking if it's also MTK BDP..."); println!("\nChecking if it's also MTK BDP...");
let last_file = File::open(last_file_path.unwrap())?; let last_file = File::open(last_file_path.unwrap())?;
let mtk_extraction_path = app_ctx.output_dir.join(format!("{}", i + 1)); let mtk_extraction_path = app_ctx.output_dir.join(format!("{}", i));
//this is getting stupid... //this is getting stupid...
let ctx: AppContext = AppContext { input: InputTarget::File(last_file), output_dir: mtk_extraction_path, options: app_ctx.options.clone() }; let ctx: AppContext = AppContext { input: InputTarget::File(last_file), output_dir: mtk_extraction_path, options: app_ctx.options.clone() };