news 2025/12/29 8:00:47

代码裸奔?PyInstaller打包的EXE文件竟能轻松“扒光”还原——手把手教你用PyMe开发反编译工具

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
代码裸奔?PyInstaller打包的EXE文件竟能轻松“扒光”还原——手把手教你用PyMe开发反编译工具

欢迎回到我们的《零基础:100个小案例玩转Python软件开发!》系列!在第六节课,我将教大家如何开发一个反编译工具。

一、PyInstaller打包EXE

首先我们要知道,如果要将一个Python文件或PyMe项目打包成EXE可执行文件,需要使用专门的打包工具,比如pyinstaller,nuitka等,其中最常用的是pyinstaller,因为它的命令行比较简单。比如我们有下面一个login.py:

import tkinter as tk from tkinter import messagebox # 创建窗口 window = tk.Tk() window.title("登录") window.geometry("250x200") # 测试账户 users = {"admin": "123456", "test": "test123"} # 标题 tk.Label(window, text="用户登录", font=("Arial", 14)).pack(pady=10) # 用户名 tk.Label(window, text="用户名:").pack() user_entry = tk.Entry(window) user_entry.pack() # 密码 tk.Label(window, text="密码:").pack() pwd_entry = tk.Entry(window, show="*") pwd_entry.pack() # 登录按钮 def check_login(): user = user_entry.get() pwd = pwd_entry.get() if user in users and users[user] == pwd: messagebox.showinfo("成功", "登录成功!") # 打开新窗口 new_window = tk.Toplevel(window) new_window.title("主界面") new_window.geometry("300x200") tk.Label(new_window, text=f"欢迎 {user}!").pack(pady=50) tk.Button(new_window, text="退出", command=new_window.destroy).pack() else: messagebox.showerror("错误", "账号或密码错误!") tk.Button(window, text="登录", command=check_login, width=10).pack(pady=20) # 运行 window.mainloop()

它运行时的样子是这样的:

我们在代码文件所在的文件夹里进入cmd命令行,然后输入命令:

pyinstaller -c -w -F login.py

回车运行后,pyinstaller会开始工作,结束后会将当前文件打包成一个独立的EXE。

打包过程中会生成两个文件夹,一个是build,主要用于存放打包的临时生成文件,另一个是dist,是用于发布的结果。打包结束后,会在dist中生成login.exe文件,双击运行,可以看到一切正常。

虽然PyInstaller可以将Python脚本、依赖库和解释器打包成单个可执行文件,但实际上这些资源只是被"包裹"在一起,并没有真正的加密保护。这一节我们就开发一个pyinstaller反编译工具,看能不能将上面的login.exe还原为源码文件。

二、开发自己的反编译工具

我们启动PyMe,新建一个空白工具“反编译工具”,在设计器从左边的控件工具体中拖动Label、Entry、LabelButton到界面上,修改文字和样式,做成如下所示的界面。

我们希望在点击Python文件对应的“浏览”按钮时,将文件路径填入到Entry_1中,在点击导出文件夹对应的“浏览”按钮时,将文件夹路径填入到Entry_2中,然后点击"导出"时能够将EXE反编译出python文件并导出到指定文件夹。

在第一个“浏览”按钮上用鼠标右键单击,然后在弹出菜单中选择”事件响应“菜单项,进入事件响应编辑框后在左边选择Command事件,在右边选择”调用其它界面“,然后再选择”调用打开文件框“。

进入代码编辑器后,修改生成的Fun.OpenFile函数参数,将Python改为EXE,代表打开EXE文件,判断一下返回的openPath是否有效,如果有效设置到Entry_1中。

#LabelButton 'LabelButton_1' 's Command Event : def LabelButton_1_onCommand(uiName,widgetName,threadings=0): openPath = Fun.OpenFile(对话框标题="打开EXE文件",文件类型列表=[('EXE File','*exe'),('All files','*')],初始文件夹路径= os.path.abspath('.'),选择多文件=False) if openPath: Fun.SetText(界面名称=uiName,控件名称='Entry_1',字符串文本=openPath)

接下来可以返回设计器为第二个浏览按钮如法炮制来”打开目录查找“并设置到Entry_2中。也可以在代码编辑器右边的微缩界面中点选第二个浏览按钮,然后在下面的控件事件类型列表中为“按钮点击”事件绑定函数“,这样就可以直接生成LabelButton_2_onCommand函数了。

