-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #727 from ReFirmLabs/wince
Wince
- Loading branch information
Showing
7 changed files
with
243 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} |