Replacing text in windows executables

Hi All,

I'm trying to write a poor mans asdf replacement for windows and for that I needed to create shims. I'm new to windows and completely ignorant about binary files. The idea is to create a shim for each command we're handling in a directory which is in the PATH. The shim will then invoke an asdf.exe command which calculates the required version and in turn call the real exe file. In order to make it as fast as possible, I thought how I would embed all the non dynamic data inside the shim so I'll need to do as little as possible when running the command (e.g. the plugin the executable belongs to, etc).

So I thought of the most naive solution which would be to do a binary search/replace of the content of the original shim and write it modified to the file system. Here is what I came up with for replacing string in the shim (using bstr create):

use bstr::ByteSlice;
use std::{
    fs::{self, File},
    io::Read,
};

fn main() {
    let mut f = File::open("./TMP/shim.exe").unwrap();
    let mut bts: Vec<u8> = vec![];
    f.read_to_end(&mut bts).unwrap();
    let new = &bts.replace("WORLDXXX!", "Replaced!");
    fs::write("./new.exe", &new).unwrap();
    println!("wrote new.exe!");
}

Amazingly enough it seems to work :slight_smile: . I have the original executable (which outputs "Hello WORLDXXX!") in the TMP directory and I'm creating a new executable with replaced output.

My question is, Is it a valid solution? Or maybe it could fail on many use cases?

Anyone with experience with binary files, please advise?

Thanks

Haim
.

This is a hacky solution. It requires that you reserve exactly the right amount of space in the original binary. In addition it would likely causr antivirus to trigger on your executable eventually due to being self modifying, which has been used by malware more than once to try to evade signature based malware detection and make static analysis harder. Finally it break digital signatures. On windows this is not a big issue due to signatures being optional, but on m1 macs digital signatures are mandatory. By default the linker gives you an ad-hoc signature, but modifying the executable in any way breaks this signature and requires you to sign it again.

3 Likes

Thanks for the info. This is indeed very important.

Regarding OS, this is windows only (mac and linuxes can use asdf and don't need this).

mmm, I see, this completely breaks if the size is not the same. pitty ...

Do you know if there's a way to achieve this? I don't have to use this solution, I can get the data from a config file, Just thought it would be nice to save some steps...

Thanks.

Using a normal config mechanism (e.g. registry or config files) would be the best solution.

If you want to continue with embedding a version number in the target executable and you have control over how they get created, you could use the same approach but reserve a sufficiently large amount of space in the binary and pad it out with zeroes.

You could also modify the executable to have a asdf-specific section. I've only ever played around with libraries for parsing/saving ELF binaries, so can't really give you any pointers here.

Alternatively, you could use proper Windows APIs to intercept the normal "spawn process" machinery and have your program run instead.

Keep in mind that these techniques are almost indistinguishable from malware.

Yeah I completely agree. The idea was to make things simpler and faster :slight_smile:.

Thanks for the detailed explenation and suggestions. It was very interesting.

Damn, I keep forgetting that you can only have one solution :frowning:.

In any case, thank you both @Michael-F-Bryan and @bjorn3 for the info and suggestions.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.