Hello, this an extremely simple tutorial on how to call the win32api from WASI to peek your curisoty and maybe incite you to do more I promise suuuper simple.
First what is web assembly?
Well the official definition is : “WebAssembly (abbreviated Wasm ) is a binary instruction format for a stack-based virtual machine. Wasm is designed as a portable target for compilation of high-level languages like C/C++/Rust”,
Or: " WebAssembly is an assembly language for a conceptual machine, not a physical one. This is why it can be run across a variety of different machine architectures."
Now what about WASI?
The Official definitions goes as follow : " WASI is a modular system interface for WebAssembly. Focused on stability and portability…"
Or: “Just as WebAssembly is an assembly language for a conceptual machine, WebAssembly needs a system interface for a conceptual operating system, not any single operating system. This way, it can be run across all different OSs.
This is what WASI is — a system interface for the WebAssembly platform.
We aim to create a system interface that will be a true companion to WebAssembly and last the test of time. This means upholding the key principles of WebAssembly — portability and security”
The key thing in here is that WASI itself is a standard, it has multiple implentations, for now there is two that are of interest.
Which both provide a runtime, compilation backends, and an ABI and both support embeding(Note that wasmer has a greater support in general and have more bindings) , that means that you can call the runtime from a multitude of language. The Wasmtime binary is the CLI implementation of that, not the actual runtime itself.
Wasmtime uses Just in time compilation and cranelift as a backend.
A few Disclaimer first: WASI and WASM in general is a really new technology, it is unsatble, and outside of the broswer has very few actual practical cases, it’s support for the WindowsAPi is close to inexistant appart from the ability to read/write to files and to readDaClock, first because the standard wishes to have a POSIX like sycall inteface and also because calling the API isn’t safe by definition, it coudl allow for sandbox evasion, DLL injections and others which I am trying to implement(poorly) and that the people working on the different implentations seems to value SAfEtY above all esle. MoAr abstraction == Moar Safety it is known.
I Believe that it will be oneday perfect to run modular malwares that day isn’t here yet, I have made a shellcode Loader which works but that is still a long way from being able to compile Windows.h to WASM and have a full abstracted interface, until then let’s MessageBoxA ourself to paradise.
Requirements: a Rust compiler, ability to read and write Rust, Extensive Knowledge of MessageBoxA, WIndows10, a text editor, and that’s about it.
So first of all let’s install rust if it isn’t already the case https://static.rust-lang.org/rustup/dist/i686-pc-windows-gnu/rustup-init.exe
run it and then check everything is alright rustc --version.
then : rustup target add wasm32-unknown-unknown and rustup target add wasm32-wasi to be able to compile to our desired format.
then you shall ReCusively clone the wasmtime repo, don’t forget --recursive or after that it won’t build because the .witx file will be missing.
git clone --recursive https://github.com/bytecodealliance/wasmtime.git
and then finally cargo build or cargo build --release then go do something else because that may take a while, now if it compiled without any problem you should be set for the next Part if not look at the errors and fix what went wrong.
Now, to add a new sycall to wasmtime you need to do two things -1 : you need to edit the wasi_snapshot_preview1.witx located at wasmtime/crates/wasi-common/WASI/phases/snapshot/witx/wasi_snapshot_preview1.witx in order to declare the new syscall
The function takes two arguments, and retunrs a error erno you will see later that is not true due to my laziness, it will always return Ok(()) no matter what,
then to the second part open crates/wasi-common/src/snapshots/wasi_snapshot_preview1.rs
This is where you will be defining and implementing the actual function, btw I am using the Winapi crate https://docs.rs/winapi/0.3.8/winapi/ so don’t forget to add it to the cargo manifest.
Now you will notice a few things first a reference of self(Needed for the trait impl), and the the two Agruments have the types &GuestPtr<> which is from the https://docs.rs/wiggle/0.16.0/wiggle/struct.GuestPtr.html crate, I suggest you read the doumentation, as well as https://github.com/WebAssembly/WASI/blob/2b027d91c29e6141a3768e638076daa23f51621c/phases/snapshot/witx/typenames.witx the types definitions. We are using an unsafe Block and not MessageBoxW(Quicker to implement but you could definitly use a Utf16 vector insted of a str)Now this should compile just fine, now how do you call it you may ask, that’s actually the easier part
make a new project cargo new --lib whatever edit the cargo.toml and add under lib add crate-type =
First define our entry point, this is needed at the moment otherwise this won’t be considered a wasi module by the runtime, next direct the compiler to link with the previously edited snapshot
#[link(wasm_import_module = “wasi_snapshot_preview1”)]
THe next thing to do is to define the function signature, this is important because as mistmatch will prevent you from calling it sucessfully,
Next make your call to message Box with proper arguments.
cargo build --target wasm32-unknown-unknown
next where the wasmtime cli has been built give the path of where the library has been built and press enter, you should see the message box poping, if you want to see a trace and possible error message you should set RUST_LOG=wasi_common=trace wasmtime env variable.
congrats you have now MessageBoxA from WASI, pretty useless I know, you now have the recipe for GetProcAddress, GetModuleHandle, VirtualAlloc, CreateRemoteThread ect…
If you are interested you should try to add these to the snapshot, make a PEloader or a process hollower, use it with the runtime embeded, maybe try to compile Windows.h to WASI if it’s possible.
anyway thanks for your time.
Ressource I used to make this where it’s much better explained to be honest I could have both linked these two and been done with it but Idk didn’t feel complete: