二进制代码比对分析研究

0. 引言

传统的恶意代码攻击溯源方法是通过单个组织的技术力量,获取局部的攻击相关信息,无法构建完整的攻击链条,一旦攻击链中断,往往会使得前期大量的溯源工作变得毫无价值。同时,面对可持续、高威胁、高复杂的大规模网络攻击,没有深入分析攻击组织之间的关系,缺乏利用深层次恶意代码的语义知识,后续学术界也提出了一些解决措施。

下图展示了Lazarus盗窃孟加拉国央行的行动流程,通过Alreay攻击组件篡改SWIFT软件,使得黑客能够操作银行账号任意进行转账,从而窃取了8100万美元。同时,在2017年最早版本的WannaCry病毒中,安全厂商发现了其中存在着Lazarus使用过的代码,从而判断该病毒是由Lazarus制作的。Lazarus确实是一支非常厉害的APT组织。

为了进一步震慑黑客组织与网络犯罪活动,目前学术界和产业界均展开了恶意代码溯源分析与研究工作。其基本思路是:

  • 同源分析: 利用恶意样本间的同源关系发现溯源痕迹,并根据它们出现的前后关系判定变体来源。恶意代码同源性分析,其目的是判断不同的恶意代码是否源自同一套恶意代码或是否由同一个作者、团队编写,其是否具有内在关联性、相似性。从溯源目标上来看,可分为:
    • 恶意代码家族溯源
    • 作者溯源
  • 家族溯源: 家族变体是已有恶意代码在不断的对抗或功能进化中生成的新型恶意代码,针对变体的家族溯源是通过提取其特征数据及代码片段,分析它们与已知样本的同源关系,进而推测可疑恶意样本的家族。例如,Kinable等人提取恶意代码的系统调用图,采用图匹配的方式比较恶意代码的相似性,识别出同源样本,进行家族分类。
  • 作者溯源: 恶意代码作者溯源即通过分析和提取恶意代码的相关特征,定位出恶意代码作者特征,揭示出样本间的同源关系,进而溯源到已知的作者或组织。例如,Gostev等通过分析Stuxnet与Duqu所用的驱动文件在编译平台、时间、代码等方面的同源关系,实现了对它们作者的溯源。

0x1:同源分析

0x2:恶意代码家族和作者的编码相似性

编码相似性是指恶意代码在编码环境及特征上具有相似性,基于恶意代码的编码特性,同一作者或者同一家族的恶意代码在内容和结构上往往存在相似之处,这为恶意代码的溯源提供了线索。

1、同家族恶意代码的编码相似性(功能相似)

恶意代码以功能行为划分家族,同家族恶意软件的代码和行为具有相似甚至相同部分。作者为了快速构建恶意代码,复用已有恶意代码生成变体,使得同家族恶意代码中大部分代码及资源保持不变。

而这些特性在编译后文件中表现为代码片段的相似性,其相似性主要集中在执行敏感操作的代码元素中,例如系统调用、关键字符串(如权限、重打包名字)和代码结构(逻辑结构)等。

  • 系统调用:同家族恶意代码为了实施相同的功能行为,往往调用相同或相似的系统敏感函数API.
  • 关键字符串:主要指的是硬编码字符串,同家族恶意代码为实现特定元素相关的行为,会在代码中采用关键字符串.
  • 代码结构:同家族恶意代码在实施相同的功能行为时,会执行相似代码流程,因此其代码结构相似.

利用上述特性识别恶意代码变体,并根据已知恶意代码家族揭示变体家族。

2、同作者或团队的编码相似性(风格相似)

同作者或团队编写的恶意代码由于受拥有的相关领域知识、经验、编码工具等限制,使得编写的代码在内容和结构上具有相似性。

这种相似性抽象刻画了作者的编码风格,即使通过混淆技术隐藏或不留下其身份信息,但是人的编码习惯不会因为创建非同恶意代码而产生强大的差异。

基于人的编程习惯,研究人员可挖掘和利用代码风格追踪到相关的作者。

http://www.jos.org.cn/html/2019/8/5767.htm 

https://blog.csdn.net/Eastmount/article/details/103703819 

Relevant Link:  

https://blog.csdn.net/Eastmount/article/details/103703819

 

