3.2. Man Page

Pyarmor is a powerful tool to obfuscate Python scripts with rich option set that provides both high-level operations and full access to internals.

3.2.1. pyarmor

Syntax

pyarmor [options] <command> …

Options
-h, --help show available command set then quit
-v, --version show version information then quit
-q, --silent suppress all normal output ...
-d, --debug show more information in the console ...
--home PATH set Pyarmor HOME path ...

These options can be used after pyarmor but before command, here are available commands:

gen Obfuscate scripts
gen key Generate outer runtime key
cfg Show and configure environments
reg Register Pyarmor

See pyarmor <command> -h for more information on a specific command.

Description
-q, --silent

Suppress all normal output.

For example:

pyarmor -q gen foo.py
-d, --debug

Show more information in the console

When something is wrong, print more debug informations in the console. For example:

pyarmor -d gen foo.py
--home PATH[,GLOBAL[,LOCAL[,REG]]]

Set Pyarmor Home Path, Global Configuration Path, Local Configuration Path and Registration File Path

The default paths

All of them could be changed by this option. For example, change home path to ~/.pyarmor2:

$ pyarmor --home ~/.pyarmor2 ...

Then

Another example, keep all others but change global path only:

$ pyarmor --home ,config2 ...

This command sets Global Configuration Path to ~/.pyarmor/config2

Another example, keep all others but change local path only:

$ pyarmor --home ,,/var/myproject/ ...

This command sets Local Configuration Path to /var/myproject

Another example, set Registration File Path to /opt/pyarmor/:

$ pyarmor --home ,,,/opt/pyarmor ...

It’s useful when may use sudo to run pyarmor occassionally. This makes sure the registration file could be found even switch to another user.

When there are many Pyarmor Licenses registerred in one machine, set each license to different Registration File Path

There are 2 soltions

  • one license one home
  • same home, one license one path

For example, the first solution:

$ pyarmor --home ~/.pyarmor1 reg pyarmor-regfile-2051.zip
$ pyarmor --home ~/.pyarmor2 reg pyarmor-regfile-2052.zip

$ pyarmor --home ~/.pyarmor1 gen project1/foo.py
$ pyarmor --home ~/.pyarmor2 gen project2/foo.py

The second solution:

$ pyarmor --home ,,,pyarmor1 reg pyarmor-regfile-2051.zip
$ pyarmor --home ,,,pyarmor2 reg pyarmor-regfile-2052.zip
                 ,,,
$ pyarmor --home ,,,pyarmor1 gen project1/foo.py
$ pyarmor --home ,,,pyarmor2 gen project2/foo.py

Start pyarmor with clean configuration by setting Global Configuration Path and Local Configuration Path to any non-exists path x:

$ pyarmor --home ,x,x, gen foo.py

See also

PYARMOR_HOME

3.2.2. pyarmor gen

Generate obfuscated scripts and all the required runtime files.

Syntax

pyarmor gen <options> <SCRIPT or PATH>

Options
-h, --help show option list and help information then quit
-O PATH, --output PATH
 output path ...
-r, --recursive
 search scripts in recursive mode ...
-e DATE, --expired DATE
 set expired date ...
-b DEV, --bind-device DEV
 bind obfuscated scripts to device ...
--period N check runtime key periodically ...
--outer enable outer runtime key ...
--platform NAME
 cross platform obfuscation ...
-i store runtime files inside package ...
--prefix PREFIX
 import runtime package with PREFIX ...
--obf-module <0,1>
 obfuscate whole module (default is 1) ...
--obf-code <0,1>
 obfuscate each function (default is 1) ...
--no-wrap disable wrap mode ...
--enable <jit,rft,bcc,themida>
 enable different obfuscation features ...
--mix-str protect string constant ...
--restrict enable restrict mode for package ...
--assert-import
 assert module is obfuscated ...
--assert-call assert function is obfuscated ...
--pack BUNDLE repack bundle with obfuscated scripts ...
Description
-O PATH, --output PATH

Set the output path for all the generated files, default is dist

-r, --recursive

When obfuscating package, search all scripts recursively. No this option, only the scripts in package path are obfuscated.

