最近做了一道pyc的逆向題,主要難點在於python環境的opcode被置換,就簡單記錄一下相關知識。
opcode其實是指python原始碼的操作碼,python源***.py編譯後可以得到二進位制檔案*.pyc,*.pyc檔案中就含有opcode序列。對於不同版本的python,其opcode是不完全相同的,這也就是為什麼某一版本的python虛擬機器不能執行另乙個版本的原始碼。
檢視當前版本opcode的方式有很多種,最簡單的是直接匯入opcode庫檢視:
import opcode
for key in opcode.opmap.keys():
print (key, opcode.opmap[key])
或者在/python/include/opcode.**件中檢視。
乙個簡單原始碼的opcode檢視如下:
import dis
def foo():
x = 20
y = 10
z = x - y
return z
dis.dis(foo)
輸出如下:
3 0 load_const 1 (20)
2 store_fast 0 (x)
4 4 load_const 2 (10)
6 store_fast 1 (y)
5 8 load_fast 0 (x)
10 load_fast 1 (y)
12 binary_subtract
14 store_fast 2 (z)
6 16 load_fast 2 (z)
18 return_value
或者可以在命令列執行 python -m py_compile filename.pyc,然後利用pycdas等軟體去反編譯至opcode。
一些逆向題會構建乙個修改的python環境,從而使對應的*.pyc檔案只能被本地識別並執行,而不能在別的計算機執行。
那如何構建這樣的環境呢,一般是通過原始碼安裝python的方式實現,在安裝前更改opcode的相關檔案。對於2.7.13版本以下,似乎只需要更改/include/opcode.h,/lib/opcode.py兩個檔案,而2.7.14及以上版本則還需要修改/python/opcode_targets.**件。本文的例子是針對2.7.16的。
構建三個補丁檔案(這裡以加減法交換為例)如下,分別命名為re1.patch,re2.patch,re3.patch。
--- include/opcode.h
+++ include/opcode.h
@@ -30,2 +30,2 @@
-#define binary_add 23
-#define binary_subtract 24
+#define binary_add 24
+#define binary_subtract 23
--- lib/opcode.py
+++ lib/opcode.py
@@ -65,2 +65,2 @@
-def_op('binary_add', 23)
-def_op('binary_subtract', 24)
+def_op('binary_add', 24)
+def_op('binary_subtract', 23)
--- python/opcode_targets.h
+++ python/opcode_targets.h
@@ -25,2 +25,2 @@
- &&target_binary_add,
- &&target_binary_subtract,
+ &&target_binary_subtract,
+ &&target_binary_add,
執行以下命令:
~$ xz -d python-2.7.16.tar.xz
~$ tar -xvf python-2.7.16.tar
~$ cd python-2.7.16
~/python-2.7.16$ cp ~/re1.patch re1.patch
~/python-2.7.16$ cp ~/re2.patch re2.patch
~/python-2.7.16$ cp ~/re3.patch re3.patch
~/python-2.7.16$ patch -p0 < re1.patch
~/python-2.7.16$ patch -p0 < re2.patch
~/python-2.7.16$ patch -p0 < re3.patch
~/python-2.7.16$ ./configure --prefix=/usr/local/python
~/python-2.7.16$ sudo make & make install
此時python環境編譯成功,可以用下面的小例子測試一下:
x = 10
y = input("number:")
print x-y
然後將原始碼編譯為pyc檔案:python -m py_compile main.py,分別在不同平台上執行main.pyc如下:
在windows下使用uncompyle6嘗試對main.pyc反編譯:
d:\>uncompyle6 main.pyc
# uncompyle6 version 3.2.6
# python bytecode 2.7 (62211)
# decompiled from: python 2.7.16 (v2.7.16:413a49145e, mar 4 2019, 01:37:19) [msc v.1500 64 bit (amd64)]
# embedded file name: main.py
# compiled at: 2019-06-20 14:51:58
x = 10
y = input('number:')
print x + y
# okay decompiling main.pyc
我們發現,加減法已經被置換了。
簡單置換也可以置換多個opcode,需要注意的是上面三個檔案中opcode的順序必須是一致的,否則make將會失敗。
使用編譯好的pycdc就可以反編譯到正確的原始碼了。
其實我們一般做題很難事先知道正確的opcode順序是什麼,主要還是得通過一次反編譯之後的原始碼,對照其中異常的語句猜測正確的opcode值。
逆向 簡單的pyc
這個是i c的比賽逆向題目 比賽還沒結束qaq 題目內容很簡單 提示說要逆向乙個pyc 直接拉進去 執行 得到如下內容 import base64 def encode message s for i in message x ord i 32 x x 16 s chr x return base6...
180627 逆向 pyc還原指令碼
針對suctf的python 好一題,通過解析內容還原pyc的指令碼 對於不同的解析內容需要另加修改,但原理一致 將元素按照 格式識別符號 len 內容的形式遞迴填入即可 值得說明的一點是指令碼無法還原出原來一模一樣的pyc,但可以還原出相同的py檔案 這是因為python在編譯pyc的時候,會將一...
關於pyc檔案的逆向
關於pyc檔案的逆向 最近感覺遇到的pyc檔案逆向的越來越多了,所以就來總結下。參考了大佬的blog 0x1 pyc的檔案結構 在命令列輸入 python m filename.py的時候,便會得到乙個對應的filename.pyc。拖進hxd中看二進位制。其中,開頭的4個位元組是magic num...