在函数里用鼠标右键单击,就可以在弹出菜单中选择”系统函数“下的”打开目录查找“来生成弹出对话框界面。

最终代码完善如下:

#LabelButton 'LabelButton_2' 's Command Event : def LabelButton_2_onCommand(uiName,widgetName,threadings=0): openPath = Fun.SelectDirectory(title='打开目录查找',initDir=os.path.abspath('.')) if openPath: Fun.SetText(界面名称=uiName,控件名称='Entry_2',字符串文本=openPath)

最后是为”导出“按钮绑定点击事件函数并进行反编译逻辑处理,这段代码比较长,我们需要先用pyinstxtractor来从EXE提取文件。

pyinstxtractor下载地址如下:

https://github.com/extremecoders-re/pyinstxtractor

下载完后将文件放置到当前工程工程文件夹下,然后调用以下命令就可以将exe中的文件提取出来。

python pyinstxtractor.py your_app.exe

如果你是VIP会员,你可以鼠标右键,通过"AI生成代码“来生成这段处理逻辑。

在编程小助手输入框中输入:”调用pyinstxtractor对exePath进行反编译”,它就可以生成对应的函数。

具体逻辑如下:

#LabelButton 'LabelButton_3' 's Command Event : def LabelButton_3_onCommand(uiName,widgetName,threadings=0): exePath = Fun.GetText(uiName,'Entry_1') srcPath = Fun.GetText(uiName,'Entry_2') import io import os import sys import subprocess import tempfile import shutil # 强制标准输出使用UTF-8编码 sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace') def extract_exe_with_pyinstxtractor(exePath, srcPath=None): """ 使用pyinstxtractor提取PyInstaller打包的exe文件 Args: exePath (str): 要提取的exe文件路径 srcPath (str, optional): 输出目录路径。如果为None,则在exe同目录创建输出文件夹 Returns: str: 提取后的目录路径 """ #检查exe文件是否存在 if not os.path.exists(exePath): raise FileNotFoundError(f"找不到exe文件: {exePath}") #如果未指定输出路径,则在exe同目录创建输出文件夹 if srcPath is None: exe_dir = os.path.dirname(exePath) exe_name = os.path.splitext(os.path.basename(exePath))[0] srcPath = os.path.join(exe_dir, f"{exe_name}_extracted") #获取pyinstxtractor.py的路径 #方法1: 如果pyinstxtractor已安装 try: import pyinstxtractor pyinstxtractor_path = os.path.join(os.path.dirname(pyinstxtractor.__file__), 'pyinstxtractor.py') except ImportError: print("pyinstxtractor未安装") return #执行pyinstxtractor print(f"正在提取 {exePath} ...") print(f"输出目录: {srcPath}") try: #使用Python运行pyinstxtractor cmd = [sys.executable, pyinstxtractor_path, exePath] #运行命令 result = subprocess.run( cmd, capture_output=True, text=True, cwd=srcPath, #在输出目录中运行 encoding='utf-8' ) #检查执行结果 if result.returncode != 0: print(f"pyinstxtractor执行错误:\n{result.stderr}") raise RuntimeError(f"pyinstxtractor执行失败,返回码: {result.returncode}") print("提取完成!") print(f"输出: {result.stdout}") #查找提取的文件夹(pyinstxtractor会在当前目录创建以exe名开头的文件夹) extracted_dirs = [d for d in os.listdir(srcPath) if d.startswith(os.path.basename(exePath)) and os.path.isdir(os.path.join(srcPath, d))] if extracted_dirs: extracted_dir = os.path.join(srcPath, extracted_dirs[0]) print(f"提取的文件位于: {extracted_dir}") return extracted_dir else: print("警告: 未找到提取的文件夹") return srcPath except Exception as e: print(f"提取过程中出错: {e}") raise extract_exe_with_pyinstxtractor(exePath, srcPath)

不过这时只是完成了EXE文件提取出pyc文件,运行测试一下,点击导出时,将会开始处理提取。

完成后可以在目标文件夹看到生成的login.pyc。

