首页
社区
课程
招聘
[原创]python_mmdt:从0到1--实现简单恶意代码分类器(二)
发表于: 2021-1-21 22:44 7761

[原创]python_mmdt:从0到1--实现简单恶意代码分类器(二)

2021-1-21 22:44
7761

上篇文章python_mmdt:一种基于敏感哈希生成特征向量的python库(一)我们介绍了一种叫mmdt_hash(mmdt敏感哈希)生成方法,并对其中的概念做了基本介绍。本篇,我们重点谈谈mmdt_hash的分类应用场景。

设想这么一个需求场景:有一批文件需要判定是否属于恶意文件,并且需要给出恶意文件所属的家族类型。这个需求该怎么高效处理呢?处理过程又该怎么固化成我们自己的经验呢?当以后面临同样的需求时,能否复用之前的结果呢?

我能想到的方法有以下三种:

针对以上三种方法,分别讨论其优点和缺点:

上诉需求场景也许太过特殊化,但还是有一定的代表性的。针对以上的需求场景,python_mmdt工具的分类算法,可以很好的覆盖上述场景。

使用python_mmdt的做法,具有以下优点等

同时,有三个缺点需要指出:

因此,可以在不同的场景使用不同的判定分值,判定分值越高,准确率越高;判定分值越低,漏报率越低。如判定分值设定为1.0,则几乎没有误报;如判定分值设定设定为0.85,则比判定分值设为0.95的漏报率低。

使用pip安装python_mmdt之后,会向系统中添加如下命令:

mmdt_hash值结构如:"index_hash:value_hash"index_hash是4字节敏感哈希索引,value_hash是16字节敏感哈希值,两个哈希值之间使用:冒号隔开。敏感哈希索引用于快速定位相似哈希,敏感哈希值用于计算两个mmdt_hash之间的相似度。

mmdt_hash值的标准差,用于衡量生成的mmdt_hash的好坏。从大量统计结果看,当标准差低于10.0左右时,计算生成的mmdt_hash
的有效性太差,不能有效表示原始文件。

计算两个文件的相似度,输入2个文件路径,输出

计算两个输入文件的相似度,相似度本质采用欧几里得距离衡量。计算两个mmdt_hash的欧几里得距离,并进行归一化处理,得到相似度。

遍历指定文件目录,计算该目录下所有文件的mmdt_hash,并从标签文件中读取对应标签,生成标签索引,组合到特征向量集合中。输入的标签文件采用文件名,标签csv格式存储。mmdt_feature.label是本特征向量集合的标签文件,用于将标签索引还原为原始名称;mmdt_feature.data是特征向量集合文件。两文件都使用pickle序列化,同时使用zip压缩保存。

特征向量集合的通用过滤方法,计算特征向量集合中mmdt_hash值的标准差,移除标准差小于10.0的mmdt_hash。如前所说,标准差小于10.0的mmdt_hash有效性很低,无法使用。

简单分类算法的特定过滤方式,移除完全相同的特征向量,并覆盖原始特征向量集合。

需要将特征向量集合文件或特征向量集合标签文件拷贝到工具目录,才可正常使用分类功能。

重要说明,需要将生成的mmdt_feature.labelmmdt_feature.data文件拷贝到python_mmdt的安装路径,命令如下:

特别注意:

python_mmdt的核心功能,实现未知样本的快速识别。mmdt-classify . 0.8 1表示对当前目录下的文件进行分类,分类判定分值设定为0.8,分类算法采用1(简单分类算法)。

本篇主要介绍了python_mmdt的一种简单分类应用。在实际使用简单分类器时,python_mmdt会将特征向量集合转成简单分类特征库,通过查找相等的索引哈希,计算对应mmdt_hash的相似度,满足判定分值,则返回判定结果。利用python_mmdt,可以实现自动特征的提取、积累、复用,通过不断的积累,期待实现“见过即可查”的目标。

另外,目前python_mmdt直接对压缩包类型的文件计算敏感哈希,其mmdt_hash值常常不可用,后续会尝试对压缩包进行解压缩,计算实际文件。当前使用哈希索引匹配的的方式,虽然效率高,但是漏报率也高。后续会尝试使用KNN算法对特征向量集合进行计算,提高基检出率。

如果恶意代码分析人员,可以共建一个mmdt_hash特征向量库,一定可以大大方便恶意代码分析这件事。设想一下,每个特征向量20个字节,1亿条特征向量的集合大小在2G左右,1亿条特征向量可以检出的恶意代码数量可能达到上百亿,上千亿,提供的恶意代码检测覆盖面就广阔的多了。更重要的,共享mmdt_hash值不会导致原始文件信息的泄漏,同时又能提供非常有价值的信息。

 
 
