diff --git a/Cargo.lock b/Cargo.lock index a4d2af845..62a040f27 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -123,6 +123,7 @@ dependencies = [ "flate2", "log", "md5", + "memmap2", "miniz_oxide 0.8.0", "plotters", "serde", @@ -676,6 +677,15 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "memmap2" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" +dependencies = [ + "libc", +] + [[package]] name = "miniz_oxide" version = "0.7.4" diff --git a/Cargo.toml b/Cargo.toml index ae2819fee..5b0f30bea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,7 @@ aho-corasick = "1.1.3" serde = { version = "1.0", features = ["derive"]} clap = { version = "4.5.16", features = ["derive"] } xxhash-rust = { version = "0.8.12", features = ["xxh32"] } +memmap2 = "0.9.5" [dependencies.uuid] version = "1.10.0" diff --git a/src/binwalk.rs b/src/binwalk.rs index 933970ded..482de9b60 100644 --- a/src/binwalk.rs +++ b/src/binwalk.rs @@ -14,7 +14,7 @@ use std::os::windows; #[cfg(unix)] use std::os::unix; -use crate::common::{is_offset_safe, read_file}; +use crate::common::{is_offset_safe, mmap_file}; use crate::extractors; use crate::magic; use crate::signatures; @@ -699,11 +699,10 @@ impl Binwalk { debug!("Analysis start: {}", target_file); - // Read file into memory - if let Ok(file_data) = read_file(target_file) { + if let Ok(file_mmap) = mmap_file(target_file) { // Scan file data for signatures info!("Scanning {}", target_file); - results.file_map = self.scan(&file_data); + results.file_map = self.scan(&file_mmap); // Only extract if told to, and if there were some signatures found in this file if do_extraction && !results.file_map.is_empty() { @@ -712,7 +711,7 @@ impl Binwalk { "Submitting {} signature results to extractor", results.file_map.len() ); - results.extractions = self.extract(&file_data, target_file, &results.file_map); + results.extractions = self.extract(&file_mmap, target_file, &results.file_map); } } diff --git a/src/common.rs b/src/common.rs index cb1276a4c..8e0b59aeb 100644 --- a/src/common.rs +++ b/src/common.rs @@ -1,24 +1,22 @@ //! Common Functions use chrono::prelude::DateTime; -use log::{debug, error}; +use log::error; +use memmap2::Mmap; use std::fs::File; -use std::io::Read; -/// Read a file into memory and return its contents. +/// Map the file into memory and return a [Mmap] instance +/// that provides access into the file's contents. /// /// ## Example /// /// ``` -/// # fn main() { #[allow(non_snake_case)] fn _doctest_main_src_common_rs_11_0() -> Result<(), Box> { -/// use binwalk::common::read_file; +/// use binwalk::common::mmap_file; /// -/// let file_data = read_file("/etc/passwd")?; +/// let file_data = mmap_file("/etc/passwd")?; /// assert!(file_data.len() > 0); -/// # Ok(()) -/// # } _doctest_main_src_common_rs_11_0(); } +/// # Ok::<(), std::io::Error>(()) /// ``` -pub fn read_file(file: impl Into) -> Result, std::io::Error> { - let mut file_data = Vec::new(); +pub fn mmap_file(file: impl Into) -> Result { let file_path = file.into(); match File::open(&file_path) { @@ -26,15 +24,12 @@ pub fn read_file(file: impl Into) -> Result, std::io::Error> { error!("Failed to open file {}: {}", file_path, e); Err(e) } - Ok(mut fp) => match fp.read_to_end(&mut file_data) { + Ok(fp) => match unsafe { Mmap::map(&fp) } { Err(e) => { - error!("Failed to read file {} into memory: {}", file_path, e); + error!("Failed to map file {} into memory: {}", file_path, e); Err(e) } - Ok(file_size) => { - debug!("Loaded {} bytes from {}", file_size, file_path); - Ok(file_data) - } + Ok(mmap) => Ok(mmap), }, } } diff --git a/src/entropy.rs b/src/entropy.rs index e3455262f..5628ad890 100644 --- a/src/entropy.rs +++ b/src/entropy.rs @@ -1,4 +1,4 @@ -use crate::common::read_file; +use crate::common::mmap_file; use entropy::shannon_entropy; use log::error; use plotters::prelude::*; @@ -87,7 +87,7 @@ pub fn plot(file_path: impl Into) -> Result { } // Read in the target file data - if let Ok(file_data) = read_file(&target_file) { + if let Ok(file_data) = mmap_file(&target_file) { let mut points: Vec<(i32, i32)> = vec![]; // Calculate the entropy for each file block diff --git a/src/main.rs b/src/main.rs index 586d1f968..0e389e25d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -305,7 +305,7 @@ fn carve_file_map(results: &binwalk::AnalysisResults) -> usize { // No results, don't do anything if !results.file_map.is_empty() { // Read in the source file - if let Ok(file_data) = common::read_file(&results.file_path) { + if let Ok(file_data) = common::mmap_file(&results.file_path) { // Loop through all identified signatures in the file for signature_result in &results.file_map { // If there is data between the last signature and this signature, it is some chunk of unknown data