python代码加密——编译与反编译方法总结

  • 引言
  • 打包成.pyc文件
  • 编译成pyd文件或pyo文件
  • pyc文件反编译
  • 反编译库总结与说明
  • 在线网站进行加密
  • python解释器加密
  • 总结

引言

因为python是作为一种动态语言,所以如果要将python代码进行加密其实是一件很难的事情。但听说2018年python官方还是公布了一些针对现有python代码比较好的加密方式,本篇对此作出一些简单的总结。

打包成.pyc文件

简单来说,pyc文件就是Python的字节码文件,我们都知道Python是一种全平台的解释性语言,全平台其实就是Python文件在经过解释器解释之后(或者称为编译)生成的pyc文件可以在多个平台下运行,这样同样也可以隐藏源代码。

pyc文件只有在文件被当成模块导入时才会生成。也就是说,Python解释器认为,只有import进行的模块才需要被重用。 生成pyc文件的好处显而易见,当我们多次运行程序时,不需要重新对该模块进行重新的解释。另外其实当我们运行程序的时候就自动生成了pyc文件,下面就来详细介绍。

当我们之前有启动项目成功时,python自动就会创建在每一级有调用到文件的目录一个叫_pycache_的文件夹当成缓存,那么之后启动的速度会极大的提升。
python代码加密——编译与反编译方法总结_第1张图片
但自动生成的缓存文件夹中,我们需要运用Linux命令 mv * ../ 将编译的pyc文件弄到上一级,然后用rename批量改名,并且每一个文件目录都需要运行相同的命令,这样感觉太过于麻烦,所以这里就需要引入其它方法了。


利用compileall和py_compile来预编译python代码:

这两个从某种意义上是互通的,一般anaconda预装了这两个东西,原装python的话不太清楚,所以我们可以直接用,语法格式为:

python -m py_compile file.py #把单个.py文件编译为字节码文件
python -m py_compile /path/to/src/ #批量生成字节码文件,/path/to/src/是包含.py文件名的路径
python -m compileall file.py #把单个.py文件编译为字节码文件
python -m compileall /path/to/src/ #批量生成字节码文件,/path/to/src/是包含.py文件名的路径

上面的py_compile针对文件夹是会有一些问题,但理论上这种语法应该是可以的。我们用compileall对一个还未运行过的项目进行compile,当跑完程序后,会在所有可以运行的文件下自动生成编译pyc文件:
python代码加密——编译与反编译方法总结_第2张图片
但Windows比较坑的是,当我在上面运行完命令后,发现在我项目文件夹下多了一个_pycache_文件夹,这就和上面的一样了,然后我回到Linux服务器跑,则不会出现这种问题。所以建议最好在Linux环境下编译,Windows感觉有点莫名其妙,我猜它是直接去把代码运行了一遍,提前生成了pyc文件,目录格式为:

          |---test.py

          |---test2.py

          |---test3.py

          |---__pycache__

                    |----test.cpython-36.pyc

                    |----test2.cpython-36.pyc

                    |----test3.cpython-36.pyc

然后我们还可以写成一个脚本对项目文件进行编译加密:

# 批量编译py文件
import compileall
compileall.compile_dir("/usr/to/src")

sudo find /usr/to/src -name "*.py" | xargs rm -rf	# 删除该目录下所有的py文件

对于compileall更详细的参数以及命令解析可以看下面的链接:https://docs.python.org/3/library/compileall.html

编译成pyd文件或pyo文件

与上面的编译类似,我们可以写一个脚本文件,然后对某一个文件进行编译,但在此之前,我们需要先下载Cpython模块,步骤为:

# 前提
pip intall Cpython

# 脚本文件
from distutils.core import setup
from Cython.Build import cythonize
 
setup(
  name = 'Hello world app',
  ext_modules = cythonize("test.py"),
)

然后我们就退回到目录下运行命令就会生成pyd文件:

python setup.py build_ext --inplace

另外这个是基于Windows环境下编译成pyd文件,如果是linux,那么就是so文件了。

而pyo文件其实更简单,就是上面pyc命令的改版:

python -O -m py_compile file.py
python -O -m py_compile /path/to/src/
python -O -m compileall file.py
python -O -m compileall /path/to/src/

或者
python -OO -m py_compile file.py
python -OO -m py_compile /path/to/src/
python -OO -m compileall file.py
python -OO -m compileall /path/to/src/

python代码加密——编译与反编译方法总结_第3张图片


pyc文件反编译

这里可以推荐一个在线网站:https://tool.lu/pyc/ ,当我们提交一个pyc文件时,它会自动反编译出一个py文件出来:
python代码加密——编译与反编译方法总结_第4张图片
当然,不太清楚这个网站到底是怎样进行反编译的,不过确实有效,另外就是另一个python的包了:uncompyle

