Skip to content

Instantly share code, notes, and snippets.

@Stupremee
Created August 5, 2020 07:31
Show Gist options
  • Save Stupremee/86befd8e128e0dcd051129dcaf4fa130 to your computer and use it in GitHub Desktop.
Save Stupremee/86befd8e128e0dcd051129dcaf4fa130 to your computer and use it in GitHub Desktop.
Track thread spawning using ptrace syscall and Rust
// The source code for `/tmp/crab` which is used to test the code.
use std::thread;
use std::time::Duration;
fn main() {
let t1 = thread::spawn(|| {
println!("[1] Thread started working");
thread::sleep(Durtaion::from_millis(5000));
println!("[1] Thread finished working");
};
let t2 = thread::spawn(|| {
println!("[2] Thread started working");
thread::sleep(Durtaion::from_millis(5000));
println!("[2] Thread finished working");
};
t1.join().unwrap();
t2.join().unwrap();
}
use nix::sys::{
ptrace::{self, Options},
signal::Signal,
wait::{waitpid, WaitStatus},
};
use nix::unistd::{execv, fork, getpid, ForkResult, Pid};
use std::ffi::CString;
type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
fn main() -> Result<()> {
let (child, status) = launch("/tmp/crab")?;
println!("Current status: {:?}", status);
let mut threads = vec![child];
ptrace::cont(child, None)?;
loop {
let status = waitpid(None, None)?;
let pid = status.pid().unwrap();
if threads.contains(&pid) {
println!("found unknown child {}", pid);
}
match status {
WaitStatus::PtraceEvent(pid, Signal::SIGTRAP, 3) => {
let new_child = ptrace::getevent(pid)?;
let new_child = Pid::from_raw(new_child as i32);
println!("New child created {}", new_child);
threads.push(new_child);
}
WaitStatus::Exited(pid, status) => {
let idx = threads.iter().position(|p| *p == pid).unwrap();
threads.remove(idx);
println!("Child {} exited with {}", pid, status);
if threads.is_empty() {
println!("No childs left");
break;
}
continue;
}
WaitStatus::Signaled(pid, signal, _) => {
println!("Child {} exited with signal {}", pid, signal);
continue;
}
_ => {}
};
ptrace::cont(pid, None)?;
}
Ok(())
}
fn launch(path: &str) -> Result<(Pid, WaitStatus)> {
match fork()? {
ForkResult::Parent { child } => {
let pid = getpid();
println!("Start tracking child {} in parent {}", child, pid);
let status = waitpid(child, None)?;
let options = Options::PTRACE_O_EXITKILL | Options::PTRACE_O_TRACECLONE;
ptrace::setoptions(child, options)?;
Ok((child, status))
}
ForkResult::Child => {
ptrace::traceme()?;
unsafe {
const ADDR_NO_RANDOMIZE: libc::c_ulong = 0x0040000;
libc::personality(ADDR_NO_RANDOMIZE);
}
let path = CString::new(path)?;
execv(&path, &[path.as_ref()])?;
unreachable!();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment