通過反編譯和機器學習檢測惡意樣本代碼重用
工作來源
DIMVA 2021
工作背景
很少有調查研究如何在大范圍內自動檢測和識別特定的高級攻擊組織使用的惡意軟件樣本。此前,安全社區已經廣泛研究了如何根據代碼相似性檢測未知攻擊。最近,社區也開始探索使用現代機器學習方法來檢測更復雜的惡意軟件攻擊,例如 APT。但現有方法不足以處理現代惡意軟件中的代碼重用和攻擊歸因。
這主要有兩個原因:首先,關于 APT 樣本的相關數據很少。因此,在實際部署中,這種限制使得常見的機器學習技術在查找特定類型的惡意軟件方面的效率明顯降低。其次,由于惡意軟件作者大量使用規避技術,當前的靜態代碼相似性分析方法在定位以前未知的威脅上失靈,這使得幾乎所有現有的靜態分析方法在實踐中的效果都乏善可陳。
已有方法大多依賴于通過靜態分析提取的二進制代碼的特定語法特征,例如控制流圖(CFG)。但無法應對反分析技術對靜態分析的巨大影響。
此前還有研究根據開發者的編碼風格對用戶進行跟蹤,在編譯過程中不會丟失源碼級別的作者編碼風格。最近的工作依賴于編碼風格特征,并利用機器學習來開發更強大的代碼作者歸屬機制。例如:
- Abuhamad 提出可以有效利用深度神經網絡對大規模代碼進行特征化的系統。
- Caliskan-Islam 依靠隨機森林和 AST 的語法特征跟蹤開發者。
這種方法在編碼風格特征(如變量命名約定)改變的情況下,效果是很差的。
惡意軟件聚類的三大類方法:① 依賴靜態特征,例如 MutantX-S。② 依賴運行時特征。③ 依賴執行前后的特征,例如 DUET。但惡意軟件聚類的目標是識別未知、混淆的家族,不是用于確定歸因。
幾乎所有基于惡意軟件的攻擊(包括高級、有針對性的攻擊,如 APT)都遵循經過實踐證明的模式來開發實際的 Payload。惡意軟件很少從頭開始編寫,并且通常依賴于現有的代碼或特定的、獨特的代碼(例如 Mimikatz)。當然,分析惡意軟件樣本時的一項主要挑戰就是缺乏源代碼。
為了能夠構建有效、準確的代碼相似性檢測方法,適用于現實世界的惡意軟件二進制文件,第一步,使用動態分析技術執行代碼,然后創建運行樣本的進程快照。第二步,從內存快照中重構相應的高級源代碼,并自動定位極有可能用于惡意行為的代碼段。
工作設計
需要提取給定的 Payload 再進行反編譯,開發用于相似性計算反編譯代碼的有效編碼機制,并構建無監督模型以對未知樣本運行代碼分析。整體架構如下所示:

反編譯
對給定的文件在 Lastline 沙盒中執行,在分析的關鍵時刻生成多個進程 Dump。關鍵時刻如下所示:
- 執行創建新進程的 API 時,如 CreateProcess;執行創建新文件的 API 時,如 CreateFile;執行權限提升 API 時,如 AdjustTokenPrivileges
- 執行在原始 PE Image 之外時
- 原始 PE Image 更改時
進程 Dump 中有正在分析的二進制文件的加載代碼和內存塊的運行時信息。當引擎檢測到可疑行為(例如,來自不受信任的內存區域的敏感 API 調用)時,就會獲取進程 Dump。使用 Ghidra 插件解析這些 Dump,在分析后再重建源碼,該插件將 Dump 中的內存區域映射到 Ghidra 的虛擬內存空間,并進行反編譯。
向量化
依賴于孿生神經網絡(SNN)進行向量編碼,SSN 由兩個或多個具有相同架構的子網絡組成,SNN 在很多領域表現都很好。神經網絡的結構如下所示,同時接受兩個輸入并為輸入計算兩個向量,然后利用距離度量來估計兩個向量之間的相似性。每個子網絡都是一個 LSTM 網絡,這種 RNN 網絡在異常檢測和預測時間序列數據上都很成功。

