LCOV - code coverage report
Current view: top level - src/pe - resources.rs (source / functions) Coverage Total Hit
Test: lief.lcov Lines: 45.5 % 268 122
Test Date: 2025-02-23:00:00:00 Functions: 40.0 % 65 26

            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 : );
        

Generated by: LCOV version 2.1-1