該題來源為2022愛春秋冬季賽ezpython,難度不是很大剛好適合我這樣的萌新入門
3 0 LOAD_CONST 1 (204)
3 LOAD_CONST 2 (141)
6 LOAD_CONST 3 (44)
9 LOAD_CONST 4 (236)
12 LOAD_CONST 5 (111)
15 LOAD_CONST 6 (140)
18 LOAD_CONST 6 (140)
21 LOAD_CONST 7 (76)
24 LOAD_CONST 3 (44)
27 LOAD_CONST 8 (172)
30 LOAD_CONST 9 (7)
33 LOAD_CONST 9 (7)
36 LOAD_CONST 10 (39)
39 LOAD_CONST 11 (165)
42 LOAD_CONST 12 (70)
45 LOAD_CONST 9 (7)
48 LOAD_CONST 10 (39)
51 LOAD_CONST 13 (166)
54 LOAD_CONST 11 (165)
57 LOAD_CONST 14 (134)
60 LOAD_CONST 14 (134)
63 LOAD_CONST 6 (140)
66 LOAD_CONST 1 (204)
69 LOAD_CONST 11 (165)
72 LOAD_CONST 9 (7)
75 LOAD_CONST 10 (39)
78 LOAD_CONST 15 (230)
81 LOAD_CONST 6 (140)
84 LOAD_CONST 11 (165)
87 LOAD_CONST 12 (70)
90 LOAD_CONST 3 (44)
93 LOAD_CONST 8 (172)
96 LOAD_CONST 16 (102)
99 LOAD_CONST 17 (6)
102 LOAD_CONST 6 (140)
105 LOAD_CONST 1 (204)
108 LOAD_CONST 15 (230)
111 LOAD_CONST 15 (230)
114 LOAD_CONST 7 (76)
117 LOAD_CONST 18 (198)
120 LOAD_CONST 19 (38)
123 LOAD_CONST 20 (175)
126 BUILD_LIST 42
129 STORE_FAST 0 (flag)
4 132 SETUP_LOOP 54 (to 189)
135 LOAD_GLOBAL 0 (range)
138 LOAD_CONST 21 (42)
141 CALL_FUNCTION 1
144 GET_ITER
>> 145 FOR_ITER 40 (to 188)
148 STORE_FAST 1 (i)
5 151 LOAD_FAST 0 (flag)
154 LOAD_FAST 1 (i)
157 BINARY_SUBSCR //讀取列表中的值
158 LOAD_CONST 22 (5)
161 BINARY_RSHIFT
162 LOAD_FAST 0 (flag)
165 LOAD_FAST 1 (i)
168 BINARY_SUBSCR
169 LOAD_CONST 23 (3)
172 BINARY_LSHIFT
173 BINARY_OR
174 LOAD_CONST 24 (255)
177 BINARY_AND
178 LOAD_FAST 0 (flag)
181 LOAD_FAST 1 (i)
184 STORE_SUBSCR
185 JUMP_ABSOLUTE 145
>> 188 POP_BLOCK
>> 189 LOAD_CONST 0 (None)
192 RETURN_VALUE
先了解python的位元組碼結構,如下:
原始碼行號 | 指令在函數中的偏移 | 指令符號 | 指令引數 | 實際引數值
第一個為原始碼行號,從上述題目中我們可以瞭解到,本題只有5行原始碼,但是隻給了從第3行開始的位元組碼
第二個指令在函數中的偏移和第四個指令引數對於做題來說不是太過重要,我們在做題的時候主要還是看指令符號和實際引數值
在第3行的位元組碼指令符號中,有LOAD_CONST ,BUILD_LIST ,STORE_FAST 三種型別
LOAD_CONST 載入常數,通常為整數值
BUILD_LIST 建立一個列表
STORE_FAST 一般用於儲存值到區域性變數
理解了上述指令符號含義後,我們來看題目中第3行的位元組碼,先看第一個
分析後知道載入了一個常數,數值為204,以此向後分析發現,大部分一樣,至此我們知道載入瞭如下常數
204, 141, 44, 236, 111, 140, 140, 76, 44, 172, 7, 7, 39, 165, 70, 7, 39, 166, 165, 134, 134, 140, 204, 165, 7, 39, 230, 140, 165, 70, 44, 172, 102, 6, 140, 204, 230, 230, 76, 198, 38, 175
然後我們來這裡
這裡建立一個列表,長度為42,你也可以通過數前面載入的常數發現,剛好是42個常數,然後儲存值到變數flag中,那這裡儲存的值是什麼呢?其實就是位於該指令符號前面的所有的值。
綜上我們就得到python原始碼的第3行原始碼
flag = [204, 141, 44, 236, 111, 140, 140, 76, 44, 172, 7, 7, 39, 165, 70, 7, 39, 166, 165, 134, 134, 140, 204, 165, 7, 39, 230, 140, 165, 70, 44, 172, 102, 6, 140, 204, 230, 230, 76, 198, 38, 175]
接著分析第4行位元組碼:
這裡的指令符號有:
SETUP_LOOP,用於開始迴圈,括號裡的189表示迴圈退出點(位元組碼結構中的第二個指令在函數中偏移)
LOAD_GLOBAL,用來載入全域性變數,包括指定函數名,類名,模組名等全域性符號
LOAD_CONST ,(請看上文)
CALL_FUNCTION,用來表示前面載入全域性變數的引數個數
GET_ITER,FOR_ITER ,獲取引數,開始迭代。這兩個不需要過多理解,屬於for-in結構特有的,它們通常同時出現。
STORE_FAST,(請看上文)
綜上分析:開始迴圈,載入了一個全域性函數range,載入了一個常數42,range函數的引數為1,執行迴圈的變數i,得到原始碼如下:
for i in range(42):
繼續分析第5行位元組碼:
這裡出現了前面沒出現過的位元組碼有:
BINARY_SUBSCR ,讀取迭代器中某個下標的值
BINARY_RSHIFT,進行右移運算
BINARY_LSHIFT ,左移運算
BINARY_OR,或運算
BINARY_AND ,與運算
STORE_SUBSCR ,修改迭代器中某個下標的值
JUMP_ABSOLUTE ,回到迴圈起點
RETURN_VALUE ,函數結束標誌
POP_BLOCK,特有的,不用特別理解,對轉換回原始碼不重要,通常和LOAD_CONST 0 (None)一起出現。
整體理解:先讀取了flag[i]的值,然後載入一個常數5進行右移,得到如下:
flag[i] >> 5
然後繼續讀取flag[i]的值,載入一個常數3進行左移,得到如下:
flag[i] << 3
然後進行或運算,得到如下:
(flag[i] >> 5) | (flag[i] << 3)
載入一個常數255,接著進行與運算,得到如下:
(flag[i] >> 5) | (flag[i] << 3) & 255
最後存入flag[i],得到如下:
flag[i] = (flag[i] >> 5) | (flag[i] << 3) & 255
注意位元組碼從上到下的順序和原始碼運算的優先順序順序。
最終從全部的位元組碼翻譯過來的原始碼如下:
flag = [204, 141, 44, 236, 111, 140, 140, 76, 44, 172, 7, 7, 39, 165, 70, 7, 39, 166, 165, 134, 134, 140, 204, 165, 7, 39, 230, 140, 165, 70, 44, 172, 102, 6, 140, 204, 230, 230, 76, 198, 38, 175] for i in range(42): flag[i] = (flag[i] >> 5) | (flag[i] << 3) & 255
最終解題指令碼如下:
flag = [204, 141, 44, 236, 111, 140, 140, 76, 44, 172, 7, 7, 39, 165, 70, 7, 39, 166, 165, 134, 134, 140, 204, 165, 7, 39, 230, 140, 165, 70, 44, 172, 102, 6, 140, 204, 230, 230, 76, 198, 38, 175] for i in range(42): flag[i] = (flag[i] >> 5) | (flag[i] << 3) & 255 str_flag = '' for i in flag: str_flag += chr(i) print(str_flag)
得到flag:flag{ddbae889-2895-44df-897d-2ae30df77b61}
死磕python位元組碼-手工還原python原始碼 - 知乎 (zhihu.com)
python 位元組碼死磕 - 大步向前blue - 部落格園 (cnblogs.com)