1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/*
 * Copyright © 2020-2021 Keegan Saunders
 *
 * Licence: wxWindows Library Licence, Version 3.1
 */

use {crate::NativePointer, core::ffi::c_void, cstr_core::CString, frida_gum_sys as gum_sys};

use core::{
    fmt::{Debug, Display, LowerHex, UpperHex},
    ops::Range,
};

#[cfg(not(feature = "module-names"))]
use alloc::vec::Vec;

pub struct MatchPattern {
    pub(crate) internal: *mut gum_sys::GumMatchPattern,
}

impl MatchPattern {
    pub fn from_string(pattern: &str) -> Option<Self> {
        let pattern = CString::new(pattern).unwrap();

        let internal =
            unsafe { gum_sys::gum_match_pattern_new_from_string(pattern.as_ptr().cast()) };
        if !internal.is_null() {
            Some(Self { internal })
        } else {
            None
        }
    }
}

impl Drop for MatchPattern {
    fn drop(&mut self) {
        unsafe { gum_sys::gum_match_pattern_unref(self.internal) }
    }
}

#[allow(dead_code)]
pub struct ScanResult {
    pub address: usize,
    pub size: usize,
}

#[derive(Clone)]
pub struct MemoryRange {
    pub(crate) memory_range: gum_sys::GumMemoryRange,
}

impl MemoryRange {
    pub(crate) fn from_raw(memory_range: *const gum_sys::GumMemoryRange) -> MemoryRange {
        MemoryRange {
            memory_range: unsafe { *memory_range },
        }
    }

    pub fn new(base_address: NativePointer, size: usize) -> MemoryRange {
        MemoryRange {
            memory_range: gum_sys::GumMemoryRange {
                base_address: base_address.0 as u64,
                size: size as _,
            },
        }
    }

    /// Get the start address of the range.
    pub fn base_address(&self) -> NativePointer {
        NativePointer(self.memory_range.base_address as *mut c_void)
    }

    /// Get the size of the range.
    /// The end address of the range can be computed by adding the [`MemoryRange::base_address()`]
    /// to the size.
    pub fn size(&self) -> usize {
        self.memory_range.size as usize
    }

    pub fn scan(&self, pattern: &MatchPattern) -> Vec<ScanResult> {
        let mut results = Vec::new();
        unsafe {
            #[cfg(target_pointer_width = "32")]
            extern "C" fn callback32(address: u64, size: u32, user_data: *mut c_void) -> i32 {
                callback64(address, size as u64, user_data)
            }

            extern "C" fn callback64(address: u64, size: u64, user_data: *mut c_void) -> i32 {
                let results: &mut Vec<ScanResult> =
                    unsafe { &mut *(user_data as *mut Vec<ScanResult>) };
                results.push(ScanResult {
                    address: address as usize,
                    size: size as usize,
                });
                0
            }

            #[cfg(target_pointer_width = "32")]
            let callback = callback32;

            #[cfg(target_pointer_width = "64")]
            let callback = callback64;

            gum_sys::gum_memory_scan(
                &self.memory_range as *const gum_sys::GumMemoryRange,
                pattern.internal,
                Some(callback),
                &mut results as *mut _ as *mut _,
            );
        }

        results
    }
}

impl LowerHex for MemoryRange {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        LowerHex::fmt(&self.base_address(), f)?;
        write!(f, "..")?;
        LowerHex::fmt(&(self.base_address().0 as usize + self.size()), f)
    }
}

impl UpperHex for MemoryRange {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        UpperHex::fmt(&self.base_address(), f)?;
        write!(f, "..")?;
        UpperHex::fmt(&(self.base_address().0 as usize + self.size()), f)
    }
}

impl Display for MemoryRange {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        write!(
            f,
            "{}..{}",
            self.base_address(),
            self.base_address().0 as usize + self.size()
        )
    }
}

impl Debug for MemoryRange {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        let range: Range<usize> = self.into();
        f.debug_tuple("MemoryRange").field(&range).finish()
    }
}

impl From<&MemoryRange> for Range<usize> {
    fn from(value: &MemoryRange) -> Self {
        value.base_address().0 as usize..(value.base_address().0 as usize + value.size())
    }
}

impl From<MemoryRange> for Range<usize> {
    fn from(value: MemoryRange) -> Self {
        (&value).into()
    }
}