Use the same way to protect binary file of c/c++, that is, obfuscate each function body in executable or library binary file, insert an instruction "jump" at the begin of each function entry, jump to special function to restore obfuscated code. Byte-code is binary code of Python script, so
- First compile python script to code object
- Then iterate each code object, obfuscate co_code of each code object as the following
0 JUMP_ABSOLUTE n = 3 + len(bytecode)
3
...
... Here it's obfuscated bytecode
...
n LOAD_GLOBAL ? (__pyarmor__)
n+3 CALL_FUNCTION 0
n+6 POP_TOP
n+7 JUMP_ABSOLUTE 0
- Save obfuscated code object as .pyc or .pyo file
Those obfuscated file (.pyc or .pyo) can be used by normal python interpreter, when those code object is called first time
First op is JUMP_ABSOLUTE, it will jump to offset n
At offset n, the instruction is to call a PyCFunction. This function will restore those obfuscated bytecode between offset 3 and n, and put the original byte-code at offset 0. The obfuscated code can be got by the following code
char *obfucated_bytecode;
Py_ssize_t len;
PyFrameObject* frame = PyEval_GetFrame();
PyCodeObject *f_code = frame->f_code;
PyObject *co_code = f_code->co_code;
PyBytes_AsStringAndSize(co_code, &obfucated_bytecode, &len)
After this function returns, the last instruction is to jump to
offset 0. The really byte-code now is executed.
There is a tool Pyarmor to obfuscate python scripts by this way.