恶意代码家族和作者的编码相似性

 

  

1. 什么是二进制代码同源比对分析

0x1:概念简介

在闭源情况下,寻找并定位二进制代码之间存在(源)代码复用、存在的差异。

0x2:同源分析任务的不同场景

  • 相同版本的源码、面向相同的架构、使用不同的编译选项进行编译。
  • 相同版本的源码、使用相同的编译选项进行编译、面向不同的架构
  • 部分相同的源码(函数模块抄袭)、使用相同的编译选项进行编译、面向不同的架构 

 

2. 二进制比对的应用场景

  • 软件(代码模块)剽窃鉴定。
  • 补丁分析:对更新前后的二进制程序进行相似性分析,得到所更改的内容并分析漏洞成因
  • 恶意代码同源检测:通过代码片段的相似性发现恶意代码的家族关系,尤其对APT样本进行细粒度的同源分析是攻击溯源的重要手段
  • 逆向分析辅助:通过相似性对比,发现样本已经被识别的部分,从而减轻逆向工作量
  • 通过已知漏洞识别发现未知漏洞:例如我们已知某种缓冲区移出漏洞的代码结构,可以基于这个结构,对新的未知样本进行相似性搜索,从而提高漏洞挖掘的效率
  • 自主可控分析
  • 代码成分分析

0x1:软件成分分析与剽窃检测

通过对可疑软件的二进制与受保护软件的二进制进行比对分析,能够检测可疑软件中代码的抄袭情况。

 

通过测试多款市面上的压缩软件与开源软件7zip比对,发现了几款软件存在大量函数和代码片断与7zip相同或逻辑相似。

某厂商交换机和思科Catalyst 2960X,从公开渠道获取的固件进行比对分析。发现存在高度相似性,可以断定两份固件大部分代码同源。

0x2:已知漏洞识别

通过对待检测二进制代码与漏洞库中存在漏洞的二进制函数进行比对,定位漏洞的影响范围。

CVE-2019-1208漏洞是微软今年6月公布的一个vbscript漏洞,随后在微软的9月补丁星期二发表并修复,报告中提到这个漏洞通过补丁比可以被发现在rtJoin函数中,在对数组内的元素进行操作前后,加了一对SafeArrayLock/SafeArrayUnlock函数。

0x3:恶意代码同源分析

通过代码片段的相似性发现恶意代码的家族关系,尤其对APT样本进行细粒度的同源分析是攻击溯源的重要手段。

多款后门病毒利用某驱动软件短时间内大规模感染数万台电脑,通过二进制同源代码比对,我们发现推送病毒执行的升级模块,与“人生日历”升级模块代码存在同源性。

0x4:逆向工程辅助

在对IOT设备逆向过程中,二进制代码比能够直接帮助逆向人员完成了前期的大量工作。通过代码溯源可以告诉逆向人员固件中使用的开源库情况,通过插件配置甚至能够标注出部分模块函数功能,直接搜索易受攻击的函数。

 

3. 二进制同源分析的技术挑战

  • 粒度:识别同源代码的粒度(片段、函数、或整个二进制文件),独立越细难度越大
  • 准确性:高准确性可以大大减少后续人工处理开销,应用结果可信
  • 跨平台:相同源代码可能被编译成不同平台(指令集、操作系统)上的二进制代码,需要不受平台特性影响识别代码同源
  • 抗混淆:二进制代码被混淆变换,加大同源分析的难度,要从语义层面识别同源代码
  • 性能:对于大代码,海量代码的细粒度比对存在性能问题,需要并行、可扩展的解决方案

 

4. 二进制代码比对研究现状

  • 基于控制流图(CFG)
    • Genius
    • Gemini
    • DiscovRE
  • 基于原始字节
    • aDff
  • 基于符号执行
    • Esh
    • BinHunt
    • iBinHunt
  • 基于多种特征
    • Diaphora
    • BinDiff
  • 基于程序依赖图
    • GPLAG
    • CBCD
  • 基于树
    • Deckard
    • TEDEM
  • 基于API
    • SCDG
    • API2VEC
  • 基于自然语言处理
    • Asm2Vec
  • 基于I/O样例
    • Multi-MH
    • BinGo

 

5. BinDiff [Google]

