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}