obfus
A comprehensive Python code obfuscation engine.
Features
- String Obfuscation - Multiple encoding methods (XOR, Base64, ROT13, multi-layer)
- Name Mangling - Local variables, arguments, code names, attributes
- Code Object Obfuscation - Bytecode encryption and protection
- Module Protection - Prevent modification and inspection
- Wrap Mode - Dynamic deobfuscation at runtime
- RFT (Refactoring) - Complete identifier renaming
- Import Obfuscation - Hide import statements
- Control Flow Obfuscation - Opaque predicates, dead code injection
- Zero Dependencies - Pure Python, no external packages required
Installation
pip install obfus
Or install from source:
git clone https://github.com/rodmena-limited/obfus.git
cd obfus
pip install -e .
Quick Start
Basic Usage
from obfus import ObfuscationConfig, ObfuscationEngine
# Use preset configurations
config = ObfuscationConfig.minimal() # Light obfuscation
config = ObfuscationConfig.standard() # Balanced obfuscation
config = ObfuscationConfig.aggressive() # Heavy obfuscation
# Create engine and obfuscate
engine = ObfuscationEngine(config)
obfuscated = engine.obfuscate_source('''
def hello(name):
return f"Hello, {name}!"
print(hello("World"))
''')
print(obfuscated)
Convenience Functions
from obfus import obfuscate, obfuscate_file, obfuscate_directory
# Obfuscate a string
result = obfuscate("print('Hello')")
# Obfuscate a file
obfuscate_file("input.py", "output.py")
# Obfuscate entire directory
obfuscate_directory("src/", "dist/")
Command Line
# Obfuscate a single file
obfus input.py -o output.py
# Obfuscate a directory
obfus src/ -o dist/
# With specific preset
obfus input.py -o output.py --preset aggressive
Configuration
Presets
| Preset | Description | Use Case |
|---|---|---|
minimal() |
Light obfuscation, preserves readability | Development, debugging |
standard() |
Balanced protection and performance | General distribution |
aggressive() |
Heavy obfuscation, harder to reverse | Production releases |
maximum() |
Maximum protection, slower execution | High-security applications |
Custom Configuration
from obfus import ObfuscationConfig, ObfuscationEngine, WrapMode
config = ObfuscationConfig(
# Name obfuscation
mix_localnames=True, # Obfuscate local variable names
mix_argnames=False, # Keep argument names (for keyword args)
mix_coname=1, # Hide code object names (0-2)
mix_attr=False, # Obfuscate attribute names
# String obfuscation
mix_str=True, # Obfuscate string constants
mix_str_threshold=8, # Min string length to obfuscate
# Module protection
obf_module=True, # Obfuscate module bytecode
obf_code=1, # Code object obfuscation level (0-2)
wrap_mode=WrapMode.SIMPLE, # Dynamic deobfuscation
# Advanced features
enable_rft=False, # Full identifier renaming
enable_control_flow=False, # Control flow obfuscation
enable_dead_code=False, # Dead code injection
)
engine = ObfuscationEngine(config)
Configuration Options Reference
Name Obfuscation
| Option | Type | Default | Description |
|---|---|---|---|
mix_localnames |
bool | True | Obfuscate local variable names |
mix_argnames |
bool | False | Obfuscate function argument names |
mix_coname |
int | 0 | Hide code object names (0=off, 1=partial, 2=full) |
mix_attr |
bool | False | Obfuscate attribute access names |
String Obfuscation
| Option | Type | Default | Description |
|---|---|---|---|
mix_str |
bool | False | Enable string constant obfuscation |
mix_str_threshold |
int | 8 | Minimum string length to obfuscate |
Module Protection
| Option | Type | Default | Description |
|---|---|---|---|
obf_module |
bool | True | Obfuscate module-level bytecode |
obf_code |
int | 1 | Code object encryption level (0-2) |
wrap_mode |
WrapMode | SIMPLE | Dynamic deobfuscation mode |
restrict_module |
RestrictionLevel | BASIC | Module access restrictions |
readonly_module |
bool | False | Make module attributes read-only |
Advanced Features
| Option | Type | Default | Description |
|---|---|---|---|
enable_rft |
bool | False | Enable full refactoring/renaming |
enable_control_flow |
bool | False | Add control flow obfuscation |
enable_dead_code |
bool | False | Inject dead code blocks |
enable_opaque_predicates |
bool | False | Add opaque predicates |
RFT (Refactoring) Mode
RFT mode performs complete identifier renaming across your codebase:
config = ObfuscationConfig(
enable_rft=True,
rft_excludes={'main', 'setup'}, # Names to preserve
rft_preserve_exports=True, # Keep __all__ names
)
RFT Options
| Option | Type | Default | Description |
|---|---|---|---|
rft_excludes |
Set[str] | {} | Names to exclude from renaming |
rft_auto_exclude |
int | 1 | Auto-exclude behavior (0-2) |
rft_preserve_exports |
bool | True | Preserve names in __all__ |
Limitations and Compatibility
Works With
- Pure Python code
- Standard library usage
- Internal class hierarchies
- Async/await patterns
- Generators and iterators
- Context managers
- Decorators
- Metaclasses
- Dataclasses and enums
May Break
| Scenario | Risk Level | Mitigation |
|---|---|---|
exec()/eval() with string names |
High | Use rft_excludes |
getattr()/setattr() with strings |
High | Use rft_excludes |
| Serialization (pickle, JSON) | High | Use minimal() preset |
| Framework magic (Django, Flask) | High | Use minimal() or skip |
| pytest fixtures | Medium | Don't obfuscate test files |
| CLI tools (Click, argparse) | Medium | Keep argument names |
| External API contracts | Medium | Use rft_excludes |
| Reflection-based libraries | Medium | Test thoroughly |
Safe Usage Guidelines
# For libraries with external interfaces
config = ObfuscationConfig.minimal()
# For standalone scripts
config = ObfuscationConfig.aggressive()
# For maximum protection (internal tools only)
config = ObfuscationConfig.maximum()
Performance
Obfuscation adds minimal runtime overhead:
| Operation | Overhead |
|---|---|
| Import time | ~0-5% |
| Simple operations | ~0-10% |
| String-heavy code | ~10-20% |
| With wrap mode | ~5-15% |
Test suite performance is typically within 5% of original code.
Examples
Obfuscate a Package
from obfus import obfuscate_directory, ObfuscationConfig
config = ObfuscationConfig.standard()
obfuscate_directory(
"mypackage/",
"dist/mypackage/",
config=config,
recursive=True,
)
Preserve Specific Names
config = ObfuscationConfig(
enable_rft=True,
rft_excludes={
'main',
'run',
'setup',
'teardown',
'__init__',
'__call__',
},
)
Skip Certain Files
from pathlib import Path
from obfus import ObfuscationEngine, ObfuscationConfig
config = ObfuscationConfig.standard()
engine = ObfuscationEngine(config)
for py_file in Path("src").rglob("*.py"):
# Skip test files and configs
if "test" in py_file.name or py_file.name == "config.py":
continue
source = py_file.read_text()
obfuscated = engine.obfuscate_source(source)
output = Path("dist") / py_file.relative_to("src")
output.parent.mkdir(parents=True, exist_ok=True)
output.write_text(obfuscated)
Testing
# Run all tests
pytest
# Run with coverage
pytest --cov=obfus --cov-report=html
# Run specific test class
pytest tests/test_obfuscator.py::TestAllFeatures -v
Contributing
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
License
MIT License - see LICENSE for details.
Metadata
Release files for obfus 3.7.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| obfus-3.7.2.tar.gz | 39.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| obfus-3.7.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 64.4 kB
Release files / obfus-3.7.2.tar.gz
| Download URL | obfus-3.7.2.tar.gz |
|---|---|
| Size | 39.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2610fe0c288a6f4baf205fc53b9a7069774924a14c028bdb71ae1c70e0e52350
|
|
BLAKE2b-256 checksum How to use checksums |
4bc29271b3141eabb319e314f816f1568b7ea8f2c6268c6697ea56dcb0def285
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.3
|
Release files / obfus-3.7.2-py3-none-any.whl
| Download URL | obfus-3.7.2-py3-none-any.whl |
|---|---|
| Size | 24.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
61def12aa307e74a1d1b2a7decc1d5f24281cd3f7de1354709caef441e8e7c68
|
|
BLAKE2b-256 checksum How to use checksums |
4555809498359ed4487b9042ea1ddd8ab6aad7f56e064ff624bdf44679a8e25d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.3
|