使用多种特征进行同源分析,包括:

  • 基本块数量
  • 基本块反编译代码
  • 控制流图
  • 函数调用等等

实现多平台的二进制代码比对。

Relevant Link:   

http://vlambda.com/wz_5fwPIikIeMq.html
https://www.zynamics.com/software.html
https://www.cnblogs.com/lsdb/p/10543411.html

 

6. 基于控制流图CFG [angr]

在二进制代码中寻找并且利用漏洞是一项非常具有挑战性的工作,它的挑战性主要在于人工很难直观的看出二进制代码中的数据结构、控制流信息等。

angr是一个基于python的二进制漏洞分析框架,它将以前多种分析技术集成进来,方便后续的安全研究人员的开发。­­­它能够进行动态的符号执行分析(如,KLEE和Mayhem),也能够进行多种静态分析。

0x1:angr的简要过程

  • 将二进制程序载入angr分析系统
  • 将二进制程序转换成中间件语言(intermediate representation, IR)
  • 将IR语言转换成语义较强的表达形式,比如,这个程序做了什么,而不是它是什么。
  • 执行进一步的分析,比如,完整的或者部分的静态分析(依赖关系分析,程序分块)、程序空间的符号执行探索(挖掘溢出漏洞)、一些对于上面方式的结合。

Relevant Link:    

https://www.anquanke.com/post/id/85039

 

7. Multi-MH

通过求解不同输入的输出结果实现无源代码跨平台二进制比对。

大致方法是:

  • 汇编指令转换成中间表示
  • 使用符号执行求解基本块输入/输出值
  • 使用MinHash作为LSH求解距离
  • 基于CFG(控制流图)匹配实现函数比对

 

8. Genius

基于ACFG检测跨平台的二进制代码相似检测。

大致方法是:

  • 提取函数ACFG(属性控制流图,包含基本块特征的控制流图)
  • 对海量ACFG聚类
  • 使用NN算法计算函数向量
  • LSH全局搜索

这种方法的好处在于:提出将函数之间图的相似性转换成与中心节点距离的相似性。

这种方法的不足之处在于:

  • 仅依赖于CFG,无法抵抗改变CFG的代码混淆
  • 人为的选择基本块属性,存在一定局限性,依赖领域经验

 

9. Gemini

基于ACFG生成向量表示检测跨平台的二进制代码相似检测。

大致方法是:

  • 提取函数ACFG
  • 基于神经网络生成向量表示
  • 使用孪生网络实现相似性检测

 

10. αDiff

对跨版本,跨编译器,跨平台的二进制进行相似代码检测。

特征提取:

  • 原始字节
  • 函数调用图
  • 导入函数

大致方法:

  • 基于CNN(卷积神经网络)孪生网络将原始字节转成向量,
  • 调用图的出度入度,
  • 导入函数的匹配,

  

11. Asm2Vec

不可跨平台,基于自然语言处理,仅使用语义表示,实现抗代码混淆和编译优化的二进制同源检测。

大致方法:

  • 利用PV-DM模型为每个函数生成语义向量
  • 使用余弦距离判断同源相似度

这个方法的好处是:

  • 基于自然语言处理
  • 与现有静态工具比较,证明了自然语言处理技术在二进制代码比对的有效性

这个方法的缺点是:

  • 不可跨平台
  • 局限于单一平台,无法进行跨平台的二进制代码比对

 

12. 基于LLVM IR的跨架构函数比较算法

大致方法:

  • 使用RetDec工具将二进制文件转化为LLVM IR
  • 使用改编的SimHash方法将函数转化为向量形式并计算函数间相似度

 

Relevant Link:  

https://edu.heibai.org/%E4%BA%8C%E8%BF%9B%E5%88%B6%E4%BB%A3%E7%A0%81%E6%AF%94%E5%AF%B9%E5%88%86%E6%9E%90%E4%BA%91%E5%B9%B3%E5%8F%B0BigCodeDiff.pdf 

 

13. bin2img图像相似度分析

对于二进制程序文件,天生就是ascii img图像,我们可以将bin文件转换为灰度图(grey image),之后就可以利用图像领域的方法来进行分析。

