日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

Python3 字节码详解

發布時間:2023/12/10 python 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Python3 字节码详解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 前言
  • 什么是 py 字節碼?
  • 變量
  • 常用數據類型
    • list
    • dict
    • slice
  • 循環
    • while
    • for
  • if
  • 其他指令
  • 后記

前言

在逆向的時候遇到過反編譯 py 字節碼,之前也就沒咋在意,啥不會查就完事兒了,好家伙,省賽讓我給遇到了,直接嚶嚶嚶😭,但還好解出來了;

今天趁這個機會,系統的學習一下,以防下次陰溝里翻船,本博文的 Python 版本是3.8.5,版本不同形成的字節碼會略有不同,但是大同小異;

【記】2021年第四屆浙江省大學生網絡安全技能挑戰賽:

  • CSDN
  • 個人博客
    ?

什么是 py 字節碼?

Python 代碼先被編譯為字節碼后,再由 Python 虛擬機來執行字節碼,Python 的字節碼是一種類似匯編指令的中間語言,一個 Python 語句會對應若干字節碼指令,虛擬機一條一條執行字節碼指令,從而完成程序執行。

Python 的 dis 模塊支持對 Python 代碼進行反匯編, 生成字節碼指令。

結構:

源碼行號 | 指令在函數中的偏移 | 指令符號 | 指令參數 | 實際參數值

源碼:

str = [88, 117, 124, 124, 127, 48, 71, 127, 98, 124, 116, 48, 61, 61, 121, 116, 33, 32, 100, 62]def test():for st in str:print(chr(st^16),end='')test()

字節碼:

1 0 LOAD_CONST 0 (0)2 LOAD_CONST 1 (None)4 IMPORT_NAME 0 (dis)6 STORE_NAME 0 (dis)3 8 LOAD_CONST 2 (88)10 LOAD_CONST 3 (117)12 LOAD_CONST 4 (124)14 LOAD_CONST 4 (124)16 LOAD_CONST 5 (127)18 LOAD_CONST 6 (48)20 LOAD_CONST 7 (71)22 LOAD_CONST 5 (127)24 LOAD_CONST 8 (98)26 LOAD_CONST 4 (124)28 LOAD_CONST 9 (116)30 LOAD_CONST 6 (48)32 LOAD_CONST 10 (61)34 LOAD_CONST 10 (61)36 LOAD_CONST 11 (121)38 LOAD_CONST 9 (116)40 LOAD_CONST 12 (33)42 LOAD_CONST 13 (32)44 LOAD_CONST 14 (100)46 LOAD_CONST 15 (62)48 BUILD_LIST 2050 STORE_NAME 1 (str)5 52 LOAD_CONST 16 (<code object test at 0x0170E2F8, file "1.py", line 5>)54 LOAD_CONST 17 ('test')56 MAKE_FUNCTION 058 STORE_NAME 2 (test)9 60 LOAD_NAME 2 (test)62 CALL_FUNCTION 064 POP_TOP66 LOAD_CONST 1 (None)68 RETURN_VALUEDisassembly of <code object test at 0x0170E2F8, file "1.py", line 5>:6 0 LOAD_GLOBAL 0 (str)2 GET_ITER>> 4 FOR_ITER 24 (to 30)6 STORE_FAST 0 (st)7 8 LOAD_GLOBAL 1 (print)10 LOAD_GLOBAL 2 (chr)12 LOAD_FAST 0 (st)14 LOAD_CONST 1 (16)16 BINARY_XOR18 CALL_FUNCTION 120 LOAD_CONST 2 ('')22 LOAD_CONST 3 (('end',))24 CALL_FUNCTION_KW 226 POP_TOP28 JUMP_ABSOLUTE 4>> 30 LOAD_CONST 0 (None)32 RETURN_VALUE

稍后會詳細介紹;
?

變量

1、CONST

LOAD_CONST 加載 const 變量,比如數值、字符串等等,一般用于傳給函數的參數;

11 52 LOAD_NAME 2 (test)54 LOAD_CONST 16 ('nice')56 CALL_FUNCTION 158 POP_TOP test('nice')

?

2、局部變量

  • LOAD_FAST 一般加載局部變量的值,也就是讀取值,用于計算或者函數調用傳參等;
  • STORE_FAST 一般用于保存值到局部變量;
61 77 LOAD_FAST 0 (n)80 LOAD_FAST 3 (p)83 INPLACE_DIVIDE84 STORE_FAST 0 (n) n = n / p

那問題來了,函數的形參也是局部變量,如何區分出是函數形參還是其他局部變量呢?

我們可以自己寫一段代碼推敲一下:

import disstr = ''def test(arg):str = 'idi10t'print(arg,str)dis.dis(test) 6 0 LOAD_CONST 1 ('idi10t')2 STORE_FAST 1 (str) 7 4 LOAD_GLOBAL 0 (print)6 LOAD_FAST 0 (arg) 8 LOAD_FAST 1 (str) 10 CALL_FUNCTION 2 12 POP_TOP14 LOAD_CONST 0 (None) 16 RETURN_VALUE

