pub struct AutoItBinary { /* private fields */ }Expand description
High-level view of an AutoIt payload.
Produced by AutoItBinary::try_parse, this type owns every recovered view:
the recognized container facts and analysis observations, the parsed AU3 records,
any recovered scripts and non-script artifacts, and raw strings found in the
payload bytes. Each view is exposed through an accessor and kept additive, so
partial recovery from a malformed sample still yields everything decoded
before the failure.
Implementations§
Source§impl AutoItBinary
impl AutoItBinary
Sourcepub fn try_parse(data: &[u8]) -> Result<Self, Error>
pub fn try_parse(data: &[u8]) -> Result<Self, Error>
Attempts to parse an AutoIt payload from bytes.
Recognizes the container (PE, .a3x, or a carved record stream) and its
encoding, then parses the AU3 record stream when one is located:
decrypting and decompressing record payloads, recovering scripts
(including EA06 detokenization), preserving non-script artifacts, and
extracting raw strings. Record parsing is tolerant — records recovered
before a later malformed record remain available via Self::records,
with the failure reported in Self::record_diagnostics.
§Errors
Returns Error when the input is not recognized as AutoIt, or when a
recognized container is too malformed to begin record parsing. Use
Error::recognition_failure to distinguish the cause.
Examples found in repository?
7fn main() -> ExitCode {
8 let mut args = env::args_os();
9 let _program = args.next();
10 let mut path = None;
11 for arg in args {
12 if path.is_none() {
13 path = Some(arg);
14 } else {
15 eprintln!("usage: dump <autoit-exe-or-a3x>");
16 return ExitCode::FAILURE;
17 }
18 }
19 let Some(path) = path else {
20 eprintln!("usage: dump <autoit-exe-or-a3x>");
21 return ExitCode::FAILURE;
22 };
23
24 let data = match fs::read(&path) {
25 Ok(data) => data,
26 Err(err) => {
27 eprintln!("failed to read input: {err}");
28 return ExitCode::FAILURE;
29 }
30 };
31
32 match AutoItBinary::try_parse(&data) {
33 Ok(binary) => {
34 print_text(&binary);
35 ExitCode::SUCCESS
36 }
37 Err(err) if err.recognition_failure() == Some(RecognitionFailure::NotRecognized) => {
38 eprintln!("not recognized as AutoIt");
39 ExitCode::FAILURE
40 }
41 Err(err) => {
42 eprintln!("failed to parse AutoIt payload: {err}");
43 ExitCode::FAILURE
44 }
45 }
46}Sourcepub const fn input_kind(&self) -> InputKind
pub const fn input_kind(&self) -> InputKind
Returns the recognized input container kind.
§Returns
The InputKind determined during analysis (InputKind::Pe,
InputKind::A3x, or InputKind::RawStream).
Examples found in repository?
59fn print_overview(binary: &AutoItBinary) {
60 section("overview");
61 field("input kind", format!("{:?}", binary.input_kind()));
62 field("encoding", opt_debug(binary.encoding()));
63 field("records", binary.records().len().to_string());
64 field("scripts", binary.scripts().len().to_string());
65 field("artifacts", binary.artifacts().len().to_string());
66 field("strings", binary.strings().len().to_string());
67 field(
68 "record diagnostics",
69 binary.record_diagnostics().len().to_string(),
70 );
71}Sourcepub const fn encoding(&self) -> Option<Encoding>
pub const fn encoding(&self) -> Option<Encoding>
Returns the recognized AutoIt payload encoding, if known.
§Returns
Some with the recognized Encoding, or None when no encoding could be
determined from the container.
Examples found in repository?
59fn print_overview(binary: &AutoItBinary) {
60 section("overview");
61 field("input kind", format!("{:?}", binary.input_kind()));
62 field("encoding", opt_debug(binary.encoding()));
63 field("records", binary.records().len().to_string());
64 field("scripts", binary.scripts().len().to_string());
65 field("artifacts", binary.artifacts().len().to_string());
66 field("strings", binary.strings().len().to_string());
67 field(
68 "record diagnostics",
69 binary.record_diagnostics().len().to_string(),
70 );
71}Sourcepub const fn container(&self) -> &ContainerInfo
pub const fn container(&self) -> &ContainerInfo
Returns summarized container-level facts.
§Returns
A reference to the ContainerInfo built from the recorded observations.
Examples found in repository?
73fn print_container(binary: &AutoItBinary) {
74 let container = binary.container();
75 section("container");
76 field("input kind", format!("{:?}", container.input_kind()));
77 field("encoding", opt_debug(container.encoding()));
78 field(
79 "autoit signature offset",
80 container
81 .autoit_signature_offset()
82 .map_or_else(|| "none".to_string(), |offset| format!("{offset}")),
83 );
84 field(
85 "version marker",
86 container.version_marker().map_or_else(
87 || "none".to_string(),
88 |marker| format!("{:?} @ offset {}", marker.encoding, marker.offset),
89 ),
90 );
91 field(
92 "payload stream offsets",
93 if container.payload_stream_offsets().is_empty() {
94 "none".to_string()
95 } else {
96 format!("{:?}", container.payload_stream_offsets())
97 },
98 );
99
100 match container.pe_script_resource() {
101 None => field("pe script resource", "none".to_string()),
102 Some(resource) => {
103 println!(" pe script resource:");
104 subfield(
105 "type",
106 match resource.type_name {
107 Some(name) => format!("{} ({name})", resource.type_id),
108 None => resource.type_id.to_string(),
109 },
110 );
111 subfield("name", escape_inline(resource.name));
112 subfield(
113 "language id",
114 resource
115 .language_id
116 .map_or_else(|| "none".to_string(), |id| id.to_string()),
117 );
118 subfield("rva", format!("{:#x}", resource.rva));
119 subfield("file offset", resource.offset.to_string());
120 subfield("size", format!("{} bytes", resource.size));
121 }
122 }
123
124 if container.packed_markers().is_empty() {
125 field("packed markers", "none".to_string());
126 } else {
127 println!(" packed markers:");
128 for marker in container.packed_markers() {
129 println!(" {} @ offset {}", marker.name, marker.offset);
130 }
131 }
132}Sourcepub const fn observations(&self) -> &ObservationLog
pub const fn observations(&self) -> &ObservationLog
Returns the analysis observations.
§Returns
A reference to the ObservationLog holding the concrete observations
recorded during analysis.
Sourcepub fn records(&self) -> &[Record]
pub fn records(&self) -> &[Record]
Returns parsed AU3 records.
Records recovered before any later malformed record remain present here;
the failure is reported separately via Self::record_diagnostics.
§Returns
A slice of the parsed Record values, empty when no record stream was
located.
Examples found in repository?
48fn print_text(binary: &AutoItBinary) {
49 print_overview(binary);
50 print_container(binary);
51 print_observations(binary);
52 print_records(binary.records());
53 print_record_diagnostics(binary);
54 print_scripts(binary.scripts());
55 print_artifacts(binary.artifacts());
56 print_strings(binary.strings());
57}
58
59fn print_overview(binary: &AutoItBinary) {
60 section("overview");
61 field("input kind", format!("{:?}", binary.input_kind()));
62 field("encoding", opt_debug(binary.encoding()));
63 field("records", binary.records().len().to_string());
64 field("scripts", binary.scripts().len().to_string());
65 field("artifacts", binary.artifacts().len().to_string());
66 field("strings", binary.strings().len().to_string());
67 field(
68 "record diagnostics",
69 binary.record_diagnostics().len().to_string(),
70 );
71}Sourcepub fn record_diagnostics(&self) -> &[RecordParseDiagnostic]
pub fn record_diagnostics(&self) -> &[RecordParseDiagnostic]
Returns diagnostics from tolerant AU3 record parsing.
§Returns
A slice of RecordParseDiagnostic entries describing records that failed
to parse; empty when every record parsed cleanly.
Examples found in repository?
59fn print_overview(binary: &AutoItBinary) {
60 section("overview");
61 field("input kind", format!("{:?}", binary.input_kind()));
62 field("encoding", opt_debug(binary.encoding()));
63 field("records", binary.records().len().to_string());
64 field("scripts", binary.scripts().len().to_string());
65 field("artifacts", binary.artifacts().len().to_string());
66 field("strings", binary.strings().len().to_string());
67 field(
68 "record diagnostics",
69 binary.record_diagnostics().len().to_string(),
70 );
71}
72
73fn print_container(binary: &AutoItBinary) {
74 let container = binary.container();
75 section("container");
76 field("input kind", format!("{:?}", container.input_kind()));
77 field("encoding", opt_debug(container.encoding()));
78 field(
79 "autoit signature offset",
80 container
81 .autoit_signature_offset()
82 .map_or_else(|| "none".to_string(), |offset| format!("{offset}")),
83 );
84 field(
85 "version marker",
86 container.version_marker().map_or_else(
87 || "none".to_string(),
88 |marker| format!("{:?} @ offset {}", marker.encoding, marker.offset),
89 ),
90 );
91 field(
92 "payload stream offsets",
93 if container.payload_stream_offsets().is_empty() {
94 "none".to_string()
95 } else {
96 format!("{:?}", container.payload_stream_offsets())
97 },
98 );
99
100 match container.pe_script_resource() {
101 None => field("pe script resource", "none".to_string()),
102 Some(resource) => {
103 println!(" pe script resource:");
104 subfield(
105 "type",
106 match resource.type_name {
107 Some(name) => format!("{} ({name})", resource.type_id),
108 None => resource.type_id.to_string(),
109 },
110 );
111 subfield("name", escape_inline(resource.name));
112 subfield(
113 "language id",
114 resource
115 .language_id
116 .map_or_else(|| "none".to_string(), |id| id.to_string()),
117 );
118 subfield("rva", format!("{:#x}", resource.rva));
119 subfield("file offset", resource.offset.to_string());
120 subfield("size", format!("{} bytes", resource.size));
121 }
122 }
123
124 if container.packed_markers().is_empty() {
125 field("packed markers", "none".to_string());
126 } else {
127 println!(" packed markers:");
128 for marker in container.packed_markers() {
129 println!(" {} @ offset {}", marker.name, marker.offset);
130 }
131 }
132}
133
134fn print_observations(binary: &AutoItBinary) {
135 let observations = binary.observations().entries();
136 section(&format!("observations ({})", observations.len()));
137 for observation in observations {
138 println!(" {observation:?}");
139 }
140}
141
142fn print_records(records: &[Record]) {
143 section(&format!("records ({})", records.len()));
144 for record in records {
145 println!(" #{} @ offset {}", record.index(), record.offset());
146 subfield("subtype", escape_inline(record.subtype()));
147 subfield("name", escape_inline(record.name()));
148 let profile = record.profile();
149 subfield(
150 "profile",
151 format!(
152 "encoding={:?} encryption={:?} compression={:?}",
153 profile.encoding, profile.encryption, profile.compression
154 ),
155 );
156 subfield(
157 "compressed",
158 format!(
159 "{} (compressed_size={}, uncompressed_size={})",
160 record.compressed(),
161 record.compressed_size(),
162 record.uncompressed_size()
163 ),
164 );
165 subfield(
166 "checksum",
167 format!(
168 "{:#010x} ({})",
169 record.checksum(),
170 if record.checksum_valid() {
171 "valid"
172 } else {
173 "invalid"
174 }
175 ),
176 );
177 subfield(
178 "timestamps",
179 format!(
180 "created={} last_write={}",
181 record.creation_time(),
182 record.last_write_time()
183 ),
184 );
185 subfield(
186 "data sizes",
187 format!(
188 "encrypted={} decrypted={} decompressed={} payload={}",
189 record.encrypted_data().len(),
190 record.decrypted_data().len(),
191 record
192 .decompressed_data()
193 .map_or_else(|| "none".to_string(), |data| data.len().to_string()),
194 record.payload_data().len()
195 ),
196 );
197 subfield(
198 "decompression",
199 format!("{:?}", record.decompression_status()),
200 );
201 }
202}
203
204fn print_record_diagnostics(binary: &AutoItBinary) {
205 let diagnostics = binary.record_diagnostics();
206 if diagnostics.is_empty() {
207 return;
208 }
209 section(&format!("record diagnostics ({})", diagnostics.len()));
210 for diagnostic in diagnostics {
211 println!(
212 " record #{} @ offset {}: {:?}",
213 diagnostic.record_index, diagnostic.offset, diagnostic.reason
214 );
215 }
216}Sourcepub fn scripts(&self) -> &[Script]
pub fn scripts(&self) -> &[Script]
Returns recovered script records.
§Returns
A slice of recovered Script views; empty when no script records were
found.
Examples found in repository?
48fn print_text(binary: &AutoItBinary) {
49 print_overview(binary);
50 print_container(binary);
51 print_observations(binary);
52 print_records(binary.records());
53 print_record_diagnostics(binary);
54 print_scripts(binary.scripts());
55 print_artifacts(binary.artifacts());
56 print_strings(binary.strings());
57}
58
59fn print_overview(binary: &AutoItBinary) {
60 section("overview");
61 field("input kind", format!("{:?}", binary.input_kind()));
62 field("encoding", opt_debug(binary.encoding()));
63 field("records", binary.records().len().to_string());
64 field("scripts", binary.scripts().len().to_string());
65 field("artifacts", binary.artifacts().len().to_string());
66 field("strings", binary.strings().len().to_string());
67 field(
68 "record diagnostics",
69 binary.record_diagnostics().len().to_string(),
70 );
71}Sourcepub fn artifacts(&self) -> &[Artifact]
pub fn artifacts(&self) -> &[Artifact]
Returns recovered non-script artifact records.
§Returns
A slice of Artifact views for every record that was not recovered as a
Script; empty when there are none.
Examples found in repository?
48fn print_text(binary: &AutoItBinary) {
49 print_overview(binary);
50 print_container(binary);
51 print_observations(binary);
52 print_records(binary.records());
53 print_record_diagnostics(binary);
54 print_scripts(binary.scripts());
55 print_artifacts(binary.artifacts());
56 print_strings(binary.strings());
57}
58
59fn print_overview(binary: &AutoItBinary) {
60 section("overview");
61 field("input kind", format!("{:?}", binary.input_kind()));
62 field("encoding", opt_debug(binary.encoding()));
63 field("records", binary.records().len().to_string());
64 field("scripts", binary.scripts().len().to_string());
65 field("artifacts", binary.artifacts().len().to_string());
66 field("strings", binary.strings().len().to_string());
67 field(
68 "record diagnostics",
69 binary.record_diagnostics().len().to_string(),
70 );
71}Sourcepub fn strings(&self) -> &[StringFinding]
pub fn strings(&self) -> &[StringFinding]
Returns raw strings found in recovered record payload bytes.
§Returns
A slice of StringFinding values extracted from record payloads; empty
when none were found.
Examples found in repository?
48fn print_text(binary: &AutoItBinary) {
49 print_overview(binary);
50 print_container(binary);
51 print_observations(binary);
52 print_records(binary.records());
53 print_record_diagnostics(binary);
54 print_scripts(binary.scripts());
55 print_artifacts(binary.artifacts());
56 print_strings(binary.strings());
57}
58
59fn print_overview(binary: &AutoItBinary) {
60 section("overview");
61 field("input kind", format!("{:?}", binary.input_kind()));
62 field("encoding", opt_debug(binary.encoding()));
63 field("records", binary.records().len().to_string());
64 field("scripts", binary.scripts().len().to_string());
65 field("artifacts", binary.artifacts().len().to_string());
66 field("strings", binary.strings().len().to_string());
67 field(
68 "record diagnostics",
69 binary.record_diagnostics().len().to_string(),
70 );
71}Trait Implementations§
Source§impl Clone for AutoItBinary
impl Clone for AutoItBinary
Source§fn clone(&self) -> AutoItBinary
fn clone(&self) -> AutoItBinary
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more