-i

When obfuscating package, store the runtime files inside package. For example:

$ pyarmor gen -r -i mypkg

The runtime package will be stored inside package dist/mypkg:

$ ls dist/
...      mypkg/

$ ls dist/mypkg/
...            pyarmor_runtime_000000/

Without this option, the output path is like this:

$ ls dist/
...      mypkg/
...      pyarmor_runtime_000000/

This option can’t be used to obfuscate script.

--prefix PREFIX

Only used when obfuscating many packages at the same time and still store the runtime package inside package.

In this case, use this option to specify which package is used to store runtime package. For example:

$ pyarmor gen --prefix mypkg src/mypkg mypkg1 mypkg2

This command tells pyarmor to store runtime package inside dist/mypkg, and make dist/mypkg1 and dist/mypkg2 to import runtime package from mypkg.

Checking the content of .py files in output path to make it clear.

As a comparison, obfuscating 3 packages without this option:

$ pyarmor gen -O dist2 src/mypkg mypkg1 mypkg2

And check .py files in the path dist2.

-e DATE, --expired DATE

Expired date of obfuscated scripts.

It supports 4 forms:

  • A number stands for valid days
  • A date with iso format YYYY-MM-DD
  • A leading . with above 2 forms

Without leading dot, the obfuscated scripts checks NTP server time. For example:

$ pyarmor gen -e 30 foo.py
$ pyarmor gen -e 2022-12-31 foo.py

With leading dot, it checks local time. For example:

$ pyarmor gen -e .30 foo.py
$ pyarmor gen -e .2022-12-31 foo.py
-b DEV, --bind-device DEV

Use this option multiple times to bind multiple machines

Bind obfuscated script to specified device. Now only harddisk serial number, ethernet address and IPv4 address are available.

For example:

$ pyarmor gen -b 128.16.4.10 foo.py
$ pyarmor gen -b 52:38:6a:f2:c2:ff foo.py
$ pyarmor gen -b HXS2000CN2A foo.py

Also set 30 valid days for this device:

$ pyarmor gen -e 30 -b 128.16.4.10 foo.py

Check all of hardware informations in this device:

$ pyarmor gen -b "128.16.4.10 52:38:6a:f2:c2:ff HXS2000CN2A" foo.py

Using this options multiple times means binding many machines. For example, the following command makes the obfuscated scripts could run 2 machiens:

$ pyarmor gen -b "52:38:6a:f2:c2:ff" -b "f8:ff:c2:27:00:7f" foo.py

In case there are more network cards, binding anyone by this form:

$ pyarmor gen -b "<2a:33:50:46:8f>" foo.py

Bind all network cards by this form:

$ pyarmor gen -b "<2a:33:50:46:8f,f0:28:69:c0:24:3a>" foo.py

In Linux, it’s possible to bind named ethernet card:

$ pyarmor gen -b "eth1/fa:33:50:46:8f:3d" foo.py

If there are many harddisks. In Windows, binding anyone by sequence no:

$ pyarmor gen -b "/0:FV994730S6LLF07AY" foo.py
$ pyarmor gen -b "/1:KDX3298FS6P5AX380" foo.py

In Linux, binding to specify name:

$ pyarmor gen -b "/dev/vda2:KDX3298FS6P5AX380" foo.py
--period N

Check Runtime Key periodically.

Support units:

  • s
  • m
  • h

The default unit is hour, for example, the following examples are Equivalent:

$ pyarmor gen --period 1 foo.py
$ pyarmor gen --period 3600s foo.py
$ pyarmor gen --period 60m foo.py
$ pyarmor gen --period 1h foo.py

Note

If the obfuscated script enters an infinite loop without call any obfuscated function, it doesn’t trigger periodic check.

--outer

Enable outer key

It tells the obfuscated scripts find runtime key in outer file.

Once this option is specified, pyarmor gen key must be used to generate an outer key file and copy to the corresponding path in target device. Otherwise the obfuscated scripts will complain of missing license key to run the script

The default name of outer key is pyarmor.rkey, it can be changed by this command:

$ pyarmor cfg outer_keyname=".pyarmor.key"

