最近在 Reddit ReverseEngineering上,我偶然發現了Python中的自修改代碼。查看 Github存儲庫很有啟發性,我發現以CFG形式公開的Python字節碼程序的圖片:
我想知道是否有一些工具可以對Python字節碼程序執行靜態分析,這些程序具有一些不錯的功能(例如生成CFG或允許操縱代碼等)?
最近在 Reddit ReverseEngineering上,我偶然發現了Python中的自修改代碼。查看 Github存儲庫很有啟發性,我發現以CFG形式公開的Python字節碼程序的圖片:
我想知道是否有一些工具可以對Python字節碼程序執行靜態分析,這些程序具有一些不錯的功能(例如生成CFG或允許操縱代碼等)?
Maynard是Python字節碼的(反)彙編程序,由Python核心成員和Python 3.4的發布管理器編寫。在此處和此處閱讀材料。我不知道可以像這樣進行CFG可視化的公共工具(除了鏈接的工具之外),但是您當然可以在Maynard的基礎上構建一個工具。
有幾種專用於Python字節碼反轉的工具:
'uncompyle'將Python字節碼轉換回等效的Python源。它僅接受Python版本2.7中的字節碼。生成的源代碼可讀性很強:文檔字符串,列表,元組和哈希值打印得很漂亮。
“ uncompyle”還可以通過編譯並比較兩個字節碼來驗證生成的源的等效性。 “ uncompyle”基於John Aycock的通用小語言編譯器“ spark”和他先前對“ decompyle”的研究。
pyREtic,比簡單的程序更強大的框架
pyREtic是可擴展的框架,可幫助執行Python語言項目的各種逆向工程任務。它幫助一個逆向工程師在獲得源代碼(的.py的)從字節碼(.pyc文件的)回來了,特別是當被逆轉的代碼已經把一些精力投入到使用標準工具包試圖阻止反編譯它有助於。
pycdc,它比uncompyle更好,並且比pyRetic更易於使用
Decompyle ++旨在翻譯編譯的Python字節碼重新轉換為有效且人類可讀的Python源代碼。儘管其他項目也取得了不同程度的成功,但Decompyle ++的獨特之處在於它尋求支持任何版本的Python的字節碼。
Decompyle ++包括字節碼反彙編程序(pycdas)和反編譯器( pycdc)。
Manyard框架,專用於Python3
pyREtic也可以為查找原始源代碼和執行修改提供一些幫助。
您可能會對本文檔中該工具的功能感興趣:“ pyREtic,用於混淆Python字節碼的內存反向工程” 史密斯[PDF]
編寫提取python字節碼控制流的工具時遇到的一個挑戰是,到目前為止有大約25個左右的Python字節碼版本可供選擇(如果您包含pypy變體)。
示例圖中的字節碼及其 JUMP_IF_FALSE
後跟一些 POP_TOP
和 PRINT_NEWLINE
指令,反映了2.7之前的Python。
但是,來自Flare_bytecode_graph的註釋之一及其 POP_TOP_IF_FALSE
的示例示例為2.7。 Python 3刪除了 PRINT_ITEM
指令。
任何編寫此類工具的人都必須牢記這一點。或對使用單一版本的Python感到滿意,對於它,2.7可能是最受歡迎的選擇。或者,您可以確保正在運行的Python版本與要分析的字節碼匹配,並使用Python提供的當前 dis 和 opcode 模塊。但是,即使在這裡,那些模塊也會隨著時間而改變,至少不是特定的字節碼指令。
我為那些想要在所有版本的Mac上工作的人編寫了一個名為 xdis的python包。 Python字節碼,並且不想使用字節碼所需的相同版本的Python。
在此過程中,您可能要做的下一件事是將指令分類像那些可以分支的分支和那些不能分支的分支,以及分支是否是有條件的。
Python的一些列表涵蓋了其中的某些部分(“ hasjrel”,“ hasjabs”),但是可惜它沒有最有用的類別。出於歷史原因,類別是列表而不是集合。但是再次xdis在這裡進行救援;它使用“ CONDITION_OPS”,“ JUMP_UNCONDITIONAL”和“ JUMP_OPS”集填充此信息。
使用此代碼,我編寫了 https://github.com/rocky/python-control-flow,該代碼使用xdis並具有一些基本代碼,這些代碼將為大多數Python字節碼。有一些代碼可以創建點文件,我使用graphviz進行顯示。我注意到Python可以創建很多無效代碼。
該軟件包的預期用途是重建高級Python控制結構。有一些基本的控制結構檢測,儘管這需要做很多工作。當您包含try / while / for“ else”子句和“ finally”子句時,Python控件結構非常豐富。即使如此,基本塊的帶註釋的控制流對於手動重建結構化控制流也非常有幫助。
完成後,我可以用 lot 替換hacky代碼在 uncompyle6中執行此操作。
這使我進入了公認的答案中提到的反編譯器列表...
如上所述,uncompyle和uncompyle2的那些特定版本僅處理Python 2.7。如建議的那樣,有一些舊版本可以處理多個Python版本1.5至2.3或2.4左右。那就是如果您有Python 2.3或2.4解釋器可以在其上運行。
但是這些項目都沒有得到積極維護。在uncompyle中,目前有 25個左右的代碼問題,我已經在uncompyle6中解決了許多問題。這是用於不再更改的Python版本! (為公平起見,儘管uncompyle6中有一些bug在uncompyle2中不存在。要解決這些問題,我真的需要進行更好的控制流分析)
許多只需執行與uncompyle6相同的操作即可輕鬆解決uncompyle中的錯誤,我想我已經在問題中提到了其中的一些。在這一點上,uncompyle2比uncompyle更好,並且,如果您僅對Python 2.7感興趣,那將是最準確的。
對於pycdc而言,儘管它的體積相對較小(與uncompyle6相比)相當不錯,但也無法保持與Python更改保持同步的水平。因此它在Python 3.4左右的版本中較弱,而在以後的版本中逐漸變得較弱。 Uncompyle6也是如此,但目前還不是。 pycdc記錄了60多個問題,我懷疑很快就會解決這些問題。其中有些並不是 難以修復的。我對這兩個反編譯器的比較(可能是傾斜的)是 https://github.com/rocky/python-uncompyle6/wiki/pycdc-compared-with-uncompyle6
火炬字節碼圖項目可以幫助圖形化字節碼CFG表示。從項目 README
中獲取:
...
也可以使用GraphViz創建控制流程圖。圖中的反彙編可以包括一個簡單的窺孔反編譯器的輸出。import bytecode_graphdef Sample():如果i == 4,則i = 2 + 2:打印“ 2 + 2 =%d “%i else:print” oops“ bcg = bytecode_graph.BytecodeGraph(Sample .__ code __)graph = bytecode_graph.Render(bcg,Sample .__ code __)。dot()graph.write_png('example_graph.png')