如何避免别人反编译我们的 Python .exe 程序

2024-04-22 13:17:23 浏览数 (1)

前言

  • 防止 Python 可执行文件(.exe)被反编译是一项重要的安全措施,尤其是当你希望保护你的知识产权、算法、或者商业逻辑时。虽然绝对的安全是不存在的,但可以采取一些措施来增加反编译的难度,使得攻击者更难以获取你的源代码。

常用方案

pyinstaller 使用 --key 进行加密

  • 我们可以在打包命令后面添加 --key 参数来进行加密,例如:
代码语言:python代码运行次数:0复制
 pyinstaller --onefile   -p venv/Lib/site-packages .print-studentmain.py --key '1234'
  • 再次解压,抽取的中间结果变为了 .pyc.encrypted,无法正常反编译。

PyInstaller v6.0 移除加密命令

  • Bytecode encryption was removed in PyInstaller v6.0. Please remove your --key=xxx argument. For the rationale and alternatives see https://github.com/pyinstaller/pyinstaller/pull/6999
  • 官方 github 的一些讨论:
  • 大概的意思就是说,解密密钥必须存储在构建的应用程序中的某个位置以使应用程序能够运行,字节码加密对于窥探的眼睛只能起到轻微的威慑作用。任何愿意挖掘 PyInstaller 源代码以获取可执行存档的确切布局和快速十六进制转储的人都可以破解它,一旦您知道在哪里查找即可获取密钥。
  • 然而现在,像 PyExtractor 这样的 PyInstaller 逆向工程工具已经内置了这一切。例如,在下面的步骤中,我们的窥探用户甚至不需要知道他们试图打开的应用程序是加密的,更不用说必须采取任何巧妙的措施来解密它。
代码语言:python代码运行次数:0复制
git clone https://github.com/Rdimo/PyExtractor.git
cd PyExtractor
pip install -r requirements.txt
python main.py some/pyinstaller/application
  • 由于逆向工程的知识障碍,加密构建现在与常规构建相同,用户可能被误导认为加密的 PyInstaller 构建是放置 API 密钥等内容的安全位置。最后即使添加了更多代码混淆最终会导致相同的结果,因此完全删除加密功能。
  • 当然也有朋友提出将加密密码交给使用者运行时填入,但是对于源码的加密实际上并没有很大的实际意义,且会增加维护成本。

使用Cython配合加密打包程序

  • Python 在打包或优化运行速度时会生成.pyc文件,类似于 Java 的.class文件。这些.pyc文件可以被简单地反编译为.py文件,就像 Java 的.class文件可以反编译为 Java 源代码一样。然而,相比之下,由C语言编译生成的机器码更难以反编译。实际上,机器码反编译后通常是汇编代码或难以阅读的C语言代码。目前还没有一种直接将机器码转换回 Python 代码的方法。因此,我们可以利用这一点来加密我们的代码。
  • Cython 是一个编译器,可以将 Cython 源代码转换为高效的C或C 源代码。然后,我们可以将这些源代码编译 为Python 扩展模块或独立的可执行文件。通过使用 Cython 将我们的 Python 代码转换为C或C ,可以大大增加反编译的难度。

安装 Cython

代码语言:txt复制
pip install cython

配置 Cython 文件 & 编译

  • 配置 build_pyd.py 文件:
代码语言:txt复制
from distutils.core import setup
from Cython.Build import cythonize
 
setup(
    name='一个名字',
    ext_modules=cythonize(
        [
            "Python脚本文件.py",
            "Python脚本文件夹/*.py",
            # ...
        ],
        language_level=3
    ),
)

// 编译
python build_pyd.py build_ext --inplace
  • 可以看到生成了一些.pyd文件,这是Windows的DLL文件,相对来说破解和反编译都比.pyc文件要难一些,可以达到一定的加密效果。生成.pyd文件后的目录结构:
代码语言:txt复制
│  app.c
│  app.cp38-win_amd64.pyd
│  app.py
│  build_pyd.py
│  config.c
│  config.cp38-win_amd64.pyd
│  config.py
│  gui.c
│  gui.cp38-win_amd64.pyd
│  gui.py
│  log.c
│  log.cp38-win_amd64.pyd
│  log.py
│  run.py
│  
├─.idea
│      ......省略......    
│       
├─build
│      ......省略......     
│       
├─images
│      icon.ico
│  
├─logs
│      ......省略......  
│         
├─venv
│      ......省略......    
│      
└─__pycache__

重新打包

代码语言:txt复制
pyinstaller -F run.py --hidden-import json --hidden-import tkinter --hidden-import tkinter.filedialog --hidden-import requests --hidden-import docx --hidden-import openpyxl --hidden-import log --hidden-import gui --hidden-import tkinter.ttk --hidden-import config
  • 当我们将 Python 源文件编译成.pyd文件时,由于.pyd文件是二进制文件,PyInstaller 在分析需要导入的包时无法直接解析.pyd文件。导致 PyInstaller 不知道.pyd文件中导入了哪些模块。
  • 因此,我们需要使用--hidden-import参数告诉 PyInstaller 我们需要导入哪些模块,以便正确地打包应用程序。

总结

  • 本文介绍了两种常见的 Python .exe 源码加密方式,但实际上无论哪种方式都无法做到完全加密,只是相对的提高了反编译的难度。简单来说,Python 属于解释型语言,执行器解析的是源码,即使进行加密,运行时也需要解密为源码,不同于 C、C 等编译型语言,执行器执行的机器码,机器码的反编译难度指数级上升。

参考

  • https://www.cnblogs.com/minuhy/p/17747925.html

个人简介

0 人点赞