L3S DRM Developer Guide

WASM Build & Security

This guide covers the essential build process and security considerations for implementing L3S DRM in your WASM module. These security measures are crucial for protecting your aircraft against tampering and reverse engineering.

Important: These security measures are highly recommended for any public release. With default compiler settings, the generated .wasm file tends to be fairly human-readable, making it easier for attackers to locate and modify critical DRM-related logic.


Security Implementation

1. Using the Latest Include Files

Ensure you're using the latest files from the include/ directory provided with L3S DRM. These files contain the most current security features and should be copied to your project's include path.


2. String Obfuscation

L3S DRM includes a header-only library (obfusheader.h) that enables simple string obfuscation in C++. This makes it significantly harder for attackers to identify sensitive information in your compiled WASM.

Usage:

  1. Add #include "obfusheader.h" to your C++ file
  2. Wrap sensitive strings in OBF(...), for example: OBF("\work\auth.l3")

Recommended strings to obfuscate:

  • Activation URLs
  • Local file paths
  • Regex patterns

Example implementation:

#include "obfusheader.h"
std::string apiKey = OBF("YOUR_API_KEY");

3. Remove All "DRM" References from Your Binary

Your compiled .wasm file contains every string literal from your C++ code in plaintext. An attacker can open the file in a text editor (e.g. Notepad++) and search for "DRM" to instantly locate security-critical code paths.

Wrap every string containing "DRM" with OBF():

// BAD — plaintext "DRM" will appear in the .wasm binary
std::cout << "Starting DRM check..." << std::endl;

// GOOD — obfuscated at compile time, invisible in the binary
std::cout << OBF("Starting DRM check...") << std::endl;

Avoid naming your own functions or variables with "DRM" in the name. Function and variable names can end up in the binary. The compiler visibility flags (see below) hide most internal symbol names, but not all. Instead of InitializeDRM() or drmStatus, use ambiguous names that do not hint at the purpose of the code.

Verification: After building and running wasm-opt (see build steps below), open the final .wasm file in a text editor and search for DRM (case-insensitive). You should find zero matches. If any remain, either wrap the corresponding string with OBF() or rename the function/variable.


4. Compiler Visibility Flags

To reduce the number of exported symbols in your WASM module (making reverse engineering harder), add the following compiler flags:

/clang:-fvisibility=hidden /clang:-fvisibility-inlines-hidden

Where to set in Visual Studio:

  1. Right-click the project → Properties
  2. Navigate to C/C++Command Line
  3. Add the flags to Additional Options

Important: These flags must be applied to your main WASM project and any class library projects that are linked into it, if applicable.


5. Build Configuration Setup

It's recommended to set up separate build configurations for Marketplace (incl. XBOX) and Direct Sales releases. The _MARKETPLACE_PKG compiler flag should be defined for Marketplace builds.

This enables conditional compilation, allowing you to include or exclude certain security features based on your distribution method.


Complete Build Process

1. Build the WASM file

Compile your .wasm file using your standard build process.

2. Optimize the WASM file (optional but highly recommended)

This step makes reverse engineering more difficult:

wasm-opt INPUT_FILE.wasm -o optimized.wasm ^
  --strip-debug ^
  --strip-dwarf ^
  --strip-producers

Tip: This process is easy to automate using a .bat or build script. See the automation examples below.


Build Automation Examples

Visual Studio Pre-Build Event

The pre-build script auto-generates file hashes for integrity verification. Add this to your project configuration:

Pre-Build Event Command:

$(ProjectDir)scripts\prebuild-msfs.bat $(ProjectDir) $(SolutionDir)

This script generates file hashes automatically at compile time, eliminating the need to manually look up hashes in debug mode. See the demo project for a complete example of the prebuild script.


Visual Studio Post-Build Event

For Visual Studio projects, you can automate the optimization and copy process using a post-build event. Add this to your project configuration:

Post-Build Event Command:

$(ProjectDir)scripts\postbuild-msfs.bat $(SolutionDir) $(OutDir)

Example post-build script (postbuild-msfs.bat):

@echo off
setlocal enabledelayedexpansion

echo ---- BEGIN POST BUILD SCRIPT ----
echo solution dir = %1%
echo output dir = %2%

cd /d "%~dp0"
if errorlevel 1 exit /b 1

REM Find the first .wasm file
set "WASM_FILE="
for %%F in ("%2%\*.wasm") do (
    set "WASM_FILE=%%~fF"
    goto :found_wasm
)

echo No .wasm file found in %2%
exit /b 1

:found_wasm
echo wasm file = !WASM_FILE!

echo -- WASM-OPT ---
wasm-opt "!WASM_FILE!" -o "!WASM_FILE!" ^
  --strip-debug ^
  --strip-dwarf ^
  --strip-producers
if errorlevel 1 exit /b 1

echo -- COPY INTO AIRCRAFT SOURCE FOLDER --
copy /Y "!WASM_FILE!" "%1%..\..\PackageSources\SimObjects\Airplanes\MyCompany_CommBus_Aircraft\panel\"
if errorlevel 1 exit /b 1

echo ---- END POST BUILD SCRIPT ----

Tip: This script automatically finds the .wasm file, optimizes it, and copies it to your aircraft package folder—all in one step!


Marketplace/Xbox vs Direct Sales Summary

FeatureMarketplace BuildDirect Sales Build
Keyless ModeSet to trueSet to false

Troubleshooting

String obfuscation not working

Ensure you're including obfusheader.h and wrapping strings with OBF(...). Verify by inspecting the compiled .wasm file in a text editor for unobfuscated strings.

Build errors with visibility flags

Make sure the flags are added to Additional Options under C/C++ → Command Line, not under other compiler settings. Also ensure the flags are set for all linked projects.