要识别两张图片是否相似,从机器学习的的角度来说,首先要提取图片的特征,将这些特征进行分类处理,训练并建立模型,然后在进行识别。

为了得到两张相似的图片,在这里通过以下几种计算方式来计算图片的相似度:

  • 直方图计算图片的相似度
  • 通过哈希值,汉明距离计算
  • 通过图片的余弦距离计算
  • 通过图片结构度量计算

0x1:直方图计算图片的相似度

利用直方图计算图片的相似度时,是按照颜色的全局分布情况来看待的,无法对局部的色彩进行分析,同一张图片如果转化成为灰度图时,在计算其直方图时差距就更大了。

本质上说,直方图提取的特征,丢失了原始图像的大量信息。

0x2:通过哈希值,汉明距离计算

1、图像指纹

所谓图像指纹,和人的指纹一样,是身份的象征,而图像指纹简单点来讲,就是将图像按照一定的哈希算法,经过运算后得出的一组二进制数字。

2、汉明距离

假如一组二进制数据为101,另外一组为111,那么显然把第一组的第二位数据0改成1就可以变成第二组数据111,所以两组数据的汉明距离就为1。

简单点说,汉明距离就是一组二进制数据变成另一组数据所需的步骤数,显然,这个数值可以衡量两张图片的差异,

  • 汉明距离越小,则代表相似度越高。
  • 汉明距离为0,即代表两张图片完全一样。

3、感知哈希算法

感知哈希算法是一类算法的总称,从原理上类似模糊化哈希和局部敏感哈希,包括aHash、pHash、dHash。 

1)平均哈希算法(aHash)

该算法是基于比较灰度图每个像素与平均值来实现。

aHash的hanming距离步骤:

  • 先将图片压缩成8*8的小图
  • 将图片转化为灰度图
  • 计算图片的Hash值,这里的hash值是64位,或者是32位01字符串
  • 将上面的hash值转换为16位的
  • 通过hash值来计算汉明距离
# 均值哈希算法
def ahash(image):
    # 将图片缩放为8*8的
    image = cv2.resize(image, (8, 8), interpolation=cv2.INTER_CUBIC)
    # 将图片转化为灰度图
    gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
    # s为像素和初始灰度值,hash_str为哈希值初始值
    s = 0
    # 遍历像素累加和
    for i in range(8):
        for j in range(8):
            s = s + gray[i, j]
    # 计算像素平均值
    avg = s / 64
    # 灰度大于平均值为1相反为0,得到图片的平均哈希值,此时得到的hash值为64位的01字符串
    ahash_str = ''
    for i in range(8):
        for j in range(8):
            if gray[i, j] > avg:
                ahash_str = ahash_str + '1'
            else:
                ahash_str = ahash_str + '0'
    result = ''
    for i in range(0, 64, 4):
        result += ''.join('%x' % int(ahash_str[i: i + 4], 2))
    # print("ahash值:",result)
    return result

2)感知哈希算法(pHash)

均值哈希虽然简单,但是受均值影响大。如果对图像进行伽马校正或者进行直方图均值化都会影响均值,从而影响哈希值的计算。所以就有人提出更健壮的方法,通过离散余弦(DCT)进行低频提取。

离散余弦变换(DCT)是种图像压缩算法,它将图像从像素域变换到频率域。然后一般图像都存在很多冗余和相关性的,所以转换到频率域之后,只有很少的一部分频率分量的系数才不为0,大部分系数都为0(或者说接近于0)。

  • 缩小图片:32 * 32是一个较好的大小,这样方便DCT计算转化为灰度图
  • 计算DCT:利用Opencv中提供的dct()方法,注意输入的图像必须是32位浮点型,所以先利用numpy中的float32进行转换
  • 缩小DCT:DCT计算后的矩阵是32 * 32,保留左上角的8 * 8,这些代表的图片的最低频率
  • 计算平均值:计算缩小DCT后的所有像素点的平均值。
  • 进一步减小DCT:大于平均值记录为1,反之记录为0.
  • 得到信息指纹:组合64个信息位,顺序随意保持一致性。
  • 最后比对两张图片的指纹,获得汉明距离即可。
# phash
def phash(path):
    # 加载并调整图片为32*32的灰度图片
    img = cv2.imread(path)
    img1 = cv2.resize(img, (32, 32),cv2.COLOR_RGB2GRAY)
