Skip to main content

A comprehensive Python code obfuscation engine

Project description

obfus

A comprehensive Python code obfuscation engine.

Python 3.9+ License: MIT

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

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

MIT License - see LICENSE for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

obfus-3.7.2.tar.gz (39.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

obfus-3.7.2-py3-none-any.whl (24.7 kB view details)

Uploaded Python 3

File details

Details for the file obfus-3.7.2.tar.gz.

File metadata

  • Download URL: obfus-3.7.2.tar.gz
  • Upload date:
  • Size: 39.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.3

File hashes

Hashes for obfus-3.7.2.tar.gz
Algorithm Hash digest
SHA256 2610fe0c288a6f4baf205fc53b9a7069774924a14c028bdb71ae1c70e0e52350
MD5 fa85668b1cd84a754435130bf73a2c51
BLAKE2b-256 4bc29271b3141eabb319e314f816f1568b7ea8f2c6268c6697ea56dcb0def285

See more details on using hashes here.

File details

Details for the file obfus-3.7.2-py3-none-any.whl.

File metadata

  • Download URL: obfus-3.7.2-py3-none-any.whl
  • Upload date:
  • Size: 24.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.3

File hashes

Hashes for obfus-3.7.2-py3-none-any.whl
Algorithm Hash digest
SHA256 61def12aa307e74a1d1b2a7decc1d5f24281cd3f7de1354709caef441e8e7c68
MD5 280b724671ad4f81e6da29948704e7cc
BLAKE2b-256 4555809498359ed4487b9042ea1ddd8ab6aad7f56e064ff624bdf44679a8e25d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page