By this command the name of outer key is set to .pyarmor.key.

--platform NAME

Specify target platform to run obfuscated scripts.

The name must be one of standard platform defined by Pyarmor.

It requires pyarmor.cli.runtime to get prebuilt binary libraries of other platforms.

--restrict

Enable restirct mode for package, do not use it to obfuscate scripts.

When restrict mode is enabled, all the modules excpet __init__.py in the package could not be imported by plain scripts.

For example, obfuscate a restrict package to dist/joker:

$ pyarmor gen -i --restrict joker
$ ls dist/
...    joker/

Then create a plaint script dist/foo.py

import joker
print('import joker should be OK')
from joker import queens
print('import joker.queens should fail')

Run it to verify:

$ cd dist
$ python foo.py
... import joker should be OK
... RuntimeError: unauthorized use of script

If there are extra modules need to be exported, list all the modules in this command:

$ pyarmor cfg exclude_restrict_modules="__init__ queens"

Then obfuscate the package again.

--obf-module <0,1>

Enable the whole module (default is 1)

--obf-code <0,1>

Enable each function in module (default is 1)

--no-wrap

Disable wrap mode

If wrap mode is enabled, when enter a function, it’s restored. but when exit, this function will be obfuscated again.

If wrap mode is disabled, once the function is restored, it’s never be obfuscated again.

If --obf-code is 0, this option is meaningless.

--enable <jit,rft,bcc,themida>

Enable different obfuscation features.

--enable-jit

Use JIT to process some sentensive data to improve security.

--enable-rft

Enable RFT Mode to obfuscate the script pro

--enable-bcc

Enable BCC Mode to obfuscate the script pro

--enable-themida

Use Themida to protect extension module in runtime package

Only works for Windows platform.

--mix-str

Mix the string constant in scripts basic

--assert-call

Assert function is obfuscated

If this option is enabled, Pyarmor scans each function call in the scripts. If the called function is in the obfuscated scripts, protect it as below, and leave others as it is. For example,

def fib(n):
    a, b = 0, 1
    return a, b

print('hello')
fib(n)

will be changed to

def fib(n):
    a, b = 0, 1

print('hello')
__assert_armored__(fib)(n)

The function __assert_armored__ is a builtin function in obfuscated script. It checks the argument, if it’s an obfuscated function, then returns this function, otherwise raises protection exception.

In this example, fib is protected, print is not.

--assert-import

Assert module is obfuscated

If this option is enabled, Pyarmor scans each import statement in the scripts. If the imported module is obfuscated, protect it as below, and leave others as it is. For example,

import sys
import foo

will be changed to

import sys
import foo
__assert_armored__(foo)

The function __assert_armored__ is a builtin function in obfuscated script. It checks the argument, if it’s an obfuscated module, then return this module, otherwise raises protection exception.

This option neither touchs statement from import, nor the module imported by function __import__.

--pack BUNDLE

Repack bundle with obfuscated scripts

Here BUNDLE is an executable file generated by PyInstaller

Pyarmor just obfuscates the script first.

Then unpack the bundle.

Next replace all the .pyc in the bundle with obfuscated scripts, and append all the runtime files to the bundle.

Finally repack the bundle and overwrite the original BUNDLE.

3.2.3. pyarmor gen key

Generate outer key for obfuscated scripts.

Syntax

pyarmor gen key <options>

Options
-O PATH, --output PATH
 output path
-e DATE, --expired DATE
 set expired date
--period N check runtime key periodically
-b DEV, --bind-device DEV
 bind obfuscated scripts to device
Description

This command is used to generate outer key, the options in this command have same meaning as in the pyarmor gen.

There must be at least one of option -e or -b for outer key.

It’s invalid that outer key is neither expired nor binding to a device. For this case, don’t use outer key.

By default the outer key is saved to dist/pyarmor.rkey. For example:

$ pyarmor gen key -e 30
$ ls dist/pyarmor.rkey

Save outer key to other path by this way:

$ pyarmor gen key -O dist/mykey2 -e 10
$ ls dist/mykey2/pyarmor.rkey

By default the outer key name is pyarmor.rkey, use the following command to change outer key name to any others. For example, sky.lic:

