python_mmdt:從0到1–實現簡單惡意程式碼分類器(二)
概述
上篇文章python_mmdt:一種基於敏感哈希生成特徵向量的python庫(一)我們介紹了一種叫mmdt_hash
(敏感哈希)生成方法,並對其中的概念做了基本介紹。本篇,我們重點談談mmdt_hash
的分類應用場景。
需求場景
設想這麼一個需求:有一批文件需要判定是否屬於惡意文件,並且需要給出惡意文件所屬的家族類型。這個需求該怎麼高效處理呢?處理過程又該怎麼固化成我們自己的經驗呢?當以後面臨同樣的需求時,能否復用之前的結果呢?
我能想到的做法有以下三種:
- 做法一:本地下載殺毒軟體,使用殺毒軟體對這批文件進行掃描,查看檢測結果。
- 做法二:將這些文件上傳到諸如Virustotal之類的檢測平台,查看檢測結果。
- 做法三:隨機抽取樣本分析,判定為惡意的,則提取yara規則,利用yara規則對剩餘文件進行掃描,未掃出的文件繼續人工分析,繼續提yara規則,如此反覆,直到處理完成。
針對以上三種做法,分別討論其優點和缺點:
- 做法一:
- 優點:處理方式簡單快捷,誤報率極低,處理效率高
- 缺點:單一殺軟漏報率可能較高;在Linux/MacOS上安裝、使用殺軟不方便;處理過程很難固化為經驗;有可能導致文件泄漏(聯網使用殺軟雲查可能導致文件被廠商收集)
- 做法二:
- 優點:適用Windows/Linux/MacOS平台;檢測誤報率、漏報率都極低,結果豐富;處理效率高
- 缺點:有聯網要求;有一定的程式碼開發工作;文件百分百泄漏
- 做法三:
- 優點:處理過程天然可固化為經驗;適用任意平台;適用隔離網路;經驗可積累,可復用;保證文件安全性
- 缺點:工作量極大,處理效率極低;
這裡的需求場景也許太過訂製化,但還是有一定的代表性的。針對以上的需求場景,python_mmdt
工具的分類演算法,可以很好的覆蓋上述場景。
使用python_mmdt
的做法,具有以下優點
- 處理方式簡單、快捷、處理效率高
- 可打包為可執行文件,附帶特徵向量,跨平台適用Windows/Linux/MacOS
- 無聯網要求,文件保密性高
- 處理過程可固化為經驗,經驗固化方式簡單,處理結果復用方便
mmdt_hash
大小固定,存儲佔用空間小
當然,有三個缺點不能不提:
- 準確率可能較低(依賴於判定分值的設定)
- 漏報率可能較高(依賴於判定分值的設定)
- 部分文件的
mmdt_hash
值沒有意義,不能用作分類規則。
因此,可以在不同的場景使用不同的判定分值,判定分值越高,準確率越高;判定分值越低,漏報率越低。
程式碼項目地址
- python_mmdt
- 版本:0.1.3
- 特性:實現簡單分類器,項目附帶基礎敏感哈希特徵庫,可實現惡意樣本匹配
基本介紹
使用pip
安裝python_mmdt
之後,會向系統中添加如下命令:
- mmdt-hash:計算指定文件的
mmdt_hash
值 - mmdt-std:計算
mmdt_hash
的標準差,用于衡量mmdt_hash
的好壞 - mmdt-compare:比較兩個文件的
相似度
- mmdt-gen:利用已知樣本集,生成基於
mmdt_hash
的特徵向量集合 - mmdt-filter:對生成的的特徵向量集合,進行過濾,移除相同的特徵向量
- mmdt-filter-simple:對生成的特徵向量集,進行簡單過濾(去重),適用與簡單分類器
- mmdt-classify:對未知樣本集進行分類處理,輸出分類結果
基本命令使用
1. 計算文件的mmdt_hash
計算單個文件mmdt_hash
值
- 輸入參數1:文件路徑
- 螢幕輸出:
mmdt_hash
的值 - 文件輸出:無
# ➜ mmdt-hash APT28_1
# 5D58573C:B39A90BCDCB4D491BEC74B207AE5FE39
$ mmdt-hash $file
簡單分類的mmdt_hash
結構如:index_hash:value_hash
,:
冒號前的是敏感哈希索引,:
冒號後的是敏感哈希真值。敏感哈希索引用於快速定位相似哈希,敏感哈希真值用於計算兩個mmdt_hash
之間的相似度。
2. 計算mmdt_hash
的標準差
計算單個mmdt_hash
值的標準差
- 輸入參數1:單個
mmdt_hash
值 - 螢幕輸出:
mmdt_hash
值的標準差 - 文件輸出:無
# ➜ mmdt-std 5D58573C:B39A90BCDCB4D491BEC74B207AE5FE39
# standard deviation: 45.333946
$ mmdt-std $mmdt_hash_str
mmdt_hash
值的標準差,用于衡量生成的mmdt_hash
的好壞。從大量統計結果看,當標註差低於10.0左右時,計算生成的mmdt_hash
的有效性太差,不能有效表示原始文件。
3. 計算兩個文件的相似度
計算兩個文件的相似度,輸入2個文件路徑,輸出
- 輸入參數1:文件1路徑
- 輸入參數2:文件2路徑
- 螢幕輸出:兩個文件的相似度
- 文件輸出:無
# ➜ mmdt-compare APT28_1 APT28_2
# 0.9929302916167373
$ mmdt-compare $file1 $file2
計算兩個輸入文件的相似度,相似度本質採用歐幾里得距離衡量。計算兩個mmdt_hash
的歐幾里得距離,並歸一化,計算得到相似度。
4. 生成特徵向量集合
生成基於mmdt_hash
的特徵向量集合
- 輸入參數1:已知樣本集的路徑
- 輸入參數2:已知樣本集的標籤文件路徑
- 螢幕輸出:生成特徵向量過程資訊
- 文件輸出:當前文件夾生成兩個文件,
mmdt_feature.label
和mmdt_feature.data
# ➜ mmdt-gen APT28 apt28.tags
# ...
# process: APT28_3, 22
# process: APT28_4, 23
# end gen mmdt set.
# ➜ ll mmdt_feature.*
# -rw-r--r-- 1 ddvv staff 703B 1 16 10:34 mmdt_feature.data
# -rw-r--r-- 1 ddvv staff 133B 1 16 10:34 mmdt_feature.label
$ mmdt-gen $file_path $file_tag
遍歷指定文件目錄,計算該目錄下所有文件的mmdt_hash
,並從標籤文件中讀取對應標籤,生成標籤索引,記錄到特徵向量集合中。輸入的標籤文件採用文件名,標籤
的csv格式存儲。
5. 特徵向量過濾
對生成的特徵向量集合進行過濾處理
- 輸入參數1:特徵向量集合文件
- 輸入參數2:過濾條件的標準差下限
- 螢幕輸出:過濾特徵向量過程資訊
- 文件輸出:覆蓋輸入的特徵向量集合文件路徑
# ➜ mmdt-filter mmdt_feature.data 10.0
# start filter mmdt set.
# old len: 23
# new len: 21
# end filter mmdt set.
# ➜ ll mmdt_feature.*
# -rw-r--r-- 1 ddvv staff 689B 1 16 10:39 mmdt_feature.data
# -rw-r--r-- 1 ddvv staff 133B 1 16 10:34 mmdt_feature.label
$ mmdt-filter $mmdt_feature_file_name $dlt
特徵向量集合的一般過濾方法,計算特徵向量集合中mmdt_hash
值的標準差,移除標準差小於10.0的mmdt_hash
。如前所說,標準差小於10.0的mmdt_hash
有效性很低,無法使用。
6. 簡單分類器特徵向量過濾
對生成的基於mmdt_hash
特徵向量集合進行適配簡單分類器(去重)過濾處理
- 輸入參數1:特徵向量集合文件
- 螢幕輸出:過濾特徵向量過程資訊
- 文件輸出:覆蓋當前路徑的
mmdt_feature.data
文件
# ➜ mmdt-filter-simple mmdt_feature.data
# start filter mmdt set.
# old len: 21
# new len: 21
# end filter mmdt set.
# ➜ ll mmdt_feature.*
# -rw-r--r-- 1 ddvv staff 689B 1 16 10:39 mmdt_feature.data
# -rw-r--r-- 1 ddvv staff 133B 1 16 10:34 mmdt_feature.label
$ mmdt-filter-simple $mmdt_feature_file_name
簡單分類演算法的特定過濾方式,移除完全相同的特徵向量,並覆蓋原始特徵向量集合。
7. 分類器的使用
對指定文件或文件夾進行分類識別
- 輸入參數1:目標文件路徑或文件夾路徑
- 輸入參數2:相似度下限,可選,默認0.95
- 輸入參數3:分類器類型,可選,默認1,簡單分類器
- 螢幕輸出:分類過程結果輸出
- 文件輸出:無
重要,需要將生成的mmdt_feature.label
和mmdt_feature.data
文件拷貝到python_mmdt
的安裝路徑,命令如下:
- 拷貝特徵向量集文件:
mmdt-copy mmdt_feature.data
- 拷貝特徵向量集對應標籤文件:
mmdt-copy mmdt_feature.label
特別注意:
mmdt_feature.label
和mmdt_feature.data
文件名不可更改- 當缺失
mmdt_feature.data
文件時,分類器默認是用python_mmdt
的特徵向量集 - 當缺失
mmdt_feature.label
文件時,分類器仍可以工作,但是判定結果僅輸出是否識別文件,而不會輸出對應的判定標籤
# ➜ mmdt-classify . 0.8 1
# ...
# ./APT28_5,1.000000,group_apt28,39.660364
# ./APT28_2,0.992930,group_apt28,44.917703
# ./APT28_23,1.000000,group_apt28,39.682770
# ...
# 注意:缺失mmdt_feature.label文件時,只會輸出是否匹配,而不會輸出對應標籤
# ➜ mmdt-classify . 0.8 1
# ...
# ./APT28_5,1.000000,matched_0,39.660364
# ./APT28_2,0.992930,matched_0,44.917703
# ./APT28_23,1.000000,matched_0,39.682770
# ...
$ mmdt-classify $file_or_path $sim_value $classify_type
python_mmdt
的核心功能,實現未知樣本的快速識別。mmdt-classify . 0.8 1
表示對當前目錄下的文件進行分類,分類判定分值設定為0.8,分類演算法採用1(簡單分類演算法)。
結束
本篇主要介紹了python_mmdt
的一種簡單分類應用。在實際使用簡單分類器時,python_mmdt
會將特徵向量集合轉成簡單分類特徵庫,通過查找相等的索引哈希,計算對應mmdt_hash
的相似度,滿足判定分值,則返回判定結果。利用python_mmdt
,可以實現自動特徵的提取、積累、復用,通過不斷的積累,期待實現「見過即可查」的目標。
如果惡意程式碼分析人員,可以共建一個mmdt_hash
特徵向量庫,一定可以大大方便惡意程式碼分析這件事。設想一下,每個特徵向量20個位元組,1億條特徵向量的集合大小也就2G左右,1億條特徵向量可以檢出的惡意程式碼數量可能達到上百億,上千億,提供的保護覆蓋面就廣闊的多了。更重要的,共享的mmdt_hash
值也不會導致原始文件資訊的泄漏,但卻能提供非常有價值的資訊。
另外,目前python_mmdt
直接對壓縮包類型的文件計算敏感哈希,其mmdt_hash
值常常不可用,後續會嘗試對壓縮包進行解壓縮,計算實際文件。當前使用哈希索引匹配的的方式,雖然效率高,但是漏報率也高。後續會嘗試使用KNN演算法對特徵向量集合進行計算,提高基檢出率。