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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
//! # Data Structure Parsing
//!
//! Both signatures and internal extractors may need to parse data structures used by various file formats.
//! Structure parsing code is placed in the `structures` module.
//!
//! ## Helper Functions
//!
//! There are some definitions and helper functions in `structures::common` that are generally helpful for processing data structures.
//!
//! The `structures::common::parse` function provides a way to parse basic data structures by defining the data structure format,
//! the endianness to use, and the data to cast the structure over. It is heavily used by most structure parsers.
//! It supports the following data types:
//!
//! - u8
//! - u16
//! - u24
//! - u32
//! - u64
//!
//! Regardless of the data type specified, all values are returned as `usize` types.
//! If an error occurs (typically due to not enough data available to process the specified data structure), `Err(structures::common::StructureError)` is returned.
//!
//! The `structures::common::size` function is a convenience function that returns the number of bytes required to parse a defined data structure.
//!
//! The `structures::common::StructureError` struct is typically used by structure parsers to return an error.
//!
//! ## Writing a Structure Parser
//!
//! Structure parsers may be defined however they need to be; there are no strict rules here.
//! Generally, however, they should:
//!
//! - Accept some data to parse
//! - Parse the data structure
//! - Validate the structure fields for correctness
//! - Return an error or success status
//!
//! ### Example
//!
//! To write a structure parser for a simple, fictional, `FooBar` file header:
//!
//! ```no_run
//! use binwalk::common::{crc32, get_cstring};
//! use binwalk::structures::common::{self, StructureError};
//!
//! #[derive(Debug, Default, Clone)]
//! pub struct FooBarHeader {
//! pub data_crc: usize,
//! pub data_size: usize,
//! pub header_size: usize,
//! pub original_file_name: String,
//! }
//!
//! /// This function parses and validates the FooBar file header.
//! /// It returns a FooBarHeader struct on success, StructureError on failure.
//! fn parse_foobar_header(foobar_data: &[u8]) -> Result<FooBarHeader, StructureError> {
//! // The header CRC is calculated over the first 13 bytes of the header (everything except the header_crc field)
//! const HEADER_CRC_LEN: usize = 13;
//!
//! // Define a data structure; structure members must be in the order in which they appear in the data
//! let foobar_struct = vec![
//! ("magic", "u32"),
//! ("flags", "u8"),
//! ("data_size", "u32"),
//! ("data_crc", "u32"),
//! ("header_crc", "u32"),
//! // NULL-terminated original file name immediately follows the header structure
//! ];
//!
//! let struct_size: usize = common::size(&foobar_struct);
//!
//! // Parse the provided data in accordance with the layout defined in foobar_struct, interpret fields as little endian
//! if let Ok(foobar_header) = common::parse(foobar_data, &foobar_struct, "little") {
//!
//! if let Some(crc_data) = foobar_data.get(0..HEADER_CRC_LEN) {
//! // Validate the header CRC
//! if foobar_header["header_crc"] == (crc32(crc_data) as usize) {
//! // Get the NULL-terminated file name that immediately follows the header structure
//! if let Some(file_name_bytes) = foobar_data.get(struct_size..) {
//! let file_name = get_cstring(file_name_bytes);
//!
//! // The file name should be non-zero in length
//! if file_name.len() > 0 {
//! return Ok(FooBarHeader{
//! data_crc: foobar_header["data_crc"],
//! data_size: foobar_header["data_size"],
//! header_size: struct_size + file_name.len() + 1, // Total header size is structure size + name length + NULL byte
//! original_file_name: file_name.clone(),
//! });
//! }
//! }
//! }
//! }
//! }
//!
//! return Err(StructureError);
//! }
//! ```