Line data Source code
1 : //! This module contains the different structures involved in the PE's resource tree
2 : //!
3 : //! One can access this tree using either: [`crate::pe::Binary::resources`] or by parsing raw bytes
4 : //! with [`Node::from_slice`]. The [`Manager`] provides a logical API over the resource tree
5 : //! to access specifics parts of the tree.
6 :
7 : use lief_ffi as ffi;
8 :
9 : use std::pin::Pin;
10 : use std::{fmt, marker::PhantomData};
11 :
12 : use crate::to_slice;
13 : use crate::{common::FromFFI, declare_iterator};
14 : use crate::common::into_optional;
15 :
16 : /// This enum represents a node in the resource tree which can be either: a **directory** node
17 : /// or a data (leaf) node.
18 460 : #[derive(Debug)]
19 : pub enum Node<'a> {
20 : /// A *data* node (i.e. a leaf)
21 : Data(Data<'a>),
22 : /// A directory node
23 : Directory(Directory<'a>),
24 : }
25 :
26 : impl Node<'_> {
27 : /// Parse a resource tree from the provided slice. The original RVA must be provided
28 : /// to resolve the content of the data nodes.
29 100 : pub fn from_slice(content: &[u8], rva: u64) -> Option<Node> {
30 100 : unsafe {
31 100 : let ptr = ffi::PE_ResourceNode::from_slice(content.as_ptr(), content.len(), rva);
32 100 : if ptr.is_null() {
33 0 : return None
34 100 : }
35 100 : Some(Node::from_ffi(ptr))
36 : }
37 100 : }
38 : }
39 :
40 : /// Trait that is shared by both [`Node::Data`] and [`Node::Directory`].
41 : pub trait NodeBase {
42 : #[doc(hidden)]
43 : fn get_base(&self) -> &ffi::PE_ResourceNode;
44 :
45 : #[doc(hidden)]
46 : fn base_as_pin_mut(&mut self) -> Pin<&mut ffi::PE_ResourceNode>;
47 :
48 : /// Integer that identifies the Type, Name, or Language ID of the entry
49 : /// depending on its [`NodeBase::depth`] in the tree
50 2020 : fn id(&self) -> u32 {
51 2020 : self.get_base().id()
52 2020 : }
53 :
54 : /// Current depth of the Node in the resource tree
55 360 : fn depth(&self) -> u32 {
56 360 : self.get_base().depth()
57 360 : }
58 :
59 : /// Iterator on node's children
60 2060 : fn children(&self) -> Children {
61 2060 : Children::new(self.get_base().childs())
62 2060 : }
63 :
64 : /// Name of the node (if any)
65 0 : fn name(&self) -> Option<String> {
66 0 : if !self.get_base().has_name() {
67 0 : return None;
68 0 : }
69 0 : Some(self.get_base().name().to_string())
70 0 : }
71 :
72 : /// Add a new child node to the current and return the newly-added node
73 0 : fn add_child(&mut self, node: &Node) -> Node {
74 0 : Node::from_ffi(self.base_as_pin_mut().add_child(node.get_base()))
75 0 : }
76 :
77 : /// Delete the child node with the given id
78 0 : fn delete_child(&mut self, id: u32) {
79 0 : self.base_as_pin_mut().delete_child(id);
80 0 : }
81 : }
82 :
83 : impl std::fmt::Debug for &dyn NodeBase {
84 2020 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
85 2020 : f.debug_struct("NodeBase").field("id", &self.id()).finish()
86 2020 : }
87 : }
88 :
89 :
90 : impl std::fmt::Display for &dyn NodeBase {
91 0 : fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
92 0 : write!(f, "{}", self.get_base().print())
93 0 : }
94 : }
95 :
96 : impl<'a> FromFFI<ffi::PE_ResourceNode> for Node<'a> {
97 4080 : fn from_ffi(ffi_entry: cxx::UniquePtr<ffi::PE_ResourceNode>) -> Self {
98 4080 : unsafe {
99 4080 : let cmd_ref = ffi_entry.as_ref().unwrap();
100 4080 :
101 4080 : if ffi::PE_ResourceDirectory::classof(cmd_ref) {
102 2520 : let raw = {
103 2520 : type From = cxx::UniquePtr<ffi::PE_ResourceNode>;
104 2520 : type To = cxx::UniquePtr<ffi::PE_ResourceDirectory>;
105 2520 : std::mem::transmute::<From, To>(ffi_entry)
106 2520 : };
107 2520 : Node::Directory(Directory::from_ffi(raw))
108 : } else {
109 1560 : assert!(
110 1560 : ffi::PE_ResourceData::classof(cmd_ref),
111 0 : "Must be a ResourceData node"
112 : );
113 :
114 1560 : let raw = {
115 1560 : type From = cxx::UniquePtr<ffi::PE_ResourceNode>;
116 1560 : type To = cxx::UniquePtr<ffi::PE_ResourceData>;
117 1560 : std::mem::transmute::<From, To>(ffi_entry)
118 1560 : };
119 1560 : Node::Data(Data::from_ffi(raw))
120 : }
121 : }
122 4080 : }
123 : }
124 :
125 : pub struct Data<'a> {
126 : ptr: cxx::UniquePtr<ffi::PE_ResourceData>,
127 : _owner: PhantomData<&'a Node<'a>>,
128 : }
129 :
130 : impl Data<'_> {
131 : /// Create a new Data node with the provided payload
132 0 : pub fn with_buffer(buffer: &[u8]) -> Data<'static> {
133 0 : unsafe {
134 0 : Data::from_ffi(ffi::PE_ResourceData::create_from_data(buffer.as_ptr(), buffer.len()))
135 0 : }
136 0 : }
137 :
138 : /// Create a new Data node
139 0 : pub fn new() -> Data<'static> {
140 0 : Data::from_ffi(ffi::PE_ResourceData::create())
141 0 : }
142 :
143 : /// Return the code page that is used to decode code point
144 : /// values within the resource data. Typically, the code page is the unicode code page.
145 1560 : pub fn code_page(&self) -> u32 {
146 1560 : self.ptr.code_page()
147 1560 : }
148 :
149 : /// Reserved value. Should be `0`
150 1560 : pub fn reserved(&self) -> u32 {
151 1560 : self.ptr.reserved()
152 1560 : }
153 :
154 : /// Offset of the content within the resource
155 : ///
156 : /// <div class="warning">this value may change when rebuilding resource table</div>
157 1560 : pub fn offset(&self) -> u32 {
158 1560 : self.ptr.offset()
159 1560 : }
160 :
161 : /// Resource content
162 1560 : pub fn content(&self) -> &[u8] {
163 1560 : to_slice!(self.ptr.content());
164 1560 : }
165 :
166 : /// Change or set the raw data associated with this node
167 0 : pub fn set_content(&mut self, content: &[u8]) -> &mut Self {
168 0 : unsafe {
169 0 : self.ptr.pin_mut().set_content(content.as_ptr(), content.len());
170 0 : }
171 0 : self
172 0 : }
173 :
174 : /// Change or set the code page
175 0 : pub fn set_code_page(&mut self, code_page: u32) -> &mut Self {
176 0 : self.ptr.pin_mut().set_code_page(code_page);
177 0 : self
178 0 : }
179 :
180 : /// Change or set the *reserved* field
181 0 : pub fn set_reserved(&mut self, reserved: u32) -> &mut Self {
182 0 : self.ptr.pin_mut().set_reserved(reserved);
183 0 : self
184 0 : }
185 : }
186 :
187 : impl NodeBase for Data<'_> {
188 1560 : fn get_base(&self) -> &ffi::PE_ResourceNode {
189 1560 : self.ptr.as_ref().unwrap().as_ref()
190 1560 : }
191 :
192 0 : fn base_as_pin_mut(&mut self) -> Pin<&mut ffi::PE_ResourceNode> {
193 0 : unsafe {
194 0 : Pin::new_unchecked({
195 0 : (self.ptr.as_ref().unwrap().as_ref()
196 0 : as *const ffi::PE_ResourceNode
197 0 : as *mut ffi::PE_ResourceNode).as_mut().unwrap()
198 0 : })
199 0 : }
200 0 : }
201 : }
202 :
203 : impl fmt::Debug for Data<'_> {
204 1560 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
205 1560 : let base = self as &dyn NodeBase;
206 1560 : f.debug_struct("Data")
207 1560 : .field("base", &base)
208 1560 : .field("code_page", &self.code_page())
209 1560 : .field("reserved", &self.reserved())
210 1560 : .field("offset", &self.offset())
211 1560 : .finish()
212 1560 : }
213 : }
214 :
215 : impl<'a> FromFFI<ffi::PE_ResourceData> for Data<'a> {
216 1560 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_ResourceData>) -> Self {
217 1560 : Self {
218 1560 : ptr,
219 1560 : _owner: PhantomData,
220 1560 : }
221 1560 : }
222 : }
223 :
224 : pub struct Directory<'a> {
225 : ptr: cxx::UniquePtr<ffi::PE_ResourceDirectory>,
226 : _owner: PhantomData<&'a Node<'a>>,
227 : }
228 :
229 : impl Directory<'_> {
230 : /// Create a new Directory node with the given d
231 0 : pub fn with_id(id: u32) -> Directory<'static> {
232 0 : Directory::from_ffi(ffi::PE_ResourceDirectory::create_from_id(id))
233 0 : }
234 :
235 : /// Create a new Directory node
236 0 : pub fn new() -> Directory<'static> {
237 0 : Directory::from_ffi(ffi::PE_ResourceDirectory::create())
238 0 : }
239 :
240 : /// Resource characteristics. This field is reserved for future use.
241 : /// It is currently set to zero.
242 460 : pub fn characteristics(&self) -> u32 {
243 460 : self.ptr.characteristics()
244 460 : }
245 :
246 : /// The time that the resource data was created by the
247 : /// resource compiler.
248 460 : pub fn time_date_stamp(&self) -> u32 {
249 460 : self.ptr.time_date_stamp()
250 460 : }
251 :
252 : /// The major version number, set by the user.
253 460 : pub fn major_version(&self) -> u32 {
254 460 : self.ptr.major_version()
255 460 : }
256 :
257 : /// The minor version number, set by the user.
258 460 : pub fn minor_version(&self) -> u32 {
259 460 : self.ptr.minor_version()
260 460 : }
261 :
262 : /// The number of directory entries immediately
263 : /// following the table that use strings to identify Type,
264 : /// Name, or Language entries (depending on the level of the table).
265 460 : pub fn numberof_name_entries(&self) -> u32 {
266 460 : self.ptr.numberof_name_entries()
267 460 : }
268 :
269 :
270 : /// The number of directory entries immediately
271 : /// following the Name entries that use numeric IDs for
272 : /// Type, Name, or Language entries.
273 460 : pub fn numberof_id_entries(&self) -> u32 {
274 460 : self.ptr.numberof_id_entries()
275 460 : }
276 : }
277 :
278 : impl NodeBase for Directory<'_> {
279 2880 : fn get_base(&self) -> &ffi::PE_ResourceNode {
280 2880 : self.ptr.as_ref().unwrap().as_ref()
281 2880 : }
282 :
283 0 : fn base_as_pin_mut(&mut self) -> Pin<&mut ffi::PE_ResourceNode> {
284 0 : unsafe {
285 0 : Pin::new_unchecked({
286 0 : (self.ptr.as_ref().unwrap().as_ref()
287 0 : as *const ffi::PE_ResourceNode
288 0 : as *mut ffi::PE_ResourceNode).as_mut().unwrap()
289 0 : })
290 0 : }
291 0 : }
292 :
293 : }
294 :
295 : impl NodeBase for Node<'_> {
296 0 : fn get_base(&self) -> &ffi::PE_ResourceNode {
297 0 : match &self {
298 0 : Node::Data(n) => {
299 0 : n.get_base()
300 : }
301 0 : Node::Directory(n) => {
302 0 : n.get_base()
303 : }
304 : }
305 0 : }
306 :
307 0 : fn base_as_pin_mut(&mut self) -> Pin<&mut ffi::PE_ResourceNode> {
308 0 : match self {
309 0 : Node::Data(n) => {
310 0 : n.base_as_pin_mut()
311 : }
312 0 : Node::Directory(n) => {
313 0 : n.base_as_pin_mut()
314 : }
315 : }
316 0 : }
317 :
318 : }
319 :
320 : impl fmt::Debug for Directory<'_> {
321 460 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
322 460 : let base = self as &dyn NodeBase;
323 460 : f.debug_struct("Directory")
324 460 : .field("base", &base)
325 460 : .field("characteristics", &self.characteristics())
326 460 : .field("time_date_stamp", &self.time_date_stamp())
327 460 : .field("major_version", &self.major_version())
328 460 : .field("minor_version", &self.minor_version())
329 460 : .field("numberof_name_entries", &self.numberof_name_entries())
330 460 : .field("numberof_id_entries", &self.numberof_id_entries())
331 460 : .finish()
332 460 : }
333 : }
334 :
335 : impl<'a> FromFFI<ffi::PE_ResourceDirectory> for Directory<'a> {
336 2520 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_ResourceDirectory>) -> Self {
337 2520 : Self {
338 2520 : ptr,
339 2520 : _owner: PhantomData,
340 2520 : }
341 2520 : }
342 : }
343 :
344 : /// This manager abstracts the tree representation to provide a comprehensive API over
345 : /// the information wrapped by the resources tree.
346 : pub struct Manager<'a> {
347 : ptr: cxx::UniquePtr<ffi::PE_ResourcesManager>,
348 : _owner: PhantomData<&'a Node<'a>>,
349 : }
350 :
351 : impl<'a> FromFFI<ffi::PE_ResourcesManager> for Manager<'a> {
352 100 : fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_ResourcesManager>) -> Self {
353 100 : Self {
354 100 : ptr,
355 100 : _owner: PhantomData,
356 100 : }
357 100 : }
358 : }
359 :
360 : #[allow(non_camel_case_types)]
361 0 : #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
362 : pub enum Types {
363 : CURSOR,
364 : BITMAP,
365 : ICON,
366 : MENU,
367 : DIALOG,
368 : STRING,
369 : FONTDIR,
370 : FONT,
371 : ACCELERATOR,
372 : RCDATA,
373 : MESSAGETABLE,
374 : GROUP_CURSOR,
375 : GROUP_ICON,
376 : VERSION,
377 : DLGINCLUDE,
378 : PLUGPLAY,
379 : VXD,
380 : ANICURSOR,
381 : ANIICON,
382 : HTML,
383 : MANIFEST,
384 : UNKNOWN(u32),
385 : }
386 :
387 : impl From<u32> for Types {
388 0 : fn from(value: u32) -> Self {
389 0 : match value {
390 0 : 0x00000001 => Types::CURSOR,
391 0 : 0x00000002 => Types::BITMAP,
392 0 : 0x00000003 => Types::ICON,
393 0 : 0x00000004 => Types::MENU,
394 0 : 0x00000005 => Types::DIALOG,
395 0 : 0x00000006 => Types::STRING,
396 0 : 0x00000007 => Types::FONTDIR,
397 0 : 0x00000008 => Types::FONT,
398 0 : 0x00000009 => Types::ACCELERATOR,
399 0 : 0x0000000a => Types::RCDATA,
400 0 : 0x0000000b => Types::MESSAGETABLE,
401 0 : 0x0000000c => Types::GROUP_CURSOR,
402 0 : 0x0000000e => Types::GROUP_ICON,
403 0 : 0x00000010 => Types::VERSION,
404 0 : 0x00000011 => Types::DLGINCLUDE,
405 0 : 0x00000013 => Types::PLUGPLAY,
406 0 : 0x00000014 => Types::VXD,
407 0 : 0x00000015 => Types::ANICURSOR,
408 0 : 0x00000016 => Types::ANIICON,
409 0 : 0x00000017 => Types::HTML,
410 0 : 0x00000018 => Types::MANIFEST,
411 0 : _ => Types::UNKNOWN(value),
412 :
413 : }
414 0 : }
415 : }
416 : impl From<Types> for u32 {
417 0 : fn from(value: Types) -> u32 {
418 0 : match value {
419 0 : Types::CURSOR => 0x00000001,
420 0 : Types::BITMAP => 0x00000002,
421 0 : Types::ICON => 0x00000003,
422 0 : Types::MENU => 0x00000004,
423 0 : Types::DIALOG => 0x00000005,
424 0 : Types::STRING => 0x00000006,
425 0 : Types::FONTDIR => 0x00000007,
426 0 : Types::FONT => 0x00000008,
427 0 : Types::ACCELERATOR => 0x00000009,
428 0 : Types::RCDATA => 0x0000000a,
429 0 : Types::MESSAGETABLE => 0x0000000b,
430 0 : Types::GROUP_CURSOR => 0x0000000c,
431 0 : Types::GROUP_ICON => 0x0000000e,
432 0 : Types::VERSION => 0x00000010,
433 0 : Types::DLGINCLUDE => 0x00000011,
434 0 : Types::PLUGPLAY => 0x00000013,
435 0 : Types::VXD => 0x00000014,
436 0 : Types::ANICURSOR => 0x00000015,
437 0 : Types::ANIICON => 0x00000016,
438 0 : Types::HTML => 0x00000017,
439 0 : Types::MANIFEST => 0x00000018,
440 0 : Types::UNKNOWN(value) => value,
441 :
442 : }
443 0 : }
444 : }
445 :
446 : impl Manager<'_> {
447 : /// Return the manifest as a string. This manifest matches the node associated with
448 : /// the type: [`Types::MANIFEST`].
449 0 : pub fn manifest(&self) -> String {
450 0 : self.ptr.manifest().to_string()
451 0 : }
452 :
453 : /// Change or set the manifest. If the manifest node path does not exist,
454 : /// all required nodes are created.
455 0 : pub fn set_manifest(&mut self, content: &str) {
456 0 : self.ptr.pin_mut().set_manifest(content);
457 0 : }
458 :
459 : /// Try to find the node associated with the given [`Types`]
460 : ///
461 : /// This type corresponds to the [`Node::id`] at the **level 1** of the
462 : /// resource tree.
463 0 : pub fn find_by_type(&self, res_type: Types) -> Option<Node> {
464 0 : into_optional(self.ptr.find_node_type(res_type.into()))
465 0 : }
466 :
467 : /// Return the list of [`Types`] exposed by the resource tree.
468 0 : pub fn types(&self) -> Vec<Types> {
469 0 : self.ptr.get_types().iter().map(|v| Types::from(*v)).collect()
470 0 : }
471 :
472 : /// Print the current resources a tree in a pretty representation.
473 : ///
474 : /// ```text
475 : /// │ ├── Directory ID: 0016 (0x0010) type: VERSION
476 : /// │ │ └── Directory ID: 0001 (0x0001)
477 : /// │ │ └── Data ID: 1033 (0x0409) [...]
478 : /// │ │ ├── Hex: c0:03:34:00:00:00:[...]
479 : /// │ │ └── Str: ..4...V.S._.V.E.R.S.
480 : /// │ └── Directory ID: 0024 (0x0018) type: MANIFEST
481 : /// │ └── Directory ID: 0001 (0x0001)
482 : /// │ └── Data ID: 1033 (0x0409) [...]
483 : /// │ ├── Hex: 3c:3f:78:6d:6c:20:[...]
484 : /// │ └── Str: <?xml version="1.0"
485 : /// ```
486 0 : pub fn print_tree(&self) -> String {
487 0 : self.ptr.print_tree().to_string()
488 0 : }
489 :
490 : /// Same as [`Manager::print_tree`] but with a maximal depth provided in the
491 : /// first parameter.
492 0 : pub fn print_tree_with_depth(&self, depth: u32) -> String {
493 0 : self.ptr.print_tree_with_depth(depth).to_string()
494 0 : }
495 : }
496 :
497 3780 : declare_iterator!(
498 3780 : Children,
499 3780 : Node<'a>,
500 3780 : ffi::PE_ResourceNode,
501 3780 : ffi::PE_Binary,
502 3780 : ffi::PE_ResourceNode_it_childs
503 3780 : );
|