Skip to content

Commit

Permalink
Merge pull request #727 from ReFirmLabs/wince
Browse files Browse the repository at this point in the history
Wince
  • Loading branch information
devttys0 authored Oct 30, 2024
2 parents 0fe3520 + cb2206e commit 14a891e
Show file tree
Hide file tree
Showing 7 changed files with 243 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/extractors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ pub mod ubi;
pub mod uefi;
pub mod uimage;
pub mod vxworks;
pub mod wince;
pub mod yaffs2;
pub mod zip;
pub mod zlib;
Expand Down
131 changes: 131 additions & 0 deletions src/extractors/wince.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
use crate::common::is_offset_safe;
use crate::extractors::common::{Chroot, ExtractionResult, Extractor, ExtractorType};
use crate::structures::wince::{parse_wince_block_header, parse_wince_header};

/// Defines the internal extractor function for extracting Windows CE images
pub fn wince_extractor() -> Extractor {
Extractor {
utility: ExtractorType::Internal(wince_dump),
..Default::default()
}
}

/// Internal extractor for extracting data blocks from Windows CE images
pub fn wince_dump(
file_data: &[u8],
offset: usize,
output_directory: Option<&String>,
) -> ExtractionResult {
let mut result = ExtractionResult {
..Default::default()
};

// Parse the file header
if let Some(wince_data) = file_data.get(offset..) {
if let Ok(wince_header) = parse_wince_header(wince_data) {
// Get the block data, immediately following the file header
if let Some(wince_block_data) = wince_data.get(wince_header.header_size..) {
// Process all blocks in the block data
if let Some(data_blocks) = process_wince_blocks(wince_block_data) {
// The first block entry's address should equal the WinCE header's base address
if data_blocks.entries[0].address == wince_header.base_address {
// Block processing was successful
result.success = true;
result.size = Some(wince_header.header_size + data_blocks.total_size);

// If extraction was requested, extract each block to a file on disk
if output_directory.is_some() {
let chroot = Chroot::new(output_directory);

for block in data_blocks.entries {
let block_file_name = format!("{:X}.bin", block.address);

// If file carving fails, report a failure to extract
if !chroot.carve_file(
block_file_name,
wince_block_data,
block.offset,
block.size,
) {
result.success = false;
break;
}
}
}
}
}
}
}
}

result
}

/// Stores info about each WinCE block
#[derive(Debug, Default, Clone)]
struct BlockInfo {
pub address: usize,
pub offset: usize,
pub size: usize,
}

/// Stores info about all WinCE blocks
#[derive(Debug, Default, Clone)]
struct BlockData {
pub total_size: usize,
pub entries: Vec<BlockInfo>,
}

/// Process all WinCE blocks
fn process_wince_blocks(blocks_data: &[u8]) -> Option<BlockData> {
// Arbitrarily chosen, just to make sure more than one or two blocks were processed and sane
const MIN_ENTRIES_COUNT: usize = 5;

let mut blocks = BlockData {
..Default::default()
};

let mut next_offset: usize = 0;
let mut previous_offset = None;
let available_data = blocks_data.len();

// Process all blocks until the end block is reached, or an error is encountered
while is_offset_safe(available_data, next_offset, previous_offset) {
// Parse this block's header
match parse_wince_block_header(&blocks_data[next_offset..]) {
Err(_) => {
break;
}
Ok(block_header) => {
// Include the block header size in the total size of the block data
blocks.total_size += block_header.header_size;

// A block header address of NULL indicates EOF
if block_header.address == 0 {
// Sanity check the number of blocks processed
if blocks.entries.len() > MIN_ENTRIES_COUNT {
return Some(blocks);
} else {
break;
}
} else {
// Include this block's size in the total size of the block data
blocks.total_size += block_header.data_size;

// Add this block to the list of block entries
blocks.entries.push(BlockInfo {
address: block_header.address,
offset: next_offset + block_header.header_size,
size: block_header.data_size,
});

// Update the offsets for the next loop iteration
previous_offset = Some(next_offset);
next_offset += block_header.header_size + block_header.data_size;
}
}
}
}

None
}
11 changes: 11 additions & 0 deletions src/magic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -932,6 +932,17 @@ pub fn patterns() -> Vec<signatures::common::Signature> {
description: signatures::btrfs::DESCRIPTION.to_string(),
extractor: None,
},
// WinCE
signatures::common::Signature {
name: "wince".to_string(),
short: false,
magic_offset: 0,
always_display: false,
magic: signatures::wince::wince_magic(),
parser: signatures::wince::wince_parser,
description: signatures::wince::DESCRIPTION.to_string(),
extractor: Some(extractors::wince::wince_extractor()),
},
];

