danleh / wasabi

A dynamic analysis framework for WebAssembly programs.
http://wasabi.software-lab.org
MIT License
366 stars 47 forks source link

Compile Wasabi to WebAssembly itself, do instrumentation "just before instantiation" #13

Open danleh opened 5 years ago

danleh commented 5 years ago

Motivation: no "offline" instrumentation step necessary any longer, could (in principle) just add one wasabi.js file (with wasm inline) that does all the instrumentation + JS codegen

Potential steps:

rxEckT commented 4 years ago

Hi Daniel,

Thank you for your work on Wasabi!

I took a stab at compiling Wasabi to WebAssembly and this is what I have:

// lib.rs
#[derive(Serialize)]
pub struct Instrument {
    pub output: Vec<u8>,
    pub js: String
}

#[wasm_bindgen]
pub fn instrument(bytes: &[u8]) -> JsValue {
    console_error_panic_hook::set_once();
    let mut module: Module = LLModule::decode(&mut BufReader::new(bytes)).unwrap().into();
    let enabled_hooks = EnabledHooks::all();
    let js = add_hooks(&mut module, &enabled_hooks).unwrap();
    let mut wasm: Vec<u8> = Vec::new();
    {
        let mut writer = BufWriter::new(&mut wasm);
        let llmodule: LLModule = module.into();
        llmodule.encode(&mut writer);
    }
    let ret = Instrument {
        output: wasm, 
        js: js
    };
    return JsValue::from_serde(&ret).unwrap();
}

Full diff available here: https://gist.github.com/rxEckT/1b37a10197751b10110ca536aded811d


You should be able to use this html as a harness after building

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <form>
        <input id="uploadWasm" type="file" name="Upload...">
    </form>
    <script type="module">
        import init, { instrument } from "./wasabi.js";

        function instrument() {
            const file = this.files[0];
            const reader  = new FileReader();
            reader.onload = function(e) {
                const bytes = new Uint8Array(e.target.result);
                const result = instrument(bytes);
                window.result = result;
                // open console and play with window.result
                // (new Function(result.js))();
                // WebAssembly.instantiate(Uint8Array.from(result.output))...
            }
            reader.readAsArrayBuffer(file);
        }

        document.getElementById("uploadWasm").addEventListener("change", instrument, false);
    </script>
</body>
</html>
danleh commented 4 years ago

Hi rxEckT,

Ah nice, that looks very good indeed :-) If you are fine with the MIT license of the project, I will use this as a basis for implementing it with a bit more automation (e.g., patching WebAssembly.instantiate to instrument all wasm files).

Since I am travelling right now, I will have to take a look at it later. But thanks for taking it already this far!

Out of curiosity: are you using that code yourself? And more general: Are you doing research with Wasabi?

rxEckT commented 4 years ago

If you are fine with the MIT license of the project, I will use this as a basis...

No problem, go ahead :)

are you using that code yourself?

It's actually something I barely scrapped together without knowing Rust (it was hard work!)

Are you doing research with Wasabi?

Unfortunately no, but I do think Wasabi opens up a lot of possibilities for research, as noted in your paper :D