stein-exe/DevMystical-deobf

GitHub: stein-exe/DevMystical-deobf

Stars: 0 | Forks: 0

[![Python](https://img.shields.io/badge/Python-3.9%2B-3776AB?style=for-the-badge&logo=python&logoColor=white)](https://www.python.org/) [![License](https://img.shields.io/badge/License-MIT-22c55e?style=for-the-badge)](LICENSE) [![Last Commit](https://img.shields.io/github/last-commit/stein-exe/DevMystical-deobf?style=for-the-badge&color=f59e0b)](https://github.com/stein-exe/DevMystical-deobf/commits) [![Repo Size](https://img.shields.io/github/repo-size/stein-exe/DevMystical-deobf?style=for-the-badge&color=8b5cf6)](https://github.com/stein-exe/DevMystical-deobf) [![Stars](https://img.shields.io/github/stars/stein-exe/DevMystical-deobf?style=for-the-badge&color=ef4444)](https://github.com/stein-exe/DevMystical-deobf/stargazers) [![Forks](https://img.shields.io/github/forks/stein-exe/DevMystical-deobf?style=for-the-badge&color=06b6d4)](https://github.com/stein-exe/DevMystical-deobf/network/members) [![Visitors](https://visitor-badge.laobi.icu/badge?page_id=stein-exe.DevMystical-deobf&style=for-the-badge)](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.*