$ pyarmor cfg outer_keyname=sky.lic
$ pyarmor gen key -e 30
$ ls dist/sky.lic

3.2.4. pyarmor cfg

Configure or show Pyarmor environments

Syntax

pyarmor cfg <options> [OPT[=VALUE]] …

Options
-h, --help show this help message and exit
-p NAME private settings for special module or package
-g, --global do everything in global settings, otherwise local settings
-r, --reset reset option to default value
--encoding ENCODING
 specify encoding to read configuration file
Description

Run this command without arguments to show all available options:

$ pyarmor cfg

Show one exact option obf_module:

$ pyarmor cfg obf_module

Show all options which start with obf:

$ pyarmor cfg obf*

Set option to new value:

$ pyarmor cfg obf_module=0

Reset option to default:

$ pyarmor cfg -r obf_module

Change option excludes in the section finder by this form:

$ pyarmor cfg finder:excludes=ast

If no prefix finder, for example:

$ pyarmor cfg excludes=ast

Not only option excludes in section finder, but also in other sections assert.call, mix.str etc. are changed.

-p NAME

Private settings for special module or package

All the settings is only used for specified module NAME.

-g, --global

Do everything in global settings

Without this option, all the changed settings are soted in Local Configuration Path, generally it’s .pyarmor in the current path. By this option, everything is stored in Global Configuration Path, generally it’s ~/.pyarmor/config

-r, --reset

Reset option to default value

3.2.5. pyarmor reg

Register Pyarmor or upgrade Pyarmor license

Syntax

pyarmor reg [OPTIONS] [FILENAME]

Options
-h, --help show this help message and exit
-p NAME, --product NAME
 license to this product
-u, --upgrade upgrade Pyarmor license
-y, --confirm register Pyarmor without asking for confirmation
Arguments

The FILENAME must be one of these forms:

  • pyarmor-regcode-xxxx.txt got by purchasing Pyarmor license
  • pyarmor-regfile-xxxx.zip got by initial registration with above file
Description

Check the registration information:

$ pyarmor -v

Show verbose information:

$ pyarmor reg
-p NAME, --product NAME

Set product name bind to license

When initial registration, use this option to set proudct name bind to license.

If no this option, the product name is set to non-profits.

It’s meanless to use this option after initial registration.

TBD is a special product name. If product name is TBD at initial registration, the product name can be changed later.

For any other product name, it can’t be changed any more.

-y, --confirm

In initial registration, without asking for confirmation

-u, --upgrade

Upgrade old license to Pyarmor 8.0 Licese

Important

Once initial registration successfully, pyarmor-regcode-xxxx.txt may not work again. Using registration file pyarmor-regfile-xxxx.zip for next registration instead.

PLEASE BACKUP registration file pyarmor-regfile-xxxx.zip carefully, Pyarmor doesn’t provide lost-found service

Using registration file pyarmor-regfile-xxxx.zip to register Pyarmor in other machine.

Copy it to target device, then run this command:

$ pyarmor reg pyarmor-regfile-xxxx.zip

3.2.6. Environment Variables

The following environment variables only used in Build Machine when generating the obfuscated scripts, not in Target Device.

PYARMOR_HOME

Same as pyarmor --home

It mainly used in the shell scrits to change Pyarmor settings. If pyarmor --home is set, this environment var is ignored.

PYARMOR_PLATFORM

Set the right Platform to run pyarmor

It’s mainly used in some platforms Pyarmor could not tell right but still works.

PYARMOR_CC

Specify C compiler for bccmode

PYARMOR_CLI

Only for compatible with old Pyarmor, ignore this if you don’t use old command prior to 8.0

If you do not use new commands in Pyarmor 8.0, and prefer to only use old commands, set it to 7, for example:

# In Linux
export PYARMOR_CLI=7
pyarmor -h

# Or
PYARMOR_CLI=7 pyarmor -h

# In Windows
set PYARMOR_CLI=7
pyarmor -h

It forces command pyarmor to use old cli directly.

Without it, pyarmor first try new cli, if the command line couldn’t be parsed by new cli, fallback to old cli.

This only works for command pyarmor.