內容
原生Python跨版本反編譯器和片段反編譯器。 decompyle、uncompyle 和 uncompyle2 的後繼者。
uncompyle6將 Python 字節碼轉換回等效的 Python 原始碼。它接受從 Python 版本 1.0 到版本 3.8 的字節碼,涵蓋了超過 24 年的 Python 版本。我們包含 Dropbox 的 Python 2.5 字節碼和一些 PyPy 字節碼。
好吧,我會說:這個軟體太棒了。它不僅僅是普通的 hacky 反編譯器。使用編譯器技術,程式根據指令創建程式的解析樹;上層的節點看起來有點像是 Python AST 的節點。因此我們可以真正分類並理解 Python 字節碼各部分中發生的情況。
在此基礎上,與其他 CPython 字節碼反編譯器不同的另一件事是能夠僅解析原始程式碼片段並提供給定字節碼偏移量周圍的源代碼資訊。
我使用樹片段在運行時在我的 Trepan 調試器中解析程式碼片段。為此,字節碼偏移量被記錄並與原始程式碼片段相關聯。這個目的雖然符合初衷,但還是有些不同。請參閱此以了解更多資訊。
給定指令偏移量的 Python 片段解析對於顯示堆疊追蹤很有用,並且可以合併到任何想要在運行時更詳細地顯示位置而不僅僅是行號的程式中。當原始碼資訊不存在且只有字節碼時也可以使用此程式碼。我的調試器再次利用了這一點。
曾經(現在仍然)有許多 decompyle、uncompyle、uncompyle2、uncompyle3 分支。其中許多基本上來自相同的程式碼庫,並且(幾乎?)所有這些都不再被積極維護。其中一個非常擅長反編譯 Python 1.5-2.3,另一個非常擅長反編譯 Python 2.7,但僅此而已。另一個只處理 Python 3.2;另一個修補了該問題並僅處理 3.3。你明白了。這段程式碼將所有這些分叉拉到一起並向前推進。與那些舊分支相比,此程式碼庫中進行了一些認真的重構和清理。 decompyle3 中正在進行更多的實驗性重構。
這顯然在所有 Python 版本中反編譯 Python 方面表現最佳。即使有另一個專案只提供 Python 版本子集的反編譯,我們通常也會對這些版本做得更好。
我們怎麼知道?透過取得隨該版本的 Python 分發的 Python 字節碼並反編譯它們。在成功反編譯的程式中,我們可以透過執行該字節碼版本的 Python 解譯器來確保產生的程式在語法上正確。最後,如果程式本身有測試,我們可以對反編譯的程式碼進行檢查。
我們使用自動化流程來找出錯誤。在其他反編譯器的問題追蹤器中,您會發現我們一路上發現的許多錯誤。其他反編譯器中修復的問題很少甚至沒有。
git 儲存庫中的程式碼可以從 Python 2.4 到最新的 Python 版本運行,但 Python 3.0 到 3.2 除外。如果有意願的話,歡迎志工來解決這些缺陷。
它的實作方式是將連續的 Python 版本分離到 git 分支:
PyPy 3-2.4 及更高版本也可以運作。
它可以讀取的字節碼檔案已經在 1.4、2.1-2.7 和 3.0-3.8 以及更高版本的 PyPy 版本的 Python 字節碼上進行了測試。
您可以使用名稱uncompyle6
從 PyPI 安裝:
pip 安裝 uncompyle6
為了從原始碼安裝,該專案使用 setup.py,因此它遵循標準的 Python 例程:
$ pip install -e 。 # 設定從原始碼樹運行
或者:
$ python setup.py install # 可能需要 sudo
也提供了 GNU Makefile,因此make install
(可能以 root 或 sudo 身分)將執行上述步驟。
進行檢查
新增了 GNU makefile,以平滑設定運行正確的命令,並從最快到最慢運行測試。
如果您安裝了 remake,您可以透過remake --tasks
查看所有任務的列表,包括測試
跑步
$ uncompyle6 *編譯的python檔-pyc-or-pyo*
如需使用協助:
$ uncompyle6 -h
在舊版的 Python 中,可以透過反編譯字節碼,然後使用該字節碼版本的 Python 解釋器進行編譯來驗證字節碼。完成此操作後,可以將產生的字節碼與原始字節碼進行比較。然而,隨著 Python 的程式碼產生變得更好,這不再可行。
如果你想對反編譯過程的正確性進行Python語法驗證,請加入--syntax-verify
選項。然而,由於 Python 語法發生了變化,如果字節碼對於將檢查語法的 Python 解釋器來說是正確的字節碼,則應該使用此選項。
您也可以將結果與uncompyle6的另一個版本進行交叉比較,因為隨著整體品質的提高,反編譯特定字節碼有時會出現回歸。
對於Python 3.7和3.8,decompyle3中的程式碼通常會更好。
或嘗試特定的另一個 python 反編譯器,如 uncompyle2、unpyc37 或 pycdc。由於後兩者的工作方式不同,因此這裡的錯誤通常不在其中,反之亦然。
其中有一類有趣的程式可以隨時提供更強的驗證:那些在運行時測試自身的程式。我們的測試套件包括這些。
Python 也附帶了另一組這樣的程式:它的標準函式庫測試套件。我們在test/stdlib
中有一些程式碼也可以促進這種檢查。
最大的已知且可能可修復(但很難)的問題與處理控制流程有關。 (Python 可能是我見過的最多樣化、最複雜的複合語句;循環和 try 區塊上有「else」子句,我懷疑許多程式設計師都不知道。)
我見過的所有 Python 反編譯器在反編譯 Python 的控制流程時都存在問題。在某些情況下,我們可以偵測到錯誤的反編譯並報告該錯誤。
Python 對 Python 2 的支援非常好
在 Python 版本的低端,反編譯似乎相當不錯,儘管我們沒有針對 Python 的分散式測試進行任何自動化測試。另外,我們沒有 1.6 和 2.0 版本的 Python 解譯器。
在 Python 3 系列中,Python 支援在 3.4 或 3.3 左右最強,並且隨著遠離這些版本而逐漸減弱。 Python 3.0 很奇怪,因為它在某些方面比 3.1 或 2.7 更類似於 2.6。 Python 3.6 透過使用字碼而不是字節程式碼來徹底改變事情。因此,跳轉指令參數中的跳躍偏移欄位已減少。這使得EXTENDED_ARG
指令現在在跳轉指令中更普遍;以前它們很少見。也許為了補償額外的EXTENDED_ARG
指令,增加了額外的跳轉優化。因此總而言之,透過臨時手段處理控制流程(如目前所做的那樣)更糟。
在 Python 3.5、3.6、3.7 之間, MAKE_FUNCTION
和CALL_FUNCTION
指令發生了重大變化。
Python 3.8 刪除了SETUP_LOOP
、 SETUP_EXCEPT
、 BREAK_LOOP
和CONTINUE_LOOP
指令,這些指令可能會使控制流偵測變得更加困難,缺乏計畫中的更複雜的控制流分析。我們拭目以待。
目前,並非所有 Python 幻數都支援。特別是在 Python 的某些版本中,特別是 Python 3.6,幻數在一個版本內發生了多次變化。
我們僅支援已發布版本,而不支援候選版本。但請注意,發布版本的魔力通常與發布前的最後一個候選版本相同。
還有客製化的 Python 解釋器,特別是 Dropbox,它們使用自己的魔法並加密字節碼。除了 Dropbox 的舊 Python 2.5 解譯器之外,這類事情不被處理。
我們也不處理 PJOrion 或其他混淆的程式碼。對於 PJOrion,請嘗試使用 PJOrion Deobfuscator 在嘗試此工具之前對字節碼進行解密以獲得有效的字節碼; pydecipher 可能對此有所幫助。
該程式無法反編譯 Py2EXE 創建的 Microsoft Windows EXE 文件,儘管在正確提取字節碼後我們可能可以反編譯程式碼。 Pydeinstaller 可能有助於解壓縮 Pyinstaller 捆綁程式。
處理病態的長表達式或語句列表的速度很慢。我們不處理不使用字節碼的 Cython 或 MicroPython。
反編譯有很多bug。對於我遇到的所有其他 CPython 反編譯器來說都是如此,甚至是那些聲稱在某些特定版本(如 2.4)上「完美」的反編譯器。
隨著 Python 的進步,反編譯也變得越來越困難,因為編譯變得更加複雜,語言本身也變得更加複雜。我懷疑像 unpyc37(基於 3.3 反編譯器)這樣的臨時嘗試會更少,因為這樣做更困難。至少從我的角度來看,好消息是我認為我了解以更強有力的方式解決問題需要什麼。但現在,直到專案得到更好的資助時,我不打算做出任何認真的努力來支援 Python 版本 3.8 或 3.9,包括可能出現的錯誤。
透過針對 Python 用於檢查自身的標準測試套件執行測試,您可以輕鬆找到錯誤。在任何給定時間,都有數十個已知問題被很好地隔離,如果人們花時間這樣做,這些問題就可以解決。問題是沒有那麼多人致力於修復錯誤。
3.7 和 3.8 中的一些錯誤只是向後移植decompyle3中的修復程序的問題。有志工嗎?
您可能會遇到想要報告的錯誤。請閱讀如何報告錯誤後執行此操作,並在開啟問題時按照說明進行操作。
請注意,它可能暫時不會引起我的注意。如果您以某種方式贊助或支持該項目,我將優先考慮您的問題,而不是我可能正在做的其他事情。在極少數情況下,我可以付費手動反編譯字節碼。然而,這是一個巨大的支出,通常超出了大多數人願意花的錢。
uncompyle6
decompyle3
-- BlackHat 2024 Asia(影片)。非常感謝主辦單位和審稿人讓我發言。這種事情鼓勵我從事這樣的計畫。uncompyle6
結果不正確,而uncompyle2
結果不正確,但更常見的是,uncompyle6 正確,而 uncompyle2 不正確。由於uncompyle6
比慣用的 Python 更注重準確性,因此uncompyle2
在正確時可以產生看起來更自然的程式碼。目前uncompyle2
維護得很少。有關更多詳細信息,請參閱其問題追蹤器。