# ➜ mmdt-hash APT28_1
#   5D58573C:B39A90BCDCB4D491BEC74B207AE5FE39
$ mmdt-hash $file
# ➜ mmdt-hash APT28_1
#   5D58573C:B39A90BCDCB4D491BEC74B207AE5FE39
$ mmdt-hash $file
# ➜ mmdt-std 5D58573C:B39A90BCDCB4D491BEC74B207AE5FE39
#   standard deviation: 45.333946
$ mmdt-std $mmdt_hash_str
# ➜ mmdt-std 5D58573C:B39A90BCDCB4D491BEC74B207AE5FE39
#   standard deviation: 45.333946
$ mmdt-std $mmdt_hash_str
# ➜ mmdt-compare APT28_1 APT28_2
#   0.9929302916167373
$ mmdt-compare $file1 $file2
# ➜ mmdt-compare APT28_1 APT28_2
#   0.9929302916167373
$ mmdt-compare $file1 $file2
# ➜ 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-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-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-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-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
# ➜ 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
# ➜ mmdt-copy mmdt_feature.data
# ➜ mmdt-copy mmdt_feature.label
# ➜ mmdt-copy mmdt_feature.data
# ➜ mmdt-copy 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文件时,只会输出是否匹配,而不会输出对应标签,match_0表示匹配0号标签索引
# ➜ 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
# ➜ 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文件时,只会输出是否匹配,而不会输出对应标签,match_0表示匹配0号标签索引
# ➜ 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
 
 
 
1
2
3
# ➜ mmdt-hash APT28_1
#   5D58573C:B39A90BCDCB4D491BEC74B207AE5FE39
$ mmdt-hash $file
1
2
3
# ➜ mmdt-std 5D58573C:B39A90BCDCB4D491BEC74B207AE5FE39
#   standard deviation: 45.333946
$ mmdt-std $mmdt_hash_str
1
2
3
# ➜ mmdt-compare APT28_1 APT28_2
#   0.9929302916167373
$ mmdt-compare $file1 $file2
1
2
3
4
5
6
7
8
9
# ➜ 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
1
2
3
4
5
6
7
8
9
# ➜ 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

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 1
支持
分享
最新回复 (2)
雪    币: 189
活跃值: (142)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
2
有几个疑问向大佬请教 1.mmdt 和ssdeep,tlsh 这两种二进制模糊hash算法  对比效果如何 2.像golang这种恶意样本的相似度比较,mmdt能不能凸显出价值, golang样本大部分都是标准库,两个功能不一样的样本,可能90%以上相似  3.  x86,x64,arm,mips这种不同指令集,但是功能一样的样本相似度怎么样 4. hash值比较的效率怎么样,1亿 条记录,比较能有多快
2021-2-1 15:56
0
雪    币: 1887
活跃值: (2766)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
3
waqxr 有几个疑问向大佬请教 1.mmdt 和ssdeep,tlsh 这两种二进制模糊hash算法 对比效果如何 2.像golang这种恶意样本的相似度比较,mmdt能不能凸显出价值, golang样本大部 ...
别别别,不是大佬。交流交流:
1. tlsh没有研究过,暂时不清楚。和ssdeep的对比主要有几点:a.mmdt比ssdeep更不敏感,hash值空间更小,更容易发生碰撞,针对恶意代码检出来说,优点是提高了检出率,缺点是提高了误报率;b. mmdt比ssdeep检索效率更高,ssdeep最大的问题就是检索效率,例如1条ssdeep值需要和1万条ssdeep值比较,必须依次进行相似度比较,比较过程难以优化,而mmdt值由于其“组装”的特性,可是使用很多方法进行优化,例如采用矩阵运算等。
2. golang样本暂时没有进行过测试,在恶意代码检测方面,暂时不好评估准确率和误报率,但是初步考虑应该可以通过相似度进行区分。
3. mmdt并不涉及指令层面的解析,都是文件层面的解析,所以虽然是同一份代码,但是不同平台生成的文件是不同的,所以是没法考虑相似度的。只有同平台下有收集到相似的样本,比较相似度才有意义。
4. 这个就是比较算法的优化问题,目前0.2.2版本新增了knn算法,采用python的numpy库实现,万级库的检索,应该在10ms级别。具体能达到多快,这个需要看能优化到什么程度了。
2021-2-2 12:22
0
游客
登录 | 注册 方可回帖
返回
//