可以得出結論:形參沒有初始化,也就是從函數開始到 LOAD_FAST 該變量的位置,如果沒有看到 STORE_FAST,那么該變量就是函數形參;而其他局部變量在使用之前肯定會使用 STORE_FAST 進行初始化。

?

3、全局變量

  • LOAD_GLOBAL 用來加載全局變量,包括指定函數名,類名,模塊名等全局符號;
  • STORE_GLOBAL 用來給全局變量賦值;
import disdef test():global str str = 'idi10t'print(str)dis.dis(test) 5 0 LOAD_CONST 1 ('idi10t')2 STORE_GLOBAL 0 (str)6 4 LOAD_GLOBAL 1 (print)6 LOAD_GLOBAL 0 (str)8 CALL_FUNCTION 110 POP_TOP12 LOAD_CONST 0 (None)14 RETURN_VALUE

?

常用數據類型

list

BUILD_LIST 用于創建一個 list 結構:

str = [88, 117, 124, 124, 127, 48, 71, 127, 98, 124, 116, 48, 61, 61, 121, 116, 33, 32, 100, 62] 3 8 LOAD_CONST 2 (88)10 LOAD_CONST 3 (117)12 LOAD_CONST 4 (124)14 LOAD_CONST 4 (124)16 LOAD_CONST 5 (127)18 LOAD_CONST 6 (48)20 LOAD_CONST 7 (71)22 LOAD_CONST 5 (127)24 LOAD_CONST 8 (98)26 LOAD_CONST 4 (124)28 LOAD_CONST 9 (116)30 LOAD_CONST 6 (48)32 LOAD_CONST 10 (61)34 LOAD_CONST 10 (61)36 LOAD_CONST 11 (121)38 LOAD_CONST 9 (116)40 LOAD_CONST 12 (33)42 LOAD_CONST 13 (32)44 LOAD_CONST 14 (100)46 LOAD_CONST 15 (62)48 BUILD_LIST 2050 STORE_NAME 1 (str)

再看看另一種的 list 創建方式:

str = [88, 117, 124, 124, 127, 48, 71, 127, 98, 124, 116, 48, 61, 61, 121, 116, 33, 32, 100, 62][x for x in str if x != 48] 1 0 LOAD_CONST 0 (88)2 LOAD_CONST 1 (117)4 LOAD_CONST 2 (124)6 LOAD_CONST 2 (124)8 LOAD_CONST 3 (127)10 LOAD_CONST 4 (48)12 LOAD_CONST 5 (71)14 LOAD_CONST 3 (127)16 LOAD_CONST 6 (98)18 LOAD_CONST 2 (124)20 LOAD_CONST 7 (116)22 LOAD_CONST 4 (48)24 LOAD_CONST 8 (61)26 LOAD_CONST 8 (61)28 LOAD_CONST 9 (121)30 LOAD_CONST 7 (116)32 LOAD_CONST 10 (33)34 LOAD_CONST 11 (32)36 LOAD_CONST 12 (100)38 LOAD_CONST 13 (62)40 BUILD_LIST 2042 STORE_NAME 0 (str)3 44 LOAD_CONST 14 (<code object <listcomp> at 0x016FE2F8, file "1.py", line 3>)46 LOAD_CONST 15 ('<listcomp>')48 MAKE_FUNCTION 050 LOAD_NAME 0 (str)52 GET_ITER54 CALL_FUNCTION 156 POP_TOP58 LOAD_CONST 16 (None)60 RETURN_VALUEDisassembly of <code object <listcomp> at 0x016FE2F8, file "1.py", line 3>:3 0 BUILD_LIST 0 # 創建 list,為賦值給某變量2 LOAD_FAST 0 (.0)>> 4 FOR_ITER 16 (to 22)6 STORE_FAST 1 (x)8 LOAD_FAST 1 (x)10 LOAD_CONST 0 (48)12 COMPARE_OP 3 (!=)14 POP_JUMP_IF_FALSE 4 # 不滿足條件則 break16 LOAD_FAST 1 (x) # 讀取滿足條件的 x18 LIST_APPEND 2 # 把每個滿足條件的 x 存入 list20 JUMP_ABSOLUTE 4>> 22 RETURN_VALUE

?

dict

  • BUILD_MAP 用于創建一個空的 dict;
  • STORE_NAME 用于初始化 dict 的內容;
str = {'name' : 'id10t'} str['age'] = 3 1 0 LOAD_CONST 0 ('name')2 LOAD_CONST 1 ('id10t')4 BUILD_MAP 16 STORE_NAME 0 (str)2 8 LOAD_CONST 2 (3)10 LOAD_NAME 0 (str)12 LOAD_CONST 3 ('age')14 STORE_SUBSCR16 LOAD_CONST 4 (None)18 RETURN_VALUE

?

slice

這里直接借用了大佬博文的數據;

BUILD_SLICE 用于創建 slice,對于 list、元組、字符串都可以使用 slice 的方式進行訪問。

