4.2. Understanding Obfuscated Script¶
Remain as standard `.py` files
The obfuscated scripts are normal Python scripts, it’s clear by checking the content of
from pyarmor_runtime_000000 import __pyarmor__ __pyarmor__(__name__, __file__, b'\xa...')
It’s a simple script, first imports function
__pyarmor__ from package
pyarmor_runtime_000000, then call this function.
pyarmor_runtime_000000 is generated by Pyarmor, it’s also a normal Python package, here it’s package content:
$ ls dist/pyarmor_runtime_000000 ... __init__.py ... pyarmor_runtime.so
There is binary extension module
pyarmor_runtime, this is a big difference from plain Python script. Generally using binary extensions means the obfuscated scripts
- may not be compatible with different builds of CPython interpreter.
- often will not work correctly with alternative interpreters such as PyPy, IronPython or Jython
For example, when obfuscating scripts by Python 3.8, they can be run by any Python 3.8.x, but can’t be run by Python 3.7, 3.9 etc.
For example, packaging pure .py script is easy, but packaging binary extension need more work.
For example, in Android pure .py script can be run in any location, but binary extensions must be in special system paths.
The runtime package
pyarmor_runtime_000000 could be in any path, it can be taken as a third-party package, save it in any location, and import it following Python import system.
The runtime key generally is embedded into extension module
pyarmor_runtime, it also could be an outer file. It stores expire date, bind devices, and user private data etc.
pyarmor_runtime will not load the obfuscated script unless the runtime key exists and is valid.
User also could store any private data in the runtime key, then use hook script to check private data in the obfuscated scripts.
If runtime key is stored in an outer file, any readable text in the header will be ignored. User can add comment at the header of runtime key file, the rest part are bytes data, only in the obfuscaed scripts they could be read.
4.2.1. The differences of obfuscated scripts¶
Although use obfuscated scripts as they’re normal Python scripts, but the obfuscated scripts are still different from pure Python scripts, they changes a few Python features and results in some third party packages could not work.
Here are major changed features:
The obfsucated scripts are bind to Python major/minor version. For example, if it’s obfuscated by Python 3.6, it must run by Python 3.6. It doesn’t work for Python 3.5
The obfuscated scripts are platform-dependent, supported platforms and Python versions refer to Building Environments
If Python interpreter is compiled with Py_TRACE_REFS or Py_DEBUG, it will crash to run obfuscated scripts.
Any module may not work if it try to visit the byte code, or some attributes of code objects in the obfuscated scripts. For example most of
inspectfunction are broken.
Pass the obfuscated code object by
cPickleor any third serialize tool may not work.
sys._getframe([n])may get the different frame. Note that many third packages uses this feature to get local variable and broken. For example,
The code object attribute
<frozen name>other than real filename.
Note that module attribute
__file__is still filename. For example, obfuscate the script
foo.pyand run it:
def hello(msg): print(msg) # The output will be 'foo.py' print(__file__) # The output will be '<frozen foo>' print(hello.__file__)
A few options may also change something:
pyarmor cfg mix_argname=1hides annotations.
--restricthide function names in trace back
4.2.2. Supported Third-Party Interpreter¶
About third-party interperter, for example Jython, and any embeded Python C/C++ code, only they could work with CPython extension module, they could work with Pyarmor. Check third-parth interperter documentation to make sure this.
A few known issues
- On Linux, RTLD_GLOBAL must be set as loading libpythonXY.so by dlopen, otherwise obfuscated scripts couldn’t work.
- Boost::python does not load libpythonXY.so with RTLD_GLOBAL by default, so it will raise error “No PyCode_Type found” as running obfuscated scripts. To solve this problem, try to call the method sys.setdlopenflags(os.RTLD_GLOBAL) as initializing.
- PyPy could not work with pyarmor, it’s total different from CPython