mutself

Crates.iomutself
lib.rsmutself
version0.2.0
sourcesrc
created_at2023-04-13 14:47:23.575534
updated_at2023-06-16 21:50:00.686579
descriptionCreate self-modifying executables
homepage
repositoryhttps://github.com/Gui-Yom/mutself
max_upload_size
id838345
size25,349
(Gui-Yom)

documentation

README

mutself

Create self-mutating executables.

Purpose

// TODO

Usage

mutself::mutself! {
    DATA = "alice"
}

fn main() {
    if let Some(arg) = std::env::args().nth(1) {
        println!("Hello {}", &arg);
        mutself("new.exe", Some(&arg)).unwrap();
    } else {
        println!("Hello {}", &*DATA);
    }
}

Running our executable gives :

$ cargo run
Hello alice

Now with an argument :

$ cargo run -- bob
Hello bob
# This creates another executable named 'new.exe'
$ new
Hello bob

Yes, data size can be changed.

$ cargo run -- someverylongstringthatwouldntfitinsidethespace

How ?

The library parses the executable it's running in and changes values before dumping a new executable.

In depth

Simply put : an abuse of the #[link_section = ".custom"] attribute. There is no assembly patching or anything. The data entries in the mutself! macro are stored in a custom section in the executable. The code that run only has a pointer to the top of the section (that pointer always stays valid because the custom section will always be at the same place in virtual memory). All entries in the section are referenced relatively to this pointer.

The layout in memory is like so (factoring out alignment) :

#ENTRY0 size (usize) <-- hardcoded pointer
#ENTRY0
#ENTRY1 size (usize)
#ENTRY1
// And so on

Since every entry is defined relatively to the base, they can grow or shrink in size freely without fear the runtime code can't address them.

Limitations

The initializer expression must be of a type that can be stored inline (e.g. not a slice). A slice will only store a ptr and a size in the custom executable section referencing .data, which means we can't modify it.

Commit count: 5

cargo fmt