Python逆向(五)—— Python字節碼解讀


#一、前言 前些章節我們對python編譯、反匯編的原理及相關模塊已經做了解讀。讀者應該初步掌握了通過反匯編獲取python程序可讀字節碼的能力。python逆向或者反匯編的目的就是在沒有源碼的基礎上,通過字節碼來理解源代碼的運行內容,並且進一步對源碼的遠行進行調試。因此本次我們嘗試對python字節碼進行解讀。 #二、字節碼結構 字節碼結構如下: 源碼行號 | 跳轉注釋符 | 指令在函數中的偏移 | 指令符號(助記符) | 指令參數 | 實際參數值

上圖表示

  • 該字節碼指令在源碼中對應59行
  • 此處是跳轉的目的地址
  • 82該字節指令的字節碼偏移
  • 操作指令對應的助記符為LOAD_GLOBAL
  • 操作參數為6
  • 操作參數對應的實際值為disassemble

#三、字節碼實戰 ##3.1常量

加載常量只有一行LOAD_CONST,對應源碼第1行,字節碼偏移地址0字節,常量數組中索引0,實際常量值‘123’ ##3.2局部變量

加載局部變量a:LOAD_CONST加載常量1,調用STORE_NAME(參數a),並將變量a存儲為1 同理加載局部變量b ##3.3全局變量

加載全局變量a,與加載局部變量不同的是通過STORE_GLOBAL在存儲變量。 ##3.4數據類型list

先將所有的list元素加載,調用BUILD_LIST方法生成list於內存中,通過STORE_NAME將堆棧中的list存儲於局部變量a中 ##3.5數據類型dict

BUILD_MAP聲明字典元素數量,通過兩次LOAD_CONST后,調用STORE_MAP生成鍵值對存於堆棧,最終通過STORE_NAME將堆棧中長度為2的兩個鍵值對最為字典數據類型存儲在a中 ##3.6數學運算

字節碼中顯示先對局部變量a、b賦值,通過LOAD_NAME加載局部變量,調用加法BINARY_ADD,生成結果存儲與堆棧中,使用STORE_NAME將堆棧中的計算結果存儲與局部變量c 加減乘除的運算字節碼相似,不不再贅述,讀者可以自行分析,如下圖:

上圖中為對a、b做加減乘除的字節碼,因為沒有存儲計算結果,所以每次運算完沒有使用STORE_NAME方法存儲,解釋器默認調用POP_TOP方法將計算結果從堆棧頂部彈出,以保證堆棧平衡。 ##3.7循環FOR

上圖顯示一個FOR循環的過程。SETUP_LOOP表明循環開始,參數說明此循環知道字節碼偏移28字節的指令結束(也就是28字節開始不是循環)。調用range方法生成generator存於堆棧。FOR_ITER調用堆棧,聲明generator作用到字節碼偏移位置27字節。從第16字節起到27為generator迭代作用域。其中為一個print函數。 ##3.8判斷IF

以一個簡單的IF判斷為例,先加載需要比較的常量,調用COMPARE_OP指令對堆棧中兩個常量進行比較,將結果存入堆棧。調用POP_JUMP_IF_FALSE指令,判斷棧頂值來決定程序運行順序實現判斷功能。 #四、參考 本文試圖讓讀者能夠通過簡單的例子具備閱讀字節碼的能力,上文只是對字節碼的閱讀做了簡單的講解,文章難免有疏漏敬請包涵。如果讀者對字節碼的閱讀有更多的解讀需求可以前往這里:https://bbs.pediy.com/thread-246683.htm。通過官方文檔https://docs.python.org/2/library/dis.html可以對更多的字節碼指令了解。


免責聲明!

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



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