2016年11月24日 星期四

Python 反編譯第一次就上手 ~ Pyinstaller reverse engineer

觀念要先釐清

  • Disassembler
    • A disassembler is a software tool which transforms machine code into a human readable mnemonic representation called assembly language.
  • Decompiler
    • Software used to revert the process of compilation. Decompiler takes a binary program file as input and output the same program expressed in a structured higher-level language.


這裡就不說明 python 的編譯、執行方法
可以上網找找 pyc, pyo 的資料,他們說明的都比我清楚

一、開始囉

Python 的反編譯方法相當地簡單,網路上可以找到很多現成的工具
它們可以把編譯好的 pyc, pyo,還原為原始碼 py

Pyinstaller 可以將 pyc 打包成一個可執行檔,也可以增加了一些反編譯的難度
下圖是我用 7z 打開在 linux 使用 Pyinstaller 包好的執行檔的樣子…


在 linux 跑執行檔時,它會將打包的檔案解開放到 _MEIxxxxxx 的暫存資料夾
然後再進行執行,故會多出解壓縮的時間




如果你認為這樣就已經把執行檔解開了,那就太天真了
我們是RD,一定要用聰明一點的方法

二、利用 archive_viewer.py

Pyinstaller 有提供方便的作法,讓我們大家節省了很多時間
記得要下載新的版本,不然 archive_viewer.py 程式可能就會說版本不支援

既然是使用 Pyinstaller 打包程式,那麼使用它所提供的 Tools 當然是得心應手
我沒有用它去打開像是 py2exe 打包的執行檔,不知道能不能通用 (但我想是不行)

操作上不難,直接打指令
# help
python archive_viewer.py

# view
python archive_viewer.py pyi_archive


上圖利用 archive_viewer.py 成功打開了執行檔
有 4 個指令可以使用
U : 回到上一層
O : 打開 archive file,屬性為 'z'。像是 out00-PYZ.pyz 就是 python 壓縮檔
X : 解開,可以選擇直接顯示在螢幕上,或是輸出為一個檔案
Q : 離開

引用的 package 都會放在 out00-PYZ.pyz 裡頭,下 O 打開看看


我以 Python 內建的 package 'string' 做後面的測試
先直接顯示在螢幕上


輸出為一個檔案,命名為 string_extract.pyc

果然是 Python standard,註解寫得很詳細
如果是打開我自已寫的pyc,就會是一堆亂碼了 XD

三、利用 Easy Python Decompiler

我們已經得到 pyc 檔案了,那麼接下來要做的事情就直接反編譯 pyc


欸,怎麼不行,你這騙子!

呵呵,magic value 不正確
不知道什麼原因,pyinstaller包成執行檔之後,magic value就不見了
如果有人知道原因,請告訢我

py 編成 pyc 時,會在文件開頭加上 magic value,包含

  • A magic number (four bytes)
  • A timestamp (four bytes)
  • A code object (marshalled code)

magic number 就是編譯時 python 的版本。可以用查表的方法
timestamp 為編譯時的時間
marshalled …我還真的不知道,請其它大大補充
主要功能是可以確認 Python 版本是否相同、有沒有必要重新編譯等等(不過好像也沒其它的了)

詳細說明可以參考 中文 的,或是 英文
PS. Python3 magic value 長度似乎多了 tag (4 byte maybe)

Python 2 no attribute 'get_tag'

Python 3 tag is 'cpython-34'

原本我是用 archive_viewer.py 去看裡頭使用了哪一版的 python,然後就用查表的方式去找 magic number
後來有發現簡單的方式 (但不保證百分之百、一定沒問題)

像這一包是用 python 2.7,那可以查表了
另一種方式是利用 archive_viewer.py 顯示前幾包的內容,開頭的 4 bytes 就是 magic number
'03 F3 0D 0A'


下面這包是用 python 3.4,一樣可以查表
或是利用 archive_viewer.py 顯示前幾包的內容,開頭的 4 bytes 就是 magic number
'EE 0C 0D 0A'


我們回到一開始 string_extract.pyc
插入 magic value 後,再反編譯



這次就成功了!



最後一部份
依照前面的步驟,不過這次是從 python 3 的執行檔中取出 python standard 'string'
特別注意的是,要用 python3 跑 archive_viewer.py,不然解 python 3 的檔案會失敗


加上 magic value,不同於 python 2 的長度,多了 4 bytes


上工具


成功畫面~



結案,灑花,收工

2 則留言: