I am looking for how to hide my Python source code.
print "Hello World!"
How can I encode this example so that it isn't human-readable? I've been told to use base64 but I'm not sure how.
23 Answers
This is only a limited, first-level obfuscation solution, but it is built-in: Python has a compiler to byte-code:
python -OO -m py_compile <your program.py>
produces a .pyo file that contains byte-code, and where docstrings are removed, etc. You can rename the .pyo file with a .py extension, and python <your program.py> runs like your program but does not contain your source code.
PS: the "limited" level of obfuscation that you get is such that one can recover the code (with some of the variable names, but without comments and docstrings). See the first comment, for how to do it. However, in some cases, this level of obfuscation might be deemed sufficient.
PPS: If your program imports modules obfuscated like this, then you need to rename them with a .pyc suffix instead (I'm not sure this won't break one day), or you can work with the .pyo and run them with python -O ….pyo (the imports should work). This will allow Python to find your modules (otherwise, Python looks for .py modules).
so that it isn't human-readable?
i mean all the file is encoded !! when you open it you can't understand anything .. ! that what i want
As maximum, you can compile your sources into bytecode and then distribute only bytecode. But even this is reversible. Bytecode can be decompiled into semi-readable sources.
Base64 is trivial to decode for anyone, so it cannot serve as actual protection and will 'hide' sources only from complete PC illiterates. Moreover, if you plan to actually run that code by any means, you would have to include decoder right into the script (or another script in your distribution, which would needed to be run by legitimate user), and that would immediately give away your encoding/encryption.
Obfuscation techniques usually involve comments/docs stripping, name mangling, trash code insertion, and so on, so even if you decompile bytecode, you get not very readable sources. But they will be Python sources nevertheless and Python is not good at becoming unreadable mess.
If you absolutely need to protect some functionality, I'd suggest going with compiled languages, like C or C++, compiling and distributing .so/.dll, and then using Python bindings to protected code.
You can use the base64 module to encode strings to stop shoulder surfing, but it's not going to stop someone finding your code if they have access to your files.
You can then use the compile() function and the eval() function to execute your code once you've decoded it.
>>> import base64
>>> mycode = "print 'Hello World!'"
>>> secret = base64.b64encode(mycode)
>>> secret
'cHJpbnQgJ2hlbGxvIFdvcmxkICEn'
>>> mydecode = base64.b64decode(secret)
>>> eval(compile(mydecode,'<string>','exec'))
Hello World!
So if you have 30 lines of code you'll probably want to encrypt it doing something like this:
>>> f = open('myscript.py')
>>> encoded = base64.b64encode(f.read())
You'd then need to write a second script that does the compile() and eval() which would probably include the encoded script as a string literal encased in triple quotes. So it would look something like this:
import base64
myscript = """IyBUaGlzIGlzIGEgc2FtcGxlIFB5d
GhvbiBzY3JpcHQKcHJpbnQgIkhlbG
xvIiwKcHJpbnQgIldvcmxkISIK"""
eval(compile(base64.b64decode(myscript),'<string>','exec'))
You could embed your code in C/C++ and compile Embedding Python in Another Application
embedded.c
#include <Python.h>
int
main(int argc, char *argv[])
{
Py_SetProgramName(argv[0]); /* optional but recommended */
Py_Initialize();
PyRun_SimpleString("print('Hello world !')");
Py_Finalize();
return 0;
}
In Ubuntu/Debian
$ sudo apt-get install python-dev
In Centos/Redhat/Fedora
$ sudo yum install python-devel
compile with
$ gcc -o embedded -fPIC -I/usr/include/python2.7 -lpython2.7 embedded.c
run with
$ chmod u+x ./embedded
$ time ./embedded
Hello world !
real 0m0.014s
user 0m0.008s
sys 0m0.004s
initial script: hello_world.py:
print('Hello World !')
run the script
$ time python hello_world.py
Hello World !
real 0m0.014s
user 0m0.008s
sys 0m0.004s
however some strings of the python code may be found in the compiled file
$ grep "Hello" ./embedded
Binary file ./embedded matches
$ grep "Hello World" ./embedded
$
In case you want an extra bit of obfuscation you could use base64
...
PyRun_SimpleString("import base64\n"
"base64_code = 'your python code in base64'\n"
"code = base64.b64decode(base64_code)\n"
"exec(code)");
...
e.g:
create the base 64 string of your code
$ base64 hello_world.py
cHJpbnQoJ0hlbGxvIFdvcmxkICEnKQoK
embedded_base64.c
#include <Python.h>
int
main(int argc, char *argv[])
{
Py_SetProgramName(argv[0]); /* optional but recommended */
Py_Initialize();
PyRun_SimpleString("import base64\n"
"base64_code = 'cHJpbnQoJ0hlbGxvIFdvcmxkICEnKQoK'\n"
"code = base64.b64decode(base64_code)\n"
"exec(code)\n");
Py_Finalize();
return 0;
}
all commands
$ gcc -o embedded_base64 -fPIC -I/usr/include/python2.7 -lpython2.7 ./embedded_base64.c
$ chmod u+x ./embedded_base64
$ time ./embedded_base64
Hello World !
real 0m0.014s
user 0m0.008s
sys 0m0.004s
$ grep "Hello" ./embedded_base64
$
update:
this project (pyarmor) might also help:
Cython
It seems that the goto answer for this is Cython. I'm really surprised no one else mentioned this yet? Here's the home page:
In a nutshell, this transforms your python into C and compiles it, thus making it as well protected as any "normal" compiled distributable C program.
There are limitations though. I haven't explored them in depth myself, because as I started to read about them, I dropped the idea for my own purposes. But it might still work for yours. Essentially, you can't use Python to the fullest, with the dynamic awesomeness it offers. One major issue that jumped out at me, was that keyword parameters are not usable :( You must write function calls using positional parameters only. I didn't confirm this, but I doubt you can use conditional imports, or evals. I'm not sure how polymorphism is handled...
Anyway, if you aren't trying to obfuscate a huge code base after the fact, or ideally if you have the use of Cython in mind to begin with, this is a very notable option.
Maybe you can try on pyconcrete
encrypt .pyc to .pye and decrypt when import it
encrypt & decrypt by library OpenAES