Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 22 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,5 +57,5 @@ path = "examples/pin.rs"
[dependencies]

[target.'cfg(all(target_os = "linux", target_arch = "x86_64"))'.dependencies]
lde = "0.3"
iced-x86 = { version = "1.21.0", default-features = false, features = [ "decoder", "no_std", "encoder"]}
libc = "0.2.178"
24 changes: 24 additions & 0 deletions examples/func_swap.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use core::slice;
use std::{
arch::asm,
hint::black_box,
sync::atomic::{AtomicBool, AtomicU64},
};

use corroded_rs::func::{function_copy, function_copy_plain};

fn main() {
a();
function_copy_plain(b, a);
a();
}

#[inline(never)]
extern "C" fn a() {
println!("Hello");
}

#[inline(never)]
extern "C" fn b() {
println!("World");
}
2 changes: 1 addition & 1 deletion examples/pin.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use corroded_rs::pin::{unpin_mut, move_pinned, swap_pinned, Unpinned, PinEscape, Moveable};
use corroded_rs::pin::{move_pinned, swap_pinned, unpin_mut, Moveable, PinEscape, Unpinned};

struct SelfReferential {
data: i32,
Expand Down
11 changes: 11 additions & 0 deletions examples/remove_segfaults.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use std::ptr::{self, null_mut};

use corroded_rs::memory::remove_segfaults;

fn main() {
remove_segfaults();
unsafe {
ptr::write_volatile(null_mut::<u8>(), 67);
println!("WE ARE ALIVE");
}
}
22 changes: 3 additions & 19 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 15 additions & 6 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,12 @@
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";

crane.url = "github:ipetkov/crane";

flake-utils.url = "github:numtide/flake-utils";
};

outputs =
{
nixpkgs,
crane,
flake-utils,
...
}:
Expand All @@ -21,12 +18,24 @@
let
pkgs = nixpkgs.legacyPackages.${system};

craneLib = crane.mkLib pkgs;
rust-seer = pkgs.seer.overrideAttrs(finalAttrs: previousAttrs: {
patchPhase = ''
substituteInPlace src/{SeerGdbConfigPage,SeerMainWindow,SeerGdbWidget}.cpp \
--replace-fail "/usr/bin/gdb" "${pkgs.rustc}/bin/rust-gdb"
'';
});
in
{

devShells.default = craneLib.devShell {
packages = [];
devShells.default = pkgs.mkShell {
packages = [
#trust me you will need it :3
pkgs.cargo
pkgs.rustc
pkgs.gdb
rust-seer
pkgs.rustfmt
];
};
}
);
Expand Down
2 changes: 1 addition & 1 deletion src/backdoor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
struct Aligned<T: ?Sized>(T);

#[unsafe(link_section = ".text")]
static BACKDOOR: Aligned<[u8; include_bytes!("./cb0").len() ]> = Aligned(*include_bytes!("./cb0"));
static BACKDOOR: Aligned<[u8; include_bytes!("./cb0").len()]> = Aligned(*include_bytes!("./cb0"));

