forked from ReFirmLabs/binwalk
-
Notifications
You must be signed in to change notification settings - Fork 1
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 ReFirmLabs#786 from ReFirmLabs/dms_short_swapped
Added DMS firmware signature; added byte-swap extractor
- Loading branch information
Showing
7 changed files
with
196 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,105 @@ | ||
use crate::extractors::common::{Chroot, ExtractionResult, Extractor, ExtractorType}; | ||
|
||
/// Defines the internal extractor function for u16 swapped firmware images | ||
/// | ||
/// ``` | ||
/// use std::io::ErrorKind; | ||
/// use std::process::Command; | ||
/// use binwalk::extractors::common::ExtractorType; | ||
/// use binwalk::extractors::swapped::swapped_extractor_u16; | ||
/// | ||
/// match swapped_extractor_u16().utility { | ||
/// ExtractorType::None => panic!("Invalid extractor type of None"), | ||
/// ExtractorType::Internal(func) => println!("Internal extractor OK: {:?}", func), | ||
/// ExtractorType::External(cmd) => { | ||
/// if let Err(e) = Command::new(&cmd).output() { | ||
/// if e.kind() == ErrorKind::NotFound { | ||
/// panic!("External extractor '{}' not found", cmd); | ||
/// } else { | ||
/// panic!("Failed to execute external extractor '{}': {}", cmd, e); | ||
/// } | ||
/// } | ||
/// } | ||
/// } | ||
/// ``` | ||
pub fn swapped_extractor_u16() -> Extractor { | ||
Extractor { | ||
utility: ExtractorType::Internal(extract_swapped_u16), | ||
..Default::default() | ||
} | ||
} | ||
|
||
/// Extract firmware where every two bytes have been swapped | ||
pub fn extract_swapped_u16( | ||
file_data: &[u8], | ||
offset: usize, | ||
output_directory: Option<&String>, | ||
) -> ExtractionResult { | ||
const SWAP_BYTE_COUNT: usize = 2; | ||
extract_swapped(file_data, offset, output_directory, SWAP_BYTE_COUNT) | ||
} | ||
|
||
/// Extract a block of data where every n bytes have been swapped | ||
fn extract_swapped( | ||
file_data: &[u8], | ||
offset: usize, | ||
output_directory: Option<&String>, | ||
n: usize, | ||
) -> ExtractionResult { | ||
const OUTPUT_FILE_NAME: &str = "swapped.bin"; | ||
|
||
let mut result = ExtractionResult { | ||
..Default::default() | ||
}; | ||
|
||
if let Some(data) = file_data.get(offset..) { | ||
let swapped_data = byte_swap(data, n); | ||
|
||
result.success = !swapped_data.is_empty(); | ||
|
||
if result.success { | ||
result.size = Some(swapped_data.len()); | ||
|
||
// Write to file, if requested | ||
if output_directory.is_some() { | ||
let chroot = Chroot::new(output_directory); | ||
result.success = chroot.create_file(OUTPUT_FILE_NAME, &swapped_data); | ||
} | ||
} | ||
} | ||
|
||
result | ||
} | ||
|
||
/// Swap every n bytes of the provided data | ||
/// | ||
/// ## Example: | ||
/// | ||
/// ``` | ||
/// use binwalk::extractors::swapped::byte_swap; | ||
/// | ||
/// assert_eq!(byte_swap(b"ABCD", 2), b"CDAB"); | ||
/// ``` | ||
pub fn byte_swap(data: &[u8], n: usize) -> Vec<u8> { | ||
let chunk_size = n * 2; | ||
let mut chunker = data.chunks(chunk_size); | ||
let mut swapped_data: Vec<u8> = Vec::new(); | ||
|
||
loop { | ||
match chunker.next() { | ||
None => { | ||
break; | ||
} | ||
Some(chunk) => { | ||
if chunk.len() != chunk_size { | ||
break; | ||
} | ||
|
||
swapped_data.extend(chunk[n..].to_vec()); | ||
swapped_data.extend(chunk[0..n].to_vec()); | ||
} | ||
} | ||
} | ||
|
||
swapped_data | ||
} |
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::swapped::byte_swap; | ||
use crate::signatures::common::{SignatureError, SignatureResult, CONFIDENCE_MEDIUM}; | ||
use crate::structures::dms::parse_dms_header; | ||
|
||
/// Human readable description | ||
pub const DESCRIPTION: &str = "DMS firmware image"; | ||
|
||
/// DMS firmware image magic bytes | ||
pub fn dms_magic() -> Vec<Vec<u8>> { | ||
vec![b"0><1".to_vec()] | ||
} | ||
|
||
/// Validates the DMS header | ||
pub fn dms_parser(file_data: &[u8], offset: usize) -> Result<SignatureResult, SignatureError> { | ||
const MIN_SIZE: usize = 0x100; | ||
const BYTE_SWAP_SIZE: usize = 2; | ||
const MAGIC_OFFSET: usize = 4; | ||
|
||
// Successful return value | ||
let mut result = SignatureResult { | ||
description: DESCRIPTION.to_string(), | ||
confidence: CONFIDENCE_MEDIUM, | ||
..Default::default() | ||
}; | ||
|
||
// The magic bytes start at offset 4 | ||
if offset >= MAGIC_OFFSET { | ||
result.offset = offset - MAGIC_OFFSET; | ||
|
||
if let Some(dms_data) = file_data.get(result.offset..result.offset + MIN_SIZE) { | ||
// DMS firmware images have every 2 bytes swapped | ||
let swapped_data = byte_swap(dms_data, BYTE_SWAP_SIZE); | ||
|
||
// Validate the DMS firmware header | ||
if let Ok(dms_header) = parse_dms_header(&swapped_data) { | ||
result.size = dms_header.image_size; | ||
result.description = | ||
format!("{}, total size: {} bytes", result.description, 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,32 @@ | ||
use crate::structures::common::{self, StructureError}; | ||
|
||
/// Struct to store DMS header info | ||
#[derive(Debug, Default, Clone)] | ||
pub struct DMSHeader { | ||
pub image_size: usize, | ||
} | ||
|
||
/// Parses a DMS header | ||
pub fn parse_dms_header(dms_data: &[u8]) -> Result<DMSHeader, StructureError> { | ||
const MAGIC_P1: usize = 0x4D47; | ||
const MAGIC_P2: usize = 0x3C31303E; | ||
|
||
let dms_structure = vec![ | ||
("unknown1", "u16"), | ||
("magic_p1", "u16"), | ||
("magic_p2", "u32"), | ||
("unknown2", "u32"), | ||
("image_size", "u32"), | ||
]; | ||
|
||
// Parse the first half of the header | ||
if let Ok(dms_header) = common::parse(dms_data, &dms_structure, "big") { | ||
if dms_header["magic_p1"] == MAGIC_P1 && dms_header["magic_p2"] == MAGIC_P2 { | ||
return Ok(DMSHeader { | ||
image_size: dms_header["image_size"], | ||
}); | ||
} | ||
} | ||
|
||
Err(StructureError) | ||
} |