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]
|
[dependencies]
|
||||||
ctor = "0.5.0"
|
ctor = "0.5.0"
|
||||||
libc = "0.2.175"
|
libc = "0.2.175"
|
||||||
|
log = "0.4.27"
|
||||||
|
nix = { version = "0.30.1", features = ["process", "fs", "feature", "ptrace"] }
|
||||||
pretty_env_logger = "0.5.0"
|
pretty_env_logger = "0.5.0"
|
||||||
|
subprocess = "0.2.9"
|
||||||
# syscalls = "0.6.18"
|
# syscalls = "0.6.18"
|
||||||
syscall_lib = { path = "syscall_lib" }
|
syscall_lib = { path = "syscall_lib" }
|
||||||
syscaller = "0.2.2"
|
syscaller = "0.2.2"
|
||||||
|
|
||||||
[build-dependencies]
|
# [build-dependencies]
|
||||||
cmake = "0.1"
|
# cmake = "0.1"
|
||||||
|
|
||||||
[lib]
|
# [lib]
|
||||||
name = "intercept"
|
# name = "intercept"
|
||||||
crate-type = ["rlib", "cdylib"]
|
# crate-type = ["rlib", "cdylib"]
|
||||||
|
|||||||
+7
-2
@@ -10,6 +10,7 @@ use std::{
|
|||||||
|
|
||||||
use log::{error, info, trace};
|
use log::{error, info, trace};
|
||||||
use nix::libc::{self, MAP_ANONYMOUS, MAP_PRIVATE, PROT_READ, PROT_WRITE, user_regs_struct};
|
use nix::libc::{self, MAP_ANONYMOUS, MAP_PRIVATE, PROT_READ, PROT_WRITE, user_regs_struct};
|
||||||
|
use nix::sys::ptrace;
|
||||||
use nix::unistd::Pid;
|
use nix::unistd::Pid;
|
||||||
use subprocess::{Popen, PopenConfig, Redirection};
|
use subprocess::{Popen, PopenConfig, Redirection};
|
||||||
use syscall_lib::Syscall;
|
use syscall_lib::Syscall;
|
||||||
@@ -61,7 +62,7 @@ fn handle_connection(stream: &mut TcpStream) -> Result<(), std::io::Error> {
|
|||||||
|
|
||||||
let syscall = Syscall::decode(&buf).unwrap();
|
let syscall = Syscall::decode(&buf).unwrap();
|
||||||
|
|
||||||
trace!("{:?}", syscall);
|
// trace!("{:?}", syscall);
|
||||||
|
|
||||||
// let result = match decoded {
|
// let result = match decoded {
|
||||||
// Syscall::Write(..) => 0,
|
// 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;
|
// let result: u64 = result.unwrap().rax;
|
||||||
|
|
||||||
@@ -90,6 +93,8 @@ fn handle_connection(stream: &mut TcpStream) -> Result<(), std::io::Error> {
|
|||||||
|
|
||||||
// let result = 0;
|
// let result = 0;
|
||||||
|
|
||||||
|
// ptrace::
|
||||||
|
|
||||||
trace!("{:?} -> {:?}", syscall, result);
|
trace!("{:?} -> {:?}", syscall, result);
|
||||||
|
|
||||||
let bytes: [u8; 8] = result.to_be_bytes();
|
let bytes: [u8; 8] = result.to_be_bytes();
|
||||||
|
|||||||
+1
-1
@@ -196,7 +196,7 @@ impl UserProcess {
|
|||||||
r8: u64,
|
r8: u64,
|
||||||
r9: u64,
|
r9: u64,
|
||||||
) -> HostResult<user_regs_struct> {
|
) -> 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];
|
let syscall_instruction = [0x0Fu8, 0x05u8];
|
||||||
|
|
||||||
// Cache original registers, original instruction pointer (rip), and the original instructions
|
// Cache original registers, original instruction pointer (rip), and the original instructions
|
||||||
|
|||||||
+1
-1
@@ -43,7 +43,7 @@ impl Host {
|
|||||||
let mut response = [0u8; 8];
|
let mut response = [0u8; 8];
|
||||||
self.reader.read_exact(&mut response).unwrap();
|
self.reader.read_exact(&mut response).unwrap();
|
||||||
|
|
||||||
let response = u64::from_be_bytes(response);
|
let response = i64::from_be_bytes(response);
|
||||||
|
|
||||||
println!("{:?}", 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 = "6.17"
|
||||||
# kernel = "1.0.0"
|
# kernel = "1.0.0"
|
||||||
libc = "0.2.175"
|
libc = "0.2.175"
|
||||||
|
log = "0.4.27"
|
||||||
nix = "0.30.1"
|
nix = "0.30.1"
|
||||||
syscaller = "0.2.2"
|
syscaller = "0.2.2"
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ const CONFIG: bincode::config::Configuration = bincode::config::standard();
|
|||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
fmt::Debug,
|
fmt::Debug,
|
||||||
marker::PhantomData,
|
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use bincode::{Decode, Encode};
|
use bincode::{Decode, Encode};
|
||||||
|
use log::error;
|
||||||
|
|
||||||
use crate::{types, types::*};
|
use crate::{types, types::*};
|
||||||
|
|
||||||
@@ -12,11 +13,19 @@ impl Syscall {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn decode(bytes: &[u8]) -> Option<Self> {
|
pub fn decode(bytes: &[u8]) -> Option<Self> {
|
||||||
if let Ok((decoded, _)) = bincode::decode_from_slice(&bytes[..], crate::CONFIG) {
|
match bincode::decode_from_slice(&bytes[..], crate::CONFIG) {
|
||||||
Some(decoded)
|
Ok((decoded, _)) => Some(decoded),
|
||||||
} else {
|
Err(e) => {
|
||||||
None
|
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::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};
|
use crate::{AsPtr, types::MAX_STR_LEN};
|
||||||
|
|
||||||
@@ -15,12 +20,11 @@ fn trunc(str: &str) -> String {
|
|||||||
out_str
|
out_str
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Encode, Decode)]
|
pub struct StrRef(pub *const libc::c_char);
|
||||||
pub struct StrRef(pub libc::c_ulong);
|
|
||||||
|
|
||||||
impl StrRef {
|
impl StrRef {
|
||||||
pub fn new(ptr: libc::c_ulong) -> Self {
|
pub fn new(ptr: libc::c_ulong) -> Self {
|
||||||
Self(ptr)
|
Self(ptr as *const libc::c_char)
|
||||||
}
|
}
|
||||||
pub fn read(&self) -> String {
|
pub fn read(&self) -> String {
|
||||||
let ptr = self.0 as *const libc::c_char;
|
let ptr = self.0 as *const libc::c_char;
|
||||||
@@ -43,3 +47,56 @@ impl AsPtr for StrRef {
|
|||||||
self.0 as libc::c_ulong
|
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