Python is inherently readable — .pyc files are trivially decompiled and .py source is plain text. Protecting your software requires a layered approach.
Layer 1 — PyArmor (Obfuscation)
PyArmor obfuscates Python source code and adds runtime protection:
pip install pyarmor
pyarmor gen your_script.py
Output is obfuscated .py files that require PyArmor runtime to execute. Slows casual reverse-engineering significantly but not determined attackers.
Layer 2 — Cython (Compile to C)
Cython compiles Python to C extension modules (.pyd/.so). Much harder to reverse-engineer than .pyc:
# setup.py
from setuptools import setup
from Cython.Build import cythonize
setup(ext_modules=cythonize('your_module.pyx'))
python setup.py build_ext --inplace
The resulting .pyd file contains compiled C code. Decompiling it is significantly harder than decompiling Python bytecode.
Layer 3 — PyInstaller (Packaging)
Bundle everything into a single .exe:
pyinstaller --onefile --noconsole your_script.py
Note: PyInstaller doesn't protect code — executables can be unpacked. Combine with Cython for real protection.
Layer 4 — Online License Validation
This is the most important layer. Even if someone bypasses all obfuscation, they need to call your validation server:
import requests, hashlib, platform, uuid
def validate_license(key):
machine_id = hashlib.sha256(
f"{platform.node()}{uuid.getnode()}".encode()
).hexdigest()[:32]
try:
r = requests.post('https://yourapi.com/validate',
json={'key': key, 'machine_id': machine_id},
timeout=10)
return r.json().get('valid', False)
except:
return False # Or implement grace period
Layer 5 — Anti-Debug Detection
import ctypes, sys
if sys.gettrace() is not None:
sys.exit(1)
# Windows: check IsDebuggerPresent
if ctypes.windll.kernel32.IsDebuggerPresent():
sys.exit(1)
ZeroPhantom offers licensed, protected software tools →