如果我们想要将pyc进一步还原为python代码,还需要另一个工具uncompyle6或直接到https://www.decompiler.com/上传上传pyc文件即可查看源码。

通过 pip install uncompyle6 安装一下。

然后在提取代码后面稍做修改,调用uncompyle6来进行pyc到py文件的转换。

extracted_dir = extract_exe_with_pyinstxtractor(exePath, srcPath) import uncompyle6 pycfilelist = Fun.WalkAllResFiles(文件夹路径=extracted_dir,是否遍历子文件夹=False,是否指定扩展名="pyc") for pyc in pycfilelist: if os.path.exists(pyc): print(f"\n=== 正在反编译 {pyc} ===") os.system(f"uncompyle6 {pyc} > {pyc.replace('.pyc', '_decompiled.py')}") print(f"已保存:{pyc.replace('.pyc', '_decompiled.py')}")

好啦,现在整个工程逻辑就完成啦,我们运行测试一下,可以将EXE文件反编译到指定文件夹下并生成对应的python文件。

打开login_decompiled.py,就可以看到代码源文件啦!

三、PyMe的防护措施

经过上面的开发,相信大家对于pyinstaller打包EXE又有了新的认识,虽然说pyinstaller打包很快很方便,但是并不是很安全,开发一些小工具倒是可以,但是如果想要有更好的源代码保护,就建议使用加密打包或Nuitka打包,这两项在PyMe中都支持,在发布时弹出的打包对话框中,你可以通过切换打包工具使用nuitka,或者直接在pyinstaller中使用加密保护源码选项。这两项都会将源码先转换成c语言代码再编译,大大强化EXE的反编译保护。

最后,在PyMe的”案例商店“的"文件操作"分类中有一个专门测试PyMe工程EXE反编译的工具案例”EXE2PY“,感兴趣小伙伴也可以下载体验。

它的原理和本节类似,只是更加完善一些。

在本节的课程中,我们通过一个反编译工具的开发案例讲述了Python打包工具的和反编译保护的知识,关注PyMe公众号教程,跟着我继续学习,让我们一起加油!

官网:www.py-me.com

下载https://pyme.lanzoum.com/igiUy3cviulg

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2025/12/26 4:01:03

电商包装测试

消费品行业包括消费者在商城购买的所有产品,在上架之前,他们必须要通过对产品及其包装施加压力的分销渠道。在某些情况下,这些应力会对包装或产品造成损害,使其不适合消费者使用,这些类型的损害是昂贵的但可以避免。封…

作者头像 李华
网站建设 2025/12/17 11:07:29

高性能GPU推荐列表:运行EmotiVoice最适配的显卡型号

高性能GPU推荐列表:运行EmotiVoice最适配的显卡型号 在虚拟主播实时互动、智能客服拟人化应答、有声书自动朗读等场景中,用户对语音合成系统的要求早已超越“能说话”的基础功能。如今,真正打动人的,是那句带着笑意的问候、一声略…

作者头像 李华
网站建设 2025/12/17 11:06:17

《打破大模型幻觉:ReAct框架与Agent开发的最通俗解读》

1. 开篇:为什么Chatbot时代已经结束?观点: 简单的问答已经卷不动了,未来的趋势是Agent(智能体)——不仅能聊,还能使用工具、自主决策。举例: 传统的GPT只能给你写代码,Ag…

作者头像 李华
网站建设 2025/12/21 15:53:05

小型房屋租赁|基于springboot 小型房屋租赁系统(源码+数据库+文档)

小型房屋租赁 目录 基于springboot vue小型房屋租赁系统 一、前言 二、系统功能演示 三、技术选型 四、其他项目参考 五、代码参考 六、测试参考 七、最新计算机毕设选题推荐 八、源码获取: 基于springboot vue小型房屋租赁系统 一、前言 博主介绍&…

作者头像 李华
网站建设 2025/12/17 11:05:58

花店管理|基于springboot花店管理系统(源码+数据库+文档)

花店管理 目录 基于springboot vue花店管理系统 一、前言 二、系统功能演示 三、技术选型 四、其他项目参考 五、代码参考 六、测试参考 七、最新计算机毕设选题推荐 八、源码获取: 基于springboot vue花店管理系统 一、前言 博主介绍:✌️大…

作者头像 李华