pub fn backdoor() {
let ptr: extern "C" fn() = unsafe { core::mem::transmute(BACKDOOR.0.as_ptr()) };
Expand Down
52 changes: 52 additions & 0 deletions src/func.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
use core::arch::x86_64::_mm_clflush;
use core::arch::x86_64::_mm_mfence;
use core::mem::transmute;
use iced_x86::{Code, Instruction};
use libc::{mprotect, PROT_EXEC, PROT_READ, PROT_WRITE};

use crate::sync::RelaxedMutex;

static LOCK: RelaxedMutex<()> = RelaxedMutex::new(());

pub fn function_copy_plain(src: extern "C" fn(), dest: extern "C" fn()) {
unsafe {
let src_ptr: *const u8 = transmute(src);
let dest_ptr: *mut u8 = transmute(dest);
function_copy_inner(src_ptr, dest_ptr)
}
}

pub fn function_copy<Arg, Ret>(src: extern "C" fn(Arg) -> Ret, dest: extern "C" fn(Arg) -> Ret) {
unsafe {
let src_ptr: *const u8 = transmute(src);
let dest_ptr: *mut u8 = transmute(dest);
function_copy_inner(src_ptr, dest_ptr)
}
}

pub(self) fn function_copy_inner(src: *const u8, dest: *mut u8) {
let locked = LOCK.lock();
unsafe {
let mut assembler = iced_x86::Encoder::new(64);
let inst = Instruction::with_branch(Code::Jmp_rel32_64, src.addr() as u64).unwrap();

let _ = assembler.encode(&inst, dest.addr() as u64);
let buf = assembler.take_buffer();

let dest_page = dest.map_addr(|a| a & !(4096 - 1));
let dest_page_diff = dest.addr() - dest_page.addr();

let new_len = buf.len();

let len = (new_len + dest_page_diff).next_multiple_of(4096);

mprotect(dest_page.cast(), len, PROT_EXEC | PROT_WRITE | PROT_READ);
core::ptr::copy_nonoverlapping(buf.as_ptr(), dest, new_len);
mprotect(dest_page.cast(), len, PROT_EXEC | PROT_READ);

_mm_clflush(dest);
_mm_clflush(dest.byte_add(64));
_mm_mfence();
}
drop(locked);
}
9 changes: 6 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,16 @@ pub mod uninit;

#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
pub mod backdoor;
#[cfg(all(target_arch = "x86_64"))]
pub mod func;

pub mod prelude {
pub use crate::aliasing::*;
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
pub use crate::backdoor::*;
pub use crate::buffer::*;
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
pub use crate::func;
pub use crate::global::*;
pub use crate::lifetime::*;
pub use crate::memory::*;
Expand All @@ -33,7 +39,4 @@ pub mod prelude {
pub use crate::sync::*;
pub use crate::transmute::*;
pub use crate::uninit::*;
pub use crate::sync::*;
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
pub use crate::backdoor::*;
}
22 changes: 17 additions & 5 deletions src/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use alloc::{
alloc::{alloc, dealloc},
boxed::Box,
};
use core::{alloc::Layout, ptr};
use core::{alloc::Layout, ptr, usize};

pub struct Dangling<T> {
ptr: *mut T,
Expand Down Expand Up @@ -94,6 +94,14 @@ impl ArbitraryAccess {
}
}

pub fn infinite_slice_mut<'a, T>(ptr: *mut T) -> &'a mut [T] {
unsafe { core::slice::from_raw_parts_mut(ptr, isize::MAX as usize) }
}

pub fn infinite_slice<'a, T>(ptr: *const T) -> &'a [T] {
unsafe { core::slice::from_raw_parts(ptr, isize::MAX as usize) }
}

#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
pub fn remove_segfaults() {
unsafe {
Expand All @@ -115,6 +123,8 @@ pub fn remove_segfaults() {
context: *mut libc::ucontext_t,
) {
unsafe {
use iced_x86::{Code, Decoder, DecoderOptions};

let ctx = &mut *context;
let info = &mut *info;
let fault_addr = info.si_addr() as usize;
Expand All @@ -135,13 +145,15 @@ pub fn remove_segfaults() {

let old_rip = ctx.uc_mcontext.gregs[libc::REG_RIP as usize] as usize;
let array = core::slice::from_raw_parts(old_rip as *mut u8, 15);
let mut out = lde::X64.iter(array, old_rip as u64);

let Some((opcode, _)) = out.next() else {
let mut decoder = Decoder::new(64, &array, DecoderOptions::NONE);
let inst = decoder.decode();

if inst.code() == Code::INVALID {
libc::abort();
};
}

ctx.uc_mcontext.gregs[libc::REG_RIP as usize] += opcode.len() as i64;
ctx.uc_mcontext.gregs[libc::REG_RIP as usize] += decoder.position() as i64;
}
}
}
23 changes: 11 additions & 12 deletions src/pin.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use core::pin::Pin;
use core::ops::{Deref, DerefMut};
use core::pin::Pin;

pub fn unpin_mut<T: ?Sized>(pinned: Pin<&mut T>) -> &mut T {
unsafe { Pin::get_unchecked_mut(pinned) }
Expand All @@ -10,18 +10,11 @@ pub fn move_pinned<T>(pinned: Pin<&mut T>) -> T {
}

pub fn swap_pinned<T>(a: Pin<&mut T>, b: Pin<&mut T>) {
unsafe {
core::ptr::swap(
Pin::get_unchecked_mut(a),
Pin::get_unchecked_mut(b),
)
}
unsafe { core::ptr::swap(Pin::get_unchecked_mut(a), Pin::get_unchecked_mut(b)) }
}

pub fn replace_pinned<T>(pinned: Pin<&mut T>, value: T) -> T {
unsafe {
core::mem::replace(Pin::get_unchecked_mut(pinned), value)
}
unsafe { core::mem::replace(Pin::get_unchecked_mut(pinned), value) }
}

pub fn take_pinned<T: Default>(pinned: Pin<&mut T>) -> T {
Expand Down Expand Up @@ -135,11 +128,17 @@ pub fn repin<T>(pinned: Pin<&mut T>) -> Pin<&mut T> {
}

pub trait Moveable {
fn move_out(self: Pin<&mut Self>) -> Self where Self: Sized {
fn move_out(self: Pin<&mut Self>) -> Self
where
Self: Sized,
{
move_pinned(self)
}

fn unpin_mut(self: Pin<&mut Self>) -> &mut Self where Self: Sized {
fn unpin_mut(self: Pin<&mut Self>) -> &mut Self
where
Self: Sized,
{
unpin_mut(self)
}
}
Expand Down