-
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 #751 from cohaereo/dxbc-magic
Added support for DirectX shader bytecode files
- Loading branch information
Showing
7 changed files
with
174 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,59 @@ | ||
use crate::extractors::common::{Chroot, ExtractionResult, Extractor, ExtractorType}; | ||
use crate::structures::dxbc::parse_dxbc_header; | ||
|
||
/// Defines the internal extractor function for carving out DXBC images | ||
/// | ||
/// ``` | ||
/// use std::io::ErrorKind; | ||
/// use std::process::Command; | ||
/// use binwalk::extractors::common::ExtractorType; | ||
/// use binwalk::extractors::dxbc::dxbc_extractor; | ||
/// | ||
/// match dxbc_extractor().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 dxbc_extractor() -> Extractor { | ||
Extractor { | ||
do_not_recurse: true, | ||
utility: ExtractorType::Internal(extract_dxbc_file), | ||
..Default::default() | ||
} | ||
} | ||
|
||
pub fn extract_dxbc_file( | ||
file_data: &[u8], | ||
offset: usize, | ||
output_directory: Option<&String>, | ||
) -> ExtractionResult { | ||
const OUTFILE_NAME: &str = "shader.dxbc"; | ||
|
||
let mut result = ExtractionResult { | ||
..Default::default() | ||
}; | ||
|
||
if let Ok(header) = parse_dxbc_header(&file_data[offset..]) { | ||
// Report success | ||
result.size = Some(header.size); | ||
result.success = true; | ||
|
||
// Do extraction, if requested | ||
if output_directory.is_some() { | ||
let chroot = Chroot::new(output_directory); | ||
result.success = | ||
chroot.carve_file(OUTFILE_NAME, file_data, offset, result.size.unwrap()); | ||
} | ||
} | ||
|
||
result | ||
} |
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::signatures::common::{ | ||
SignatureError, SignatureResult, CONFIDENCE_HIGH, CONFIDENCE_MEDIUM, | ||
}; | ||
use crate::structures::dxbc::parse_dxbc_header; | ||
|
||
/// Human readable description | ||
pub const DESCRIPTION: &str = "DirectX shader bytecode"; | ||
|
||
/// DXBC file magic bytes | ||
pub fn dxbc_magic() -> Vec<Vec<u8>> { | ||
vec![b"DXBC".to_vec()] | ||
} | ||
|
||
/// Validates the DXBC header | ||
pub fn dxbc_parser(file_data: &[u8], offset: usize) -> Result<SignatureResult, SignatureError> { | ||
const CHUNK_SM4: [u8; 4] = *b"SHDR"; | ||
const CHUNK_SM5: [u8; 4] = *b"SHEX"; | ||
|
||
// Successful return value | ||
let mut result = SignatureResult { | ||
offset, | ||
description: DESCRIPTION.to_string(), | ||
confidence: CONFIDENCE_MEDIUM, | ||
..Default::default() | ||
}; | ||
|
||
if let Ok(header) = parse_dxbc_header(&file_data[offset..]) { | ||
result.confidence = CONFIDENCE_HIGH; | ||
result.size = header.size; | ||
|
||
let shader_model = if header.chunk_ids.contains(&CHUNK_SM4) { | ||
"Shader Model 4" | ||
} else if header.chunk_ids.contains(&CHUNK_SM5) { | ||
"Shader Model 5" | ||
} else { | ||
"Unknown Shader Model" | ||
}; | ||
|
||
result.description = format!("{}, {}", result.description, shader_model); | ||
|
||
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,56 @@ | ||
use crate::structures::common::{self, StructureError}; | ||
|
||
#[derive(Debug, Default, Clone)] | ||
pub struct DXBCHeader { | ||
pub size: usize, | ||
pub chunk_ids: Vec<[u8; 4]>, | ||
} | ||
|
||
// http://timjones.io/blog/archive/2015/09/02/parsing-direct3d-shader-bytecode | ||
pub fn parse_dxbc_header(data: &[u8]) -> Result<DXBCHeader, StructureError> { | ||
let dxbc_header_structure = vec![ | ||
("magic", "u32"), | ||
("signature_p1", "u64"), | ||
("signature_p2", "u64"), | ||
("one", "u32"), | ||
("total_size", "u32"), | ||
("chunk_count", "u32"), | ||
]; | ||
|
||
// Parse the header | ||
if let Ok(header) = common::parse(data, &dxbc_header_structure, "little") { | ||
if header["one"] != 1 { | ||
return Err(StructureError); | ||
} | ||
|
||
// Sanity check: There are at least 14 known chunks, but most likely no more than 32. | ||
// Prevents the for loop from spiraling into an OOM on the offchance that both the magic and "one" check pass on garbage data | ||
if header["chunk_count"] > 32 { | ||
return Err(StructureError); | ||
} | ||
|
||
let header_end = common::size(&dxbc_header_structure); | ||
|
||
let mut chunk_ids = vec![]; | ||
for i in 0..header["chunk_count"] { | ||
let offset_data = data | ||
.get((header_end + i * 4)..(header_end + i * 4) + 4) | ||
.ok_or(StructureError)?; | ||
let offset = u32::from_le_bytes(offset_data.try_into().unwrap()) as usize; | ||
|
||
chunk_ids.push( | ||
data.get(offset..offset + 4) | ||
.ok_or(StructureError)? | ||
.try_into() | ||
.unwrap(), | ||
); | ||
} | ||
|
||
return Ok(DXBCHeader { | ||
size: header["total_size"], | ||
chunk_ids, | ||
}); | ||
} | ||
|
||
Err(StructureError) | ||
} |