stein-exe/DevMystical-deobf
GitHub: stein-exe/DevMystical-deobf
Stars: 0 | Forks: 0
[](https://www.python.org/)
[](LICENSE)
[](https://github.com/stein-exe/DevMystical-deobf/commits)
[](https://github.com/stein-exe/DevMystical-deobf)
[](https://github.com/stein-exe/DevMystical-deobf/stargazers)
[](https://github.com/stein-exe/DevMystical-deobf/network/members)
[](https://github.com/stein-exe/DevMystical-deobf)
### ◆ AST-Level Python Obfuscation — Sandbox-Hardened Deobfuscator Included
*Origin by [DevMystical](https://github.com/DevMystical/Obfuscator) · Maintained by [Stein](https://github.com/stein-exe)*
## ⟡ At a Glance
| ◈ | Detail |
|---|---|
| 🐍 **Language** | Python 3.9+ |
| 📦 **Dependencies** | None — stdlib only |
| 🔒 **Deobfuscation model** | Static analysis · sandbox-isolated exec · AST-only unpickling |
| 🎯 **Obfuscation target** | Any valid Python source file |
| 📁 **Core files** | `obf.py` · `deobf.py` |
| ⚠️ **Use case** | Educational · authorized code analysis · CTF · research |
## ▸ Quick Start
# Clone
git clone https://github.com/stein-exe/DevMystical-deobf.git
cd DevMystical-deobf
# Obfuscate — no install needed, pure stdlib
python obf.py
# Enter input file path: myscript.py
# Output written to: a.py
# Deobfuscate back
python deobf.py
# Enter file path (99 to exit): a.py
# Success! Saved to: a_deobf.py
## ✦ Project Structure
DevMystical-deobf/
├── obf.py ← obfuscation engine — AST → pickle → lambda chain
├── deobf.py ← deobfuscator — static reconstruction, sandbox-hardened
├── README.md
└── LICENSE ← MIT
## ◆ Features
### 「 Obfuscator 」
| ✦ | Technique |
|---|---|
| **AST serialization** | Every node individually pickled with ISO-8859-1 encoding |
| **Lambda/type class chain** | Anonymous class hierarchy — all names replaced with `_`, `__`, `___` sequences |
| **Prime factorization encoding** | Integers expressed as chains of math identities — no numeric literals survive |
| **Nested character tree** | Every byte stored in obfuscated attribute chains — no string literals visible |
| **Runtime reconstruction** | AST rebuilt from pickle fragments and run via `compile` + `exec` |
### 「 Deobfuscator 」
| ✦ | Guarantee |
|---|---|
| **Static-only analysis** | The payload **never executes** |
| **Minimal sandbox** | `exec` runs with a strict allowlist — `open`, `os`, `eval`, `import` are absent |
| **`_AstOnlyUnpickler`** | Blocks all non-`ast.*` classes at the pickle layer |
| **`ast.Expr` exclusion** | The final `exec(…)` call is stripped before analysis begins |
| **Output validation** | Result is re-parsed with `ast.parse()` before writing |
| **Zero dependencies** | Pure Python stdlib |
## ⚡ How the Obfuscation Works
Five stacked transformation layers, applied in sequence:
flowchart TD
A[Python source] --> B[AST Serialization\nEach node pickled individually\nISO-8859-1 encoding]
B --> C[Lambda / Type Class Chain\nlambda _: type(*_) hierarchy\nAll identifiers → underscore sequences]
C --> D[Number Encoding\nPrime factorization chains\nco_argcount-derived primitives]
D --> E[Character Storage\nEvery byte in nested class tree\nAccess via obfuscated attribute chains]
E --> F[Runtime Reconstruction\nAST rebuilt from pickle fragments\ncompile + exec]
F --> G[Obfuscated output runs\nas original code]
## 🛡️ Security Model
The deobfuscator reconstructs source **statically** — it never runs the obfuscated payload. Three explicit threat mitigations:
| ⚠️ Risk | ✗ Unpatched | ✔ Hardened |
|---|---|---|
| **Malicious assignments at analysis time** | `exec` with full `builtins` — `open`, `os`, `eval`, `import` all live | `exec` with a minimal allowlist — only `type`, `getattr`, `setattr`, `hasattr`, `isinstance`, `len`, and primitives |
| **Pickle deserializing arbitrary classes** | `pickle.loads` with zero restrictions | `_AstOnlyUnpickler` — only `ast.*` classes pass; everything else raises `UnpicklingError` |
| **`exec(…)` nodes triggering the payload** | `ast.Expr` nodes could leak into the analysis batch | `ast.Expr` nodes excluded from the execution batch entirely |
## ▸ Usage
### 「 Obfuscator 」
**CLI**
python obf.py
# Enter input file path: myscript.py
# Output written to: a.py
**Python API**
from obf import obfuscate
with open("myscript.py", "r", encoding="utf-8") as f:
source = f.read()
obfuscated = obfuscate(source)
with open("myscript_obf.py", "w", encoding="utf-8") as f:
f.write(obfuscated)
### 「 Deobfuscator 」
**CLI**
python deobf.py
# Enter file path (99 to exit): a.py
# Processing: a.py ...
# Success! Saved to: a_deobf.py
**Python API**
from deobf import deobfuscate_file, deobfuscate_source
# File API — reads input, writes _deobf.py, returns output path
output_path = deobfuscate_file("a.py")
# String API — pass source directly, get restored source back
with open("a.py", encoding="utf-8") as f:
source = f.read()
restored = deobfuscate_source(source)
## ⟡ How the Deobfuscator Works
flowchart TD
A[Obfuscated .py input] --> B[ast.parse\nStatic parse only — zero execution]
B --> C[Extract assignments\nexec in minimal sandbox\nno os / open / eval / import]
C --> D[Find pickle list\nLocates list of path + bytes pairs]
D --> E[_AstOnlyUnpickler\nRebuilds ast.* nodes\nBlocks ALL other classes → UnpicklingError]
E --> F[Reconstruct AST tree\nWalks path fragments\nSets nodes in reverse order]
F --> G[ast.unparse\nProduces clean Python source]
G --> H[ast.parse validation\nConfirms output is valid syntax]
H --> I[Write _deobf.py output]
## ⚠️ Limitations
| 🚧 | Detail |
|---|---|
| **Format lock-in** | Only supports the DevMystical obfuscation format — other obfuscators are not supported |
| **No comment recovery** | Output is compact `ast.unparse` style — comments and original formatting are not stored in the AST |
| **Corrupted input** | If the obfuscated file was modified post-obfuscation, partial output may be produced with warnings on stderr |
## 🗺️ Roadmap
| ◈ | Item |
|---|---|
| ☐ | **Batch mode** — obfuscate/deobfuscate entire directories in one pass |
| ☐ | **Formatted output** — run `black` or `autopep8` on deobfuscated result automatically |
| ☐ | **Format detection** — auto-detect obfuscation variant and route to correct deobfuscator |
| ☐ | **Test suite** — property-based round-trip tests (obfuscate → deobfuscate → compare AST) |
## ⟡ Looking for Stronger Obfuscation?
If you need production-grade Python obfuscation, check out [hermit](https://github.com/stein-exe/hermit/) — a more advanced obfuscator built by [Stein](https://github.com/stein-exe).
## 📄 License
Released under the **MIT License**. See [`LICENSE`](LICENSE) for full terms.
*Built on Python's AST — because real obfuscation happens at the syntax tree, not the surface.*