但是要注意 BUILD_SLICE 用于 [x:y:z] 這種類型的 slice,結合 BINARY_SUBSCR 讀取 slice 的值,結合 STORE_SUBSCR 用于修改 slice 的值。

另外 SLICE + n 用于 [a:b] 類型的訪問,STORE_SLICE + n 用于 [a:b] 類型的修改,其中 n 表示如下:

SLICE+0() Implements TOS = TOS[:].SLICE+1() Implements TOS = TOS1[TOS:].SLICE+2() Implements TOS = TOS1[:TOS].SLICE+3() Implements TOS = TOS2[TOS1:TOS]. 13 0 LOAD_CONST 1 (1)3 LOAD_CONST 2 (2)6 LOAD_CONST 3 (3)9 BUILD_LIST 312 STORE_FAST 0 (k1) //k1 = [1, 2, 3]14 15 LOAD_CONST 4 (10)18 BUILD_LIST 121 LOAD_FAST 0 (k1)24 LOAD_CONST 5 (0)27 LOAD_CONST 1 (1)30 LOAD_CONST 1 (1)33 BUILD_SLICE 336 STORE_SUBSCR //k1[0:1:1] = [10]15 37 LOAD_CONST 6 (11)40 BUILD_LIST 143 LOAD_FAST 0 (k1)46 LOAD_CONST 1 (1)49 LOAD_CONST 2 (2)52 STORE_SLICE+3 //k1[1:2] = [11]16 53 LOAD_FAST 0 (k1)56 LOAD_CONST 1 (1)59 LOAD_CONST 2 (2)62 SLICE+363 STORE_FAST 1 (a) //a = k1[1:2]17 66 LOAD_FAST 0 (k1)69 LOAD_CONST 5 (0)72 LOAD_CONST 1 (1)75 LOAD_CONST 1 (1)78 BUILD_SLICE 381 BINARY_SUBSCR82 STORE_FAST 2 (b) //b = k1[0:1:1]

?

循環

while

Python3.8 及以上就沒有 SETUP_LOOP 了,

大致意思就是將循環塊送入到堆棧當中去,

i = 0 while i < 10:i += 1 1 0 LOAD_CONST 0 (0)2 STORE_NAME 0 (i)2 >> 4 LOAD_NAME 0 (i)6 LOAD_CONST 1 (10)8 COMPARE_OP 0 (<)10 POP_JUMP_IF_FALSE 223 12 LOAD_NAME 0 (i)14 LOAD_CONST 2 (1)16 INPLACE_ADD18 STORE_NAME 0 (i)20 JUMP_ABSOLUTE 4>> 22 LOAD_CONST 3 (None)24 RETURN_VALUE

?

for

Python 中典型的 for in 結構:

for i in range(8): 2 4 LOAD_NAME 1 (range)6 LOAD_CONST 1 (8)8 CALL_FUNCTION 110 GET_ITER>> 12 FOR_ITER 38 (to 52)14 STORE_NAME 2 (i)...50 JUMP_ABSOLUTE 12>> 52 LOAD_CONST 6 (None)

?

if

POP_JUMP_IF_FALSE 和 JUMP_FORWARD 一般用于分支判斷跳轉:

  • POP_JUMP_IF_FALSE 表示條件結果為 FALSE 就跳轉到目標偏移指令;
  • JUMP_FORWARD 直接跳轉到目標偏移指令;
i = 0 if i < 5:print('i < 5') elif i > 5:print('i > 5') else:print('i = 5') 1 0 LOAD_CONST 0 (0)2 STORE_NAME 0 (i)2 4 LOAD_NAME 0 (i)6 LOAD_CONST 1 (5)8 COMPARE_OP 0 (<)10 POP_JUMP_IF_FALSE 223 12 LOAD_NAME 1 (print)14 LOAD_CONST 2 ('i < 5')16 CALL_FUNCTION 118 POP_TOP20 JUMP_FORWARD 26 (to 48)4 >> 22 LOAD_NAME 0 (i)24 LOAD_CONST 1 (5)26 COMPARE_OP 4 (>)28 POP_JUMP_IF_FALSE 405 30 LOAD_NAME 1 (print)32 LOAD_CONST 3 ('i > 5')34 CALL_FUNCTION 136 POP_TOP38 JUMP_FORWARD 8 (to 48)7 >> 40 LOAD_NAME 1 (print)42 LOAD_CONST 4 ('i = 5')44 CALL_FUNCTION 146 POP_TOP>> 48 LOAD_CONST 5 (None)50 RETURN_VALUE

?

其他指令

上述就是比較常用的一些指令了,當然還有更多的指令,這里就不一一介紹了,詳情見官方文檔,這里的是 Python3.8 版本的官方文檔;

?

后記

開卷有益,多多益善;

參考:

官方文檔
Python內置模塊dis.py源碼詳解
死磕python字節碼-手工還原python源碼
?

總結

以上是生活随笔為你收集整理的Python3 字节码详解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。