|
| 1 | +# SWAMPED CLI |
| 2 | + |
| 3 | +CLI for applying 22 semantics-preserving perturbation methods to WebAssembly modules. |
| 4 | + |
| 5 | +## Install |
| 6 | + |
| 7 | +```bash |
| 8 | +# Requires WABT (wasm2wat / wat2wasm) on PATH |
| 9 | +brew install wabt # macOS |
| 10 | +apt install wabt # Debian/Ubuntu |
| 11 | + |
| 12 | +# Install swamped globally |
| 13 | +pip install -e . |
| 14 | +``` |
| 15 | + |
| 16 | +## Quick start |
| 17 | + |
| 18 | +```bash |
| 19 | +# List all 22 perturbation methods |
| 20 | +swamped list |
| 21 | + |
| 22 | +# Apply specific strategies |
| 23 | +swamped obfuscate input.wasm -o output.wasm -s nop_insertion shift_transformation |
| 24 | + |
| 25 | +# Apply all strategies at once |
| 26 | +swamped obfuscate input.wasm -o output.wasm -s all |
| 27 | + |
| 28 | +# Only structural or only code-level |
| 29 | +swamped obfuscate input.wasm -o output.wasm -s structural |
| 30 | +swamped obfuscate input.wasm -o output.wasm -s code |
| 31 | + |
| 32 | +# Exclude specific strategies with -e |
| 33 | +swamped obfuscate input.wasm -o output.wasm -s all -e data_encryption direct_to_indirect |
| 34 | +swamped obfuscate input.wasm -o output.wasm -s code -e nop_insertion |
| 35 | + |
| 36 | +# Control intensity (0.0 = none, 1.0 = max) |
| 37 | +swamped obfuscate input.wasm -o output.wasm -s all --ratio 0.3 |
| 38 | + |
| 39 | +# Validate the output after obfuscation |
| 40 | +swamped obfuscate input.wasm -o output.wasm -s nop_insertion --validate |
| 41 | + |
| 42 | +# Stack operation insertion: all 6 variants (default) |
| 43 | +swamped obfuscate input.wasm -o output.wasm -s stack_op_insertion |
| 44 | + |
| 45 | +# Stack operation insertion: only specific variants |
| 46 | +swamped obfuscate input.wasm -o output.wasm -s stack_op_insertion --stackop m b f |
| 47 | +``` |
| 48 | + |
| 49 | +Accepts both `.wasm` and `.wast` as input/output — conversion is automatic. |
| 50 | + |
| 51 | +## The 22 perturbation methods |
| 52 | + |
| 53 | +### Structural perturbations (9) |
| 54 | + |
| 55 | +| # | Name | Description | |
| 56 | +| --- | ------------------------ | ------------------------------------------------ | |
| 57 | +| 1 | `function_sig_insertion` | Inject unused function type signatures | |
| 58 | +| 2 | `import_insertion` | Inject unused import declarations | |
| 59 | +| 3 | `function_insertion` | Inject entire dummy function bodies | |
| 60 | +| 4 | `function_body_cloning` | Clone functions with proxy redirection | |
| 61 | +| 5 | `global_insertion` | Inject dummy global variables | |
| 62 | +| 6 | `element_insertion` | Inject table element entries | |
| 63 | +| 7 | `export_insertion` | Inject unused export declarations | |
| 64 | +| 8 | `data_insertion` | Inject unused data segments | |
| 65 | +| 9 | `data_encryption` | XOR-encrypt data segments with runtime decryptor | |
| 66 | + |
| 67 | +### Code-level perturbations (13) |
| 68 | + |
| 69 | +| # | Name | Description | |
| 70 | +| --- | ------------------------------- | -------------------------------------------------------- | |
| 71 | +| 10 | `custom_section_insertion` | Inject custom named sections _(not yet implemented)_ | |
| 72 | +| 11 | `nop_insertion` | Insert NOP instructions | |
| 73 | +| 12 | `stack_op_insertion` | Insert dummy stack operations (see sub-variants below) | |
| 74 | +| 13 | `opaque_predicate_insertion` | Insert always-true/false Collatz-based predicates | |
| 75 | +| 14 | `proxy_function_insertion` | Insert proxy wrapper functions _(not yet implemented)_ | |
| 76 | +| 15 | `direct_to_indirect` | Convert direct calls to indirect table calls | |
| 77 | +| 16 | `add_sub_transformation` | Transform add/sub operations (a+b <-> a-(-b)) | |
| 78 | +| 17 | `shift_transformation` | Convert shifts to mul/div equivalents | |
| 79 | +| 18 | `eqz_transformation` | Rewrite eqz as comparison with zero | |
| 80 | +| 19 | `offset_expansion` | Decompose memory offset encoding | |
| 81 | +| 20 | `mba_transformation` | Replace XOR/OR with mixed boolean-arithmetic expressions | |
| 82 | +| 21 | `constant_value_splitting` | Split constants into arithmetic sums | |
| 83 | +| 22 | `constant_value_transformation` | Replace constants with global variable reads | |
| 84 | + |
| 85 | +### Stack operation sub-variants (`--stackop`) |
| 86 | + |
| 87 | +When using `stack_op_insertion`, you can select specific sub-variants with `--stackop`. If omitted, all 6 are applied. |
| 88 | + |
| 89 | +| Flag | Description | |
| 90 | +| ---- | ------------------------------ | |
| 91 | +| `m` | memory/local/global operations | |
| 92 | +| `n` | arithmetic operations | |
| 93 | +| `b` | bitwise operations | |
| 94 | +| `c1` | type conversions (int/float) | |
| 95 | +| `c2` | floating-point conversions | |
| 96 | +| `f` | float operations | |
| 97 | + |
| 98 | +Example: `swamped obfuscate input.wasm -o out.wasm -s stack_op_insertion --stackop m n b` |
| 99 | + |
| 100 | +## Options |
| 101 | + |
| 102 | +| Flag | Default | Description | |
| 103 | +| ------------ | ------- | ------------------------------------------------------------ | |
| 104 | +| `-s` | — | Strategy names, or `all` / `structural` / `code` | |
| 105 | +| `-e` | — | Exclude strategies (useful with `all`/`structural`/`code`) | |
| 106 | +| `-o` | — | Output path (`.wasm` or `.wast`) | |
| 107 | +| `--stackop` | all | Stack operation sub-variants: `m`, `n`, `b`, `c1`, `c2`, `f` | |
| 108 | +| `--ratio` | `1.0` | Fraction of targets to perturb | |
| 109 | +| `--alpha` | `1.0` | Beta-distribution alpha (target selection bias) | |
| 110 | +| `--beta` | `1.0` | Beta-distribution beta (target selection bias) | |
| 111 | +| `--validate` | off | Run `wasm-validate` on the output | |
| 112 | + |
| 113 | +## Parameters |
| 114 | + |
| 115 | +Defaults (`alpha=1, beta=1, ratio=1`) match the original project. |
| 116 | + |
| 117 | +**`--ratio`** controls how much gets perturbed: |
| 118 | + |
| 119 | +- `1.0` = everything (default), `0.5` = half, `0.1` = light |
| 120 | + |
| 121 | +**`--alpha`** and **`--beta`** shape a [Beta distribution](https://en.wikipedia.org/wiki/Beta_distribution) that determines _where_ perturbations are applied within each function or section. Instead of picking targets purely at random, these parameters let you bias selection toward specific regions of the instruction sequence: |
| 122 | + |
| 123 | +- `alpha=1, beta=1` — uniform distribution, all positions equally likely (default) |
| 124 | +- `alpha=1, beta=3` — skewed toward the beginning (early instructions are more likely to be perturbed) |
| 125 | +- `alpha=3, beta=1` — skewed toward the end (later instructions are more likely to be perturbed) |
| 126 | +- `alpha=2, beta=2` — bell-shaped, concentrates perturbations in the middle |
| 127 | + |
| 128 | +If you just want to control how much gets changed, `--ratio` is enough. Use `--alpha`/`--beta` when you need finer control over the spatial distribution of perturbations. |
| 129 | + |
| 130 | +## Preliminary tests |
| 131 | + |
| 132 | +**Setup:** the `function_insertion` strategy requires a symlink `strategies/data/function_body.pkl` pointing to one of the precomputed pool files. Create it before running obfuscation: |
| 133 | + |
| 134 | +```bash |
| 135 | +ln -s function_body_tmp100.pkl strategies/data/function_body.pkl |
| 136 | +``` |
| 137 | + |
| 138 | +Strategies could work correctly when applied individually. |
| 139 | + |
| 140 | +Known issues: |
| 141 | + |
| 142 | +- `function_body_cloning` + `function_insertion` — cloned proxy calls break when new functions shift indices |
| 143 | +- `data_encryption` — injected decryption function may have mismatched signatures on certain modules |
| 144 | + |
| 145 | +Use `--validate` to catch failures, and `-e` to exclude problematic strategies: |
| 146 | + |
| 147 | +```bash |
| 148 | +swamped obfuscate input.wasm -o out.wasm -s structural -e data_encryption function_body_cloning --validate |
| 149 | +``` |
| 150 | + |
| 151 | +## License |
| 152 | + |
| 153 | +See [LICENSE](../LICENSE). |
0 commit comments