​
    # 创建二维列表
    h, w = img.shape[:2]
    vis0 = np.zeros((h, w), np.float32)
    vis0[:h, :w] = img1
​
    # DCT二维变换
    # 离散余弦变换,得到dct系数矩阵
    img_dct = cv2.dct(cv2.dct(vis0))
    img_dct.resize(8,8)
    # 把list变成一维list
    img_list = np.array().flatten(img_dct.tolist())
    # 计算均值
    img_mean = cv2.mean(img_list)
    avg_list = ['0' if i<img_mean else '1' for i in img_list]
    return ''.join(['%x' % int(''.join(avg_list[x:x+4]),2) for x in range(0,64,4)])

Phash哈希算法过于严格,不够精确,更适合搜索缩略图,为了获得更精确的结果可以选择感知哈希算法,它采用的是DCT(离散余弦变换)来降低频率的方法。

3)差异值哈希算法(dHash)

  • 先将图片压缩成9*8的小图,有72个像素点
  • 将图片转化为灰度图
  • 计算差异值:dHash算法工作在相邻像素之间,这样每行9个像素之间产生了8个不同的差异,一共8行,则产生了64个差异值,或者是32位01字符串。
  • 获得指纹:如果左边的像素比右边的更亮,则记录为1,否则为0.
  • 通过hash值来计算汉明距离
# 差异值哈希算法
def dhash(image):
    # 将图片转化为8*8
    image = cv2.resize(image, (9, 8), interpolation=cv2.INTER_CUBIC)
    # 将图片转化为灰度图
    gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
    dhash_str = ''
    for i in range(8):
        for j in range(8):
            if gray[i, j] > gray[i, j + 1]:
                dhash_str = dhash_str + '1'
            else:
                dhash_str = dhash_str + '0'
    result = ''
    for i in range(0, 64, 4):
        result += ''.join('%x' % int(dhash_str[i: i + 4], 2))
    # print("dhash值",result)
    return result

0x3:通过余弦相似度(cosin)

把图片表示成一个向量,通过计算向量之间的余弦距离来表征两张图片的相似度。

1、对图片进行归一化处理

# 对图片进行统一化处理
def get_thum(image, size=(64, 64), greyscale=False):
    # 利用image对图像大小重新设置, Image.ANTIALIAS为高质量的
    image = image.resize(size, Image.ANTIALIAS)
    if greyscale:
        # 将图片转换为L模式,其为灰度图,其每个像素用8个bit表示
        image = image.convert('L')
    return image

2、计算余弦距离

# 计算图片的余弦距离
def image_similarity_vectors_via_numpy(image1, image2):
    image1 = get_thum(image1)
    image2 = get_thum(image2)
    images = [image1, image2]
    vectors = []
    norms = []
    for image in images:
        vector = []
        for pixel_tuple in image.getdata():
            vector.append(average(pixel_tuple))
        vectors.append(vector)
        # linalg=linear(线性)+algebra(代数),norm则表示范数
        # 求图片的范数??
        norms.append(linalg.norm(vector, 2))
    a, b = vectors
    a_norm, b_norm = norms
    # dot返回的是点积,对二维数组(矩阵)进行计算
    res = dot(a / a_norm, b / b_norm)
    return res

 

0x4:图片SSIM(结构相似度量)

SSIM(Structural SIMilarity)是一种全参考的图像质量评价指标,分别从

  • 亮度
  • 对比度
  • 结构

三个方面度量图像相似性。

SSIM取值范围[0, 1],值越大,表示图像失真越小。

在实际应用中,可以利用滑动窗将图像分块,令分块总数为N,考虑到窗口形状对分块的影响,采用高斯加权计算每一窗口的均值、方差以及协方差,然后计算对应块的结构相似度SSIM,最后将平均值作为两图像的结构相似性度量,即平均结构相似性SSIM。

ssim1 = compare_ssim(img1, img2, multichannel=True)

Relevant Link:  

https://zhuanlan.zhihu.com/p/68215900
https://zhuanlan.zhihu.com/p/67199699 

 

posted @ 2020-08-12 13:32  郑瀚Andrew  阅读(3803)  评论(5编辑  收藏  举报