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}