Work on things.

This commit is contained in:
Michael Mikovsky
2025-08-23 09:12:40 -06:00
parent 8ba4e92d60
commit 0e36538e84
18 changed files with 347 additions and 268 deletions
+8 -2
View File
@@ -1,8 +1,14 @@
TODO:
[ ] - Copy memory over network
Server:
[x] - Intercept syscalls
[x] - Transmit syscalls over network
[x] - Execute syscalls
[x] - Read memory from buffers.
[ ] - Mutate syscalls into Rust
[ ] - Copy memory over network
[ ] - Figure out which system calls should be forwarded and not
Mimic:
[x] - Execute syscalls
[ ] - Mutate syscalls back into C
[ ] - Create subprocess and mimic system calls in it.
+4 -2
View File
@@ -4,7 +4,7 @@ use std::{
thread,
};
use syscall_lib::{Syscall, execute_syscall};
use syscall_lib::Syscall;
fn main() {
println!("This program has PID: {}", std::process::id());
@@ -43,7 +43,9 @@ fn handle_connection(stream: &mut TcpStream) -> Result<(), std::io::Error> {
// Syscall::Write(..) => 0,
// _ => syscall_exec::execute_syscall(decoded),
// };
let result = execute_syscall(decoded);
let result = unsafe { decoded.execute_syscall() };
// let result = 0;
println!("{:?}", result);
+1 -1
View File
@@ -3,7 +3,7 @@ use std::{
net::TcpStream,
};
use syscall_lib::{ProgramMemory, Syscall};
use syscall_lib::Syscall;
// use crate::syscall_exec;
+3 -18
View File
@@ -85,10 +85,6 @@ extern "C" fn hook(
}
};
// if syscall_should_proxy(syscall_num) {
// return InterceptResult::Forward;
// }
unsafe {
unset_hook_fn();
}
@@ -96,22 +92,9 @@ extern "C" fn hook(
let args = [arg0, arg1, arg2, arg3, arg4, arg5];
let syscall = Syscall::from_syscall(syscall_num as libc::c_long, args).unwrap();
// if !syscall_should_proxy(&syscall) {
// return InterceptResult::Forward;
// }
// Return if is print
// if syscall_num == libc::SYS_write as _ && arg0 == 1 {
// return InterceptResult::Forward;
// }
// if syscall_num == libc::SYS_close as _ && arg0 == 1 {
// return InterceptResult::Forward;
// }
if let Syscall::Unimplemented(_) = syscall {
println!("{:?}", syscall);
if let Syscall::Unimplemented(_) = syscall {
unsafe {
set_hook_fn(hook);
}
@@ -121,6 +104,8 @@ extern "C" fn hook(
*result = unsafe { syscall.execute_syscall() };
println!("{:?} -> {}", syscall, result);
// unsafe {
// #[allow(static_mut_refs)]
// if let Some(host) = HOST.as_ref() {
-2
View File
@@ -1,2 +0,0 @@
mod x86_64;
pub use x86_64::*;
+7 -2
View File
@@ -1,5 +1,3 @@
mod arch_types;
mod proxy_list;
mod syscall;
mod types;
@@ -16,6 +14,13 @@ use bincode::{Decode, Encode};
pub use syscall::Syscall;
pub use types::*;
pub enum FwdType {
Local,
Remote,
Clone,
Force { return_code: libc::c_int },
}
// Type aliases for pointers to improve readability.
// pub type Ptr<_> = libc::c_long;
// pub type ConstPtr<_> = libc::c_long;
+14 -16
View File
@@ -1,5 +1,3 @@
use std::mem::transmute;
use crate::*;
impl Syscall {
@@ -30,9 +28,9 @@ impl Syscall {
flags: args[1] as libc::c_int,
mode: args[2] as libc::c_int,
},
libc::SYS_close => Syscall::Close {
fd: args[0] as libc::c_uint,
},
// libc::SYS_close => Syscall::Close {
// fd: args[0] as libc::c_uint,
// },
libc::SYS_stat => Syscall::Stat {
path: StrRef::new(args[0]),
statbuf: Ptr::new(args[1]),
@@ -55,14 +53,14 @@ impl Syscall {
// offset: args[1] as libc::off_t,
// whence: args[2] as libc::c_uint,
// },
libc::SYS_mmap => Syscall::Mmap {
addr: PtrVoid(args[0]),
len: args[1] as libc::size_t,
prot: args[2] as libc::c_int,
flags: args[3] as libc::c_int,
fd: args[4] as libc::c_int,
offset: args[5] as libc::off_t,
},
// libc::SYS_mmap => Syscall::Mmap {
// addr: PtrVoid(args[0]),
// len: args[1] as libc::size_t,
// prot: args[2] as libc::c_int,
// flags: args[3] as libc::c_int,
// fd: args[4] as libc::c_int,
// offset: args[5] as libc::off_t,
// },
// libc::SYS_mprotect => Syscall::Mprotect {
// addr: args[0] as Ptr<libc::c_void>,
// len: args[1] as libc::size_t,
@@ -925,9 +923,9 @@ impl Syscall {
// rqtp: args[2] as ConstPtr<libc::timespec>,
// rmtp: args[3] as Ptr<libc::timespec>,
// },
// libc::SYS_exit_group => Syscall::ExitGroup {
// error_code: args[0] as libc::c_int,
// },
libc::SYS_exit_group => Syscall::ExitGroup {
error_code: args[0] as libc::c_int,
},
// libc::SYS_epoll_wait => Syscall::EpollWait {
// epfd: args[0] as libc::c_int,
// events: args[1] as Ptr<libc::epoll_event>,
+3 -3
View File
@@ -71,8 +71,6 @@ use syscaller::{syscall0, syscall1, syscall2, syscall3, syscall4, syscall5, sysc
// }
// }
use libc::{c_long, c_ulong};
// The Syscall enum and type aliases from the previous response are assumed to be present here.
#[allow(unused_unsafe, unsafe_op_in_unsafe_fn)]
impl Syscall {
@@ -411,7 +409,9 @@ impl Syscall {
// Syscall::ClockNanosleep(arg0, arg1, arg2, arg3) => unsafe {
// syscall4(230, arg0, arg1, arg2, arg3)
// },
// Syscall::ExitGroup(arg0) => unsafe { syscall1(231, arg0) },
Syscall::ExitGroup { error_code } => unsafe {
syscall1(libc::SYS_exit_group as usize, *error_code as usize)
},
// Syscall::EpollWait(arg0, arg1, arg2, arg3) => unsafe {
// syscall4(232, arg0, arg1, arg2, arg3)
// },
+7 -6
View File
@@ -1,9 +1,10 @@
use bincode::{Decode, Encode};
use crate::{arch_types, types::*};
use crate::{types, types::*};
mod create;
mod exec;
mod proxy_list;
impl Syscall {
pub fn encode(&self) -> Vec<u8> {
@@ -45,11 +46,11 @@ pub enum Syscall {
},
Stat {
path: StrRef,
statbuf: Ptr<arch_types::stat>,
statbuf: Ptr<types::stat>,
},
Fstat {
fd: libc::c_uint,
statbuf: Ptr<arch_types::stat>,
statbuf: Ptr<types::stat>,
},
// Lstat {
// path: Buf<libc::c_char>,
@@ -935,9 +936,9 @@ pub enum Syscall {
// rqtp: Ptr<libc::timespec>,
// rmtp: Ptr<libc::timespec>,
// },
// ExitGroup {
// error_code: libc::c_int,
// },
ExitGroup {
error_code: libc::c_int,
},
// EpollWait {
// epfd: libc::c_int,
// events: Ptr<libc::epoll_event>,
@@ -1,4 +1,13 @@
// use crate::{Syscall, syscall_num::Sysno};
use crate::{FwdType, Syscall};
impl Syscall {
pub fn get_fwd_type(&self) -> FwdType {
match self {
// Syscall::Close { fd }
_ => FwdType::Local,
}
}
}
// pub fn syscall_should_proxy(syscall: &Syscall) -> bool {
// match syscall {
-210
View File
@@ -1,210 +0,0 @@
use core::slice;
use std::any::{self, Any, TypeId};
use std::ffi::CStr;
use std::marker::PhantomData;
use std::{fmt::Debug, mem::transmute};
use bincode::{Decode, Encode};
const MAX_STR_LEN: usize = 30;
pub trait AsPtr {
fn as_ptr(&self) -> usize;
}
#[derive(Encode, Decode)]
pub struct Ptr<T>(pub libc::c_ulong, PhantomData<T>);
impl<T> Ptr<T>
where
T: Debug,
{
pub fn new(location: libc::c_ulong) -> Self {
Self(location, PhantomData) // ooo
}
}
impl<T: Debug> Debug for Ptr<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
unsafe {
let ptr = transmute::<libc::c_ulong, *const T>(self.0);
f.write_str(format!("0x{:X} -> {:?}", self.0, *ptr).as_str())
}
}
}
impl<T: Debug> AsPtr for Ptr<T> {
fn as_ptr(&self) -> usize {
self.0 as usize
}
}
#[derive(Encode, Decode)]
pub struct PtrVoid(pub libc::c_ulong);
impl PtrVoid {
pub fn new(location: libc::c_ulong) -> Self {
Self(location) // ooo
}
}
impl Debug for PtrVoid {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(format!("0x{:X} -> void", self.0).as_str())
}
}
impl AsPtr for PtrVoid {
fn as_ptr(&self) -> usize {
self.0 as usize
}
}
fn trunc(str: &str) -> String {
let mut out_str = str[0..MAX_STR_LEN.min(str.len())].to_string();
if str.len() > MAX_STR_LEN {
out_str += "...";
}
out_str
}
#[derive(Encode, Decode)]
pub struct Buf<T>(pub libc::c_ulong, PhantomData<T>);
impl<T: Debug> Buf<T> {
pub fn new(ptr: libc::c_ulong) -> Self {
Self(ptr, PhantomData)
}
pub fn read(&self, len: usize) -> &[T] {
// Convert the address to a raw pointer
let ptr = self.0 as *const T;
// Create a slice from the raw pointer and length
let slice = unsafe { slice::from_raw_parts::<T>(ptr, len) };
// Copy the data into a Vec to return owned data
slice
}
}
impl<T: Debug> Debug for Buf<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(format!("Buf<{}>", any::type_name::<T>()).as_str())
// f.debug_tuple("Buf").field(self.read().len()).finish()
}
}
impl<T: Debug> AsPtr for Buf<T> {
fn as_ptr(&self) -> usize {
self.0 as usize
}
}
#[derive(Encode, Decode)]
pub struct StrRef(pub libc::c_ulong);
impl StrRef {
pub fn new(ptr: libc::c_ulong) -> Self {
Self(ptr)
}
pub fn read(&self) -> String {
let ptr = self.0 as *const libc::c_char;
let c_str = unsafe { CStr::from_ptr(ptr) };
c_str.to_string_lossy().to_string()
}
}
impl Debug for StrRef {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(format!("\"{}\"", trunc(self.read().as_str())).as_str())
// f.debug_tuple("Buf").field(self.read().len()).finish()
}
}
impl AsPtr for StrRef {
fn as_ptr(&self) -> usize {
self.0 as usize
}
}
#[repr(u8)]
#[derive(Encode, Decode)]
pub enum Void {
__variant1,
__variant2,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct AioContext;
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct Iocb;
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct IoEvent;
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct IoUringParams;
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct Mmsghdr;
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct GetcpuCache;
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct RobustListHead;
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct FutexWaitv;
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct KexecSegment;
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct CapUserHeaderT;
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct CapUserDataT;
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct Rlimit64;
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct FileHandle;
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct PerfEventAttr;
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct SchedAttr;
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct CloneArgs;
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct BpfAttr;
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct Statx;
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct Rseq;
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct OpenHow;
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct MountAttr;
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct LandlockRulesetAttr;
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct LandlockRule;
+39
View File
@@ -0,0 +1,39 @@
use core::slice;
use std::any::type_name;
use std::{fmt::Debug, marker::PhantomData};
use bincode::{Decode, Encode};
use crate::AsPtr;
#[derive(Encode, Decode)]
pub struct Buf<T>(pub libc::c_ulong, PhantomData<T>);
impl<T: Debug> Buf<T> {
pub fn new(ptr: libc::c_ulong) -> Self {
Self(ptr, PhantomData)
}
pub fn read(&self, len: usize) -> &[T] {
// Convert the address to a raw pointer
let ptr = self.0 as *const T;
// Create a slice from the raw pointer and length
let slice = unsafe { slice::from_raw_parts::<T>(ptr, len) };
// Copy the data into a Vec to return owned data
slice
}
}
impl<T: Debug> Debug for Buf<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(format!("Buf<{}>", type_name::<T>()).as_str())
// f.debug_tuple("Buf").field(self.read().len()).finish()
}
}
impl<T: Debug> AsPtr for Buf<T> {
fn as_ptr(&self) -> usize {
self.0 as usize
}
}
+20
View File
@@ -0,0 +1,20 @@
mod ptr;
pub use ptr::Ptr;
mod ptr_void;
pub use ptr_void::PtrVoid;
mod buf;
pub use buf::Buf;
mod str_ref;
pub use str_ref::StrRef;
mod x86_64;
pub use x86_64::*;
const MAX_STR_LEN: usize = 30;
pub trait AsPtr {
fn as_ptr(&self) -> usize;
}
+69
View File
@@ -0,0 +1,69 @@
use std::mem::transmute;
use std::ptr;
use std::{fmt::Debug, marker::PhantomData};
use bincode::{BorrowDecode, Decode, Encode};
use crate::AsPtr;
pub struct Ptr<T>(pub libc::c_ulong, PhantomData<T>);
impl<T> Ptr<T>
where
T: Debug,
{
pub fn new(location: libc::c_ulong) -> Self {
Self(location, PhantomData) // ooo
}
}
impl<T: Debug> Debug for Ptr<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
unsafe {
let ptr = transmute::<libc::c_ulong, *const T>(self.0);
f.write_str(format!("0x{:X} -> {:?}", self.0, *ptr).as_str())
}
}
}
impl<T: Debug> AsPtr for Ptr<T> {
fn as_ptr(&self) -> usize {
self.0 as usize
}
}
impl<T: Encode> Encode for Ptr<T> {
fn encode<E: bincode::enc::Encoder>(
&self,
encoder: &mut E,
) -> Result<(), bincode::error::EncodeError> {
let ptr = unsafe { transmute::<libc::c_ulong, *const T>(self.0) };
let data = unsafe { ptr::read(ptr) };
data.encode(encoder)?;
Ok(())
}
}
impl<T: Decode<Context> + Debug, Context> Decode<Context> for Ptr<T> {
fn decode<D: bincode::de::Decoder<Context = Context>>(
decoder: &mut D,
) -> Result<Self, bincode::error::DecodeError> {
let data = <T>::decode(decoder)?;
let ptr = &data as *const T;
let ptr = unsafe { transmute::<*const T, libc::c_ulong>(ptr) };
Ok(Ptr::new(ptr))
}
}
impl<'de, T: BorrowDecode<'de, Context> + Debug, Context> BorrowDecode<'de, Context> for Ptr<T> {
fn borrow_decode<D: bincode::de::BorrowDecoder<'de, Context = Context>>(
decoder: &mut D,
) -> Result<Self, bincode::error::DecodeError> {
let data = <T>::borrow_decode(decoder)?;
let ptr = &data as *const T;
let ptr = unsafe { transmute::<*const T, libc::c_ulong>(ptr) };
Ok(Ptr::new(ptr))
}
}
+26
View File
@@ -0,0 +1,26 @@
use std::fmt::Debug;
use bincode::{Decode, Encode};
use crate::AsPtr;
#[derive(Encode, Decode)]
pub struct PtrVoid(pub libc::c_ulong);
impl PtrVoid {
pub fn new(location: libc::c_ulong) -> Self {
Self(location) // ooo
}
}
impl Debug for PtrVoid {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(format!("0x{:X} -> void", self.0).as_str())
}
}
impl AsPtr for PtrVoid {
fn as_ptr(&self) -> usize {
self.0 as usize
}
}
+45
View File
@@ -0,0 +1,45 @@
use std::ffi::CStr;
use std::fmt::Debug;
use bincode::{Decode, Encode};
use crate::{AsPtr, types::MAX_STR_LEN};
fn trunc(str: &str) -> String {
let mut out_str = str[0..MAX_STR_LEN.min(str.len())].to_string();
if str.len() > MAX_STR_LEN {
out_str += "...";
}
out_str
}
#[derive(Encode, Decode)]
pub struct StrRef(pub libc::c_ulong);
impl StrRef {
pub fn new(ptr: libc::c_ulong) -> Self {
Self(ptr)
}
pub fn read(&self) -> String {
let ptr = self.0 as *const libc::c_char;
let c_str = unsafe { CStr::from_ptr(ptr) };
c_str.to_string_lossy().to_string()
}
}
impl Debug for StrRef {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(format!("\"{}\"", trunc(self.read().as_str())).as_str())
// f.debug_tuple("Buf").field(self.read().len()).finish()
}
}
impl AsPtr for StrRef {
fn as_ptr(&self) -> usize {
self.0 as usize
}
}
+86
View File
@@ -0,0 +1,86 @@
use core::slice;
use std::any::{self, Any, TypeId};
use std::ffi::CStr;
use std::marker::PhantomData;
use std::ptr;
use std::task::Context;
use std::{fmt::Debug, mem::transmute};
use bincode::{BorrowDecode, Decode, Encode};
#[repr(u8)]
#[derive(Encode, Decode)]
pub enum Void {
__variant1,
__variant2,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct AioContext;
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct Iocb;
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct IoEvent;
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct IoUringParams;
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct Mmsghdr;
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct GetcpuCache;
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct RobustListHead;
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct FutexWaitv;
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct KexecSegment;
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct CapUserHeaderT;
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct CapUserDataT;
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct Rlimit64;
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct FileHandle;
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct PerfEventAttr;
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct SchedAttr;
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct CloneArgs;
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct BpfAttr;
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct Statx;
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct Rseq;
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct OpenHow;
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct MountAttr;
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct LandlockRulesetAttr;
#[repr(C)]
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct LandlockRule;