How to run EXE file in memory on Windows OS?

Just to clarify before I even begin, this is red teaming project.

I have already compiled EXE file for Windows that I want to load in memory of Windows machine and run it like I did double click on it, in normal circumstances. I dont need to pass arguments for that executable file but I just want to ask for the sake of learning (maybe Ill need it in future), how to pass arguments in addition?

Since there is no crate for this, I need to do this solo. Anyways, even if crate existed, I would like to do this without it since Ill get knowledge in low-level programming and memory manipulation with Rust.

You will have to learn about the structure of an executable file on your platform first.

I can recommend this series:

3 Likes

Thanks for the link but thats for Linux. I am interested in Windows, not Linux :)))

The principles of what you will be learning are the same

I would like anyways to read on something precisely for Windows, not Linux. So if anybody got link or something. A lot of content for C and C++ but not Rust

Here's a Stack Overflow question about what exactly happens when you double-click an executable.

It says to use ShellExecuteW. There's a crate that exposes ShellExecuteW as an unsafe fn. Using it from Rust is not totally trivial, as you'll need to construct null-terminated UTF-16 strings of type PCWSTR.

EDIT: I think you can pass something like HSTRING::from("C:\\foo\\bar\\baz.exe").

1 Like

In the same sense as principles of interstellar spaceship are similar to principles of car design. They both move you from point A to point B, right? Have to be similar.

On Linux kernel actually does very little when it loads the process in memory. The whole thing is around 2000 lines of code long: it just loads the dynamic linker by mmaping it in memory, prepares arguments (argc, argv and so on) and doing jump to starting point. That's it. Everything else happens in userspace.

On Windows? On Windows process is entirely different. Loader is part of Windows kernel, and, most importantly, it has access to facilities that one just simplty couldn't do from userpace.

It means that even if you would get source code for such loader (there were leaks of previous versions of Windows so that's not entirely implausible)… they wouldn't help you.

Now, if you dont't want to execute just some random binary that you downloaded from some random web site and put in the array in your Rust program, but just want to execute some code that you generated… look on how dynasm does that, e.g.

Bot loading arbitrary binary entirely from memory? I would be ready to hear how you have done that, if you are pesistent you may do that in 10 years or so.

7 Likes

The way I usually run executables is std::process::Command. Try that before ShellExecuteW.

Twenty years ago ISTR that, in programming languages that existed at the time, stuff like Command usually popped up an unwanted console window on Windows. No idea if that's still true!

Console windows should only pop up when the program that you try to execute has it's subsystem set to console rather than windows. Rustc sets it to console by default as setting it to windows will always disconnect stdin/stdout/stderr even when launching from an existing terminal. You can use #![windows_subsystem = "windows"] to change it though. /SUBSYSTEM (Specify Subsystem) | Microsoft Learn

6 Likes

Have you read the very first line of that topic? Do you know what Red Team is?

TC doesn't need help to run binary, the goal is to stealthily run binary.

Which naturally leads us to the following idea: let's somehow inject that binary in the buffer of Chrome process or something like that and then we'll run it instead of doing crazy ibjections, working with memory of other processes via peek/poke and so on.

Idea sounds logical till the moment where you realize that you have replaced hairy and complicated problem with something crazy hard and insanely complicted.

2 Likes

Mutual exclusion?

It is possible to do. Here in link, guy loaded exe in already existing process. Its different than what I asked but anyways.. I thought like to put EXE in memory, create thread and start new process. I think its totally doable

Show me, plz. It would be really of great help for many people. Not a joke and not a sarcasm.

Not trivial, but [relatively] easy.

And that's the impossible part. As in: Windows doesn't provide any APIs which can create new process and/or shape new thread into the form you want/need.

The only API provided is “here's an EXE of the image on disk, load it”. And many operations needed for that are Ring0 operations that are exposed and public APIs on Linux and hidden and private APIs on WIndows.

And it's not just idle chatter: there are literally thousand of people working on emulating things that in POSIX world are part of official API. Cygwin, MinGW and many other libraries use different tricks to pretend that you can create processes and/or threads with layout you actually want. It's not easy and quite fragile.

They don't quite achieve that (100% reproduction or process or thread layout is not possible on Windows), but they just do enough work to run POSIX apps.

So this guy actually did an easy part. How about the other side of the story?

As I've said: go and try that. In 10 years, if you would be persistent enough, you would have another API emulator good enough for some use. Been there, done that, even have some T-shirts. That was about 10 years ago, it's possible that Windows team suddenly decided to reverse something that they perceive is an important security feature… but unlikely.

P.S. Of course programs line VMWare or VirtualBox achieve all that and more when they install appropriate driver and use it, Windows kernel provides appropriate APIs to drivers, but installation of driver is kinda way too visible operation for Red team use.

1 Like

Some binaries don't do any visible work when double-clicked, no contradiction here.

CreateRemoteThread looks like it does exactly that.

I think you've misparsed that English, I believe it's intended to be read as:

Windows doesn't provide any APIs which can (create new process) and/or (shape new thread [of the new process] into the form you want/need.)

Eg you can push a thread into an existing process, but you can't create a process without Windows running the loader laying it the new process and configuring the main thread from a PE file on disk.

1 Like

It creates thread in the shape that operation system wants, not in the shape you want. There are no way to put what you need/want into TCB.

In POSIX world that's responsibility of the standard library (and there are syscalls provided for that), on Windows that's artomic operation: “gimme a thread” — “here it is”.

That's why Wine is just a normal app on Linux (and it, basically, does what TC wanted) while on Windows every program that runs Linux apps is either a full-blown CPU simulator or needs a kernel driver.

1 Like

I wanted to link this CreateRemoteThread API but guy did that faster.

So if I understood, loading EXE in memory is impossible? Why then its possible to CreateRemoteThread and inject it in already existing process? I dont understand your answers fully. Loading EXE and creating own process is impossible?

The only mechanism Windows provides (at least to user applications) to create a process requires an executable file that Windows runs it's loader on.

CreateRemoteThread is intended essentially a debugging API that lets you execute code in the context of someone else's process, for example to send information back to your debbugger.

1 Like

And that executable file needs to be on disk, right? So no support for running it in memory?