Big thanks to RĂ©mi Mevaere for the userful tutorial for protecting of Python files! Original tutorial link is there: https://www.sciences-physiques.net/555d13e4a9b34836bb4753192f14225c
Introduction
As you know, it’s a bit hard to protect python code. Cause it’s interpreted ; with a small modification of python source code you could extract all the code (even if it’s obfuscated).
The method I will explain here is really solid and use a third-party tool named “The Enigma Protector”.
Prerequisites
- Using windows
- Cython
- MSVC build-tools installed
- The enigma protector software (199$), the trial version will obviously raise some alerts from antivirus cause some crackers & hackers use it to protect their apps.
Installing and using Cython
“Cython is a programming language that aims to be a superset of the Python programming language, designed to give C-like performance with code that is written mostly in Python with optional additional C-inspired syntax. Cython is a compiled language that is typically used to generate CPython extension modules.”
In one word : Cython could generate with your python code a c++ file compiled in a dynamic link library (DLL) which could be directly called by your python code.
Setup
pip install cython
Example
The first file is the python file script you want to run at the speed of C. Please note the extension .pyx
File : fib.pyx
#cython: language_level=3
def fib(n):
"""Print the Fibonacci series up to n."""
a, b = 0, 1
while b < n:
print(b, end=' ')
a, b = b, a + b
print()
Now we need to create the setup.py, which is like a python Makefile (for more information see Source Files and Compilation)
File : setup.py
from setuptools import setup
from Cython.Build import cythonize
setup(
ext_modules=cythonize("fib.pyx"),
)
Now convert and compile all this with
python setup.py build_ext --inplace
Calling the dll created (fib.cp38-win_amd64.pyd) is really easy from python. It’s just treating it like a module.
import fib
fib.fib(50000000) # will give the expected result
Protecting your app
The goal is to protect your python app. In order to do this, you will need :
- some of your most important code in a .pyx file which will be converted in c++, only this code will be protected
- call the API of enigma protector to introduce the protection (RISC virtual machine etc.)
- packed the dll produced by cython with enigma protector
- Use it !
BONUS :As you know, C compilation is largely faster than python cause it doesn’t deal with python object structure. C is also faster when it deals with loops. And cause it doesn’t deal with the GIL, cython gives you the opportunity to use all your CPU cores.
Prepare the compilation
File : setup.py
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
setup(
name = 'Test app',
ext_modules=[
Extension('test',
sources=['script_test.pyx'],
extra_link_args=['/MAP'],
libraries = ["enigma_ide64"],
language="c++")
],
cmdclass = {'build_ext': build_ext}
)
Watch the API
“A Marker is a set of bytes placed into the source code and helping Enigma Protector find the code inside markers for processing. A marker consists of two parts: begin marker and end marker.”
// Markers API
void __declspec(dllimport) __stdcall EP_Marker(char* Name);
“EP_RegHardware function serves for retrieving unique user PC information. The function does not have parameters. If the function succeeds, the return value is a pointer to the null terminated ANSI string. If the function fails, the return value is 0.”
// Registration API
LPCWSTR __declspec(dllimport) __stdcall EP_RegHardwareIDW();
Some files to add in the directory (sdk path of enigma protector)
And you must add to the top of enigma_ide.h
#include <windows.h>
The script test
# distutils: language = c++
# cython: language_level=3
# Declare EP_Marker function in enigma_ide64.lib
cdef extern from "enigma_ide.h":
void EP_Marker(char* Name)
# Declare EP_RegHardwareID function in enigma_ide64.lib
cdef extern from "enigma_ide.h":
char* EP_RegHardwareID()
# Declare a trivial function
def sum_it(number1,number2):
return number1 + number2
# Call and print the EP_RegHardwareID
print(EP_RegHardwareID())
# Crypt this stuff which will only be decrypt with registration
EP_Marker("reg_crypt_begin1")
print("here it's crypted")
EP_Marker("reg_crypt_end1")
# Protect this with virtualization
EP_Marker("vm_risc_begin")
a = 4
b = 7
c = a + b
print('Virtualized :', c)
EP_Marker("vm_risc_end")
# Classic python code
print("Give me the sum :", sum_it(1,2))
input("End, press key")
Build-it
python setup.py build_ext --inplace
Protect-it with enigma protector
Call-it
BONUS : using widestring character wchar_t*
from cpython.ref cimport PyObject
from libc.stddef cimport wchar_t
cdef extern from "Python.h":
PyObject* PyUnicode_FromWideChar(wchar_t *w, Py_ssize_t size)
cdef extern from "enigma_ide.h":
wchar_t* EP_RegHardwareIDW()
cdef PyObject * pystr = PyUnicode_FromWideChar(EP_RegHardwareIDW(), -1)
print(<object>pystr)