在這裡分享一些技巧和經驗給大家。辛苦撰文分享,轉載或引用請保留本文作者信息及文章鏈接。
作者的環境:
win7+python3.5(anaconda3)理論上,win7及以上的系統和python任意版本均可。
win7+python3.5(anaconda3)
首先我們構建一個簡單的腳本,比如輸出一串數字、文本之類,這裡我們輸出一串文字的同時計算一下3次方好了。
# -*- coding: utf-8 -*- """ Created on Wed Aug 29 09:18:13 2018 @author: Li Zeng hai """
def test(num): print(num={n}, {n}^3={n2}.format(n=num, n2=num**3))
if __name__ == __main__: while 1: try: num = input(提示:輸入"q"退出程序。 請輸入一個數字:) if num.lower() == q: break num = float(num) print(num) except: print(輸入的數字不正確!) continue
test(num)
把這段腳本保存為mylib.py,運行一下這個腳本:
可以看到,腳本正常運行了。
為了演示,我們把下面的腳本新建到main.py腳本文件中,並且從mylib中引入測試函數。
# -*- coding: utf-8 -*-
from mylib import *
while 1: try: num = input(提示:輸入"q"退出程序。 請輸入一個數字:) if num.lower() == q: break num = float(num) print(num) except: print(輸入的數字不正確!) continue
使用如下命令,將其打包為單一exe(去掉-F則不是單一exe)
pyinstaller -F main.py
打包過程如下:
E: >pyinstaller -F main.py 505 INFO: PyInstaller: 3.3.1 505 INFO: Python: 3.5.5 505 INFO: Platform: Windows-7-6.1.7601-SP1 505 INFO: wrote E: main.spec 505 INFO: UPX is not available. 505 INFO: Extending PYTHONPATH with paths [E:\t, E:\t] 505 INFO: checking Analysis 505 INFO: Building Analysis because out00-Analysis.toc is non existent 505 INFO: Initializing module dependency graph... 521 INFO: Initializing module graph hooks... 521 INFO: Analyzing base_library.zip ... 6269 INFO: running Analysis out00-Analysis.toc 6269 INFO: Adding Microsoft.Windows.Common-Controls to dependent assemblies of final executable required by d:anaconda3python.exe 6956 INFO: Caching module hooks... 6956 INFO: Analyzing E: main.py 6956 INFO: Loading module hooks... 6956 INFO: Loading module hook "hook-pydoc.py"... 6956 INFO: Loading module hook "hook-xml.py"... 7283 INFO: Loading module hook "hook-encodings.py"... 7533 INFO: Looking for ctypes DLLs 7549 INFO: Analyzing run-time hooks ... 7549 INFO: Looking for dynamic libraries 7720 INFO: Looking for eggs 7720 INFO: Using Python library d:anaconda3python35.dll 7720 INFO: Found binding redirects: [] 7720 INFO: Warnings written to E: uildmainwarnmain.txt 7751 INFO: Graph cross-reference written to E: uildmainxref-main.html 7767 INFO: checking PYZ 7767 INFO: Building PYZ because out00-PYZ.toc is non existent 7767 INFO: Building PYZ (ZlibArchive) E: uildmainout00-PYZ.pyz 8345 INFO: Building PYZ (ZlibArchive) E: uildmainout00-PYZ.pyz completed successfully. 8345 INFO: checking PKG 8345 INFO: Building PKG because out00-PKG.toc is non existent 8345 INFO: Building PKG (CArchive) out00-PKG.pkg 9954 INFO: Building PKG (CArchive) out00-PKG.pkg completed successfully. 9954 INFO: Bootloader d:anaconda3libsite-packagesPyInstallerootloaderWindows-64bit un.exe 9954 INFO: checking EXE 9954 INFO: Building EXE because out00-EXE.toc is non existent 9954 INFO: Building EXE from out00-EXE.toc 9954 INFO: Appending archive to EXE E: distmain.exe 9954 INFO: Building EXE from out00-EXE.toc completed successfully.
E: >
最終在目錄下生成build、disk文件夾。其中exe文件在disk中。運行正常。如下圖:
三、反編譯Pyinstaller打包的exe
這樣的exe已經可以被遷移到別的電腦上使用了,如果是為了方便其他電腦使用,到這一步就已經結束了。但有時候,我們可能是把這個功能給很多人用,但如果不想開源或者被別人破解,到這一步是還不夠的。
因為到這一步的exe是可以被別人反編譯出源碼的。
此處用到的工具:
exe反編譯工具:pyinstxtractor.py:點擊此處去下載
pyc反編譯工具:Easy Python Decompiler 或者在線反編譯pyc。
將pyinstxtractor.py放到exe文件相同目錄,執行以下cmd命令:
python pyinstxtractor.py main.exe
如果成功執行,將在同目錄下生成新的反編譯文件夾——main.exe_extracted,如下圖:
同時,我們可以在下圖圈起來的路徑下,找到當時我們exe引入的mylib模塊,其為pyc格式。
pyc格式的文件,反編譯起來就非常簡單了。用前文提供的工具或者網上找個在線的分分鐘反編譯出來,我們看下反編譯的結果:
#!/usr/bin/env python # visit http://tool.lu/pyc/ for more information
Created on Wed Aug 29 09:18:13 2018
@author: Li Zeng hai
def test(num): print(num={n}, {n}^3={n2}.format(n=num, n2=num ** 3))
if __name__ == __main__: while None:
try: num = input( xe6x8fx90xe7xa4xbaxefxbcx9axe8xbex93xe5x85xa5"q"xe9x80x80xe5x87xbaxe7xa8x8bxe5xbax8fxe3x80x82 xe8xafxb7xe8xbex93xe5x85xa5xe4xb8x80xe4xb8xaaxe6x95xb0xe5xadx97xefxbcx9a) if num.lower() == q: break num = float(num) print(num) except: None None None print( xe8xbex93xe5x85xa5xe7x9ax84xe6x95xb0xe5xadx97xe4xb8x8dxe6xadxa3xe7xa1xaexefxbcx81) continue
可以看到,基本上完美的把源碼反編譯出來了。其中涉及到中文的地方,會因為編碼問題有所改變。但是非中文部分,幾乎一模一樣。
就問你怕不怕!!!
好怕怕 ,哈哈。
如何解決呢,可以考慮將模塊py文件編譯為動態鏈接庫,這樣破解難度將大大增加。其中,在python裏,pyd格式即動態鏈接庫。使用cython即可編譯,如果是anaconda是自帶,python有的可能不帶cython,安裝即可:
pip install Cython
我們在main.py所在的文件夾新建py文件,在此處我命名為build_pyd.py,其內容如下:
# -*- coding: utf-8 -*- """ Created on Wed Aug 29 13:33:20 2018
@author: Li Zeng hai """
from distutils.core import setup from Cython.Build import cythonize
setup( name = any words....., ext_modules = cythonize(["mylib.py",
] ), )
然後執行以下cmd命令:
python build_pyd.py build_ext --inplace
運行過程及生成結果如下圖,其中紅框的pyd文件即編譯好了。因為我是64位的系統和python,所以會生成amd64後綴,我們把這個刪掉重命名為mylib.pyd即可。
註:當同時存在mylib.pyd和mylib.py時,引入優先順序是pyd>py,所以不用移除py文件,默認引入時就是pyd。
此時,我們刪除build、disk文件夾,重複步驟二,再次編譯為exe即可。
注意:編譯需要相關的VC環境,因為python3.5是基於 VS14版本的,所以我這裡安裝的也是。不安裝是無法編譯的。
可以驗證一下:
再次反編譯main.exe後,原來的路徑E: distmain.exe_extractedout00-PYZ.pyz_extracted之下,已經找不到mylib.pyc了。
因為他已經不是可以直接反編譯出來的文件了。
那麼他在哪呢,他是作為pyd存在於上層目錄中了。如下圖:
pyd的反編譯難度是相當高的,至此,就大功告成了!
本文首發於個人博客:PyInstaller將Python文件打包為exe後如何反編譯(破解源碼)以及防止反編譯 - Python量化投資
歡迎關注公眾號:python_trader,準備開始爬蟲系列教程。