將pyinstaller打包後的exe還原成py / 防止還原 1. 將exe文件解壓 2 獲取pyc文件 3 反編譯pyc文件 4 複雜的腳本 5 防止還原

1. 將exe文件解壓

好多教程或者說明文檔,都說這個過程是反編譯,在我看來是兩個過程,1. 解壓,2.反編譯,其實,pyinstaller的原理:
把python解析器、腳本以及被打包腳本依賴的其他腳本(三方庫)和需要的windows dll文件等等 打包成一個可執行的文件,這個文件可以不依賴python環境直接在wondows機器上執行起來。

既然是打包起來的,第一步就需要把包拆開(解壓),看看裏邊具體是什麼,下載拆包工具:pyinstxtractor.py:https://sourceforge.net/projects/pyinstallerextractor/
然後執行拆包命令:

pyinstxtractor.py  test.exe

會得到一個文件夾 “可執行文件名稱test.exe_extracted”的文件夾


2 獲取pyc文件

在上述獲取到的文件夾中找到 “test” 文件,這個文件不能直接作爲pyc文件反編譯,這是因爲pyc文件以特定的頭字節(magic head,包含Python的版本號和時間戳),pyinstxtractor雖然反編譯出了test的文件的內容,但沒有給它加上pyc文件的頭字節,因此 需要先將缺失的字節補充回來,才能編譯成功。根據網上大神介紹,與“test”同目錄下的“struct”文件的頭字節是pyc文件的一種,將“test”的頭自己補充完成後,在重命名pyc文件,即可開始反編譯


以16進制的文件形式打開兩個文件,我用的是notepad++,裝了16進制查看文件的插件HEX-Editor,直接修改test,然後保存,重命名成pyc格式的文件


另外一個方法就是使用python對二進制文件處理,增加頭文件

structPath = 'struct'
programPath = 'test'
f=open(structPath, 'rb')#打開struct文件
f2=open(programPath, 'rb')#打開待反編文件
w_all=f2.read()#先讀取待反編文件原來的內容
f2.seek(0)#讀取完之後從頭開始
w=f.read(16).hex()#再讀取16個字節用於比較
w2=f2.read(16).hex()#struct也讀取16個用於比較
print(w,w2,sep='\n')#打印出來讓我們看見
add=input('Please input the codes you need to write:')#然後問你要在開頭寫入什麼
add=bytes.fromhex(add)#把普通字符串轉換爲bytes格式,並不是encode,而是fromhex(),把字符串看成是十六進制編碼
f2.close()#關閉
f2=open(programPath+'.pyc', 'wb')#創建pyc待反編文件
f2.write(add+w_all)#把加入的字節和原來的字節合併寫入文件
f.close()
f2.close()
print('Done.')

3 反編譯pyc文件

安裝uncompyle6,(有的文檔介紹說是uncompyle2,其實安裝的時候會默認安裝uncompyle6)

pip install uncompyle6

反編譯

uncompyle6 test.pyc > compyleTest.py

======================================================

4 複雜的腳本

現實情況中不會有這麼簡單的腳本,往往都是相互引用,按照上述步驟只是反編譯出來了入口exe,至於引用的其他編寫的文件中的代碼是看不到的,比如 getValue()這個是看不到源碼的,


此時去解壓的文件中test.exe_extracted中進入PYZ-00.pyz_extracted,這個裏邊全部是引用三方或者自己編寫代碼用到的庫文件,根據import找到需要編譯的pyc文件,再次反編譯得到另外想到的源碼文件,

但是 但是 請注意
雖然PYZ-00.pyz_extracted中的文件格式都是pyc文件,但是直接試用上述方法反編譯 會出現異常,導致異常的原因還是 pyc文件的頭信息,中的python版本不匹配當前機器安裝的python版本導致問題,因此修改pyc文件中頭信息(magic head)中的版本即可再次編譯。

獲取到編譯後的Helper.py文件


5 防止還原

綜上所述,編譯過的pyc二進制文件可以還原成py文件,那麼在不做處理的時候直接使用pyinstaller的時候py文件會被編譯成pyc文件存在pycache文件中,然後將自己編寫的pyc和引用到的三方庫pyc打包到exe中,

打包的過程繞過pyc,或者找其他的方式代替pyc,經過查找可以將py文件編譯爲動態鏈接庫,打包的時候使用動態鏈接庫,這樣破解難度將大大增加。其中,在python裏,pyd格式即動態鏈接庫,pyinstaller打包時 優先級pyd > py, pyd文件是由 Cython首先把python源碼翻譯成了 .c文件,這個過程基本不可逆,然後vs再把這個.c文件編譯成了pyd文件。所以 源碼失蹤了,只剩下彙編語言。

步驟如下

  1. 安裝cython: pip install Cython
    然後在工程中創建一個build_pyd.py 文件,目的是生成對應文件的pyd文件
from distutils.core import setup
from Cython.Build import cythonize

setup(
    name='any words.....',
    ext_modules=cythonize(["one.py", "two.py", ]),
)

觸發腳本執行,生成pyd

python build_pyd.py build_ext --inplace

生成的pyd在同級目錄的同名目錄下 如圖:

  1. 做完前期操作之後 開始打包,打包方式不變,除了程序的入口py文件可以被反編譯,其他自己開發的文件解壓之後都是pyd文件,兩種情況的對比


注意 注意 注意
出錯的一個點,自己的部分代碼/三方庫沒有打包進去
調整現有代碼結構,增加一個py文件 只作爲程序入口,同時這個文件中引入整個程序用到的三方庫,目的是打包的時候給三方庫打包進去。

下面圖片中 就是缺少 import了自己編寫的庫 ,把import加上,重新打包就可以了


參考:
https://www.vanfon.net/html/1499.html
https://www.jb51.net/article/184725.htm

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章