Skip to main content

memflow_win32_ffi/win32/
kernel.rs

1use memflow_ffi::mem::phys_mem::CloneablePhysicalMemoryObj;
2use memflow_ffi::util::*;
3use memflow_win32::kernel::Win32Version;
4use memflow_win32::win32::{kernel, Win32ProcessInfo, Win32VirtualTranslate};
5
6use memflow::mem::{
7    cache::{CachedMemoryAccess, CachedVirtualTranslate, TimedCacheValidator},
8    CloneablePhysicalMemory, DirectTranslate, VirtualDMA,
9};
10
11use memflow::iter::FnExtend;
12use memflow::process::PID;
13use memflow::types::{size, Address, PageType};
14
15use super::process::Win32Process;
16use crate::kernel::start_block::StartBlock;
17
18use std::ffi::CStr;
19use std::os::raw::c_char;
20use std::time::Duration;
21
22pub(crate) type FFIMemory =
23    CachedMemoryAccess<'static, Box<dyn CloneablePhysicalMemory>, TimedCacheValidator>;
24pub(crate) type FFIVirtualTranslate = CachedVirtualTranslate<DirectTranslate, TimedCacheValidator>;
25
26pub(crate) type FFIVirtualMemory =
27    VirtualDMA<FFIMemory, FFIVirtualTranslate, Win32VirtualTranslate>;
28
29pub type Kernel = kernel::Kernel<FFIMemory, FFIVirtualTranslate>;
30
31/// Build a cloneable kernel object with default caching parameters
32///
33/// This function will take ownership of the input `mem` object.
34///
35/// # Safety
36///
37/// `mem` must be a heap allocated memory reference, created by one of the API's functions.
38/// Reference to it becomes invalid.
39#[no_mangle]
40pub unsafe extern "C" fn kernel_build(
41    mem: &'static mut CloneablePhysicalMemoryObj,
42) -> Option<&'static mut Kernel> {
43    let mem: Box<dyn CloneablePhysicalMemory> = Box::from_raw(*Box::from_raw(mem));
44    kernel::Kernel::builder(mem)
45        .build_default_caches()
46        .build()
47        .map_err(inspect_err)
48        .ok()
49        .map(to_heap)
50}
51
52/// Build a cloneable kernel object with custom caching parameters
53///
54/// This function will take ownership of the input `mem` object.
55///
56/// vat_cache_entries must be positive, or the program will panic upon memory reads or writes.
57///
58/// # Safety
59///
60/// `mem` must be a heap allocated memory reference, created by one of the API's functions.
61/// Reference to it becomes invalid.
62#[no_mangle]
63pub unsafe extern "C" fn kernel_build_custom(
64    mem: &'static mut CloneablePhysicalMemoryObj,
65    page_cache_time_ms: u64,
66    page_cache_flags: PageType,
67    page_cache_size_kb: usize,
68    vat_cache_time_ms: u64,
69    vat_cache_entries: usize,
70) -> Option<&'static mut Kernel> {
71    let mem: Box<dyn CloneablePhysicalMemory> = Box::from_raw(*Box::from_raw(mem));
72    kernel::Kernel::builder(mem)
73        .build_page_cache(move |connector, arch| {
74            CachedMemoryAccess::builder(connector)
75                .arch(arch)
76                .validator(TimedCacheValidator::new(
77                    Duration::from_millis(page_cache_time_ms).into(),
78                ))
79                .page_type_mask(page_cache_flags)
80                .cache_size(size::kb(page_cache_size_kb))
81                .build()
82                .unwrap()
83        })
84        .build_vat_cache(move |vat, arch| {
85            CachedVirtualTranslate::builder(vat)
86                .arch(arch)
87                .validator(TimedCacheValidator::new(
88                    Duration::from_millis(vat_cache_time_ms).into(),
89                ))
90                .entries(vat_cache_entries)
91                .build()
92                .unwrap()
93        })
94        .build()
95        .map_err(inspect_err)
96        .ok()
97        .map(to_heap)
98}
99
100#[no_mangle]
101pub extern "C" fn kernel_clone(kernel: &Kernel) -> &'static mut Kernel {
102    Box::leak(Box::new((*kernel).clone()))
103}
104
105/// Free a kernel object
106///
107/// This will free the input `kernel` object (including the underlying memory object)
108///
109/// # Safety
110///
111/// `kernel` must be a valid reference heap allocated by one of the above functions.
112#[no_mangle]
113pub unsafe extern "C" fn kernel_free(kernel: &'static mut Kernel) {
114    let _ = Box::from_raw(kernel);
115}
116
117/// Destroy a kernel object and return its underlying memory object
118///
119/// This will free the input `kernel` object, and return the underlying memory object. It will free
120/// the object from any additional caching that `kernel` had in place.
121///
122/// # Safety
123///
124/// `kernel` must be a valid reference heap allocated by one of the above functions.
125#[no_mangle]
126pub unsafe extern "C" fn kernel_destroy(
127    kernel: &'static mut Kernel,
128) -> &'static mut CloneablePhysicalMemoryObj {
129    let kernel = Box::from_raw(kernel);
130    Box::leak(Box::new(Box::leak(kernel.destroy().destroy())))
131}
132
133#[no_mangle]
134pub extern "C" fn kernel_start_block(kernel: &Kernel) -> StartBlock {
135    kernel.kernel_info.start_block.into()
136}
137
138#[no_mangle]
139pub extern "C" fn kernel_winver(kernel: &Kernel) -> Win32Version {
140    kernel.kernel_info.kernel_winver.mask_build_number()
141}
142
143#[no_mangle]
144pub extern "C" fn kernel_winver_unmasked(kernel: &Kernel) -> Win32Version {
145    kernel.kernel_info.kernel_winver
146}
147
148/// Retrieve a list of peorcess addresses
149///
150/// # Safety
151///
152/// `buffer` must be a valid buffer of size at least `max_size`
153#[no_mangle]
154pub unsafe extern "C" fn kernel_eprocess_list(
155    kernel: &'static mut Kernel,
156    buffer: *mut Address,
157    max_size: usize,
158) -> usize {
159    let mut ret = 0;
160
161    let buffer = std::slice::from_raw_parts_mut(buffer, max_size);
162
163    let mut extend_fn = FnExtend::new(|addr| {
164        if ret < max_size {
165            buffer[ret] = addr;
166            ret += 1;
167        }
168    });
169
170    kernel
171        .eprocess_list_extend(&mut extend_fn)
172        .map_err(inspect_err)
173        .ok()
174        .map(|_| ret)
175        .unwrap_or_default()
176}
177
178/// Retrieve a list of processes
179///
180/// This will fill `buffer` with a list of win32 process information. These processes will need to be
181/// individually freed with `process_info_free`
182///
183/// # Safety
184///
185/// `buffer` must be a valid that can contain at least `max_size` references to `Win32ProcessInfo`.
186#[no_mangle]
187pub unsafe extern "C" fn kernel_process_info_list(
188    kernel: &'static mut Kernel,
189    buffer: *mut &'static mut Win32ProcessInfo,
190    max_size: usize,
191) -> usize {
192    let mut ret = 0;
193
194    let buffer = std::slice::from_raw_parts_mut(buffer, max_size);
195
196    let mut extend_fn = FnExtend::new(|info| {
197        if ret < max_size {
198            buffer[ret] = Box::leak(Box::new(info));
199            ret += 1;
200        }
201    });
202
203    kernel
204        .process_info_list_extend(&mut extend_fn)
205        .map_err(inspect_err)
206        .ok()
207        .map(|_| ret)
208        .unwrap_or_default()
209}
210
211// Process info
212
213#[no_mangle]
214pub extern "C" fn kernel_kernel_process_info(
215    kernel: &'static mut Kernel,
216) -> Option<&'static mut Win32ProcessInfo> {
217    kernel
218        .kernel_process_info()
219        .map_err(inspect_err)
220        .ok()
221        .map(to_heap)
222}
223
224#[no_mangle]
225pub extern "C" fn kernel_process_info_from_eprocess(
226    kernel: &'static mut Kernel,
227    eprocess: Address,
228) -> Option<&'static mut Win32ProcessInfo> {
229    kernel
230        .process_info_from_eprocess(eprocess)
231        .map_err(inspect_err)
232        .ok()
233        .map(to_heap)
234}
235
236/// Retrieve process information by name
237///
238/// # Safety
239///
240/// `name` must be a valid null terminated string
241#[no_mangle]
242pub unsafe extern "C" fn kernel_process_info(
243    kernel: &'static mut Kernel,
244    name: *const c_char,
245) -> Option<&'static mut Win32ProcessInfo> {
246    let name = CStr::from_ptr(name).to_string_lossy();
247    kernel
248        .process_info(&name)
249        .map_err(inspect_err)
250        .ok()
251        .map(to_heap)
252}
253
254#[no_mangle]
255pub extern "C" fn kernel_process_info_pid(
256    kernel: &'static mut Kernel,
257    pid: PID,
258) -> Option<&'static mut Win32ProcessInfo> {
259    kernel
260        .process_info_pid(pid)
261        .map_err(inspect_err)
262        .ok()
263        .map(to_heap)
264}
265
266// Process conversion
267
268/// Create a process by looking up its name
269///
270/// This will consume `kernel` and free it later on.
271///
272/// # Safety
273///
274/// `name` must be a valid null terminated string
275///
276/// `kernel` must be a valid reference to `Kernel`. After the function the reference to it becomes
277/// invalid.
278#[no_mangle]
279pub unsafe extern "C" fn kernel_into_process(
280    kernel: &'static mut Kernel,
281    name: *const c_char,
282) -> Option<&'static mut Win32Process> {
283    let kernel = Box::from_raw(kernel);
284    let name = CStr::from_ptr(name).to_string_lossy();
285    kernel
286        .into_process(&name)
287        .map_err(inspect_err)
288        .ok()
289        .map(to_heap)
290}
291
292/// Create a process by looking up its PID
293///
294/// This will consume `kernel` and free it later on.
295///
296/// # Safety
297///
298/// `kernel` must be a valid reference to `Kernel`. After the function the reference to it becomes
299/// invalid.
300#[no_mangle]
301pub unsafe extern "C" fn kernel_into_process_pid(
302    kernel: &'static mut Kernel,
303    pid: PID,
304) -> Option<&'static mut Win32Process> {
305    let kernel = Box::from_raw(kernel);
306    kernel
307        .into_process_pid(pid)
308        .map_err(inspect_err)
309        .ok()
310        .map(to_heap)
311}
312
313/// Create a kernel process insatance
314///
315/// This will consume `kernel` and free it later on.
316///
317/// # Safety
318///
319/// `kernel` must be a valid reference to `Kernel`. After the function the reference to it becomes
320/// invalid.
321#[no_mangle]
322pub unsafe extern "C" fn kernel_into_kernel_process(
323    kernel: &'static mut Kernel,
324) -> Option<&'static mut Win32Process> {
325    let kernel = Box::from_raw(kernel);
326    kernel
327        .into_kernel_process()
328        .map_err(inspect_err)
329        .ok()
330        .map(to_heap)
331}