1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
use crate::common::is_offset_safe;
use crate::signatures::common::{SignatureError, SignatureResult, CONFIDENCE_HIGH};
use aho_corasick::AhoCorasick;
/// Human readable descriptions
pub const SREC_DESCRIPTION: &str = "Motorola S-record";
pub const SREC_SHORT_DESCRIPTION: &str = "Motorola S-record (generic)";
/// Generic, short signature for s-records, should only be matched at the beginning of a file
pub fn srec_short_magic() -> Vec<Vec<u8>> {
vec![b"S0".to_vec()]
}
/// This assumes a srec header with the hex encoded string of "HDR"
pub fn srec_magic() -> Vec<Vec<u8>> {
vec![b"S00600004844521B".to_vec()]
}
/// Validates a SREC signature
pub fn srec_parser(file_data: &[u8], offset: usize) -> Result<SignatureResult, SignatureError> {
// \r and \n
const UNIX_TERMINATING_CHARACTER: u8 = 0x0A;
const WINDOWS_TERMINATING_CHARACTER: u8 = 0x0D;
let mut result = SignatureResult {
offset,
description: SREC_DESCRIPTION.to_string(),
confidence: CONFIDENCE_HIGH,
..Default::default()
};
let available_data = file_data.len();
// Srec lines, and hence the last line of an s-record, should end with a new line or line feed
let terminating_characters = [WINDOWS_TERMINATING_CHARACTER, UNIX_TERMINATING_CHARACTER];
// Possible srec footers
let srec_footers = vec![b"\nS9", b"\nS8", b"\nS7"];
// Need to grep for the srec footer to determine total size
let grep = AhoCorasick::new(srec_footers.clone()).unwrap();
// Search for srec footer lines
for srec_footer_match in grep.find_overlapping_iter(&file_data[offset..]) {
// Assume origin OS is Unix unless proven otherwise
let mut os_type: &str = "Unix";
// Start searching for terminating EOF characters after this footer match (all footer signatures are the same size)
let mut srec_eof: usize = offset + srec_footer_match.start() + srec_footers[0].len();
let mut last_srec_eof = None;
// Found the start of a possible srec footer line, loop over remianing bytes looking for the line termination
while is_offset_safe(available_data, srec_eof, last_srec_eof) {
// All srec lines should end in \n or \r\n
if terminating_characters.contains(&file_data[srec_eof]) {
// Windows systems use \r\n
if file_data[srec_eof] == WINDOWS_TERMINATING_CHARACTER {
// There should be one more character, a \n, which is common to both windows and linux implementations
srec_eof += 1;
os_type = "Windows";
}
// Sanity check, don't want to index out of bounds
if let Some(srec_last_byte) = file_data.get(srec_eof) {
// Last byte should be a line feed (\n)
if *srec_last_byte == UNIX_TERMINATING_CHARACTER {
// Include the final line feed byte in the size of the s-record
srec_eof += 1;
// Report results
result.size = srec_eof - offset;
result.description = format!(
"{}, origin OS: {}, total size: {} bytes",
result.description, os_type, result.size
);
return Ok(result);
}
}
// Invalid srec termination, stop searching
return Err(SignatureError);
}
// Not a terminating character, go to the next byte in the file
last_srec_eof = Some(srec_eof);
srec_eof += 1;
}
}
// No valid srec footers found
Err(SignatureError)
}