rust-teeny-nostd: 4 KiB
This commit is contained in:
@@ -5,3 +5,4 @@ PoC's showing how rust can do stuff people often critiquize it about.
|
|||||||
# Members
|
# Members
|
||||||
|
|
||||||
- `rust-teeny`: A rust std binary only **8.0 KiB** big, achieves so by `abort()`ing instead of having graceful error logging, panics shouldn't have any source information nor should there be `Debug` implementations, no debug symbols and any potential path reference to `$PWD` is renamed. It carries a shellcode payload loaded into memory and executed from memory.
|
- `rust-teeny`: A rust std binary only **8.0 KiB** big, achieves so by `abort()`ing instead of having graceful error logging, panics shouldn't have any source information nor should there be `Debug` implementations, no debug symbols and any potential path reference to `$PWD` is renamed. It carries a shellcode payload loaded into memory and executed from memory.
|
||||||
|
- `rust-teeny-nostd`: Same as avobe but `no_std`, **4.1 KiB**.
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
/target
|
||||||
Generated
+16
@@ -0,0 +1,16 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.186"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rust-teeny"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
cargo-features = ["panic-immediate-abort"]
|
||||||
|
|
||||||
|
[package]
|
||||||
|
name = "rust-teeny"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
opt-level = "z"
|
||||||
|
strip = "symbols"
|
||||||
|
panic = "immediate-abort"
|
||||||
|
lto = true
|
||||||
|
codegen-units = 1
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
libc = "0"
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Same as [../rust-teeny/] but `no_std`, takes 4.1 KiB.
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
alias b := build
|
||||||
|
alias s := stat
|
||||||
|
alias z := stat-size
|
||||||
|
|
||||||
|
target := "x86_64-unknown-linux-gnu"
|
||||||
|
|
||||||
|
build:
|
||||||
|
RUSTFLAGS="\
|
||||||
|
-Zunstable-options \
|
||||||
|
\
|
||||||
|
-Zlocation-detail=none -Zfmt-debug=none \
|
||||||
|
\
|
||||||
|
-Clinker=clang -Clink-arg=-fuse-ld=lld \
|
||||||
|
-Clink-arg=-Wl,--gc-sections -Clink-arg=-Wl,--as-needed -Clink-arg=-Wl,--strip-all -Clink-arg=-Wl,--build-id=none \
|
||||||
|
\
|
||||||
|
-Cpanic=immediate-abort --remap-path-prefix=$PWD=[src] \
|
||||||
|
" cargo \
|
||||||
|
\
|
||||||
|
-Zbuild-std=core,alloc,std,panic_abort \
|
||||||
|
-Zbuild-std-features="optimize_for_size" \
|
||||||
|
\
|
||||||
|
b -r --target {{ target }}
|
||||||
|
|
||||||
|
# Base, does like nothing
|
||||||
|
strip --strip-all --strip-unneeded target/{{ target }}/release/rust-teeny
|
||||||
|
|
||||||
|
# BS, I don't want these
|
||||||
|
strip -R .comment -R .note.\* target/{{ target }}/release/rust-teeny
|
||||||
|
|
||||||
|
# Only OK because we don't do unwinding
|
||||||
|
strip -R .eh_frame\* target/{{ target }}/release/rust-teeny
|
||||||
|
|
||||||
|
# Not sure why .gnu.version and .gnu.hash don't break if I remove them in my machine, but that's very relative and its related to dynamic loading, but they could reduce size by `0.2 KiB`
|
||||||
|
|
||||||
|
stat:
|
||||||
|
stat target/{{ target }}/release/rust-teeny
|
||||||
|
|
||||||
|
stat-size:
|
||||||
|
stat target/{{ target }}/release/rust-teeny -c "%s" | numfmt --to=iec-i
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
[toolchain]
|
||||||
|
channel = "nightly"
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
use core::ffi::{c_int, c_void};
|
||||||
|
|
||||||
|
use libc::{MAP_ANONYMOUS, MAP_PRIVATE, PROT_EXEC, PROT_READ, PROT_WRITE, off_t, size_t};
|
||||||
|
|
||||||
|
// SAFETY: Shellcodes should have FFI behavior equivalent to an `unsafe extern "C" fn() -> ()`
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
static SHELLCODE: &[u8] = b"\x31\xC0\xFF\xC0\x89\xC7\x48\x8D\x35\x08\x00\x00\x00\xBA\x0E\x00\x00\x00\x0F\x05\xC3Hello, World!\n";
|
||||||
|
|
||||||
|
#[link(name = "c")]
|
||||||
|
unsafe extern "C" {
|
||||||
|
fn mmap(
|
||||||
|
addr: *mut c_void,
|
||||||
|
len: size_t,
|
||||||
|
prot: c_int,
|
||||||
|
flags: c_int,
|
||||||
|
fd: c_int,
|
||||||
|
offset: off_t,
|
||||||
|
) -> *mut c_void;
|
||||||
|
|
||||||
|
fn mprotect(addr: *mut c_void, len: size_t, prot: c_int) -> c_int;
|
||||||
|
|
||||||
|
fn exit(status: c_int) -> !;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Leaks memory
|
||||||
|
fn alloc_shellcode(content: &[u8]) -> unsafe extern "C" fn() -> () {
|
||||||
|
let exec_mem = unsafe {
|
||||||
|
mmap(
|
||||||
|
core::ptr::null_mut(),
|
||||||
|
content.len(),
|
||||||
|
PROT_READ | PROT_WRITE,
|
||||||
|
MAP_PRIVATE | MAP_ANONYMOUS,
|
||||||
|
-1,
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_ne!(exec_mem, libc::MAP_FAILED, "Map failed");
|
||||||
|
|
||||||
|
unsafe { core::ptr::copy_nonoverlapping(content.as_ptr(), exec_mem.cast(), content.len()) };
|
||||||
|
|
||||||
|
let mprotect_status = unsafe { mprotect(exec_mem, content.len(), PROT_READ | PROT_EXEC) };
|
||||||
|
assert_eq!(mprotect_status, 0, "Mprotect failed");
|
||||||
|
|
||||||
|
unsafe { core::mem::transmute(exec_mem) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
fn main() {
|
||||||
|
let exec_mem = alloc_shellcode(SHELLCODE);
|
||||||
|
unsafe { exec_mem() };
|
||||||
|
|
||||||
|
unsafe { exit(0) }
|
||||||
|
}
|
||||||
+26
-3
@@ -1,13 +1,33 @@
|
|||||||
use libc::{MAP_ANONYMOUS, MAP_PRIVATE, PROT_EXEC, PROT_READ, PROT_WRITE};
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
use core::ffi::{c_int, c_void};
|
||||||
|
|
||||||
|
use libc::{MAP_ANONYMOUS, MAP_PRIVATE, PROT_EXEC, PROT_READ, PROT_WRITE, off_t, size_t};
|
||||||
|
|
||||||
// SAFETY: Shellcodes should have FFI behavior equivalent to an `unsafe extern "C" fn() -> ()`
|
// SAFETY: Shellcodes should have FFI behavior equivalent to an `unsafe extern "C" fn() -> ()`
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
static SHELLCODE: &[u8] = b"\x31\xC0\xFF\xC0\x89\xC7\x48\x8D\x35\x08\x00\x00\x00\xBA\x0E\x00\x00\x00\x0F\x05\xC3Hello, World!\n";
|
static SHELLCODE: &[u8] = b"\x31\xC0\xFF\xC0\x89\xC7\x48\x8D\x35\x08\x00\x00\x00\xBA\x0E\x00\x00\x00\x0F\x05\xC3Hello, World!\n";
|
||||||
|
|
||||||
|
#[link(name = "c")]
|
||||||
|
unsafe extern "C" {
|
||||||
|
fn mmap(
|
||||||
|
addr: *mut c_void,
|
||||||
|
len: size_t,
|
||||||
|
prot: c_int,
|
||||||
|
flags: c_int,
|
||||||
|
fd: c_int,
|
||||||
|
offset: off_t,
|
||||||
|
) -> *mut c_void;
|
||||||
|
|
||||||
|
fn mprotect(addr: *mut c_void, len: size_t, prot: c_int) -> c_int;
|
||||||
|
|
||||||
|
fn exit(status: c_int) -> !;
|
||||||
|
}
|
||||||
|
|
||||||
/// Leaks memory
|
/// Leaks memory
|
||||||
fn alloc_shellcode(content: &[u8]) -> unsafe extern "C" fn() -> () {
|
fn alloc_shellcode(content: &[u8]) -> unsafe extern "C" fn() -> () {
|
||||||
let exec_mem = unsafe {
|
let exec_mem = unsafe {
|
||||||
libc::mmap(
|
mmap(
|
||||||
core::ptr::null_mut(),
|
core::ptr::null_mut(),
|
||||||
content.len(),
|
content.len(),
|
||||||
PROT_READ | PROT_WRITE,
|
PROT_READ | PROT_WRITE,
|
||||||
@@ -21,13 +41,16 @@ fn alloc_shellcode(content: &[u8]) -> unsafe extern "C" fn() -> () {
|
|||||||
|
|
||||||
unsafe { core::ptr::copy_nonoverlapping(content.as_ptr(), exec_mem.cast(), content.len()) };
|
unsafe { core::ptr::copy_nonoverlapping(content.as_ptr(), exec_mem.cast(), content.len()) };
|
||||||
|
|
||||||
let mprotect_status = unsafe { libc::mprotect(exec_mem, content.len(), PROT_READ | PROT_EXEC) };
|
let mprotect_status = unsafe { mprotect(exec_mem, content.len(), PROT_READ | PROT_EXEC) };
|
||||||
assert_eq!(mprotect_status, 0, "Mprotect failed");
|
assert_eq!(mprotect_status, 0, "Mprotect failed");
|
||||||
|
|
||||||
unsafe { core::mem::transmute(exec_mem) }
|
unsafe { core::mem::transmute(exec_mem) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
fn main() {
|
fn main() {
|
||||||
let exec_mem = alloc_shellcode(SHELLCODE);
|
let exec_mem = alloc_shellcode(SHELLCODE);
|
||||||
unsafe { exec_mem() };
|
unsafe { exec_mem() };
|
||||||
|
|
||||||
|
unsafe { exit(0) }
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user