為了向量化函數并將它們作為輸入提供給 SNN,方案將每個函數映射到其抽象語法樹(AST)節點。最后,為了比較兩個 LSTM 的最終隱藏狀態,利用曼哈頓距離度量將孿生神經網絡修改為 MaLSTM 的變種。
為了發現相似的函數,首先提取每個函數向量(即 AST 節點)的 n-gram,再通過局部敏感哈希對所有提取的函數 n-gram 進行哈希計算,利用局部敏感哈希將相似的函數映射到相同的桶中。研究發現單獨依賴局部敏感哈希通常會引入誤報,特別是在反編譯代碼中提取的函數有較大差異的情況下,需要結合其他技術處理誤報。
聚類
每個樣本經過 SNN 轉換為一組編碼函數,與數據庫中的集群進行比較。因為惡意樣本和良性樣本也會共享大量的代碼,例如,靜態鏈接的標準庫函數、全局變量初始化代碼和導入解析代碼等。如果函數被分類到包含惡意樣本和良性樣本函數的混合集群中,就會被認為是需要被過濾掉的噪音。
在沙盒中運行樣本并重構源碼,提取了 534 個函數,共計 45902 行代碼。有 434 個(81%)函數被認為是噪音,共計 36957 行代碼。其余 100 個函數中大部分被歸類到 Turla 的集群中,進一步調查可以確認是 Turla 的樣本。
工作準備
實驗環境
SCRUTINIZER 是用 Python 實現的,編程利用名為 Dask 的并行計算庫來提高腳本的執行速度。
實驗在 20 核的 Intel Xeon CPU、276 GB 內存的 Ubuntu 服務器上進行。
實驗數據

訓練數據集與測試數據集互不重疊,良性樣本和惡意樣本共計 44015 個,提取了 1734992 個函數。
- 訓練數據集:良性樣本 31475 個、惡意樣本 12540 個。
- 測試數據集:良性樣本 2500 個、惡意樣本 500 個。
良性樣本來自不同版本的 Windows DLL 文件,惡意樣本中包括 12253 個普通惡意樣本和 287 個 APT 惡意樣本。


從 12540 個真實的惡意軟件樣本中運行和提取運行時內存快照。然后構建工具分析進程快照并重構實際惡意 Payload 的源代碼,并檢索相應的函數代碼片段。
工作評估
函數向量化
首先使用 Ghidra 處理腳本反編譯每個文件,接著利用 Clang 將每個函數映射到一個扁平的 AST 向量。為了使 AST 構造更加精確,將向量中的每個函數或 API 調用(AST 中的 CALL EXPR 節點)替換為函數或 API 調用的具體名稱,以此區分系統函數調用和開發者編寫的函數調用。
接著訓練 MaLSTM 來識別相似和不同的函數對。腳本處理時需要過濾不共享公共原型(即函數名稱和參數)和輸出的相似函數。其次,對函數集合的子集進行了多次哈希與手動檢查,總共從惡意樣本和良性樣本中收集了 1105000 對相似和不相似的函數。
平均值、中位數和標準差如下所示:

隨機選擇了 1000 個函數,并進行手動檢查。可以確認 128 位的向量效果更好。
聚類分析
首先處理數據集中的所有樣本,提取它們的函數和對應的 AST 向量。然后使用 MaLSTM 再將它們聚類成組,并且過濾掉噪音函數。
利用 HDBSCAN 算法進行聚類。與此同時,為了加快聚類效率,再使用主成分分析(PCA)將特征維度從 128 減少到 8 維。
總共發現了 1734992 個類,每個類別都包含編碼相似的函數。其中,91% 的類別是完全良性的,3.2% 是完全惡意的,5.88% 的類別是混合的。最大的類別共有 14406 個相似的特征向量,而類的平均大小約為 5 個。
將相似的函數聚類在一起后,根據反編譯代碼中觀察到的函數的出現頻率為每個類別生成一個字典標簽。一個函數的出現頻率如下所示:

