demo/
demo.rs

1use interceptor_rs::{syscall, Interceptor};
2use std::{
3    env::args,
4    ffi::{c_char, CStr, CString},
5    mem::forget,
6    process::Command,
7};
8
9fn main() -> Result<(), Box<dyn std::error::Error>> {
10    let args = args().collect::<Vec<_>>();
11    let mut cmd = Command::new(&args[0]);
12    if let Some(args) = args.get(1..) {
13        cmd.args(args);
14    }
15    Interceptor::new(cmd)?.on(&openat).run()?;
16    Ok(())
17}
18
19#[syscall]
20fn openat(dfd: i32, mut filename: *const c_char, flags: i32, mode: i32) -> i32 {
21    let file = unsafe { CStr::from_ptr(filename).to_string_lossy() };
22    println!("openat filename: {}", file);
23    if file == "1.c" {
24        {
25            // If you want to change the content of the filename pointer, make sure that
26            // the length of the changed content is less than or equal to the original
27            // length, otherwise the extra bytes will be truncated.
28            let a = b"2.c";
29            unsafe {
30                std::ptr::copy_nonoverlapping(a.as_ptr(), filename as *mut u8, a.len());
31            }
32        }
33
34        {
35            // Alternatively, you can apply for a string memory yourself, and then change
36            // the filename pointer itself.
37            let a = CString::new("1.cpp").unwrap();
38            filename = a.as_ptr() as *mut c_char;
39            // In this case, don't forget to call `forget` to make sure that the content
40            // pointed by the return pointer is not released.
41            forget(a);
42        }
43    }
44
45    // call the `real!()` macro to pass the modified arguments to the kernel, and of course
46    // you can alse modify its return value. If you don't call the `real!()` macro, the
47    // original system call will not be called in kernel (here is `openat`), and the result
48    // will be returned directly to the caller of the original caller.
49    let ret = real!(dfd, filename, flags, mode);
50    println!("ret: {}", ret);
51    ret
52}