Python逆向(三)—— Python編譯運行及反匯編


一、前言

前期我們已經對python的運行原理以及運行過程中產生的文件結構有了了解。本節,我們將結合具體的例子來實踐python運行,編譯,反編譯的過程,並對前些章節中可能遺漏的具體細節進行補充。

二、Python編譯

python在正常運行時,有時編譯生成pyc文件,有時候沒有pyc文件的生成。那么我們能不能手動將python程序編譯成pyc文件呢?答案是可以的,不但可以編譯,還可以直接運行pyc文件以實現程序運行的效率。

2.1、pyc文件的生成

命令行模式

python -m py_compile file.py  # 生成單個pyc文件
python -m py_compile /dir/{file1,file2}.py  # 生成多個pyc文件
python -m compileall /dir/  # 生成目錄下所有py文件對應的pyc文件

交互shell模式

>>> import py_compile  # 相當於命令行中的“-m py_compile”
>>> py_compile.compile('py file path')
>>> import compileall
>>> compileall.compile_dir("py files dir")

2.2、pyo文件生成

pyo文件是源代碼文件經過優化編譯后生成的文件,是pyc文件的優化版本。編譯時需要使用-O和-OO選項來生成pyo文件。在Python3.5之后,不再使用.pyo文件名,而是生成文件名類似“test.opt-n.pyc的文件。

python -O -m py_compile file.py
python -O -m py_compile /dir/{file1,file2}.py
python -O -m compileall /dir/

2.3、直接運行編譯好的pyc或者pyo文件

三、字節碼文件反編譯

經過編譯的python文件可以提高程序的運行速度,一定程度上也對源代碼起到了保護作用。然而如果我們只有編譯過的python字節碼文件,就給我們審查源碼造成了一定的困難,這就引出了python字節碼反編譯的需求。

上一節我們介紹過pyc文件的結構,其實就是pyc文件頭部加上PyCodeObject對象。文件頭部的信息在python2中只占用固定8字節,用來攜帶一些版本類的信息,不是我們做反編譯的重點,因此通過提取8字節之后的部門做反編譯處理就可以了。

PyCodeObjectData就是我們需要提取的數據,根據python的編譯原理我們知道PyCodeObjectData是python源文件作為一個實例化的類,通過python內置庫函數marshal.dumps生成的二進制數據段,因此通過marshal.loads(PyCodeObjectData) ,我們可以得到PyCodeObjectData反序列化的對象。

可以看到PyObj對象包含了很多內置方法和屬性,這些屬性在第二節中我們已經有過介紹,各個字段的含義都已經知道了。通過對這些方法的引用可以直接看到相關字段反序列后的具體值。

使用python內置模塊dis可以對PyCodeObject進行反編譯,從而獲取到python二進制字節碼代碼段的“匯編形式”。這樣可以便於對字節碼進行閱讀。dis模塊也可以單獨對PyCodeObject中的co_data模塊進行反編譯,但是這樣得到的是單純的代碼段字節碼,缺少很多代碼段中涉及的變量名字。如上圖所示。

四、結語

本節我們對python源碼編譯生成字節碼文件和從字節碼文件反編譯生成字節碼代碼段(python的匯編形式)進行介紹。下一章節我們將對dis模塊的源碼進行解讀,以便於后續章節關於python代碼混淆技術的涉及。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM