Skip to main content

frida_rs/
module.rs

1//!Frida functions for module-level functionality.
2//!
3//!The functions in this module correspond to the JavaScript functions
4//!grouped under
5//![https://frida.re/docs/javascript-api/#module](https://frida.re/docs/javascript-api/#module).
6
7use crate::nativepointer::NativePointer;
8use crate::plumbing;
9use crate::range::RangeDetails;
10use wasm_bindgen::{JsCast, JsValue};
11
12///Get the base address of the module named `name`.
13///
14///This is the equivalent to calling `Module.findBaseAddress()` /
15///`Module.getBaseAddress()` in the JavaScript API.
16pub fn get_base_address(name: &str) -> Option<NativePointer> {
17    let ret = plumbing::module::get_base_address(name);
18
19    if ret.is_null() {
20        return None;
21    }
22
23    Some(ret)
24}
25
26///Get the absolute address of the export named `export_name`.
27///
28///This is the equivalent to calling `Module.findExportByName()` /
29///`Module.getExportByName()` in the JavaScript API.
30pub fn get_export(export_name: &str) -> Option<NativePointer> {
31    let ret = plumbing::module::get_export(JsValue::NULL, export_name);
32
33    if ret.is_null() {
34        return None;
35    }
36
37    Some(ret)
38}
39
40//// // TODO: This is not actually finding any exports and appears to be a Frida
41//// // bug. Revisit in the future...
42//// pub fn get_export_in_module(module_name: &str, export_name: &str) -> Option<NativePointer> {
43////     let ret = _get_export(JsValue::from_str(module_name), export_name);
44
45////     if ret.is_null() {
46////         return None;
47////     }
48
49////     let p: NativePointer = ret.into_serde().unwrap();
50////     Some(p)
51//// }
52
53pub struct Module {
54    ///Canonical module name.
55    pub name: String,
56
57    ///Base address of module.
58    pub base: NativePointer,
59
60    ///Size of module in bytes.
61    pub size: usize,
62
63    ///Full filesystem path of module.
64    pub path: String,
65
66    _ref: plumbing::module::Module,
67}
68
69impl From<plumbing::module::Module> for Module {
70    fn from(m: plumbing::module::Module) -> Self {
71        Module {
72            name: m.name(),
73            base: m.base(),
74            size: m.size(),
75            path: m.path(),
76            _ref: m,
77        }
78    }
79}
80
81impl Module {
82    ///Get all exports of the module.
83    ///
84    ///This is the equivalent to calling `enumerateExports()` in the
85    ///JavaScript API.
86    pub fn enumerate_exports(&self) -> Vec<ExportDetails> {
87        let mut export_details = Vec::new();
88
89        let m: plumbing::module::Module = self._ref.clone().unchecked_into();
90        let exports = m.enumerate_exports();
91
92        for export in exports.iter() {
93            let i = ExportDetails::from(plumbing::module::ExportDetails::from(export));
94            export_details.push(i);
95        }
96
97        export_details
98    }
99
100    ///Get all imports of the module.
101    ///
102    ///This is the equivalent to calling `enumerateImports()` in the
103    ///JavaScript API.
104    pub fn enumerate_imports(&self) -> Vec<ImportDetails> {
105        let mut import_details = Vec::new();
106
107        let m: plumbing::module::Module = self._ref.clone().unchecked_into();
108        let imports = m.enumerate_imports();
109
110        for import in imports.iter() {
111            let i = ImportDetails::from(plumbing::module::ImportDetails::from(import));
112            import_details.push(i);
113        }
114
115        import_details
116    }
117
118    ///Get all symbols of the module.
119    ///
120    ///This is the equivalent to calling `enumerateSymbols()` in the
121    ///JavaScript API.
122    pub fn enumerate_symbols(&self) -> Vec<SymbolDetails> {
123        let mut symbol_details = Vec::new();
124
125        let m: plumbing::module::Module = self._ref.clone().unchecked_into();
126        let symbols = m.enumerate_symbols();
127
128        for symbol in symbols.iter() {
129            let i = SymbolDetails::from(plumbing::module::SymbolDetails::from(symbol));
130            symbol_details.push(i);
131        }
132
133        symbol_details
134    }
135
136    ///Get all memory ranges satisfying `protection`.
137    ///
138    ///`protection` is a string with the form "rwx" where "rw-" means "must be
139    ///at least readable and writable."
140    ///
141    ///This is the equivalent to calling `enumerateRanges()` in the
142    ///JavaScript API.
143    pub fn enumerate_ranges(&self, protection: &str) -> Vec<RangeDetails> {
144        let mut range_details = Vec::new();
145
146        let m: plumbing::module::Module = self._ref.clone().unchecked_into();
147        let ranges = m.enumerate_ranges(protection);
148
149        for range in ranges.iter() {
150            let i = RangeDetails::from(plumbing::range::RangeDetails::from(range));
151            range_details.push(i);
152        }
153
154        range_details
155    }
156
157    //    // // TODO: This is not actually finding any exports and appears to be a Frida
158    //    // // bug. Revisit in the future...
159    //    // pub fn get_export(&self, name: &str) -> Option<NativePointer> {
160    //    //     let m: M = self._ref.clone().unchecked_into();
161    //    //     m._get_export(name)
162    //    // }
163}
164
165pub struct ExportDetails {
166    pub export_type: String, // TODO: This should be a Enum type
167    pub name: String,
168    pub address: NativePointer,
169}
170
171impl From<plumbing::module::ExportDetails> for ExportDetails {
172    fn from(m: plumbing::module::ExportDetails) -> Self {
173        ExportDetails {
174            export_type: m.export_type(),
175            name: m.name(),
176            address: m.address(),
177        }
178    }
179}
180
181pub struct ImportDetails {
182    pub import_type: Option<String>, // TODO: This should be a Enum type
183    pub name: String,
184    pub module: Option<String>,
185    pub address: Option<NativePointer>,
186    pub slot: Option<NativePointer>,
187}
188
189impl From<plumbing::module::ImportDetails> for ImportDetails {
190    fn from(m: plumbing::module::ImportDetails) -> Self {
191        ImportDetails {
192            import_type: m.import_type(),
193            name: m.name(),
194            module: m.module(),
195            address: m.address(),
196            slot: m.slot(),
197        }
198    }
199}
200
201pub struct SymbolDetails {
202    pub is_global: bool,
203    pub symbol_type: String, // TODO: This should be a Enum type
204    pub section: Option<SymbolSectionDetails>,
205    pub name: String,
206    pub address: NativePointer,
207    pub size: Option<usize>,
208}
209
210impl From<plumbing::module::SymbolDetails> for SymbolDetails {
211    fn from(m: plumbing::module::SymbolDetails) -> Self {
212        SymbolDetails {
213            is_global: m.is_global(),
214            symbol_type: m.symbol_type(),
215            section: m.section().map(|s| SymbolSectionDetails::from(s)),
216            name: m.name(),
217            address: m.address(),
218            size: m.size(),
219        }
220    }
221}
222
223pub struct SymbolSectionDetails {
224    pub id: String,
225    pub protection: String,
226}
227
228impl From<plumbing::module::SymbolSectionDetails> for SymbolSectionDetails {
229    fn from(m: plumbing::module::SymbolSectionDetails) -> Self {
230        SymbolSectionDetails {
231            id: m.id(),
232            protection: m.protection(),
233        }
234    }
235}