1. Topic

defende the source code in commercial distribution.

2. Python

  • sourcedefender(commercial): SOURCEdefender can protect your plaintext Python source code with AES 256-bit Encryption. There is no impact on the performance of your running application as the decryption process takes place during the import of your module or when loading your script on the command-line. Encrypted code won’t run any slower once loaded from a .pye file compared to loading from a .py or .pyc file
  • pyarmor(commercial): A tool used to obfuscate python scripts, bind obfuscated scripts to fixed machine or expire obfuscated scripts.
  • PyObfuscator: This module obfuscates python code.
  • pyconcrete: Protect your python script, encrypt it as .pye and decrypt when import it
  • py_complie: The py_compile module provides a function to generate a byte-code file from a source file, and another function used when the module source file is invoked as a script.
  • pyinstaller: PyInstaller bundles a Python application and all its dependencies into a single package. The user can run the packaged app without installing a Python interpreter or any modules. PyInstaller supports Python 3.8 and newer, and correctly bundles many major Python packages such as numpy, matplotlib, PyQt, wxPython, and others.

3. NodeJs

  • javascript-obfuscator: JavaScript Obfuscator is a powerful free obfuscator for JavaScript, containing a variety of features which provide protection for your source code.
  • uglifyjs: UglifyJS is a JavaScript parser, minifier, compressor and beautifier toolkit.
  • pkg: Package your Node.js project into an executable
  • bytenode: A minimalist bytecode compiler for Node.js

4. Test

4.1 python

Skip the commercial tool test because they need to register or license, so just include OSS. All test code can be find at sourcedefender-tutorial.

Setup the virtual python environment before testing:

1
2
python3.11 -m venv .venv
source .venv/bin/activate
  • pyconcrete(★★★★)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # install, NOTE: https://github.com/Falldog/pyconcrete/issues/94
    PYCONCRETE_PASSPHRASE=sourcedefender CFLAGS="-Wno-implicit-function-declaration" pip install pyconcrete # https://github.com/Falldog/pyconcrete/

    # compile, find more info by run: pyconcrete-admin.py --help
    pyconcrete-admin.py compile --source main.py --pye
    pyconcrete-admin.py compile --source main.py --pyc

    # run
    pyconcrete main.pye
    python main.pyc

    ⚠️ PYCONCRETE_PASSPHRASE is required when install pyconcrete

  • PyObfuscator(★★)

    1
    2
    3
    4
    5
    6
    7
    # obfuscate, find more info by: PyObfuscator -h
    PyObfuscator main.py --output main-obfuscated.py
    # obfuscate and generate deobfuscate.json
    PyObfuscator main.py --output main-obfuscated.py --deobfuscate

    # run
    python main-obfuscated.py

    main-obfuscated.py:

    image-20240116173002242

    deobfuscate.json:

    image-20240116173123459

    • py_complie(★)

      1
      2
      3
      4
      5
      6
      # compile
      python -m py_compile main.py # or
      python -m compileall main.py

      # run
      python ./__pycache__/main.cpython-311.pyc
    • pyinstaller(★★★★★)

      1
      2
      3
      4
      5
      # compile
      pyinstaller --onefile main.py

      # run
      ./dist/main

    Summary:

    • pyconcrete is safer than PyObfuscator because pyconcrete result is binary file, but its dependences are not bundled
    • PyObfuscator defendes the source code with obfuscation, while pyconcrete utilizes compile technology
    • pyinstaller binary result size is big because its dependences are bundled

4.2 nodejs

  • uglify.js(★)

    1
    2
    3
    4
    npm install uglify-js -g

    # obfuscate file and compare the output with source file
    uglifyjs --compress --mangle -- dist/libs/infra-config/src/lib/api-config.js
  • javascript-obfuscator(★★★)

    1
    2
    3
    4
    5
    6
    7
    npm install javascript-obfuscator -g

    # obfuscate file
    javascript-obfuscator dist/apps/demo-service/main.js

    # run obfuscated nest application and test the apis
    node dist/apps/demo-service/main-obfuscated.js

    main.js is the output result for a nest application building with webpack

  • pkg

    1
    2
    3
    4
    5
    6
    7
    npm install pkg -g

    # compile
    pkg --target node18-linux-x64 main.js

    # run
    ./main-linux # error

    ⚠️ the pkg has been archived.

    comiple failure on darwin(m2) and linux(x64) with node@18

    ❌ execute error when run the linux binary

  • bytenode(★★★★)

    1
    2
    3
    4
    5
    6
    7
    npm install -g bytenode

    # compile
    ENV_NAME=dev bytenode -c dist/apps/demo-service/main.js

    # run
    ENV_NAME=dev bytenode dist/apps/demo-service/main.jsc

Summary:

  • javascript-obfuscator obfuscate file is harder to read than uglifyjs, but the log also is obfuscated if your class name and function name in it
  • uglifyjs is not a obfuscator
  • bytenode compile the binary result which is better than the obfucated file

5. Is python compilation safe?

There many tool to decompile:

  • pycdc: C++ python bytecode disassembler and decompiler
  • others
1
2
3
4
5
6
7
8
9
10
11
# install
git clone https://github.com/zrax/pycdc
cd pycdc
cmake .
make
make check
cp pycdc ~/.local/bin

# decompile
pycdc __pycache__/main.cpython-311.pyc

The decompile result:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Source Generated with Decompyle++
# File: main.cpython-311.pyc (Python 3.11)

import requests

def get_github_status():
Unsupported opcode: PUSH_EXC_INFO
api_url = 'https://www.githubstatus.com/api/v2/status.json'
response = requests.get(api_url)
if response.status_code == 200:
status_data = response.json()
status = status_data.get('status')
description = status_data.get('body', { }).get('markdown')
print(f'''GitHub Status: {status}''')
print(f'''Status Description: {description}''')
return None
None(f'''Failed to retrieve GitHub status. Status code: {response.status_code}''')
return None
# WARNING: Decompyle incomplete

if __name__ == '__main__':
get_github_status()
return None

Summary:

The decompile result is very close to real code, so the python compile is not 100% safe.