binary_signatures
Expand Down
1 change: 1 addition & 0 deletions src/signatures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ pub mod ubi;
pub mod uefi;
pub mod uimage;
pub mod vxworks;
pub mod wince;
pub mod xz;
pub mod yaffs;
pub mod zip;
Expand Down
45 changes: 45 additions & 0 deletions src/signatures/wince.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use crate::extractors::wince::wince_dump;
use crate::signatures::common::{SignatureError, SignatureResult, CONFIDENCE_HIGH};
use crate::structures::wince::parse_wince_header;

/// Human readable description
pub const DESCRIPTION: &str = "Windows CE binary image";

/// Windows CE magic bytes
pub fn wince_magic() -> Vec<Vec<u8>> {
vec![b"B000FF\n".to_vec()]
}

/// Validates the Windows CE header
pub fn wince_parser(file_data: &[u8], offset: usize) -> Result<SignatureResult, SignatureError> {
// Successful return value
let mut result = SignatureResult {
offset,
description: DESCRIPTION.to_string(),
confidence: CONFIDENCE_HIGH,
..Default::default()
};

// Do an extraction dry-run
let dry_run = wince_dump(file_data, offset, None);

if dry_run.success {
if let Some(total_size) = dry_run.size {
result.size = total_size;

// Parse the WinCE header to get some useful info to display
if let Ok(wince_header) = parse_wince_header(&file_data[offset..]) {
result.description = format!(
"{}, base address: {:#X}, image size: {} bytes, file size: {} bytes",
result.description,
wince_header.base_address,
wince_header.image_size,
result.size
);
return Ok(result);
}
}
}

Err(SignatureError)
}
1 change: 1 addition & 0 deletions src/structures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ pub mod ubi;
pub mod uefi;
pub mod uimage;
pub mod vxworks;
pub mod wince;
pub mod xz;
pub mod yaffs;
pub mod zip;
Expand Down
53 changes: 53 additions & 0 deletions src/structures/wince.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
use crate::structures::common::{self, StructureError};

/// Struct to store WindowsCE header info
#[derive(Debug, Default, Clone)]
pub struct WinCEHeader {
pub base_address: usize,
pub image_size: usize,
pub header_size: usize,
}

/// Parses a Windows CE header
pub fn parse_wince_header(wince_data: &[u8]) -> Result<WinCEHeader, StructureError> {
let wince_header_structure = vec![
("magic_p1", "u32"),
("magic_p2", "u24"),
("image_start", "u32"),
("image_size", "u32"),
];

// Parse the WinCE header
if let Ok(wince_header) = common::parse(wince_data, &wince_header_structure, "little") {
return Ok(WinCEHeader {
base_address: wince_header["image_start"],
image_size: wince_header["image_size"],
header_size: common::size(&wince_header_structure),
});
}

Err(StructureError)
}

/// Struct to store WindowsCE block info
#[derive(Debug, Default, Clone)]
pub struct WinCEBlock {
pub address: usize,
pub data_size: usize,
pub header_size: usize,
}

/// Parse a WindowsCE block header
pub fn parse_wince_block_header(block_data: &[u8]) -> Result<WinCEBlock, StructureError> {
let wince_block_structure = vec![("address", "u32"), ("size", "u32"), ("checksum", "u32")];

if let Ok(block_header) = common::parse(block_data, &wince_block_structure, "little") {
return Ok(WinCEBlock {
address: block_header["address"],
data_size: block_header["size"],
header_size: common::size(&wince_block_structure),
});
}

Err(StructureError)
}

0 comments on commit 14a891e

Please sign in to comment.