-2

I want to run a Rust compiled into Rust:

// Not real code
fn main() {
    Process::new(code!("
        fn main() {
            println!(\"hi\");
            // Doesn't show in console
        }
    "));
}

I need that process to be totally outside program, because the program needs to auto modify, I don't wanna a thread.

I cannot do an constant or something, because that code should be compiled at compile time with platform specified compiled.

And no, I dont wanna a separate file, I want it all on a .exe.

Chayim Friedman
  • 47,971
  • 5
  • 48
  • 77
  • why do you need to compile it from another binary??? you can compile whatever you need for whatever plattform then spawn the process with that binary. Your method is overcomplicating things – Netwave May 28 '22 at 06:56
  • Unfortunately it isn't generally possible to write self-modifying programs in Rust since it is compiled ahead-of-time into a standalone executable, unlike languages like Python or Javascript that have an interpreter available at runtime. You would need to include entire the Rust compiler with your program, and I suspect this may be the wrong approach. Could you explain your use case and what led you to this approach? – Coder-256 May 28 '22 at 07:30
  • i'm sure there is a way, just compile an executable inside an executable, is not that hard, i cloud put an b"" string and write it but it would be plataform specified – WORM HACKER May 28 '22 at 14:36
  • If all you want is platform specific code, you should definitely use conditional compilation. Run-time platform detection is also possible. – Chayim Friedman May 28 '22 at 21:18
  • You may be intereseted in [this](https://stackoverflow.com/questions/7447013/how-to-write-self-modifying-code-in-c). This is talking about C, not Rust, but there are many similarities. Specifically, you don't want to write self-modifying executables, and you probably also don't have the required knowledge for that. – Chayim Friedman May 28 '22 at 21:21
  • yes i want to write automodify executable, because it has to work only one time, and you should be able to share the "used" version, even when you can just copy the working version, i already did this in other (compiled) languages, you don't have to say that I don't have the knowledge – WORM HACKER May 28 '22 at 21:31
  • Well, it is completly different story if it has access to the compiler; but why not just publish the ready executable? – Chayim Friedman May 28 '22 at 21:37
  • no, accessing the compiler is unportable, everyone should have rust installed – WORM HACKER May 28 '22 at 22:13
  • If you don't have access to the compiler; how did you wrote auto-modify executables in compiled languages? – Chayim Friedman May 28 '22 at 22:14
  • you load compiled files, anyways i think i figure out how to do this -> compile second state -> put that assembly inside rust as [u8] – WORM HACKER May 29 '22 at 01:50
  • anyways you cloud do this, do you know the diff btw functions and macros? – WORM HACKER May 29 '22 at 02:05
  • "How do I convert rust code to an executable without the program that converts rust code to an executable?" You don't. If you compile your inner program ahead of time (I can't tell if that's what you want), you could use `include_bytes!` to embed it and write it to a file at runtime. But compiled binaries are usually not portable in any case... – Colonel Thirty Two May 29 '22 at 02:32

1 Answers1

2

If you really want something like this (I doubt) here are two very ugly solutions.

The first one generates some source code, compiles it in order to obtain an executable, then runs the executable in another process.

The second one generates some source code, compiles it in order to obtain a dynamic library, then loads this library (as a plugin) and accesses the symbol of the generated function in order to call it from the current process.

All of this supposes that you can use a Rust toolchain on the execution platform. The names are hardcoded and specific to my platform (UNIX); some logic may be needed in order to adapt to various platforms. A temporary directory could be used for the source code, the executable and the library in order to clean everything afterwards, but this is a detail.

fn code_for_another_process() -> Result<(), Box<dyn std::error::Error>> {
    let exe_name = "./rust_prog";
    let code_name = "rust_prog.rs";
    let mut file = std::fs::File::create(code_name)?;
    use std::io::Write;
    file.write_all(
        "fn main() {\n\
             println!(\"in another process\");\n\
         }\n"
        .as_bytes(),
    )?;
    drop(file); // ensure file is closed
    let comp_status = std::process::Command::new("rustc")
        .arg(code_name)
        .status()?;
    if comp_status.success() {
        println!("~~~~ compilation of {} OK ~~~~", code_name);
        let run_status = std::process::Command::new(exe_name).status()?;
        if run_status.success() {
            println!("~~~~ execution of {} OK ~~~~", exe_name);
        }
    }
    Ok(())
}

fn code_for_this_process() -> Result<(), Box<dyn std::error::Error>> {
    let lib_name = "./librust_lib.so";
    let code_name = "rust_lib.rs";
    let mut file = std::fs::File::create(code_name)?;
    use std::io::Write;
    file.write_all(
        "#[no_mangle]\n\
        pub extern \"C\" fn call_me(arg: i32) -> i32 {\n\
             println!(\"called with {}\", arg);\n\
             arg*2
         }\n"
        .as_bytes(),
    )?;
    drop(file); // ensure file is closed
    let comp_status = std::process::Command::new("rustc")
        .arg("--crate-type")
        .arg("cdylib")
        .arg(code_name)
        .status()?;
    if comp_status.success() {
        println!("~~~~ compilation of {} OK ~~~~", code_name);
        unsafe {
            // requires dependency   libloading = "0.7"
            let lib = libloading::Library::new(lib_name)?;
            let call_me: libloading::Symbol<
                unsafe extern "C" fn(i32) -> i32,
            > = lib.get(b"call_me")?;
            for i in 0..5 {
                println!("--> {}", call_me(i));
            }
        }
    }
    Ok(())
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    code_for_another_process()?;
    code_for_this_process()?;
    Ok(())
}
/*
~~~~ compilation of rust_prog.rs OK ~~~~
in another process
~~~~ execution of ./rust_prog OK ~~~~
~~~~ compilation of rust_lib.rs OK ~~~~
called with 0
--> 0
called with 1
--> 2
called with 2
--> 4
called with 3
--> 6
called with 4
--> 8
*/
prog-fh
  • 13,492
  • 1
  • 15
  • 30