Skip to content

A stack-based virtual machine with encryption (and obfuscation) for protecting JavaScript code on the web.

Notifications You must be signed in to change notification settings

Thoosje/Wasm-Browser-VM

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

15 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

WASM Stack Based JavaScript VM

A stack based virtual machine with encryption for protecting JavaScript code on the web.

Note: This is my first (big) C++ project, so the code and techniques are probably not optimal. Still, I thought it would be interesting to give it a try and see how far I could get.

Features

  • Custom bytecode compiler for JavaScript subset
  • Session-based opcode randomization
  • Bytecode encryption
  • WebAssembly VM for browser execution
  • Native compiler tool (with JS AST)

Currently the compiler is very basic and does not support strings or any complex javascript. Also interacting with the DOM or external libraries is not possible.

Building

Prerequisites

For Native Compiler:

  • CMake 3.10+
  • C++17 compatible compiler (GCC 7+, Clang 5+, MSVC 2017+)
  • Nodejs with erpisma module

For WASM Module:

  • Emscripten SDK

Setup Emscripten

Install Emscripten

git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
./emsdk install latest
./emsdk activate latest
source ./emsdk_env.sh

Install node moduke

npm install esprima

Build Native Compiler

chmod +x build.sh
./build.sh

This creates build/native/pvmc - the compiler executable.

Build WASM Module

chmod +x build_wasm.sh
./build_wasm.sh

This creates build/wasm/vm.js and build/wasm/vm.wasm

Complete execution with web test server

./build_compiler.sh && ./build_wasm.sh examples/fib.js ./web --debug
./build_compiler.sh && ./build_wasm.sh examples/fib.js ./web --release

The release tag will disable all debug output to devtools and will compile more optimized.

Build-in methods

PRINT

PRINT(1)

Will print a variable or input to the devtools console.

EXIT

EXIT(1)

Will load a variable or output onto the stack and run the HALT opcode which returns the element on top of the stack out of the VM.

Usage

1. Compile JavaScript to Protected Bytecode

# Create a JS file
echo "let x = 10; let y = 5; let result = x + y;" > example.js

# Compile it
./build_compiler.sh && ./build_wasm.sh example.js ./web --debug
npm run serve

# This generates:
# - output.bc (encrypted bytecode)
# - output.bc.session (session keys for WASM)
# - Serves a test page where the code can be exucted (DevTools to see debug messages)

2. Execute in Browser

<!DOCTYPE html>
<html>
<head>
    <script src="vm.js"></script>
</head>
<body>
    <script>
        // Initialize WASM
        WasmVM().then(module => {
            module.then(module => {
                // Load your bytecode
                fetch('output.bc')
                        .then(r => r.arrayBuffer())
                        .then(data => {
                            const result = module.executeCode(new Uint8Array(data));
                            console.log('Result:', result);
                        });
            });
        }).catch(err => {
            console.log('Failed to load WASM');
        });
    </script>
</body>
</html>

Architecture

Developer Machine:                 User's Browser:
┌─────────────┐                   ┌─────────────┐
│  source.js  │                   │encrypted.bc │ ← Public
└──────┬──────┘                   └──────┬──────┘
       │                                 │
       ▼                                 │
┌─────────────┐                          │
│  Compiler   │                          │
└──────┬──────┘                          │
       │                                 │
       ├──→ encrypted.bc                 │
       └──→ encrypted.bc.session         │
              │                          │
              │                          │
       ┌──────▼────────┐                 │
       │ EMBED SESSION │                 │
       │  IN vm.wasm   │                 │
       └──────┬────────┘                 │
              │                          │
              ▼                          │
       ┌─────────────┐                   │
       │  vm.wasm    │ ←─────────────────┤
       │  ┌────────┐ │                   │
       │  │KEYS 🔑 │ │                   ▼
       │  └────────┘ │            ┌─────────────┐
       │   decrypt   │            │  EXECUTE    │
       │   execute   │            │  result: 42 │
       └─────────────┘            └─────────────┘

Security Features

  1. Bytecode Obfuscation: Source code converted to binary bytecode
  2. Encryption: XOR encryption of bytecode (Should be changed in real scenarios)
  3. Opcode Randomization: Different opcode mappings per session
  4. WASM Protection: VM logic compiled to WebAssembly

TODO

  • Add string support
  • Add access to DOM (and external libraries)
  • Better encryption
  • Look further in obfuscation and protecting the WASM

This project is currently very basic and will barely work for any legit usecase.

License

Educational use only.

About

A stack-based virtual machine with encryption (and obfuscation) for protecting JavaScript code on the web.

Topics

Resources

Stars

Watchers

Forks

Languages