How To Pack Obfuscated Scripts

The obfuscated scripts generated by PyArmor can replace Python scripts seamlessly, but there is an issue when packing them into one bundle by PyInstaller:

All the dependencies of obfuscated scripts CAN NOT be found at all

To solve this problem, the common solution is

  1. Find all the dependenices by original scripts.
  2. Add runtimes files required by obfuscated scripts to the bundle
  3. Replace original scipts with obfuscated in the bundle
  4. Replace entry scrirpt with obfuscated one

PyArmor provides command pack to achieve this. But in some cases maybe it doesn’t work. This document describes what the command pack does, and also could be as a guide to bundle the obfuscated scripts by yourself.

First install pyinstaller:

pip install pyinstaller

Then obfuscate scripts to dist/obf:

pyarmor obfuscate --output dist/obf hello.py

Next generate specfile, add the obfuscated entry script and data files required by obfuscated scripts:

pyinstaller --add-data dist/obf/license.lic
            --add-data dist/obf/pytransform.key
            --add-data dist/obf/_pytransform.*
            hello.py dist/obf/hello.py

And patch specfile hello.spec, insert the following lines after the Analysis object. The purpose is to replace all the original scripts with obfuscated ones:

a.scripts[-1] = 'hello', r'dist/obf/hello.py', 'PYSOURCE'
for i in range(len(a.pure)):
    if a.pure[i][1].startswith(a.pathex[0]):
        x = a.pure[i][1].replace(a.pathex[0], os.path.abspath('dist/obf'))
        if os.path.exists(x):
            if hasattr(a.pure, '_code_cache'):
                with open(x) as f:
                    a.pure._code_cache[a.pure[i][0]] = compile(f.read(), a.pure[i][1], 'exec')
            a.pure[i] = a.pure[i][0], x, a.pure[i][2]

Run patched specfile to build final distribution:

pyinstaller --clean -y hello.spec

Note

Option –clean is required, otherwise the obfuscated scripts will not be replaced because the cached .pyz will be used.

Check obfuscated scripts work:

# It works
dist/hello/hello.exe

rm dist/hello/license.lic

# It should not work
dist/hello/hello.exe