背景
Python 是一种解释型语言,没有编译过程,发布程序的同时就相当于公开了源码,这也是其作为开源语言的一个特性。但在某些场景下,我们的源码是不想被别人看到的,例如开发商业软件。
加密方式
参考链接: 如何给Python代码进行加密 Python 源码混淆与加密 1、代码混淆 2、发行.pyc 文件 3、使用 py2exe、pyinstaller打包为exe文件 4、使用PyArmor加密脚本 5、使用pyconcrete加密为pye文件 6、使用 Cython将py文件生成为pyd加密文件
编译与反编译过程
本文采用第6种方法,即使用 Cython将py文件生成为pyd加密文件. 正常情况下: py文件编译为exe文件过程 py—>(pyinstaller包)---->exe文件 反编译过程 exe文件—>(pyinstxtractor包)—>pyc文件—>(uncompyle6包)---->py源码
加密情况下 py文件编译为exe文件过程 py—>(Cypthon)—>c文件和pyd文件–>(pyinstaller包)---->exe文件 中间生成的pyd文件是难以反编译的
本文用到的工具
python 3.8.5 pycharm visual studio 2022(需要C编译器) pyinstaller 5.1 Cython 0.29.30 pyinstxtractor.py https://sourceforge.net/projects/pyinstallerextractor/
python3打包为exe文件
这里有个Hello.py文件 Hello.py文件内容如下:
from tkinter import *
class ChangeLabelDemo:
def __init__(self):
window = Tk()
window.title = "改变labeldemo"
frame1 = Frame(window)
frame1.pack()
self.lb1 = Label(frame1, text="Programming is fun")
self.lb1.pack()
frame2 = Frame(window)
frame2.pack()
label = Label(frame2, text="输入")
self.msg = StringVar()
entry = Entry(frame2, textvariable=self.msg)
btChangeText = Button(frame2, text="改变text", command=self.processButton)
self.v1 = StringVar()
rbRed = Radiobutton(frame2, text="Red", bg="red", variable=self.v1, value="R", command=self.processRadiobutton)
rbYellow = Radiobutton(frame2, text="Yellow", bg="yellow", variable=self.v1, value="Y",
command=self.processRadiobutton)
label.grid(row=1, column=1)
entry.grid(row=1, column=2)
btChangeText.grid(row=1, column=3)
rbRed.grid(row=1, column=4)
rbYellow.grid(row=1, column=5)
window.mainloop()
def processButton(self):
self.lb1["text"] = self.msg.get()
def processRadiobutton(self):
if self.v1.get() == "R":
self.lb1["fg"] = "red"
elif self.v1.get() == "Y":
self.lb1["fg"] = "yellow"
ChangeLabelDemo()
step1:安装pyinstaller包
pip install pyinstaller
step2:在cmd中进入当前文件路径下
cd E:\研究生\pytorch\untitled\encypt
step3:打包生成exe文件,使用如下命令,将其打包为单一exe(去掉-F则不是单一exe,-w是不生成window窗口)
pyinstaller -F -w Hello.py
生成了build,dist 和Hello.spec三个文件 exe文件在dist文件夹中,双击即可运行
python3将exe文件进行反编译为源码
exe反编译工具:pyinstxtractor.py下载:https://sourceforge.net/projects/pyinstallerextractor/
将pyinstxtractor.py放到exe文件相同目录 执行以下cmd命令,首先进入到dist文件夹下
cd dist
接下来,在cmd中执行下面命令
python pyinstxtractor.py Hello.exe
成功解压(反编译),多了个Hello.exe_extracted 文件夹 进入Hello.exe_extracted 文件夹,有个Hello文件,此为被解压出的pyc文件,需通过 接下来尝试对Hello 文件反编译 首先安装反编译uncompyle6 包
pip install uncompyle6
接下来进入exe所在文件夹
cd Hello.exe_extracted
需将Hello 文件添加.pyc 后缀,不然不能编译。运行下面代码反编译Hello.pyc 文件
uncompyle6 Hello.pyc
结果报错
Unknown magic number 227 in Hello.pyc
报错原因: 提示是Unknown magic number 227 ,这个失败因为pyinstaller 工具打包的时候,会将代码文件的magic number (python的版本及编译时间)给清除掉,所以反编译时候需要将magic numbe r添加回去才能识别,magic number 我们可以通过解压主目录下的struct 文件中提取出来(一般是前16个字节,可以对比打包前的源文件),将struct 文件体中的前16个字节提取出来,然后在添加到文件中,然后再执行uncompyle6 反编译。 报错解决方法:Python3 如何反编译EXE 我们先看看struct 文件的内容,注意看第一行,这个就是缺的信息。第二行是以E3开始的。 接下来看Hello 文件的内容(不是pyc文件,所以得把pyc后缀去掉,然后,用vs打开,pycharm和记事本打开会乱码),可以看出是以E3 为起始,相对struct 文件少一第一行。 接下来要做的就是把缺失的magic number 添加到pyc文件中
在pycharm中运行以下代码
struct_path = r"E:\研究生\pytorch\untitled\encypt\dist\Hello.exe_extracted/struct"
fn = open(struct_path, 'rb')
print(fn.seek(0))
magic_number = fn.read(16)
print(magic_number)
point_number = fn.tell()
print(point_number)
print(fn.read(1))
add_magic_num_file_name = r"E:\研究生\pytorch\untitled\encypt\dist\Hello.exe_extracted/Hello.pyc"
MAGIC_NUMBER = b'U\r\r\n\x00\x00\x00\x00\xac\x95\x15_\x01\x01\x00\x00'
f = open(add_magic_num_file_name, 'rb')
new_content = f.read()
new_add_magic_number_file_name = r"E:\研究生\pytorch\untitled\encypt\dist\Hello.exe_extracted/Hello.pyc"
n_f = open(new_add_magic_number_file_name, "wb")
n_f.write(MAGIC_NUMBER + new_content)
f.close()
n_f.close()
output>>>
0
b'U\r\r\n\x00\x00\x00\x00\xac\x95\x15_\x01\x01\x00\x00'
16
b'\xe3'
此时再用vs打开Hello 文件。完成,现在可以用uncompyle6 反编译了 在cmd中运行下面代码
uncompyle6 Hello.pyc
可见exe源代码被反编译出来,因此如果是公司开发的产品,其安全性有待考虑。
注: 1、如果注释存在中文,则会被解析成Unicode编码,可以用相应的工具转换即可 2、反编译的Hello 是主程序文件,其实还需要将PYZ-00.pyz_extracted 文件夹下的所有pyc文件都通过uncompyle6 进行反编译。 3、PYZ-00.pyz_extracted目录下的依赖库的pyc文件缺少的字节数与主程序不同,注意下PYZ-00.pyz_extracted目录下的依赖库的pyc文件缺少的字节数与主程序不同。 4、依赖库pyc文件批量反编译教程见这里
将py文件编译为pyd文件以防止反编译
将py文件编译为动态链接库,这样破解难度将大大增加。其中,在python里,pyd格式即动态链接库。使用cython即可编译为pyd文件。
首先安装cpython
pip install Cython
在Hello.py 文件创建新的.py文件,并命名为setup.py ,其内容为:
"""
Created on Friday July 1 16:40:20 2022
@author: Li Zhengping
link:
https://www.jb51.net/article/178209.html
https://blog.csdn.net/ZhaDeNianQu/article/details/87717293
"""
from distutils.core import setup
from Cython.Build import cythonize
setup(name = 'any words.....', ext_modules = cythonize(["Hello.py",]))
然后在cmd中执行以下命令
cd E:\研究生\pytorch\untitled\encypt
python setup.py build_ext --inplace
注意:编译需要相关的VC环境,我是安装 VS22版本的,不安装是无法编译的。
运行过程及生成结果如下图,其中红框的pyd文件即编译好了。因为我是64位的系统和python,所以会生成amd64后缀,我们把这个删掉重命名为Hello.pyd 即可。 注:当同时存在mylib.pyd和mylib.py时,引入优先级是pyd>py,所以不用移除py文件,默认引入时就是pyd。 此时,我们删除build文件夹 再次编译为exe即可。 cmd中运行下面代码
pyinstaller -F -w Hello.py
编译之后的文件 同样的在dist文件夹下存放exe文件
可以验证一下:再次反编译main.exe后 首先进入dist路径下
cd dist
注意要在exe同路径文件中放入pyinstxtractor.py文件 接下来运行
python pyinstxtractor.py Hello.exe
其结果是依然为Hello.pyc文件,而不是Hello.pyd文件,也就是打包的是Hello.py文件而不是Hello.pyd文件,这样操作依然能被反编译。 接下来搜了一下如何打包pyd文件,找到了如下博客:Python .py生成.pyd文件并打包.exe注意事项
首先需要创建一个main.py文件,其作为一个入口程序来导入pyd文件,pyd文件默认优先级高于py文件,因此Hello.py和Hello.pyd可以同时存在,也就是说Hello.py不需要删除。 main.py 内容如下
from tkinter import *
import Hello
if __name__ == '__main__':
Hello.ChangeLabelDemo()
注意: 1、程序的__main__ 入口只能有一个,如果源py文件中有定义main入口,需要注释掉并调整代码缩进,否则通过main.py调用pyd文件遇到if name == ‘main’ :之后的代码都不会运行。 2、源文件Hello.py 文件头部import到的第三方库需全部复制到main.py 文件头部,不然运行会闪退
接下来在cmd输入
pyinstaller -F -w main.py
接下来我们用pyinstxtractor.py 解包main.exe 文件验证一下,命令行依次输入(记得先把pyinstxtractor.py复制到当前文件夹下):
cd dist
python pyinstxtractor.py main.exe
会得到一个main.exe_extracted 文件夹,在文件夹下发现文件Hello.pyd ,而不是Hello.py 文件,说明通过引用pyd文件打包成功。pyd文件是难以反编译的,因此源码可以得到很好的保护。 大工告成
参考链接
通过pyinstaller打包为exe: 1、pyinstxtractor.py 的改进 - 反编译pyinstaller生成exe的工具 2、pyinstaller打包pyqt5编写的项目为exe(脱离环境可运行) 3、对python生成的EXE文件 进行反编译 将py文件生成为pyd文件进行反编译: 4、PyInstaller将Python文件打包为exe后如何反编译(破解源码)以及防止反编译 5、PyInstaller封装程序反编译 PyInstxtractor + Uncompale 将pyd文件打包成exe文件: 6、Python .py生成.pyd文件并打包.exe注意事项
欢迎关注我的公众号《故障诊断与python学习》
|