我们可以pip安装:

pip install uncompyle

安装成功后help一下,如果有下述命令与信息那么就表明安装成功。

Usage:
  uncompyle6 [OPTIONS]... [ FILE | DIR]...
  uncompyle6 [--help | -h | --V | --version]

Examples:
  uncompyle6      foo.pyc bar.pyc       # decompile foo.pyc, bar.pyc to stdout
  uncompyle6 -o . foo.pyc bar.pyc       # decompile to ./foo.pyc_dis and ./bar.pyc_dis
  uncompyle6 -o /tmp /usr/lib/python1.5 # decompile whole library

Options:
  -o <path>     output decompiled files to this path:
                if multiple input files are decompiled, the common prefix
                is stripped from these names and the remainder appended to
                <path>
                  uncompyle6 -o /tmp bla/fasel.pyc bla/foo.pyc
                    -> /tmp/fasel.pyc_dis, /tmp/foo.pyc_dis
                  uncompyle6 -o /tmp bla/fasel.pyc bar/foo.pyc
                    -> /tmp/bla/fasel.pyc_dis, /tmp/bar/foo.pyc_dis
                  uncompyle6 -o /tmp /usr/lib/python1.5
                    -> /tmp/smtplib.pyc_dis ... /tmp/lib-tk/FixTk.pyc_dis
  --compile | -c <python-file>
                attempts a decompilation after compiling <python-file>
  -d            print timestamps
  -p <integer>  use <integer> number of processes
  -r            recurse directories looking for .pyc and .pyo files
  --fragments   use fragments deparser
  --verify      compare generated source with input byte-code
  --verify-run  compile generated source, run it and check exit code
  --weak-verify compile generated source
  --linemaps    generated line number correspondencies between byte-code
                and generated source output
  --encoding  <encoding>
                use <encoding> in generated source according to pep-0263
  --help        show this message

Debugging Options:
  --asm     | -a  include byte-code       (disables --verify)
  --grammar | -g  show matching grammar
  --tree    | -t  include syntax tree     (disables --verify)
  --tree++        add template rules to --tree when possible

Extensions of generated files:
  '.pyc_dis' '.pyo_dis'   successfully decompiled (and verified if --verify)
    + '_unverified'       successfully decompile but --verify failed
    + '_failed'           decompile failed (contact author for enhancement)

安装好后的可执行文件名叫uncompyle6,根据上面的提示,我们需要输入uncompyle6 models.pyc > models.py将models.pyc反编译成py文件
uncompile -o . *.pyc将当前文件夹中所有的pyc文件反编译成后缀名为.pyc_dis的源文件
反编译后的效果可以说很理想,如果你的代码格式符合PEP8规范的要求,那就基本和源来的文件一样,不过各种注释就没有了。
最后改的代码还没有运行(没有生成pyc)的,就真的丢了,不过不多,再写一遍吧!

反编译库总结与说明

其实不仅仅只有这一种反编译的uncompyle,还有很多比如说uncompyle2, decompyle2, DePython, unpyc, uncompyle, pycdc,我们都可以进行相关的破解,它们相对应的pyo、pyd文件的破解形式,我们还可以对这些进行二次加密,这里限于篇幅与使用情况,我就不一一叙述了。


在线网站进行加密

网上加密是有很多地方的,不同于转成pyc的二进制加密,这种多了一些模糊层,比如说下面这个网站,注释基本也看不出端倪,如果文件不多的话可以看看。
python代码加密——编译与反编译方法总结_第5张图片
这种看起来是二进制的加密方式,但我将一个文件在这个网站编译后,再用上面的uncompile,发现并没有什么太大的作用,但这样我就不知道是基于什么情况进行的加密的,破解难度会稍微大一点。

python解释器加密

这里是看到知乎的一篇文章提到了改变python编译器的方式,因为主流是Cpython,所以可以针对某些地方进行修改,达到代码在运行的同时就达到了加密的效果,并且这里用的是RSA加密,算是目前最流行也是比较难破解的几种加密方式之一。

python代码加密——编译与反编译方法总结_第6张图片
python代码加密——编译与反编译方法总结_第7张图片
上述两图的详细地址为如何保护你的 Python 代码 (二)—— 定制 Python 解释器

总结

这篇文章写得有点艰辛,可能整体的流程安排有些乱,主要是最近感冒影响了博文进度,导致中途断断续续,不过自己正在恢复,另外,可能里面还有些小错误,后期会修改,希望看完本篇博文或多或少有所收获。



参考与推荐:

  1. http://pyob.oxyry.com/
  2. https://tool.lu/pyc/
  3. windows 下Python3.x生成pyd文件(python加密)
  4. python py、pyc、pyo、pyd文件区别

你可能感兴趣的:(python,编译与反编译)