diff --git a/src/find.rs b/src/find.rs new file mode 100644 index 0000000..17a81c1 --- /dev/null +++ b/src/find.rs @@ -0,0 +1,7 @@ +use core::ptr::NonNull; + +pub trait Find { + fn find(&self, pattern: &[u8]) -> Option>; + + fn rfind(&self, pattern: &[u8]) -> Option>; +} diff --git a/src/lib.rs b/src/lib.rs index 0f6717e..97ccf0d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,11 +1,15 @@ //! # Inka mod base; +mod find; mod program; mod section; +mod symbol; pub use base::Base; +pub use find::Find; pub use program::{program, Program}; pub use section::Section; - -pub type Name = &'static str; \ No newline at end of file +pub use symbol::Symbol; + +pub type Name = &'static str; diff --git a/src/program.rs b/src/program.rs index 94e7959..a314db5 100644 --- a/src/program.rs +++ b/src/program.rs @@ -1,4 +1,4 @@ -use crate::{Base, Section}; +use crate::{Base, Find, Section}; use core::ops::Index; use core::ptr::NonNull; use core::slice::{from_raw_parts, SliceIndex}; @@ -8,15 +8,12 @@ use rayon::iter::IndexedParallelIterator; use rayon::slice::ParallelSlice; use std::sync::LazyLock; -/// Returns a reference to the global [`Program`] instance. #[inline] pub fn program() -> &'static Program { static PROGRAM: LazyLock = LazyLock::new(Program::init); &PROGRAM } -/// Represents the `Program`'s in-memory layout, providing access to its base address, size, -/// and sections. #[derive(Debug)] pub struct Program { base: Base, @@ -25,35 +22,23 @@ pub struct Program { } impl Program { - /// Returns a base pointer of this program in memory. #[inline] pub fn base(&self) -> Base { self.base } - /// Returns the length of this program in memory. #[inline] #[allow(clippy::len_without_is_empty)] pub fn len(&self) -> usize { self.len } - /// Returns a slice containing the entire program. #[inline] pub fn as_slice(&self) -> &[u8] { // SAFETY: todo!() unsafe { from_raw_parts(self.base.as_nonnull().as_ptr(), self.len) } } - /// Returns `true` if the program contains the byte pattern. - /// - /// # Examples - /// ``` - /// use inka::program; - /// - /// let result = program().contains(&[0]); - /// assert!(result); - /// ``` pub fn contains(&self, pattern: &[u8]) -> bool { self.find(pattern).is_some() } @@ -66,81 +51,6 @@ impl Program { self.sections.iter().find(|section| section.name() == name) } - /// Returns the pointer of the first byte that matches the byte pattern. - /// - /// Returns [`None`] if the pattern doesn’t match. - /// - /// # Examples - /// ``` - /// use inka::program; - /// - /// let data = &[ - /// 0x7c, 0x73, 0xe1, 0x3d, - /// 0x1a, 0x7d, 0xb3, 0x00, - /// 0xd2, 0x6c, 0x61, 0xf9, - /// 0x5f, 0x00, 0xf1, 0x10, - /// 0x80, 0x5e, 0x5f, 0xbf, - /// ]; - /// - /// let pattern = &[ - /// 0x7c, 0x73, 0xe1, 0x3d, - /// 0x1a, 0x7d, 0xb3, 0x00, - /// 0xd2, - /// ]; - /// - /// let ptr = program() - /// .find(pattern) - /// .unwrap(); - /// - /// assert_eq!(data.as_ptr(), ptr.as_ptr()); - /// ``` - pub fn find(&self, pattern: &[u8]) -> Option> { - assert!(!pattern.is_empty()); - - self.as_slice() - .par_windows(pattern.len()) - .position_first(|window| window == pattern) - .map(|offset| unsafe { self.base.add(offset) }) - } - - /// Returns the pointer of the first byte of the last match of the pattern. - /// - /// Returns [`None`] if the pattern doesn’t match. - /// - /// # Examples - /// - /// ``` - /// use inka::program; - /// - /// let data = &[ - /// 0x7c, 0x73, 0xe1, 0x3d, - /// 0x1a, 0x7d, 0xb3, 0x00, - /// 0xd2, 0x6c, 0x61, 0xf9, - /// 0x5f, 0x00, 0xf1, 0x10, - /// 0x80, 0x5e, 0x5f, 0xbf, - /// ]; - /// - /// let pattern = &[ - /// 0x7c, 0x73, 0xe1, 0x3d, - /// 0x1a, 0x7d, 0xb3, 0x00, - /// 0xd2, - /// ]; - /// - /// let ptr = program() - /// .rfind(pattern) - /// .unwrap(); - /// - /// assert_eq!(data.as_ptr(), ptr.as_ptr()); - /// ``` - pub fn rfind(&self, pattern: &[u8]) -> Option> { - assert!(!pattern.is_empty()); - - self.as_slice() - .par_windows(pattern.len()) - .position_last(|window| window == pattern) - .map(|offset| unsafe { self.base.add(offset) }) - } - fn init() -> Self { let base = Base::program(); let pe = unsafe { PeView::module(base.as_nonnull().as_ptr()) }; @@ -169,6 +79,26 @@ impl Program { } } +impl Find for Program { + fn find(&self, pattern: &[u8]) -> Option> { + assert!(!pattern.is_empty()); + + self.as_slice() + .par_windows(pattern.len()) + .position_first(|window| window == pattern) + .map(|offset| unsafe { self.base.add(offset) }) + } + + fn rfind(&self, pattern: &[u8]) -> Option> { + assert!(!pattern.is_empty()); + + self.as_slice() + .par_windows(pattern.len()) + .position_last(|window| window == pattern) + .map(|offset| unsafe { self.base.add(offset) }) + } +} + impl> Index for Program { type Output = I::Output; diff --git a/src/section.rs b/src/section.rs index 3940130..15b2b14 100644 --- a/src/section.rs +++ b/src/section.rs @@ -1,11 +1,10 @@ -use crate::{Base, Name}; +use crate::{Base, Find, Name}; use core::ops::Index; use core::ptr::NonNull; use core::slice::{from_raw_parts, SliceIndex}; use rayon::iter::IndexedParallelIterator; use rayon::slice::ParallelSlice; -/// Represents a `Section` of the program in memory, providing access to its name, base address, and length. #[derive(Debug)] pub struct Section { name: Name, @@ -19,13 +18,11 @@ impl Section { self.name } - /// Returns a base pointer of this section. #[inline] pub fn base(&self) -> Base { self.base } - /// Returns the length of this section. #[inline] #[allow(clippy::len_without_is_empty)] pub fn len(&self) -> usize { @@ -43,7 +40,14 @@ impl Section { self.find(pattern).is_some() } - pub fn find(&self, pattern: &[u8]) -> Option> { + #[inline] + pub(crate) fn new(name: &'static str, base: Base, len: usize) -> Self { + Self { name, base, len } + } +} + +impl Find for Section { + fn find(&self, pattern: &[u8]) -> Option> { assert!(!pattern.is_empty()); self.as_slice() @@ -52,7 +56,7 @@ impl Section { .map(|offset| unsafe { self.base.add(offset) }) } - pub fn rfind(&self, pattern: &[u8]) -> Option> { + fn rfind(&self, pattern: &[u8]) -> Option> { assert!(!pattern.is_empty()); self.as_slice() @@ -60,11 +64,6 @@ impl Section { .position_last(|window| window == pattern) .map(|offset| unsafe { self.base.add(offset) }) } - - #[inline] - pub(crate) fn new(name: &'static str, base: Base, len: usize) -> Self { - Self { name, base, len } - } } impl> Index for Section { diff --git a/src/symbol.rs b/src/symbol.rs new file mode 100644 index 0000000..d8582bc --- /dev/null +++ b/src/symbol.rs @@ -0,0 +1,13 @@ +use crate::{Base, Name}; + +#[derive(Debug)] +pub struct Symbol { + name: Name, + base: Base, +} + +impl Symbol { + pub fn demangle(&self) -> String { + todo!() + } +} \ No newline at end of file