hooking/mem/inner/
linux.rs1use 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}