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];
#[derive(BinRead)]
pub struct ImageHeader {
_empty: [u8; 8],
_magic_bytes: [u8; 8], //imgARMcC
_target_bytes: [u8; 4],
_platform_id: [u8; 4],
pub image_type: u32,
pub size1: u32,
_size2: u32,
pub data_start_offset: u32,
_data_link_address: u32,
_data_entry_point_offset: u32,
pub flags: u32,
_timestamp: u32,
_build_host: [u8; 4],
_unk: [u8; 4],
_rest_of_header: [u8; 192],
// u-boot-2011.06/include/aimage.h
// (C) Copyright 2004-2008 Andre McCurdy, NXP Semiconductors
#[derive(Debug, BinRead)]
pub struct AImageHeader {
_vector: u32, // reserved for a branch instruction (if data_start_offset and data_entry_point_offset are 0)
_vector2: u32, // reserved for a branch instruction branch delay slot
_magic: u32, // 0x41676d69
_magic2: u32, // 0x43634d52
_release_id: u32, // toplevel build / release version
_platform_id: u32, // target platform information
pub image_type: u32, // image type
pub lenght: u32, // length of entire image (header + data + trailing padding)
_data_lenght: u32, // length of image data (ie from data_start_offset to start of trailing padding)
pub data_start_offset: u32, // 0 if header is part of data, sizeof(aimage_v1_header_t) if header is prepended to data
_data_link_address: u32, // for non-pic executable images, where should the image placed in memory in order to execute
_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 {
pub fn is_encrypted(&self) -> bool {
self.flags == 0x80
impl AImageHeader {
//pub fn release_id_str(&self) -> String {
// 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 {
return "initfs"
} else if self.image_type == 0x18 {
return "uImage"
} else if self.image_type == 0x3 {
return "loader"
} else if self.image_type == 0xd {
return "app_cramfs"
} else if self.image_type == 0x6 {
return "Customization Package"
} else if self.image_type == 0xe {
return "firmware_blob"
pub fn encmode_str(&self) -> &str {
let encmode_flags = self.flags & (7 << 6);
if (encmode_flags & (1 << 6)) != 0 { // image data is encrypted before signing: CBC mode, entire image in one pass
return "cbc_onepass"
} 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 "cbc_4kblocks"
} else if (encmode_flags & (3 << 6)) != 0 { // image data is encrypted before signing: CTR mode, block iv = (iv + (block offset))
return "ctr"
} else {
return "unknown"
return "none/unknown"
}
}
}
+14 -10
View File
@@ -4,7 +4,7 @@ use crate::AppContext;
use std::fs::{self, OpenOptions};
use std::path::Path;
use std::io::{Write, Seek, Read, Cursor};
use std::io::{Cursor, Read, Seek, SeekFrom, Write};
use tar::Archive;
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()? {
let mut entry = entry_result?;
let path = entry.path()?.to_path_buf();
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;
while image_reader.stream_position()? < size as u64 {
let image: ImageHeader = image_reader.read_le()?;
println!("\nImage {} - Type: {:x}({}), Size: {}, Flags: {:x}{}, Data offset: {}",
i ,image.image_type, image.type_string(), image.size1, image.flags, if image.is_encrypted(){"(Encrypted)"}else{" "}, image.data_start_offset);
let image: AImageHeader = image_reader.read_le()?;
println!(" #{} - Type: {}(0x{:x}), Lenght: {}, encmode: {}",
i, image.image_type_str(), image.image_type, image.lenght, image.encmode_str());
//println!("{:?}", image);
let data =
if image.data_start_offset == 0 {
common::read_exact(&mut image_reader, image.size1 as usize - 256)?
if image.data_start_offset == 0 { // "0 if header is part of data"
image_reader.seek(SeekFrom::Current(-256))?; //rewind header
common::read_exact(&mut image_reader, image.lenght as usize)?
} else {
let _extra_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)?
let _skip_data = common::read_exact(&mut image_reader, image.data_start_offset as usize - 256)?;
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 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)?;
let mut out_file = OpenOptions::new().write(true).create(true).open(output_path)?;
out_file.write_all(&data)?;
println!("- Saved file!");
println!(" - Saved file!\n");
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 first_entry_offset = 0;
let mut i = 1;
let mut i = 0;
loop {
if (i != 1) && (hdr_reader.position() >= first_entry_offset) {
if (i != 0) && (hdr_reader.position() >= first_entry_offset) {
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);
if i == 1 {
if i == 0 {
first_entry_offset = entry.offset as u64;
}
let obf_data = common::read_file(&file, entry.offset as u64, entry.size as usize)?;
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());
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...");
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...
let ctx: AppContext = AppContext { input: InputTarget::File(last_file), output_dir: mtk_extraction_path, options: app_ctx.options.clone() };