maple_rs/
lib.rs

1//! # maple-rs
2//!
3//! A Rust library for loading Windows PE executables and DLLs directly from memory,
4//! without needing to write them to disk first. This is a modern, safe Rust replacement
5//! for the C memorymodule library.
6//!
7//! ## ⚠️ Security Notice
8//!
9//! This library enables loading and executing code from memory buffers, which can be used
10//! for legitimate purposes such as:
11//! - Dynamic code loading in game engines
12//! - Plugin systems
13//! - Testing and debugging tools
14//! - Memory-efficient application packaging
15//!
16//! However, it could also be misused for malicious purposes. Users are responsible for
17//! ensuring they only load trusted code and comply with all applicable laws and
18//! security policies.
19//!
20//! ## Features
21//!
22//! - **In-Memory Loading**: Load PE executables (.exe) and libraries (.dll) from memory
23//! - **Full PE Support**: Complete PE parsing, import resolution, and relocation processing
24//! - **Native Execution**: Code runs exactly as if loaded from disk
25//! - **Memory Safety**: Proper memory management with automatic cleanup
26//! - **Cross-Platform Ready**: Windows implementation complete, Linux planned
27//!
28//! ## Quick Start
29//!
30//! ```rust,no_run
31//! use maple_rs::{Maple, Result};
32//! use std::fs;
33//!
34//! fn main() -> Result<()> {
35//!     // Load an executable from memory
36//!     let data = fs::read("program.exe")?;
37//!     let module = Maple::load_executable_from_memory(&data)?;
38//!     
39//!     // Execute the program's entry point
40//!     module.execute_entry_point()?;
41//!     
42//!     Ok(())
43//! }
44//! ```
45//!
46//! ## Advanced Usage
47//!
48//! ```rust,no_run
49//! use maple_rs::{MemoryModuleBuilder, Result};
50//! use std::fs;
51//!
52//! fn main() -> Result<()> {
53//!     let data = fs::read("library.dll")?;
54//!     
55//!     let module = MemoryModuleBuilder::new()
56//!         .resolve_imports(true)
57//!         .process_relocations(true)
58//!         .call_dll_main(true)
59//!         .load_from_memory(&data)?;
60//!     
61//!     // Get a function from the loaded library
62//!     let function = module.get_proc_address("MyFunction")?;
63//!     
64//!     Ok(())
65//! }
66//! ```
67//!
68//! ## Platform Support
69//!
70//! - **Windows**: Full support for PE executables and DLLs
71//! - **Linux**: Placeholder implementation (planned for future release)
72//!
73//! ## Error Handling
74//!
75//! All operations return a `Result<T, MapleError>` with comprehensive error information:
76//!
77//! ```rust,no_run
78//! use maple_rs::{Maple, MapleError};
79//! # let data = b"dummy data";
80//!
81//! match Maple::load_executable_from_memory(data) {
82//!     Ok(module) => {
83//!         // Successfully loaded
84//!     },
85//!     Err(MapleError::InvalidPEFormat(msg)) => {
86//!         eprintln!("Invalid PE file: {}", msg);
87//!     },
88//!     Err(MapleError::MemoryAllocation(msg)) => {
89//!         eprintln!("Memory allocation failed: {}", msg);
90//!     },
91//!     Err(e) => {
92//!         eprintln!("Other error: {}", e);
93//!     }
94//! }
95//! ```
96
97pub mod error;
98pub mod memory_module;
99pub mod pe;
100
101#[cfg(windows)]
102pub mod windows;
103
104#[cfg(unix)]
105pub mod linux;
106
107pub use error::MapleError;
108pub use memory_module::{MemoryModule, MemoryModuleBuilder};
109
110/// Result type alias for all maple-rs operations.
111pub type Result<T> = std::result::Result<T, MapleError>;
112
113/// Main entry point for the maple-rs library.
114///
115/// Provides convenient static methods for loading executables and libraries
116/// from memory buffers.
117pub struct Maple;
118
119impl Maple {
120    /// Loads a DLL/library from a memory buffer.
121    ///
122    /// # Arguments
123    ///
124    /// * `data` - Raw bytes of the PE file to load
125    ///
126    /// # Returns
127    ///
128    /// Returns a `MemoryModule` trait object that can be used to interact with
129    /// the loaded library, including getting function addresses.
130    ///
131    /// # Example
132    ///
133    /// ```rust,no_run
134    /// use maple_rs::Maple;
135    /// use std::fs;
136    ///
137    /// let dll_data = fs::read("library.dll").unwrap();
138    /// let module = Maple::load_library_from_memory(&dll_data).unwrap();
139    /// let func = module.get_proc_address("MyFunction").unwrap();
140    /// ```
141    ///
142    /// # Errors
143    ///
144    /// Returns `MapleError` if:
145    /// - The PE format is invalid
146    /// - Memory allocation fails
147    /// - Import resolution fails
148    /// - Platform is not supported
149    pub fn load_library_from_memory(data: &[u8]) -> Result<Box<dyn MemoryModule>> {
150        #[cfg(windows)]
151        {
152            windows::WindowsMemoryModule::from_memory(data)
153                .map(|m| Box::new(m) as Box<dyn MemoryModule>)
154        }
155
156        #[cfg(unix)]
157        {
158            linux::LinuxMemoryModule::from_memory(data)
159                .map(|m| Box::new(m) as Box<dyn MemoryModule>)
160        }
161    }
162
163    /// Loads an executable from a memory buffer.
164    ///
165    /// # Arguments
166    ///
167    /// * `data` - Raw bytes of the PE executable to load
168    ///
169    /// # Returns
170    ///
171    /// Returns a `MemoryModule` trait object that can be used to execute
172    /// the program's entry point.
173    ///
174    /// # Example
175    ///
176    /// ```rust,no_run
177    /// use maple_rs::Maple;
178    /// use std::fs;
179    ///
180    /// let exe_data = fs::read("program.exe").unwrap();
181    /// let module = Maple::load_executable_from_memory(&exe_data).unwrap();
182    /// module.execute_entry_point().unwrap();
183    /// ```
184    ///
185    /// # Errors
186    ///
187    /// Returns `MapleError` if:
188    /// - The PE format is invalid
189    /// - Memory allocation fails
190    /// - Import resolution fails
191    /// - Platform is not supported
192    pub fn load_executable_from_memory(data: &[u8]) -> Result<Box<dyn MemoryModule>> {
193        Self::load_library_from_memory(data)
194    }
195
196    /// Loads an application DLL from a memory buffer.
197    ///
198    /// Application DLLs are DLLs that contain a main application but are compiled
199    /// as DLL files instead of executables. They typically start a thread in DllMain
200    /// that runs the application logic.
201    ///
202    /// # Arguments
203    ///
204    /// * `data` - Raw bytes of the PE DLL file to load
205    ///
206    /// # Returns
207    ///
208    /// Returns a `MemoryModule` trait object that can be used to execute
209    /// the application DLL using the `execute_dll_application` method.
210    ///
211    /// # Example
212    ///
213    /// ```rust,no_run
214    /// use maple_rs::Maple;
215    /// use std::fs;
216    ///
217    /// let dll_data = fs::read("app.dll").unwrap();
218    /// let module = Maple::load_application_dll_from_memory(&dll_data).unwrap();
219    /// module.execute_dll_application().unwrap();
220    /// ```
221    ///
222    /// # Errors
223    ///
224    /// Returns `MapleError` if:
225    /// - The PE format is invalid
226    /// - Memory allocation fails  
227    /// - Import resolution fails
228    /// - Platform is not supported
229    pub fn load_application_dll_from_memory(data: &[u8]) -> Result<Box<dyn MemoryModule>> {
230        #[cfg(windows)]
231        {
232            windows::WindowsMemoryModule::from_memory_with_options(
233                data,
234                &MemoryModuleBuilder::new()
235                    .resolve_imports(true)
236                    .process_relocations(true)
237                    .call_dll_main(false) // Don't call DllMain automatically for app DLLs
238                    .is_application_dll(true),
239            )
240            .map(|m| Box::new(m) as Box<dyn MemoryModule>)
241        }
242
243        #[cfg(unix)]
244        {
245            linux::LinuxMemoryModule::from_memory_with_options(
246                data,
247                &MemoryModuleBuilder::new()
248                    .resolve_imports(true)
249                    .process_relocations(true)
250                    .call_dll_main(false)
251                    .is_application_dll(true),
252            )
253            .map(|m| Box::new(m) as Box<dyn MemoryModule>)
254        }
255    }
256}
257
258#[cfg(test)]
259mod tests {
260    use super::*;
261
262    #[test]
263    fn test_maple_creation() {
264        // Basic compilation test
265        let _maple = Maple;
266    }
267
268    #[test]
269    fn test_result_type() {
270        let success: Result<i32> = Ok(42);
271        let failure: Result<i32> = Err(MapleError::InvalidPEFormat("test".to_string()));
272
273        assert_eq!(success, Ok(42));
274        assert!(failure.is_err());
275    }
276}