第四章 混淆方法與流程
4.2 虛擬化混淆轉換
轉換每個定義的函式及物件的方法。Python 的 AST( Abstract Syntax Tree )模組 可以對原始程式檔案進行初步分析,為每個模組建立抽象語法樹,完成後便能從 Python 實現 Python 的直譯器如 Byterun,它使用與 CPython 相同的指令來解譯程 式,此外還保留了Python 先前版本的指令內容來解譯不同版本所編譯的 Python 程式。本研究以Byterun 直譯器為基礎作為實現虛擬化轉換中直譯器的產生方式
‧ 國
立 政 治 大 學
‧
N a tio na
l C h engchi U ni ve rs it y
式用於決策樹演算法中,將資料集根據其中的一項特徵值數值來把資料分成兩 堆。圖6 則是上述函式以虛擬化轉換後的結果。經由函式虛擬化轉換再製的前後 函式擁有相同的功能,但運作方式的複雜程度卻有相當程度的提升。接下來將介 紹關於混淆轉換工具的轉換流程設計以實現自動化Python 函式虛擬化轉換。
圖5: Python 函式
圖6: Python 虛擬化轉換後函式
‧ 國
立 政 治 大 學
‧
N a tio na
l C h engchi U ni ve rs it y
4.2.1 建立混淆版位元組碼
位元組碼的內容包括指令操作碼( opcode )及參數,虛擬化轉換中混淆工具 可以隨機生成一套新的指令集架構作為虛擬指令集,虛擬指令集可以設定獨特 的操作指令編碼及參數存取位置,使基於虛擬指令集輸出的位元組碼無法直接 分析其內容。
虛擬指令集除了操作指令編碼可以採用任意數值外,也可設計獨特的指令 語意。建立新指令集前,混淆工具以Python 的 DIS( Disassembler for Python bytecode )套件來取得完成函式功能所需指令。圖 7 所示為藉由使用 DIS 套件分 析圖5 Python 函式所得的位元組碼資訊,圖中每行表示位元組碼中的一個指令,
內容包括指令所對應的原始程式碼行數、當前指令、被標記的指令、指令位址、
位元組碼名稱、位元組碼參數、參數內容。
圖7: Python DIS 套件分析
‧
「LOAD_GLOBAL」及「CALL_FUNCTION」合併成超級指令(表 4 中操作碼 3 的指令),接著便能輸出新的位元組碼程式「超級指令#1,參數 1,參數 2」取代原 本的位元組碼「LOAD_GLOBAL,參數 1,CALL_FUNCTION,參數 2」。
表4: 指令集架構表格
位元組碼名稱 LOAD_GLOBAL CALL_FUNCTION 超級指令#1
操作碼 1 2 3 工作,圖8 所示為 Byterun 直譯器對於 Python 位元組碼「LOAD_GLOBAL」的 解譯方式,混淆工具可以將這樣的指令語意轉換成虛擬化混淆轉換中的指令處 理器。圖6 中第 19~27 行即為工具轉換後,可完成如圖 8 指令工作內容的程式。
7https://en.wikipedia.org/wiki/N-gram
‧ 國
立 政 治 大 學
‧
N a tio na
l C h engchi U ni ve rs it y
圖8: Byterun 直譯器的指令處理
根據生成的虛擬指令集,自訂的直譯器可以解譯混淆版本的位元組碼程式,
也因此位元組碼陣列的元素位置可以被隨機調整、加入無含意的資料。虛擬程式 計數器則會在直譯器的控制下,在每次指令工作完成後指向正確的程式陣列位 置使程式能正確執行。
調度單位及指令處理器是自訂直譯器的主要內容。調度單位會根據虛擬程 式計數器在程式陣列中所指的位置選擇要使用的指令處理器,指令處理器在執 行完指令工作後會將虛擬程式計數器引導到下個位置,根據函式所用指令,混淆 工具會選擇表2 及表 3 裡的指令工作做成指令處理器直到自訂的直譯器可以處理 所有指令。除了上述的工作,混淆工具所建立的直譯器還會額外以區塊( Block ) 來確保程式運作在正確的狀態下。例如在進入迴圈時,程式會先令區塊記錄當前 資料堆疊的狀態、迴圈結束位置,迴圈執行期間遇到「break」指令則引導程式 到迴圈結束位置、遇到「continue」指令則引導程式到迴圈起始位置,離開迴圈 時根據區塊所記錄的資訊檢查資料堆疊是否在維持在先前的高度。