Rust
Rust¶
OffensiveRust
200ThingsToRememberAboutRust
Embedded in Rust
Making a C++ Lib with Rust
Creating a statically linked Rust application
Automatically generates Rust FFI bindings to C (and some C++) libraries.
Rust GUI
Cross-platform Rust GUI
https://github.com/rust-embedded/rust-raspberrypi-OS-tutorials
https://fasterthanli.me/articles/a-half-hour-to-learn-rust
https://github.com/Dhghomon/easy_rust
Rust Memory¶
What Each memory option is for a rust variable
Cargo Settings¶
Make debug builds smaller:
export CARGO_PROFILE_RELEASE_LTO=thin
Change the Linker to another executable on linux:
[target.x86_64-unknown-linux-gnu]
rustflags = [
"-C", "link-arg=-fuse-ld=lld",
]
Overwrite Linker options:
rustflags=(
"-C link-arg=-fuse-ld=lld"
"-C link-arg=-Wl,--compress-debug-sections=zlib"
"-C force-frame-pointers=yes"
)
export RUSTFLAGS="${rustflags[*]}"
Example Cargo.toml¶
[package]
name = "ping"
version = "0.1.0"
edition = "2021"
[dependencies]
#delf = { path = "../delf" } #Used to specify a library in another directory
[profile.release]
strip = true # Automatically strip symbols from the binary.
#opt-level = "z" # Optimize for size.
opt-level = "s" # Optimize for size.
lto = true # Used to remove deadcode and unused functions
panic = "abort" # Remove backtrace when crashes
Building¶
Build and Run the release version with command line arguments:
>>> cargo run --release -- arg1 arg2
Install other versions of rust:
>>> rustup toolchain install nightly-2022-11-06
Run other version of rust:
>>> rustup run nightly cargo build
>>> cargo +nightly-2022-11-06 build --release
Cross Compiling:
>>> rustup run nightly rustc --print target-list
aarch64-apple-darwin
aarch64-apple-ios
aarch64-apple-ios-macabi
aarch64-apple-ios-sim
aarch64-apple-tvos
aarch64-apple-watchos-sim
aarch64-fuchsia
aarch64-kmc-solid_asp3
aarch64-linux-android
aarch64-nintendo-switch-freestanding
aarch64-pc-windows-gnullvm
aarch64-pc-windows-msvc
aarch64-unknown-freebsd
aarch64-unknown-hermit
aarch64-unknown-linux-gnu
aarch64-unknown-linux-gnu_ilp32
aarch64-unknown-linux-musl
aarch64-unknown-netbsd
aarch64-unknown-none
aarch64-unknown-none-softfloat
aarch64-unknown-nto-qnx710
aarch64-unknown-openbsd
aarch64-unknown-redox
aarch64-unknown-uefi
aarch64-uwp-windows-msvc
aarch64-wrs-vxworks
aarch64_be-unknown-linux-gnu
aarch64_be-unknown-linux-gnu_ilp32
arm-linux-androideabi
arm-unknown-linux-gnueabi
arm-unknown-linux-gnueabihf
arm-unknown-linux-musleabi
arm-unknown-linux-musleabihf
arm64_32-apple-watchos
armeb-unknown-linux-gnueabi
armebv7r-none-eabi
armebv7r-none-eabihf
armv4t-none-eabi
armv4t-unknown-linux-gnueabi
armv5te-none-eabi
armv5te-unknown-linux-gnueabi
armv5te-unknown-linux-musleabi
armv5te-unknown-linux-uclibceabi
armv6-unknown-freebsd
armv6-unknown-netbsd-eabihf
armv6k-nintendo-3ds
armv7-apple-ios
armv7-linux-androideabi
armv7-unknown-freebsd
armv7-unknown-linux-gnueabi
armv7-unknown-linux-gnueabihf
armv7-unknown-linux-musleabi
armv7-unknown-linux-musleabihf
armv7-unknown-linux-uclibceabi
armv7-unknown-linux-uclibceabihf
armv7-unknown-netbsd-eabihf
armv7-wrs-vxworks-eabihf
armv7a-kmc-solid_asp3-eabi
armv7a-kmc-solid_asp3-eabihf
armv7a-none-eabi
armv7a-none-eabihf
armv7k-apple-watchos
armv7r-none-eabi
armv7r-none-eabihf
armv7s-apple-ios
asmjs-unknown-emscripten
avr-unknown-gnu-atmega328
bpfeb-unknown-none
bpfel-unknown-none
hexagon-unknown-linux-musl
i386-apple-ios
i586-pc-windows-msvc
i586-unknown-linux-gnu
i586-unknown-linux-musl
i686-apple-darwin
i686-linux-android
i686-pc-windows-gnu
i686-pc-windows-msvc
i686-unknown-freebsd
i686-unknown-haiku
i686-unknown-linux-gnu
i686-unknown-linux-musl
i686-unknown-netbsd
i686-unknown-openbsd
i686-unknown-uefi
i686-uwp-windows-gnu
i686-uwp-windows-msvc
i686-wrs-vxworks
m68k-unknown-linux-gnu
mips-unknown-linux-gnu
mips-unknown-linux-musl
mips-unknown-linux-uclibc
mips64-openwrt-linux-musl
mips64-unknown-linux-gnuabi64
mips64-unknown-linux-muslabi64
mips64el-unknown-linux-gnuabi64
mips64el-unknown-linux-muslabi64
mipsel-sony-psp
mipsel-sony-psx
mipsel-unknown-linux-gnu
mipsel-unknown-linux-musl
mipsel-unknown-linux-uclibc
mipsel-unknown-none
mipsisa32r6-unknown-linux-gnu
mipsisa32r6el-unknown-linux-gnu
mipsisa64r6-unknown-linux-gnuabi64
mipsisa64r6el-unknown-linux-gnuabi64
msp430-none-elf
nvptx64-nvidia-cuda
powerpc-unknown-freebsd
powerpc-unknown-linux-gnu
powerpc-unknown-linux-gnuspe
powerpc-unknown-linux-musl
powerpc-unknown-netbsd
powerpc-unknown-openbsd
powerpc-wrs-vxworks
powerpc-wrs-vxworks-spe
powerpc64-ibm-aix
powerpc64-unknown-freebsd
powerpc64-unknown-linux-gnu
powerpc64-unknown-linux-musl
powerpc64-unknown-openbsd
powerpc64-wrs-vxworks
powerpc64le-unknown-freebsd
powerpc64le-unknown-linux-gnu
powerpc64le-unknown-linux-musl
riscv32gc-unknown-linux-gnu
riscv32gc-unknown-linux-musl
riscv32i-unknown-none-elf
riscv32im-unknown-none-elf
riscv32imac-unknown-none-elf
riscv32imac-unknown-xous-elf
riscv32imc-esp-espidf
riscv32imc-unknown-none-elf
riscv64gc-unknown-freebsd
riscv64gc-unknown-linux-gnu
riscv64gc-unknown-linux-musl
riscv64gc-unknown-none-elf
riscv64gc-unknown-openbsd
riscv64imac-unknown-none-elf
s390x-unknown-linux-gnu
s390x-unknown-linux-musl
sparc-unknown-linux-gnu
sparc64-unknown-linux-gnu
sparc64-unknown-netbsd
sparc64-unknown-openbsd
sparcv9-sun-solaris
thumbv4t-none-eabi
thumbv5te-none-eabi
thumbv6m-none-eabi
thumbv7a-pc-windows-msvc
thumbv7a-uwp-windows-msvc
thumbv7em-none-eabi
thumbv7em-none-eabihf
thumbv7m-none-eabi
thumbv7neon-linux-androideabi
thumbv7neon-unknown-linux-gnueabihf
thumbv7neon-unknown-linux-musleabihf
thumbv8m.base-none-eabi
thumbv8m.main-none-eabi
thumbv8m.main-none-eabihf
wasm32-unknown-emscripten
wasm32-unknown-unknown
wasm32-wasi
wasm64-unknown-unknown
x86_64-apple-darwin
x86_64-apple-ios
x86_64-apple-ios-macabi
x86_64-apple-tvos
x86_64-apple-watchos-sim
x86_64-fortanix-unknown-sgx
x86_64-fuchsia
x86_64-linux-android
x86_64-pc-nto-qnx710
x86_64-pc-solaris
x86_64-pc-windows-gnu
x86_64-pc-windows-gnullvm
x86_64-pc-windows-msvc
x86_64-sun-solaris
x86_64-unknown-dragonfly
x86_64-unknown-freebsd
x86_64-unknown-haiku
x86_64-unknown-hermit
x86_64-unknown-illumos
x86_64-unknown-l4re-uclibc
x86_64-unknown-linux-gnu
x86_64-unknown-linux-gnux32
x86_64-unknown-linux-musl
x86_64-unknown-netbsd
x86_64-unknown-none
x86_64-unknown-openbsd
x86_64-unknown-redox
x86_64-unknown-uefi
x86_64-uwp-windows-gnu
x86_64-uwp-windows-msvc
x86_64-wrs-vxworks
>>> rustup run nightly rustup toolchain install nightly-2022-11-06-i686-pc-windows-msvc
>>> rustup run nightly rustup target add i686-pc-windows-msvc
>>> rustup run nightly cargo build --target i686-pc-windows-msvc
Expanding Macros¶
cargo expand
Learning Rust¶
https://rustforjs.dev/
How I went about learning Rust
Roguelike Tutorial - In Rust
Writing an OS in Rust
Examples¶
https://medium.com/@ilegra/building-a-microservice-with-rust-ef9641cf2331
Concepts¶
https://doc.rust-lang.org/std/clone/trait.Clone.html
https://depth-first.com/articles/2020/01/27/rust-ownership-by-example/
https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html
https://doc.rust-lang.org/rust-by-example/scope/lifetime.html
Smart Pointers:
- Box\<T>: To store something on the heap.
- Used when you don't know the size at compile time.
- Used when the type is recursive
- Rc\<T>: If you need to have multiple functions referencing the underlined data structure
- Is only de allocated when all references are removed from scope
- Arc\<T>: Atomic Reference Counters
- Used when need multiple threads interacting with the same object
Async:
(async) Rust doesn't have to be hard
Macros¶
Simple Macro for a Function:
macro_rules! create_function {
// This macro takes an argument of designator `ident` and
// creates a function named `$func_name`.
// The `ident` designator is used for variable/function names.
($func_name:ident) => {
fn $func_name() {
// The `stringify!` macro converts an `ident` into a string.
println!("You called {:?}()",
stringify!($func_name));
}
};
}
// Create functions named `foo` and `bar` with the above macro.
create_function!(foo);
create_function!(bar);
fn main() {
foo();
bar();
}
Macro for many arguments:
// `find_min!` will calculate the minimum of any number of arguments.
macro_rules! find_min {
// Base case:
($x:expr) => ($x);
// `$x` followed by at least one `$y,`
($x:expr, $($y:expr),+) => (
// Call `find_min!` on the tail `$y`
std::cmp::min($x, find_min!($($y),+))
)
}
fn main() {
println!("{}", find_min!(1));
println!("{}", find_min!(1 + 2, 2));
println!("{}", find_min!(5, 2 * 3, 4));
}
Borrowing¶
Immutable Borrow:
fn main() {
let mut s = String::from("hello world goodbye universe");
// You can make as many imputable borrow that you want
let r1 = &s[0..5];
let r2 = &s[6..11];
let r3 = &s[12..19];
let r4 = &s[20..28];
println!("{}, {}, and {} {}", r1, r2, r3, r4);
//Only after r1, r2, and r3 are not used anymore in the scope can you use a mutable reference
let r5 = &mut s; // no problem
println!("{}", r5);
}
fn change(some_string: &mut String) {
some_string.push_str(", world");
}
fn calculate_length(s: &String) -> usize {
s.len()
}
Mutable Borrowing:
fn main() {
let mut s = String::from("hello");
//Make a mutable string
// If this is in a scope then it will be removed at the end of the
let r1 = &mut s;
// Since you have a mutable borrow then you cant have a immutable borrow. The following will fail
// let r2 = &mut s;
change(r1);
// Since there is a mutable variables based on s you cant use s only r1 until it is removed
println!("{}", r1);
}
fn change(some_string: &mut String) {
some_string.push_str(", world");
}
fn calculate_length(s: &String) -> usize {
s.len()
}
No Dangling Return:
fn main() {
let reference_to_nothing = no_dangle();
println!("{}", reference_to_nothing);
}
fn no_dangle() -> String {
let s = String::from("hello");
//You cant return a reference to a string that was created in this function scope
//&s
s
}
String Slice Borrowing:
let s = String::from("hello world");
let hello = &s[0..5];
let world = &s[6..11];
println!("{}", reference_to_nothing);
Importing from other files¶
In the main.rs
file you need include mod filename;
. This links the file to main function. Then in the actual file you can import the module with use crate::filename;
Operators¶
?
: if the function returns a Result
or Option
this extracts the value or the error from the result
Loops¶
Breaking Named:
#![allow(unreachable_code)]
fn main() {
'outer: loop {
println!("Entered the outer loop");
'inner: loop {
println!("Entered the inner loop");
// This would break only the inner loop
//break;
// This breaks the outer loop
break 'outer;
}
println!("This point will never be reached");
}
println!("Exited the outer loop");
}
Loop over Mutable:
fn main() {
let mut names = vec!["Bob", "Frank", "Ferris"];
for name in names.iter_mut() {
*name = match name {
&mut "Ferris" => "There is a rustacean among us!",
_ => "Hello",
}
}
println!("names: {:?}", names);
}
Structures¶
Remove Padding in structures:
fn main() {
struct Foo {
a: u8,
b: u32,
}
#[repr(packed)]
struct FooPacked {
a: u8,
b: u32,
}
use std::mem::size_of;
println!("Foo = {}", size_of::<Foo>());
println!("FooPacked = {}", size_of::<FooPacked>());
}
Remove Reorder:
fn main() {
// first, let's declare both structs: with Rust repr
struct IOI_Rust {
ttl: u8,
tos: u8,
flags: u8,
options_size: u8,
options_data: u32,
}
// and C repr
#[repr(C)]
struct IOI_C {
ttl: u8,
tos: u8,
flags: u8,
options_size: u8,
options_data: u32,
}
use memoffset::span_of;
use std::mem::size_of;
// let's make a quick macro, this will make this a lot easier
macro_rules! print_offset {
// the macro takes one identifier (the struct's name), then a tuple
// of identifiers (the field names)
($type: ident, ($($field: ident),*)) => {
// `$type` is an identifier, but we're going to
// print it out, so we need it as a string instead.
let t = stringify!($type);
// this will repeat for each $field
$(
let f = stringify!($field);
let span = span_of!($type, $field);
println!("{:10} {:15} {:?}", t, f, span);
)*
// finally, print the total field size
let ts = size_of::<$type>();
println!("{:10} {:15} {}", t, "(total)", ts);
println!();
};
}
print_offset!(IOI_Rust, (ttl, tos, flags, options_size, options_data));
print_offset!(IOI_C, (ttl, tos, flags, options_size, options_data));
}
/*
IOI_Rust ttl 4..5
IOI_Rust tos 5..6
IOI_Rust flags 6..7
IOI_Rust options_size 7..8
IOI_Rust options_data 0..4
IOI_Rust (total) 8
IOI_C ttl 0..1
IOI_C tos 1..2
IOI_C flags 2..3
IOI_C options_size 3..4
IOI_C options_data 4..8
IOI_C (total) 8
*/
Lifetimes¶
#[derive(Debug)]
struct Point(i32, i32);
//Used to keep the lifetime of the function to the parent function
fn left_most<'a>(p1: &'a Point, p2: &'a Point) -> &'a Point {
if p1.0 < p2.0 {
p1
} else {
p2
}
}
fn main() {
let p1: Point = Point(10, 10);
let p2: Point = Point(20, 20);
let p3 = left_most(&p1, &p2); // What is the lifetime of p3?
println!("p3: {p3:?}");
}
Hacking¶
Hooking Golang¶
https://github.com/metalbear-co/mirrord/blob/main/mirrord/layer/src/hooks.rs
Hypervisor¶
https://memn0ps.github.io/hypervisor-development-in-rust-part-1/?ref=upstract.com