實際部署
利用 3000 個未知文件來測試 SCRUTINIZER 的有效性。根據經驗分析,每個樣本平均包含 485 個函數。根據標簽,如果更多的在良性樣本中發現,就認為該函數是噪音,需要被過濾。
平均來說,SCRUTINIZER 能夠過濾 56% 的代碼。而未知樣本中中位數是有 199 個函數,有 126 個(63%)函數被過濾掉,相當于刪除了大約 11476 行(56%)代碼。

當惡意函數數量超過良性函數時,并且樣本與任何先前已知樣本的相似度超過閾值,就會將未知樣本標記為惡意軟件。實驗結果表明,過濾掉常見的函數后,準確率從 82% 提高到 92%。同時,誤報率從 10% 下降到 1.2% 左右。如下所示,ROC 也從 0.88 提升到 0.95。

如下所示,系統判斷的樣本相似與實際的樣本歸屬的列表。其中一些樣本已經被其他安全研究人員判定了歸屬,這也就可以確認 SCRUTINIZER 能夠通過函數級相似推理未知樣本的代碼重用。

案例一

海蓮花最初的攻擊可追溯到 2014 年,在 2020 年又借疫情話題發送釣魚郵件攻擊中國應急管理部等單位。樣本(fcd7227891271a65b729a27de962c0cb)中發現了 377 個不同的函數,共 18125 行代碼。SCRUTINIZER 過濾掉 247 個函數,達 8720 行(48%)代碼。其余的函數被劃分到 109 個不同類中,其中有 4 個函數被分到同一類中,即該樣本包含 105 個和建模階段觀察到的海蓮花樣本中的函數不同的函數。CrowdStrike 將該樣本識別為 Ocean Buffalo,FireEye 也判斷該樣本為為 APT32。
案例二

該樣本(276c28759d06e09a28524fffc2812580)被認為與 Barium 和 Turla 相似,樣本中發現了 971 個函數,共計 74309 行代碼。被過濾掉 767 個函數,達 59976 行(81%)代碼。其余 204 個函數被劃分到 163 個不同類中,共有 22 個函數被認為與 Barium 和 Turla 相似。進一步調查發現該樣本包含一個名為 Mimikatz 的開源黑客工具,該工具同時被這兩個攻擊組織使用。
工作思考
這項工作總體來說還是不錯的,通過查找代碼相似度分數低于 15% 的樣本,就能夠發現海蓮花的多個惡意軟件變種。盡管方法在大規模應用上仍然存在瓶頸,但仍可適用于去粗取精后的少量重點樣本的輔助分析,這和卡巴斯基之前分享過的思路也類似,值得一看。

- 準確率:與任何其他機器學習方法一樣,SCRUTINIZER 的準確性取決于用于構建檢測模型的數據量。然而,收集大量樣本相關的數據并非易事,反編譯是容易出錯的部分,可能導致準確性降低。此外,使用的 AST 構建方法也會產生誤報。在實際應用中,需要不斷更新處理方法,以將誤報率保持在可管理的范圍內。
- 分析效率:動態分析很很昂貴的,且沙盒要做的非常好,比如能處理邏輯炸彈等。
- 為 1000 個反編譯樣本中所有函數的相似性進行測試大約需要 4 個小時。每個子網絡在 5 個 epoch 中并行訓練,大約一百萬對函數的訓練過程大約需要 36 分鐘,這也是十分耗時的。
查看官方倉庫獲取更多信息
https://github.com/OMirzaei/SCRUTINIZER/blob/master/README.md
這是東北大學系統安全實驗室的工作,盡管是宣稱開源的,但是需要發送郵件才能獲取代碼和數據。根據公開信息披露,已有荷蘭科技公司(Sue B.V.)和美國海軍研究實驗室申請了訪問權限。
