Skip to main content

hooking/mem/inner/
linux.rs

1use std::ffi::c_void;
2use std::mem::MaybeUninit;
3use std::ptr::NonNull;
4
5use super::super::*;
6use libc;
7
8#[derive(Debug, Clone, Copy)]
9#[repr(transparent)]
10pub struct WindowsMemoryHandle(pub NonNull<c_void>);
11
12impl MemoryHandle for WindowsMemoryHandle {
13    fn from_ptr(ptr: NonNull<c_void>) -> Self {
14        Self(ptr)
15    }
16    fn as_ptr(&self) -> NonNull<c_void> {
17        self.0
18    }
19}
20
21pub struct LinuxMemoryAllocationInfo {
22    page_size: usize,
23    allocation_size: usize,
24    allocation_start: WindowsMemoryHandle,
25}
26
27impl AllocationInfo<LinuxMemoryController> for LinuxMemoryAllocationInfo {
28    fn page_size(&self) -> usize {
29        self.page_size
30    }
31
32    fn allocation_size(&self) -> usize {
33        self.allocation_size
34    }
35
36    fn allocation_start(&self) -> WindowsMemoryHandle {
37        self.allocation_start
38    }
39}
40
41pub struct LinuxMemoryController;
42
43impl LinuxMemoryController {
44    pub const fn new() -> Self {
45        Self
46    }
47
48    unsafe fn sys_get_page_size(&self) -> usize {
49        unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize }
50    }
51
52    #[cfg(not(feature = "win_close_alloc"))]
53    unsafe fn allocate_system_memory(
54        &self,
55        _page_size: usize,
56        size: usize,
57    ) -> Result<WindowsMemoryHandle> {
58        let handle = unsafe {
59            libc::mmap(
60                std::ptr::null_mut(),
61                size,
62                libc::PROT_READ | libc::PROT_WRITE,
63                libc::MAP_PRIVATE | libc::MAP_ANONYMOUS,
64                -1,
65                0,
66            )
67        };
68
69        NonNull::new(handle)
70            .map(WindowsMemoryHandle)
71            .ok_or(MemoryError::CantAllocate)
72    }
73
74    fn allign_up(&self, page_size: usize, address: usize) -> usize {
75        (address + page_size - 1) & !(page_size - 1)
76    }
77
78    fn allign_down(&self, page_size: usize, address: usize) -> usize {
79        address & !(page_size - 1)
80    }
81
82    fn get_native_protection_flags(&self, protection: MemoryProtection) -> i32 {
83        match protection {
84            MemoryProtection::NoAccess => 0,
85            MemoryProtection::ReadWrite => libc::PROT_READ | libc::PROT_WRITE,
86            MemoryProtection::ReadExecute => libc::PROT_READ | libc::PROT_EXEC,
87            MemoryProtection::Other(proc) => proc as i32,
88        }
89    }
90
91    unsafe fn native_set_page_protection(
92        &self,
93        page: NonNull<c_void>,
94        allocation_size: usize,
95        protection: i32,
96    ) -> Result<()> {
97        let success = unsafe { libc::mprotect(page.as_ptr(), allocation_size, protection) == 0 };
98        if !success {
99            Err(MemoryError::CantSetMemoryProtection(page.as_ptr() as usize))
100        } else {
101            Ok(())
102        }
103    }
104}
105
106impl MemoryController for LinuxMemoryController {
107    type Handle = WindowsMemoryHandle;
108
109    type AllocationInfoType = LinuxMemoryAllocationInfo;
110
111    unsafe fn allocate_memory(&self, min_size: Option<usize>) -> Result<Self::AllocationInfoType> {
112        let page_size = unsafe { self.sys_get_page_size() } as usize;
113
114        let allocation_size = if let Some(min_size) = min_size {
115            self.allign_up(page_size, min_size)
116        } else {
117            page_size
118        };
119
120        let allocation_start = unsafe { self.allocate_system_memory(page_size, allocation_size)? };
121
122        Ok(Self::AllocationInfoType {
123            page_size,
124            allocation_size,
125            allocation_start,
126        })
127    }
128    unsafe fn set_page_protection(
129        &self,
130        handle: Self::Handle,
131        size: usize,
132        protection: MemoryProtection,
133    ) -> Result<()> {
134        let protection = self.get_native_protection_flags(protection);
135
136        unsafe {
137            self.native_set_page_protection(handle.as_ptr(), size, protection)?;
138        }
139
140        Ok(())
141    }
142
143    unsafe fn get_symbol_address(
144        &self,
145        module: Option<&CStr>,
146        symbol: &CStr,
147    ) -> Result<NonNull<c_void>> {
148        let module_handle = if let Some(module) = module {
149            let module_addr = unsafe { libc::dlopen(module.as_ptr(), libc::RTLD_LAZY) };
150            if module_addr.is_null() {
151                return Err(MemoryError::CantFindModule(
152                    module.to_str().unwrap_or("<invalid-module-name>").into(),
153                ));
154            }
155            module_addr
156        } else {
157            libc::RTLD_DEFAULT
158        };
159
160        let proc_address = {
161            let proc_address = unsafe { libc::dlsym(module_handle, symbol.as_ptr()) };
162
163            NonNull::new(proc_address).ok_or_else(|| {
164                MemoryError::CantFindModule(
165                    symbol.to_str().unwrap_or("<invalid-module-name>").into(),
166                )
167            })?
168        };
169
170        Ok(proc_address)
171    }
172
173    fn protection_guard_for_page<'a>(
174        &'a self,
175        ptr: NonNull<c_void>,
176        on_enter: MemoryProtection,
177        on_exit: Option<MemoryProtection>,
178    ) -> Result<MemoryProtectionGuard<'a, Self>>
179    where
180        Self: Sized,
181    {
182        let on_exit = if let Some(on_exit) = on_exit {
183            on_exit
184        } else {
185            MemoryProtection::ReadExecute
186        };
187
188        let page_size = unsafe { self.sys_get_page_size() };
189        let alligned_address = {
190            let address =
191                self.allign_down(page_size as usize, ptr.as_ptr() as usize) as *mut c_void;
192            NonNull::new(address).ok_or(MemoryError::BadAdress(address))?
193        };
194        self.protection_guard(
195            Self::Handle::from_ptr(alligned_address),
196            page_size,
197            on_enter,
198            on_exit,
199        )
200    }
201}