Multi-language code obfuscation engine by SnailSploit
AST-based Python β’ Token-based JS/Go β’ Zero dependencies β’ Single file
SnailObfuscator uses structurally-aware engines instead of regex string hacking:
| Language | Engine | Guarantee |
|---|---|---|
| Python | ast.NodeTransformer |
Syntactically valid output via ast.unparse() |
| JavaScript | Token-based lexer | Strings and comments are never mangled |
| Go | Token-based lexer | Strings and comments are never mangled |
Why this matters: Regex-based obfuscators break on edge cases like "class Foo: # not a comment" (parsed as code), myself_score (partially matched by self. replacement), or print("nested \"quotes\" are hard") (string boundary confusion). SnailObfuscator's AST/tokenizer approach is structurally immune to all of these.
No dependencies. Requires Python 3.9+.
# Download the single file
curl -O https://raw.githubusercontent.com/snailsploit/snailobfuscator/main/snailobfuscator.py
# Or clone
git clone https://github.com/snailsploit/snailobfuscator.git# Obfuscate a Python file with the medium preset
python3 snailobfuscator.py -i script.py -o out.py --preset medium
# Obfuscate a JS file with heavy preset
python3 snailobfuscator.py -i app.js --preset heavy
# Batch process a directory
python3 snailobfuscator.py -d ./src -o ./dist --preset paranoid -r
# Watch mode (auto-obfuscate on file changes)
python3 snailobfuscator.py -d ./src -o ./dist --preset heavy --watch
# Pipe from stdin
cat script.py | python3 snailobfuscator.py --lang python --preset light
# Reproducible output with seed
python3 snailobfuscator.py -i script.py --preset heavy --seed 42| Preset | Techniques | Use Case |
|---|---|---|
light |
Name mangling, comment stripping | Quick anonymization |
medium |
+ string encoding, dead code (20%) | General distribution |
heavy |
+ integer encoding, anti-debug, MBA, opaque predicates | Commercial protection |
paranoid |
+ string array, homoglyphs | Maximum obfuscation |
fortress |
Everything maxed + compression | Single-line output blob |
Renames user-defined variables, functions, and classes. Four styles:
| Style | Example | Flag |
|---|---|---|
| Hex | _0x001a |
--name-style hex |
| IL | _IlI1lIl1 |
--name-style il |
| OO | _O0oO0O0o |
--name-style oo |
| Homoglyph | _Ξ±Π΅ΟΟΞ΅1 (Cyrillic/Greek lookalikes) |
--name-style homoglyph |
Safety features:
- Imports are never mangled (
visit_Import/visit_ImportFromadd all imported names to the reserved set) - Built-in methods like
list.count()are never mangled (attribute mangling is scoped to class-defined methods andself.Xassignments only) - Reserved words and dunder methods are always preserved
Encodes string literals. Five methods:
| Method | Python Output | JS Output |
|---|---|---|
b64 |
__import__("base64").b64decode("...").decode() |
atob("...") |
hex |
bytes.fromhex("...").decode() |
"\x68\x65\x6c..." |
chr |
"".join(chr(_c) for _c in [...]) |
String.fromCharCode(...) |
xor |
"".join(chr(_c^K) for _c in [...]) |
[...].map(c=>String.fromCharCode(c^K)).join("") |
random |
Randomly picks from above | Randomly picks from above |
Transforms integer literals (β₯2) into equivalent expressions:
42β(42 + 587) - 58742β(5 << 3) + 242β(6 * 7) + 0
Inserts unreachable code blocks. In Python, dead code is generated as AST nodes and inserted into node.body lists β indentation errors are structurally impossible.
--dead-code --dead-density 0.5 # 50% injection probability per functionReplaces simple false conditions in dead code with mathematically complex expressions that always evaluate to false:
42**2+1==0(73&1)+((73>>1)&1)>3
Mixed Boolean-Arithmetic encoding on Add/Sub operations between variables:
a + bβ(a & b) * 2 + (a ^ b)a - bβ(a ^ b) - 2 * (~a & b)
Extracts all string literals into a rotated array with accessor function:
_sArr = ["world", "hello"] # rotated
def _sRot(i): return _sArr[(i + 1) % 2]
print(_sRot(0)) # "hello"Injects runtime detection for debuggers:
- Python: Checks
sys.gettrace(), disablesdis.dis() - JavaScript: Traps
debuggerstatements viaFunction.prototype.constructoroverride
Wraps entire output in a self-extracting compressed payload:
- Python:
import zlib,base64;exec(zlib.decompress(base64.b64decode("...")).decode()) - JavaScript:
eval(atob("..."))
β οΈ This is NOT a real transpiler. It performs best-effort structural mapping for common patterns. Complex code will likely need manual correction.
# Python β JavaScript
python3 snailobfuscator.py -i script.py --target javascript --preset medium
# JavaScript β Python
python3 snailobfuscator.py -i app.js --target python --preset light
# Python β Go
python3 snailobfuscator.py -i script.py --target go --preset lightSupported conversions: defβfunction, self.βthis., f-stringsβtemplate literals, for inβfor of, class syntax, basic control flow.
usage: snailobfuscator [-h] [-i INPUT] [-d DIR] [-o OUTPUT] [-r]
[-l {python,javascript,go}]
[--target {python,javascript,go}]
[-p {light,medium,heavy,paranoid,fortress}]
[--mangle] [--no-mangle]
[--name-style {hex,il,oo,homoglyph}]
[--encode-strings] [--no-encode-strings]
[--string-method {random,b64,hex,chr,xor}]
[--encode-integers] [--dead-code]
[--dead-density FLOAT] [--opaque-predicates]
[--mba] [--string-array] [--anti-debug]
[--compress] [--strip-comments]
[--strip-docstrings] [--seed INT]
[-w] [-q]
| Flag | Description |
|---|---|
-i / --input |
Input file path |
-d / --dir |
Input directory (batch mode) |
-o / --output |
Output file or directory |
-r / --recursive |
Recurse into subdirectories |
-l / --lang |
Source language (auto-detected from extension) |
--target |
Syntax-convert to target language (experimental) |
-p / --preset |
Obfuscation preset |
-w / --watch |
Watch mode (re-obfuscate on file changes) |
-q / --quiet |
Suppress banner and stats |
--seed |
Random seed for reproducible output |
# Custom technique combo
python3 snailobfuscator.py -i app.py --mangle --name-style homoglyph \
--encode-strings --string-method xor --mba --dead-code --dead-density 0.6
# Batch with watch
python3 snailobfuscator.py -d ./src -o ./dist --preset heavy -r --watch
# Quiet mode for CI/CD pipelines
python3 snailobfuscator.py -i main.py -o main.obf.py --preset medium -q
# Cross-compile and obfuscate
python3 snailobfuscator.py -i server.py --target javascript --preset heavy -o server.obf.jsWhy AST for Python?
Python's ast module is in the standard library and guarantees syntactically valid output via ast.unparse(). Every transformation (name mangling, string encoding, integer encoding, dead code injection, MBA encoding) operates on AST nodes. It is structurally impossible to generate mismatched parentheses, indentation errors, or accidentally mangle identifiers inside string literals.
Why a tokenizer for JS/Go?
Without adding npm/Go dependencies, a full AST isn't available. The tokenizer splits source into typed tokens (STRING, COMMENT, NAME, NUMBER, etc.) and transformations only operate on the correct token type. This prevents the most common regex failure mode: mangling identifiers that appear inside strings or comments.
Why not mangle all attributes?
Python lacks static type information at the source level. If a user defines count = 0 and also calls my_list.count(1), a naive attribute mangler would rename both β breaking the built-in method call. SnailObfuscator scopes attribute mangling to methods defined inside user classes and self.X assignments only.
Why keep the syntax converter? It's explicitly marked experimental and renamed from "transpiler" to set correct expectations. For simple scripts, it produces usable output. For complex code, it's a starting point that needs manual correction. Removing it entirely would remove a genuinely useful feature for the common case.
snailobfuscator.py # Single-file, zero-dependency CLI (1,295 lines)
βββ ObfConfig # @dataclass configuration
βββ NameMangler # 4-style name generation
βββ Tokenizer # Context-aware lexer for JS/Go
βββ PythonObfuscator # ast.NodeTransformer engine
βββ JSObfuscator # Token-based JS engine
βββ GoObfuscator # Token-based Go engine
βββ syntax_convert() # Experimental cross-language conversion
βββ obfuscate() # Orchestrator / dispatch
βββ main() # CLI (argparse, batch, watch, stdin)
MIT
Kai Aizen (@SnailSploit) β GenAI Security Researcher
Built as a utility for security research, CTF challenges, and controlled red team engagements.
