mirror of
https://github.com/Astatin3/syscall-stream-rs.git
synced 2026-06-08 16:08:01 -06:00
Work on adding a puppet for the server side aswell
This commit is contained in:
+8
-5
@@ -6,14 +6,17 @@ edition = "2024"
|
||||
[dependencies]
|
||||
ctor = "0.5.0"
|
||||
libc = "0.2.175"
|
||||
log = "0.4.27"
|
||||
nix = { version = "0.30.1", features = ["process", "fs", "feature", "ptrace"] }
|
||||
pretty_env_logger = "0.5.0"
|
||||
subprocess = "0.2.9"
|
||||
# syscalls = "0.6.18"
|
||||
syscall_lib = { path = "syscall_lib" }
|
||||
syscaller = "0.2.2"
|
||||
|
||||
[build-dependencies]
|
||||
cmake = "0.1"
|
||||
# [build-dependencies]
|
||||
# cmake = "0.1"
|
||||
|
||||
[lib]
|
||||
name = "intercept"
|
||||
crate-type = ["rlib", "cdylib"]
|
||||
# [lib]
|
||||
# name = "intercept"
|
||||
# crate-type = ["rlib", "cdylib"]
|
||||
|
||||
+7
-2
@@ -10,6 +10,7 @@ use std::{
|
||||
|
||||
use log::{error, info, trace};
|
||||
use nix::libc::{self, MAP_ANONYMOUS, MAP_PRIVATE, PROT_READ, PROT_WRITE, user_regs_struct};
|
||||
use nix::sys::ptrace;
|
||||
use nix::unistd::Pid;
|
||||
use subprocess::{Popen, PopenConfig, Redirection};
|
||||
use syscall_lib::Syscall;
|
||||
@@ -61,7 +62,7 @@ fn handle_connection(stream: &mut TcpStream) -> Result<(), std::io::Error> {
|
||||
|
||||
let syscall = Syscall::decode(&buf).unwrap();
|
||||
|
||||
trace!("{:?}", syscall);
|
||||
// trace!("{:?}", syscall);
|
||||
|
||||
// let result = match decoded {
|
||||
// Syscall::Write(..) => 0,
|
||||
@@ -82,7 +83,9 @@ fn handle_connection(stream: &mut TcpStream) -> Result<(), std::io::Error> {
|
||||
}
|
||||
};
|
||||
|
||||
let result = result.rax;
|
||||
// ptrace:;
|
||||
|
||||
let result = result.gs as i64;
|
||||
|
||||
// let result: u64 = result.unwrap().rax;
|
||||
|
||||
@@ -90,6 +93,8 @@ fn handle_connection(stream: &mut TcpStream) -> Result<(), std::io::Error> {
|
||||
|
||||
// let result = 0;
|
||||
|
||||
// ptrace::
|
||||
|
||||
trace!("{:?} -> {:?}", syscall, result);
|
||||
|
||||
let bytes: [u8; 8] = result.to_be_bytes();
|
||||
|
||||
+1
-1
@@ -196,7 +196,7 @@ impl UserProcess {
|
||||
r8: u64,
|
||||
r9: u64,
|
||||
) -> HostResult<user_regs_struct> {
|
||||
log::trace!("UserProcess {} Syscall: {:#?}", self.pid, sys_call);
|
||||
// log::trace!("UserProcess {} Syscall: {:#?}", self.pid, sys_call);
|
||||
let syscall_instruction = [0x0Fu8, 0x05u8];
|
||||
|
||||
// Cache original registers, original instruction pointer (rip), and the original instructions
|
||||
|
||||
+1
-1
@@ -43,7 +43,7 @@ impl Host {
|
||||
let mut response = [0u8; 8];
|
||||
self.reader.read_exact(&mut response).unwrap();
|
||||
|
||||
let response = u64::from_be_bytes(response);
|
||||
let response = i64::from_be_bytes(response);
|
||||
|
||||
println!("{:?}", response);
|
||||
|
||||
|
||||
+154
@@ -0,0 +1,154 @@
|
||||
use libc::forkpty;
|
||||
use nix::sys::wait::wait;
|
||||
use nix::{
|
||||
errno::Errno,
|
||||
sys::{ptrace::Options, signal::Signal},
|
||||
};
|
||||
use std::{
|
||||
env::args,
|
||||
os::unix::process::CommandExt,
|
||||
process::{self, Command},
|
||||
thread,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use log::{debug, error, info, trace, warn};
|
||||
use nix::{
|
||||
sys::{
|
||||
ptrace,
|
||||
wait::{self, WaitStatus},
|
||||
},
|
||||
unistd::{ForkResult, Pid, fork},
|
||||
};
|
||||
|
||||
// pub type Error = Result<(), std::fmt::Error>;
|
||||
|
||||
#[derive(Debug)]
|
||||
enum HavocError {
|
||||
Wait,
|
||||
Register(Errno),
|
||||
Ptrace(Errno),
|
||||
}
|
||||
|
||||
fn main() -> Result<(), std::fmt::Error> {
|
||||
pretty_env_logger::formatted_builder()
|
||||
.filter_level(log::LevelFilter::Trace)
|
||||
.init();
|
||||
|
||||
let args = &(args().collect::<Vec<String>>())[1..];
|
||||
|
||||
match unsafe { fork() } {
|
||||
Ok(ForkResult::Child) => run_child(args),
|
||||
Ok(ForkResult::Parent { child }) => run_parent(child),
|
||||
Err(e) => panic!("Could not fork main process: {}", e),
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run_child(args: &[String]) {
|
||||
info!("havoc child process executing as {}", process::id());
|
||||
info!("Running: {:?}", args);
|
||||
ptrace::traceme().expect("OS could not be bothered to trace me");
|
||||
|
||||
// loop {
|
||||
// println!("test");
|
||||
// thread::sleep(Duration::from_secs(1));
|
||||
// }
|
||||
// unsafe { exit(0) };
|
||||
let e = Command::new(args.join(" ")).exec();
|
||||
}
|
||||
|
||||
fn run_parent(pid: Pid) {
|
||||
// wait for our child process to be ready
|
||||
let ws = wait().expect("Parent failed waiting for child");
|
||||
// info!("Child process ready with signal: {ws:?}, will ask it to continue untill syscall");
|
||||
|
||||
setup_tracing(pid).expect(format!("Parent failed to set up tracing for {pid:?}").as_str());
|
||||
// trace_syscall(pid, None).expect(format!("Parent failed tracing for {pid:?}").as_str());
|
||||
|
||||
loop {
|
||||
match ptrace::syscall(pid, None).map_err(HavocError::Ptrace) {
|
||||
Ok(_) => { /* nop */ }
|
||||
Err(e) => {
|
||||
error!("error: {:?}", e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
println!("pid: {}", pid);
|
||||
}
|
||||
fn wait_for_signal() -> Result<(), HavocError> {
|
||||
match wait() {
|
||||
Ok(WaitStatus::Stopped(pid_t, sig_num)) => handle_child_stopped(sig_num, pid_t),
|
||||
|
||||
Ok(WaitStatus::Exited(pid, exit_status)) => {
|
||||
debug!("Child with pid: {} exited with status {}", pid, exit_status);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Ok(status) => {
|
||||
warn!("Received unhandled wait status: {:?}", status);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Err(err) => {
|
||||
error!("An error occurred: {:?}", err);
|
||||
Err(HavocError::Wait)
|
||||
}
|
||||
}
|
||||
}
|
||||
fn handle_sigtrap(pid_t: Pid) -> Result<(), HavocError> {
|
||||
let regs = ptrace::getregs(pid_t).map_err(HavocError::Register)?;
|
||||
if regs.orig_rax == libc::SYS_msync as u64 {
|
||||
if regs.rax == -libc::ENOSYS as u64 {
|
||||
info!("Entry of syscall in {pid_t} : {}", regs.orig_rax);
|
||||
} else {
|
||||
info!("Exit of syscall in {pid_t} : {}", regs.orig_rax);
|
||||
// handle_msync(msync_counter, regs, pid_t)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn handle_child_stopped(sig_num: Signal, pid_t: Pid) -> Result<(), HavocError> {
|
||||
match sig_num {
|
||||
Signal::SIGTRAP => {
|
||||
handle_sigtrap(pid_t)?;
|
||||
trace_syscall(pid_t, None)
|
||||
}
|
||||
Signal::SIGSTOP => trace_syscall(pid_t, Some(Signal::SIGSTOP)),
|
||||
// ... some corner cases like SIGWINCH
|
||||
_ => trace_syscall(pid_t, Some(sig_num)),
|
||||
}
|
||||
}
|
||||
fn trace_syscall(pid: Pid, sig_num: Option<Signal>) -> Result<(), HavocError> {
|
||||
ptrace::syscall(pid, None).map_err(HavocError::Ptrace)?;
|
||||
trace!("{} -> {:?}", pid, sig_num);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Setup the preace options to also trace fork, clone and vfork
|
||||
fn setup_tracing(pid: Pid) -> Result<(), HavocError> {
|
||||
// ptrace::setoptions(
|
||||
// pid,
|
||||
// Options::PTRACE_O_TRACEFORK
|
||||
// .union(Options::PTRACE_O_TRACECLONE)
|
||||
// .union(Options::PTRACE_O_TRACEVFORK),
|
||||
// )
|
||||
ptrace::attach(pid).map_err(HavocError::Ptrace)
|
||||
}
|
||||
|
||||
// fn next_syscall(child_pid: libc::pid_t) -> Result<i64, OsError> {
|
||||
// match WaitPID::from_process(child_pid)? {
|
||||
// WaitPID::SysCall { .. } => (),
|
||||
// x => {
|
||||
// return Err(OsError::new(
|
||||
// ErrorKind::Other,
|
||||
// format!("Expected syscall event, got {:?} instead", x),
|
||||
// ));
|
||||
// }
|
||||
// }
|
||||
// let number = get_syscall_number(child_pid)?;
|
||||
// p_trace_syscall(child_pid, None)?;
|
||||
// Ok(number)
|
||||
// }
|
||||
@@ -9,6 +9,7 @@ bincode = "2.0.1"
|
||||
# kernel = "6.17"
|
||||
# kernel = "1.0.0"
|
||||
libc = "0.2.175"
|
||||
log = "0.4.27"
|
||||
nix = "0.30.1"
|
||||
syscaller = "0.2.2"
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ const CONFIG: bincode::config::Configuration = bincode::config::standard();
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fmt::Debug,
|
||||
marker::PhantomData,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use bincode::{Decode, Encode};
|
||||
use log::error;
|
||||
|
||||
use crate::{types, types::*};
|
||||
|
||||
@@ -12,11 +13,19 @@ impl Syscall {
|
||||
}
|
||||
|
||||
pub fn decode(bytes: &[u8]) -> Option<Self> {
|
||||
if let Ok((decoded, _)) = bincode::decode_from_slice(&bytes[..], crate::CONFIG) {
|
||||
Some(decoded)
|
||||
} else {
|
||||
None
|
||||
match bincode::decode_from_slice(&bytes[..], crate::CONFIG) {
|
||||
Ok((decoded, _)) => Some(decoded),
|
||||
Err(e) => {
|
||||
error!("Decoding error: {}", e);
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
// if let Ok((decoded, _)) = bincode::decode_from_slice(&bytes[..], crate::CONFIG) {
|
||||
// Some(decoded)
|
||||
// } else {
|
||||
// None
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
use std::ffi::CStr;
|
||||
use std::fmt::Debug;
|
||||
use std::ptr;
|
||||
use std::{ffi::CStr, mem::transmute};
|
||||
|
||||
use bincode::{Decode, Encode};
|
||||
use bincode::de::read::Reader;
|
||||
use bincode::enc::write::Writer;
|
||||
use bincode::error::DecodeError;
|
||||
use bincode::{BorrowDecode, Decode, Encode};
|
||||
use log::trace;
|
||||
|
||||
use crate::{AsPtr, types::MAX_STR_LEN};
|
||||
|
||||
@@ -15,12 +20,11 @@ fn trunc(str: &str) -> String {
|
||||
out_str
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode)]
|
||||
pub struct StrRef(pub libc::c_ulong);
|
||||
pub struct StrRef(pub *const libc::c_char);
|
||||
|
||||
impl StrRef {
|
||||
pub fn new(ptr: libc::c_ulong) -> Self {
|
||||
Self(ptr)
|
||||
Self(ptr as *const libc::c_char)
|
||||
}
|
||||
pub fn read(&self) -> String {
|
||||
let ptr = self.0 as *const libc::c_char;
|
||||
@@ -43,3 +47,56 @@ impl AsPtr for StrRef {
|
||||
self.0 as libc::c_ulong
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Encode for StrRef {
|
||||
fn encode<E: bincode::enc::Encoder>(
|
||||
&self,
|
||||
encoder: &mut E,
|
||||
) -> Result<(), bincode::error::EncodeError> {
|
||||
let data = unsafe { CStr::from_ptr(self.0 as *const libc::c_char) };
|
||||
let data = data.to_bytes_with_nul();
|
||||
|
||||
// println!("len: {}, data: {:?}", data.len(), data);
|
||||
encoder.writer().write(&data.len().to_be_bytes())?;
|
||||
data.encode(encoder)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, Context> Decode<Context> for StrRef {
|
||||
fn decode<D: bincode::de::Decoder<Context = Context>>(
|
||||
decoder: &mut D,
|
||||
) -> Result<Self, bincode::error::DecodeError> {
|
||||
let mut len = [0u8; 8];
|
||||
decoder.reader().read(&mut len)?;
|
||||
let len = usize::from_be_bytes(len) + 1;
|
||||
|
||||
let data = &decoder.reader().peek_read(len).unwrap()[1..];
|
||||
|
||||
// [0u8; 32];
|
||||
// decoder.reader().read(&mut data)?;
|
||||
// trace!("len: {}, data: {:?}", len, data);
|
||||
let data = CStr::from_bytes_with_nul(&data).unwrap();
|
||||
|
||||
let ptr = data.as_ptr();
|
||||
|
||||
Ok(StrRef(ptr))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, Context> BorrowDecode<'de, Context> for StrRef {
|
||||
fn borrow_decode<D: bincode::de::BorrowDecoder<'de, Context = Context>>(
|
||||
decoder: &mut D,
|
||||
) -> Result<Self, bincode::error::DecodeError> {
|
||||
let mut len = [0u8; 8];
|
||||
decoder.reader().read(&mut len)?;
|
||||
let len = usize::from_be_bytes(len) + 1;
|
||||
|
||||
let data = &decoder.reader().peek_read(len).unwrap()[1..];
|
||||
let data = CStr::from_bytes_with_nul(&data).unwrap();
|
||||
|
||||
let ptr = data.as_ptr();
|
||||
|
||||
Ok(StrRef(ptr))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user