摘要:打包成單文件所使用的命令為打包成文件夾所使用的命令為不管是哪種打包方式都會(huì)留下一個(gè)文件。這樣我們只需將腳本文件和腳本文件放置到同一文件夾下,運(yùn)行我們的腳本??梢钥吹揭呀?jīng)完美的反編譯出其中的腳本好了,相信大家已經(jīng)明白了反編譯的原理。
近期閱讀了一篇很感興趣的文章,為免后續(xù)文章被刪無(wú)法再閱讀,現(xiàn)自己寫(xiě)一下哈~
原文章:爆強(qiáng)!將 exe 文件反編譯成 Python 腳本!
這篇文章跟自己的另一篇文章,正好形成技術(shù)上的互逆過(guò)程,也同時(shí)歡迎閱讀指正
————————————————————————————————————————————————————————————
最近遇到了一個(gè)問(wèn)題,自己打包好的exe文件還在,但是Python源文件不知什么時(shí)候被誤刪了?,F(xiàn)在想改動(dòng)一下功能,重寫(xiě)Python腳本工程量也太大了,怎么辦?
今天我將教大家如何反編譯exe文件,即將自己或別人寫(xiě)好的exe,還原成Python源碼。
以最近寫(xiě)Python一鍵自動(dòng)整理歸類(lèi)文件為例進(jìn)行演示,運(yùn)行所需的代碼和文件都會(huì)在文末提供給大家。
打包成單文件所使用的命令為:
pyinstaller?-Fw?--icon=h.ico?auto_organize_gui.py?--add-data="h.ico;/"
打包成文件夾所使用的命令為:
pyinstaller?-w?--icon=h.ico?auto_organize_gui.py?--add-data="h.ico;."
不管是哪種打包方式都會(huì)留下一個(gè)exe文件。
首先我們需要從exe文件中抽取出其中的pyc文件:
抽取pyinstaller打包的exe中的pyc文件,提取pyc文件有兩種方法:
通過(guò) pyinstxtractor.py 腳本提取pyc文件
通過(guò) pyi-archive_viewer 工具提取pyc文件
pyinstxtractor.py 腳本可以在github項(xiàng)目 python-exe-unpacker 中下載,地址:
https://github.com/countercept/Python-exe-unpacker
下載該項(xiàng)目后把其中的pyinstxtractor.py
腳本文件復(fù)制到與exe同級(jí)的目錄。
然后進(jìn)入exe所在目錄的cmd執(zhí)行:
Python?pyinstxtractor.py?auto_organize_gui.exe
執(zhí)行后便得到exe文件名加上_extracted
后綴的文件夾:
對(duì)兩種打包方式產(chǎn)生的exe提取出的文件結(jié)構(gòu)稍有區(qū)別:
pyi-archive_viewer是PyInstaller自己提供的工具,它可以直接提取打包結(jié)果exe中的pyc文件。
詳細(xì)介紹可參考官方文檔:ttps://pyinstaller.readthedocs.io/en/stable/advanced-topics.html#using-pyi-archive-viewer
執(zhí)行pyi-archive_viewer [filename]
即可查看 exe 內(nèi)部的文件結(jié)構(gòu):
pyi-archive_viewer?auto_organize.exe
操作命令:
U:?go?Up?one?levelO?:?open?embedded?archive?nameX?:?extract?nameQ:?quit
然后可以提取出指定需要提取的文件:
要提取其他被導(dǎo)入的pyc文件,則需要先打開(kāi)PYZ-00.pyz
:
很顯然,使用PyInstaller的pyi-archive_viewer 工具操作起來(lái)比較麻煩,一次只能提取一個(gè)文件,遇到子模塊還需執(zhí)行一次打開(kāi)操作。
所以后面我也只使用pyinstxtractor.py 腳本來(lái)提取pyc文件。
有很多對(duì)pyc文件進(jìn)行解密的網(wǎng)站,例如:
https://tool.lu/pyc/
不過(guò)我們直接使用?uncompyle6
?庫(kù)進(jìn)行解碼,使用pip可以直接安裝:
pip?install?uncompyle6
uncompyle6可以反編譯.pyc后綴結(jié)尾的文件,兩種命令形式:
uncompyle6 xxx.pyc>xxx.py
uncompyle6 -o xxx.py xxx.pyc
以前面編碼過(guò)程中生成的緩存為例進(jìn)行演示:
uncompyle6?auto_organize.cpython-37.pyc>auto_organize.py
執(zhí)行后便直接將.pyc文件反編譯成Python腳本了:
從編譯結(jié)果看注釋也被保留了下來(lái):
對(duì)于不是pyc后綴結(jié)尾的文件,使用uncompyle6反編譯時(shí)會(huì)報(bào)出?must point to a Python source that can be compiled, or Python bytecode (.pyc, .pyo)?的錯(cuò)誤。
所以我們需要先對(duì)提取出的內(nèi)容人工修改后綴:
對(duì)于從pyinstaller提取出來(lái)的pyc文件并不能直接反編譯,入口運(yùn)行類(lèi)共16字節(jié)的?magic
?和?時(shí)間戳
被去掉了。
如果直接進(jìn)行反編譯,例如執(zhí)行?uncompyle6 auto_organize_gui.exe_extracted/auto_organize_gui.pyc
會(huì)報(bào)出如下錯(cuò)誤:ImportError: Unknown magic number 227 in auto_organize_gui.exe_extracted/auto_organize_gui.pyc
使用支持16進(jìn)制編輯的文本編輯器查看一探究竟,這里我使用UltraEdit32
:
分別打開(kāi)正常情況下編譯出的pyc和從pyinstaller提取出來(lái)的pyc文件進(jìn)行對(duì)比:
可以看到前16個(gè)字節(jié)都被去掉了,其中前四個(gè)字節(jié)是magic
,這四個(gè)字節(jié)會(huì)隨著系統(tǒng)和Python版本發(fā)生變化,必須一致。后四個(gè)字節(jié)包括時(shí)間戳和一些其他的信息,都可以隨意填寫(xiě)。
我們先通過(guò)UltraEdit32
向pyinstaller提取的文件添加頭信息:
選擇開(kāi)頭插入16個(gè)字節(jié)后,只需要替換前4個(gè)字節(jié)為當(dāng)前環(huán)境下的magic:
然后執(zhí)行:
uncompyle6?auto_organize_gui.exe_extracted/auto_organize_gui.pyc>auto_organize_gui.py
執(zhí)行后可以看到文件已經(jīng)順利的被反編譯:
考慮再反編譯導(dǎo)入的其他依賴(lài)文件:
先用UltraEdit32
打開(kāi)查看一下:
可以看到對(duì)于非入口運(yùn)行的pyc文件是從12字節(jié)開(kāi)始缺4個(gè)字節(jié)。
這里我們選擇第13個(gè)字節(jié)再插入四個(gè)字節(jié)即可:
然后再執(zhí)行:
uncompyle6?auto_organize_gui.exe_extracted/PYZ-00.pyz_extracted/auto_organize.pyc?>?auto_organize.py
然后成功的反編譯出依賴(lài)的文件:
代碼與原文件幾乎完全一致:
如果一個(gè)exe需要被反編譯的Python腳本只有3個(gè)以?xún)?nèi)的文件,我們都完全可以人工來(lái)操作。
但是假如一個(gè)exe涉及幾十個(gè)甚至上百個(gè)Python腳本需要反編譯的時(shí)候,人工操作未免工作量過(guò)于巨大,我們考慮將以上過(guò)程用Python實(shí)現(xiàn),從而達(dá)到批量反編譯的效果。
import?osimport?sysimport?pyinstxtractorexe_file?=?r"D:/PycharmProjects/gui_project/dist/auto_organize_gui.exe"sys.argv?=?["pyinstxtractor",?exe_file]pyinstxtractor.main()#?恢復(fù)當(dāng)前目錄位置os.chdir("..")
[*]?Processing?D:/PycharmProjects/gui_project/dist/auto_organize_gui.exe[*]?Pyinstaller?version:?2.1+[*]?Python?version:?37[*]?Length?of?package:?9491710?bytes[*]?Found?984?files?in?CArchive[*]?Beginning?extraction...please?standby[*]?Found?157?files?in?PYZ?archive[*]?Successfully?extracted?pyinstaller?archive:?D:/PycharmProjects/gui_project/dist/auto_organize_gui.exeYou?can?now?use?a?Python?decompiler?on?the?pyc?files?within?the?extracted?directory
def?find_main(pyc_dir):????for?pyc_file?in?os.listdir(pyc_dir):????????if?not?pyc_file.startswith("pyi-")?and?pyc_file.endswith("manifest"):????????????main_file?=?pyc_file.replace(".exe.manifest",?"")????????????result?=?f"{pyc_dir}/{main_file}"????????????if?os.path.exists(result):????????????????return?main_filepyc_dir?=?os.path.basename(exe_file)+"_extracted"main_file?=?find_main(pyc_dir)main_file
讀取從pyz目錄抽取的pyc文件的前4個(gè)字節(jié)作基準(zhǔn):
pyz_dir?=?f"{pyc_dir}/PYZ-00.pyz_extracted"for?pyc_file?in?os.listdir(pyz_dir):????if?pyc_file.endswith(".pyc"):????????file?=?f"{pyz_dir}/{pyc_file}"????????breakwith?open(file,?"rb")?as?f:????head?=?f.read(4)list(map(hex,?head))
["0x42",?"0xd",?"0xd",?"0xa"]
校準(zhǔn)入口類(lèi):
import?shutilif?os.path.exists("pycfile_tmp"):????shutil.rmtree("pycfile_tmp")os.mkdir("pycfile_tmp")main_file_result?=?f"pycfile_tmp/{main_file}.pyc"with?open(f"{pyc_dir}/{main_file}",?"rb")?as?read,?open(main_file_result,?"wb")?as?write:????write.write(head)????write.write(b"/0"*12)????write.write(read.read())
校準(zhǔn)子類(lèi):
pyz_dir?=?f"{pyc_dir}/PYZ-00.pyz_extracted"for?pyc_file?in?os.listdir(pyz_dir):????pyc_file_src?=?f"{pyz_dir}/{pyc_file}"????pyc_file_dest?=?f"pycfile_tmp/{pyc_file}"????print(pyc_file_src,?pyc_file_dest)????with?open(pyc_file_src,?"rb")?as?read,?open(pyc_file_dest,?"wb")?as?write:????????write.write(read.read(12))????????write.write(b"/0"*4)????????write.write(read.read())
from?uncompyle6.bin?import?uncompileif?not?os.path.exists("py_result"):????os.mkdir("py_result")for?pyc_file?in?os.listdir("pycfile_tmp"):????sys.argv?=?["uncompyle6",?"-o",????????????????f"py_result/{pyc_file[:-1]}",?f"pycfile_tmp/{pyc_file}"]????uncompile.main_bin()
完整代碼下載見(jiàn)文末。
這樣我們只需將Python腳本、exe文件和pyinstxtractor.py
腳本文件 放置到同一文件夾下,運(yùn)行我們的Python腳本。即可反編譯exe。
可以看到已經(jīng)完美的反編譯出exe其中的Python腳本:
好了,相信大家已經(jīng)明白了反編譯的原理。那么既然是攻防,如何防止自己打包的exe被反編譯呢?
只需在打包命令后面加上--key
命令即可,例如文章開(kāi)頭的命令可以更換為:
pyinstaller?-Fw?--icon=h.ico?auto_organize_gui.py?--add-data="h.ico;/"?--key?123456
123456
是你用來(lái)加密的密鑰,可以隨意更換。
該加密參數(shù)依賴(lài)tinyaes,可以通過(guò)以下命令安裝:
pip?install?tinyaes
打包后再次執(zhí)行反編譯:
exe_file?=?r"D:/PycharmProjects/gui_project/dist/auto_organize_gui.exe"uncompyle_exe(exe_file,?True)
結(jié)果只有入口腳本反編譯成功,被依賴(lài)的腳本均被加密,無(wú)法直接被反編譯:
可以看到抽取的中間結(jié)果變成了.pyc.encrypted
格式,無(wú)法直接被反編譯:
可以看到,常規(guī)手段就無(wú)法直接反編譯了。
這個(gè)時(shí)候還想反編譯就需要底層的逆向分析研究了,或者pyinstaller的源碼完整研究一遍,了解其加密處理的機(jī)制,看看有沒(méi)有破解的可能。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/122199.html
摘要:最好是客戶(hù)雙擊,完事兒。目前已經(jīng)兼容,以及和。一共會(huì)有個(gè)對(duì)象,分別是。,就是我們的工作目錄,存放我們的數(shù)據(jù)。編譯打包最后,我們執(zhí)行就好了。打包的可執(zhí)行文件會(huì)在里,中是一些打包時(shí)候需要的文件。輸出中最后有字樣,就算成功了。 showImg(https://img-blog.csdnimg.cn/20190303211533768.png?x-oss-process=image/water...
摘要:但是由于程序并沒(méi)有那么快,開(kāi)發(fā)人員多年來(lái)創(chuàng)建了幾個(gè)的編譯器,包括和。在下面的細(xì)分中,所有的編譯器都針對(duì)進(jìn)行基準(zhǔn)測(cè)試。編譯器是系列的一部分,旨在作為的現(xiàn)代替代品。不僅僅是的編譯器,它是的超集,支持與的互操作性。 簡(jiǎn)評(píng):Python 和其他的解釋型語(yǔ)言一樣經(jīng)常被吐槽性能不行,所以開(kāi)發(fā)人員為了提升性能創(chuàng)建了不少編譯器,本文則選取其中的四個(gè)做了基準(zhǔn)測(cè)試。 Python 其實(shí)是一種相當(dāng)快的語(yǔ)言,...
摘要:總所周知,因庫(kù)多,語(yǔ)法優(yōu)雅,深受開(kāi)發(fā)者的喜愛(ài)。于我來(lái)說(shuō),寫(xiě)一些小型程序,在不需要考慮太多問(wèn)題的時(shí)候,無(wú)疑是我的第一選擇。當(dāng)一切都配置好后,使用打包相應(yīng)腳本有兩種方法。 總所周知,python因庫(kù)多,語(yǔ)法優(yōu)雅,深受開(kāi)發(fā)者的喜愛(ài)。 于我來(lái)說(shuō),寫(xiě)一些小型程序,在不需要考慮太多問(wèn)題的時(shí)候,python無(wú)疑是我的第一選擇。而有的時(shí)候,雖然是小型程序,但我還是需要他們通用,即使不考慮使他跨平臺(tái)...
摘要:很想一窺源碼,查看究竟,看看大廠的前端大神們是如何規(guī)避了小程序的各種奇葩的坑。頭發(fā)減減可是問(wèn)題是吶好看的小程序,又獲得不到源代碼。所以啊,才能容易的反編譯出來(lái),如果是那就很難了一鍵獲取微信小程序源代碼 ? 1 Tips: 2 一鍵獲取微信小程序源碼, 使用了C#加nodejs制作 直接解壓在D盤(pán)根目錄下后就可以使用 將小程序文件放到 wxapkg目錄下3 這個(gè)目錄下有一些demo...
閱讀 1275·2021-10-11 10:59
閱讀 2026·2021-09-29 09:44
閱讀 944·2021-09-01 10:32
閱讀 1491·2019-08-30 14:21
閱讀 1928·2019-08-29 15:39
閱讀 3034·2019-08-29 13:45
閱讀 3598·2019-08-29 13:27
閱讀 2068·2019-08-29 12:27