threatflux_binary_analysis/formats/
wasm.rs1use crate::{
4 types::{
5 Architecture, BinaryFormat as Format, BinaryMetadata, Endianness, Export, Import, Section,
6 SectionPermissions, SectionType, SecurityFeatures, Symbol,
7 },
8 BinaryFormatParser, BinaryFormatTrait, Result,
9};
10
11use wasmparser::{Parser, Payload};
12
13pub struct WasmParser;
15
16impl BinaryFormatParser for WasmParser {
17 fn parse(data: &[u8]) -> Result<Box<dyn BinaryFormatTrait>> {
18 Ok(Box::new(WasmBinary::parse(data)?))
19 }
20
21 fn can_parse(data: &[u8]) -> bool {
22 data.len() >= 4 && &data[0..4] == b"\0asm"
23 }
24}
25
26pub struct WasmBinary {
28 #[allow(dead_code)]
29 data: Vec<u8>,
30 metadata: BinaryMetadata,
31 sections: Vec<Section>,
32 imports: Vec<Import>,
33 exports: Vec<Export>,
34}
35
36impl WasmBinary {
37 fn parse(data: &[u8]) -> Result<Self> {
38 let parser = Parser::new(0);
39 let mut sections = Vec::new();
40 let mut imports = Vec::new();
41 let mut exports = Vec::new();
42 let mut start_fn: Option<u64> = None;
43
44 for payload in parser.parse_all(data) {
45 let payload = payload?;
46 match payload {
47 Payload::Version { .. } => {}
48 Payload::StartSection { func, .. } => {
49 start_fn = Some(func as u64);
50 }
51 Payload::ImportSection(s) => {
52 let range = s.range();
53 for import in s {
54 let import = import?;
55 imports.push(Import {
56 name: import.name.to_string(),
57 library: Some(import.module.to_string()),
58 address: None,
59 ordinal: None,
60 });
61 }
62 sections.push(Section {
63 name: "import".to_string(),
64 address: 0,
65 size: (range.end - range.start) as u64,
66 offset: range.start as u64,
67 permissions: SectionPermissions {
68 read: true,
69 write: false,
70 execute: false,
71 },
72 section_type: SectionType::Other("Import".to_string()),
73 data: None,
74 });
75 }
76 Payload::ExportSection(s) => {
77 let range = s.range();
78 for export in s {
79 let export = export?;
80 exports.push(Export {
81 name: export.name.to_string(),
82 address: 0,
83 ordinal: None,
84 forwarded_name: None,
85 });
86 }
87 sections.push(Section {
88 name: "export".to_string(),
89 address: 0,
90 size: (range.end - range.start) as u64,
91 offset: range.start as u64,
92 permissions: SectionPermissions {
93 read: true,
94 write: false,
95 execute: false,
96 },
97 section_type: SectionType::Other("Export".to_string()),
98 data: None,
99 });
100 }
101 Payload::CodeSectionStart { range, .. } => {
102 sections.push(Section {
103 name: "code".to_string(),
104 address: 0,
105 size: (range.end - range.start) as u64,
106 offset: range.start as u64,
107 permissions: SectionPermissions {
108 read: true,
109 write: false,
110 execute: true,
111 },
112 section_type: SectionType::Code,
113 data: None,
114 });
115 }
116 Payload::DataSection(s) => {
117 let range = s.range();
118 for _ in s {} sections.push(Section {
121 name: "data".to_string(),
122 address: 0,
123 size: (range.end - range.start) as u64,
124 offset: range.start as u64,
125 permissions: SectionPermissions {
126 read: true,
127 write: true,
128 execute: false,
129 },
130 section_type: SectionType::Data,
131 data: None,
132 });
133 }
134 Payload::CustomSection(section) => {
135 let name = section.name().to_string();
136 sections.push(Section {
137 name: name.clone(),
138 address: 0,
139 size: section.data().len() as u64,
140 offset: section.data_offset() as u64,
141 permissions: SectionPermissions {
142 read: true,
143 write: false,
144 execute: false,
145 },
146 section_type: SectionType::Other(name),
147 data: None,
148 });
149 }
150 _ => {}
151 }
152 }
153
154 let metadata = BinaryMetadata {
155 size: data.len(),
156 format: Format::Wasm,
157 architecture: Architecture::Wasm,
158 entry_point: start_fn,
159 base_address: None,
160 timestamp: None,
161 compiler_info: None,
162 endian: Endianness::Little,
163 security_features: SecurityFeatures::default(),
164 };
165
166 Ok(Self {
167 data: data.to_vec(),
168 metadata,
169 sections,
170 imports,
171 exports,
172 })
173 }
174}
175
176impl BinaryFormatTrait for WasmBinary {
177 fn format_type(&self) -> Format {
178 Format::Wasm
179 }
180
181 fn architecture(&self) -> Architecture {
182 Architecture::Wasm
183 }
184
185 fn entry_point(&self) -> Option<u64> {
186 self.metadata.entry_point
187 }
188
189 fn sections(&self) -> &[Section] {
190 &self.sections
191 }
192
193 fn symbols(&self) -> &[Symbol] {
194 &[]
195 }
196
197 fn imports(&self) -> &[Import] {
198 &self.imports
199 }
200
201 fn exports(&self) -> &[Export] {
202 &self.exports
203 }
204
205 fn metadata(&self) -> &BinaryMetadata {
206 &self.metadata
207 }
208}