一种检测二进制文件中密码常量的方法及系统

文档序号:32747139发布日期:2022-12-30 22:44阅读:25来源:国知局
一种检测二进制文件中密码常量的方法及系统

1.本发明属于密码常量检测技术领域,尤其涉及一种检测二进制文件中密码常量的方法及系统。


背景技术:

2.本部分的陈述仅仅是提供了与本发明相关的背景技术信息,不必然构成在先技术。
3.目前检测二进制文件中密码常量的方法是获取目标二进制文件的字节码并直接通过正则表达式等方式在字节码中进行密码常量的匹配和识别,但是该方法在实际应用过程中存在着很严重的漏报和误报问题。具体问题如下:
4.1、在密码算法的实现过程中,部分短常量因为在源码中是以整数等基本数据类型直接定义的,因此在编译过程中可能会受到编译器的影响,为常量的提取和识别过程带来困难。这些常量在编译过后往往不会像数组一样存储于二进制文件的data段而是以立即数的形式直接嵌入在指令中,与汇编指令混杂在一起,以类似于“mov r1,\#0x01234567”的形式直接加载进寄存器r1使用。
5.但是一方面,某些指令集对指令的长度有限制,如32位指令集中包含操作码在内的最大指令长度位32位,无法容纳32位乃至更长的立即数,因此32位的短常量只能以“movw r1,\#0x4567;movt r1,\#0x0123”的形式分别向寄存器的低16位和高16位分步写入,而64位的短常量更是需要使用两个寄存器一起进行存储。
6.另一方面,考虑到指令格式等原因,在armv7等指令集的每条指令内部,立即数也不一定是连续存储的。这样虽然在运行时常量可以正常起作用,但是在静态的二进制文件中完整的常量被拆成多个部分,分散到不同的指令中,其特征变得不完整,因此需要首先对分散在不同指令中的常量进行恢复才能进行匹配。
7.2、有些复杂的数组常量是有固定的生成算法的,因此开发者在代码编写时可能并不会将密码常量直接写在源代码中,而是预置了算法,在程序执行时再进行常量的初始化操作。这样编写代码主要是为了避免在源代码中定义过大规模的数组,使代码变得简洁并一定程度上减少生成的二进制文件的大小。这些常量在特定程序运行之前要么没有分配固定的地址,要么有地址但还没有进行数据的初始化,即使在静态分析过程中通过反编译工具找到对应的地址也获取不到对应的常量,需要先进行常量的恢复才能进行识别。


技术实现要素:

8.为克服上述现有技术的不足,本发明提供了一种检测二进制文件中密码常量的方法,来识别其中的密码算法。
9.为实现上述目的,本发明的一个或多个实施例提供了如下技术方案:
10.第一方面,公开了一种检测二进制文件中密码常量的方法,包括:
11.建立密码常量匹配规则;
12.提取二进制文件的字节码,来获取直接存在于二进制文件中并可直接识别的标准的常量;
13.对二进制文件进行反编译,并通过对汇编指令的解析来恢复其中被编译器拆分的常量;
14.对二进制文件中的函数进行进一步的分析,通过分析函数的控制流图和数据流图定位到进行常量初始化的代码块,然后通过对目标代码进行模拟执行恢复出未初始化的常量;
15.将标准的常量、编译器拆分的常量及未初始化的常量进行汇总,并通过与建立的密码常量匹配规则进行匹配实现密码算法的识别。
16.作为进一步的技术方案,将密码算法中的常量分为短常量、长常量和数组常量三种类型,将其在二进制文件中的存在形式分为标准的常量、编译器拆分的常量和未初始化的常量三类;
17.其中编译器拆分的常量主要包括部分短常量和长常量;而未初始化的常量主要包括更为复杂的数组常量。
18.作为进一步的技术方案,对二进制文件进行反编译,通过反编译并将汇编代码转化为中间语言进行跨架构的语义分析;
19.在语义分析过程中,通过对寄存器和内存读写指令的解析,对写入同一寄存器和相邻内存单元的常量进行拼接和提取;
20.之后,根据指令之间的逻辑关系与内存地址的连续性进行同一算法中常量的分组识别。
21.作为进一步的技术方案,对二进制文件中的函数进行进一步的分析,通过解析函数的控制流图和数据流图,定位到用于计算常量的独立的算法,提取出相关代码路径。
22.作为进一步的技术方案,对写入同一寄存器和相邻内存单元的常量进行拼接和提取,常量提取过程分为基本块提取、语义分析及指令筛选、寄存器恢复、内存单元恢复和内存重组及常量提取。
23.作为进一步的技术方案,未初始化的常量的提取:
24.首先通过数据流和控制流对函数中的基本块进行过滤,排除掉与常量生成无关的代码,然后再通过提取出的代码路径进行模拟执行实现未初始化的常量的提取。
25.作为进一步的技术方案,代码路径的获取为:控制流图筛选、数据流图筛选及代码路径提取。
26.第二方面,公开了一种检测二进制文件中密码常量的系统,包括:
27.匹配规则建立模块,被配置为:建立密码常量匹配规则;
28.标准的常量提取模块,被配置为:提取二进制文件的字节码,来获取直接存在于二进制文件中并可直接识别的标准的常量;
29.编译器拆分的常量提取模块,被配置为:对二进制文件进行反编译,并通过对汇编指令的解析来恢复其中被编译器拆分的常量;
30.未初始化的常量提取模块,被配置为:对二进制文件中的函数进行进一步的分析,通过分析函数的控制流图和数据流图定位到进行常量初始化的代码块,然后通过对目标代码进行模拟执行恢复出未初始化的常量;
31.常量规则匹配模块,被配置为:将标准的常量、编译器拆分的常量及未初始化的常量进行汇总,并通过与建立的密码常量匹配规则进行匹配实现密码算法的识别。
32.以上一个或多个技术方案存在以下有益效果:
33.与传统的常量检测工具相比,本发明对密码常量进行了更细粒度的分类,并加入了静态的语义分析与动态的模拟执行方法,有针对性地对密码常量进行提取,极大地降低了检测的误报率和漏报率。
34.传统的常量检测方法在检测较短的常量时容易导致误报,因此一些比较短的常量无法作为判断依据;而本方法在加入了语义分析从而能够消除在短常量上的误报,使得很多原来无法使用的常量也可以作为判断依据,扩大了密码算法的检测范围。
35.与传统地静态和动态分析方法相比,本方法将动态与静态的方法结合起来,利用选择性动态执行的方法,克服了动态方法全文件执行困难和代码覆盖率低的问题和静态方法难以处理复杂运算逻辑的问题,极大的提高了密码算法检测的效果。
36.本发明附加方面的优点将在下面的描述中部分给出,部分将从下面的描述中变得明显,或通过本发明的实践了解到。
附图说明
37.构成本发明的一部分的说明书附图用来提供对本发明的进一步理解,本发明的示意性实施例及其说明用于解释本发明,并不构成对本发明的不当限定。
38.图1为本发明的整体构思示意图;
39.图2为编译器拆分的常量的恢复过程图;
40.图3为未初始化的常量的恢复过程图。
具体实施方式
41.应该指出,以下详细说明都是示例性的,旨在对本发明提供进一步的说明。除非另有指明,本文使用的所有技术和科学术语具有与本发明所属技术领域的普通技术人员通常理解的相同含义。
42.需要注意的是,这里所使用的术语仅是为了描述具体实施方式,而非意图限制根据本发明的示例性实施方式。
43.在不冲突的情况下,本发明中的实施例及实施例中的特征可以相互组合。
44.实施例一
45.如图1所示,本实施例公开了一种检测二进制文件中密码常量的方法,包括以下步骤:
46.(1)密码常量匹配规则库的建立:通过分析标准密码算法的官方文档与常见的开源密码库,在收集常量的基础上对常量进行了分类,分别建立不同的匹配规则以便于之后的分类检测;
47.(2)标准的常量的提取:提取二进制文件的字节码,来获取直接存在于二进制文件中并可直接识别的标准的常量;
48.(3)编译器拆分的常量的提取:对二进制文件进行反编译,并通过对汇编指令的解析来恢复其中被编译器拆分的常量;
49.(4)未初始化的常量的提取:对二进制文件中的函数进行进一步的分析,通过分析函数的控制流图和数据流图定位到进行常量初始化的代码块,然后通过对目标代码进行模拟执行恢复出未初始化的常量。
50.(5)密码算法识别:将步骤(2)(3)(4)提取出的常量汇总到一起,并通过与(1)中建立的常量匹配规则进行匹配实现密码算法的识别。
51.在步骤(1)中,常量规则库中对常量进行了细粒度的划分,将密码算法中的常量分为短常量、长常量和数组常量三种类型。随后,在进一步的分析每种常量特性的基础上,将密码常量在二进制文件中的存在形式分为标准的常量、编译器拆分的常量和未初始化的常量三类。其中编译器拆分的常量主要包括部分短常量和长常量;而未初始化的常量主要包括更为复杂的数组等常量。在完成了上述分类的基础上,本方法充分考虑了大小端字节序以及不同数据结构引入的冗余数据等问题,制定了完备的匹配规则,用于后续密码常量的匹配和识别。
52.关于短常量:本发明的密码规则将密码算法中单个尺寸小于8字节的常量划分为短常量,虽然有时多个常量组合在一起完成同一个功能,但是在代码编写过程中一般仍作为几个独立的整数存储,并不会使用数组。例如在md5中需要用到连续16个字节的初始哈希值进行算法结果缓冲区的初始化,在密码标准中其小端字节序的表示为“01 23 45 67 89 ab cd ef fe dc ba 98 76 54 32 10”,但是开发者在编写代码的时候往往使用四个独立的整数进行存储:0x67452301,0xefcdab89,0x98badcfe,0x10325476。
53.因此,创建规则时也将这些常量作为一组短常量,检测过程中,只有检测到一组短常量内的所有常量才能算匹配到密码算法。需要注意的是,若常量本身的长度大于1字节,在匹配时还需要考虑大小端的字节序问题。
54.关于长常量:密码算法中也会用到一些尺寸大于8字节的常量。这些常量往往代表固定的值或有特定的含义,在使用过程中不允许丝毫的更改或拆分,而是将整个常量作为一个整体使用,例如椭圆曲线算法中需要用到的曲线的参数,一些协议或编码标准中用于标识算法类型的字段等。在规则中直接以连续字节码的方式进行定义:“0x3020300c06082a864886f70d020205000410”。
55.关于数组常量:密码算法中也会用到一些数组常量。除了数组单元大于一字节的常量需要考虑字节序问题以外,字节数组在识别过程中也会存在新的问题,有些开发者会使用int数组等来存储字节数组,这样虽然能起到相同的作用,但是却引入了冗余数据,所以在匹配时需要加入正则表达式来兼容有效数据之间的冗余数据,以此来提高匹配效果:“0x63,[1-3],0x7c,[1-3],0x77,[1-3],0x7b
……”

[0056]
在步骤(2)中,因为标准的常量都是直接硬编码于二进制文件中,所以本发明在不对二进制文件做任何修改的基础上,直接将文件以字节码的形式读取出来,作为匹配目标。
[0057]
具体方式为:直接通过python的文件读取函数read以二进制的形式获取目标二进制文件的字节码,作为标准常量识别的目标。
[0058]
在步骤(3)中,本发明通过反编译并将汇编代码转化为中间语言实现了跨架构的语义分析。进行静态语义分析的过程中,首先进行对寄存器中的常量进行恢复,再对内存单元中的常量进行恢复,最后通过对内存地址进行聚类分析实现内存的重构和编译器拆分的常量的提取,具体的,本实施例子通过对“movw,movt,store,load”等寄存器和内存读写指
令的解析,对写入同一寄存器和相邻内存单元的常量进行拼接和提取。之后,本实施例子根据指令之间的逻辑关系与内存地址的连续性实现了同一算法中常量的分组识别。
[0059]
将二进制文件进行反编译之后提升为binaryninja的中间语言的中间表示以兼容不同架构的指令集,实现跨架构的分析。
[0060]
具体的:首先对二进制文件进行了反编译并将其转换为binaryninja中间语言的中间层表示(mlil)。该语言可以将类似“mov r5,r0”的汇编语言翻译成形如“r5=arg1”的形式,不仅具有中间语言都具有的跨架构的特性,而且相对于形如“r5=r0”的中间语言,能够更好的表示变量的作用与变量间的依赖关系,具有更高的可读性,能够极大的方便分析工作。
[0061]
在反编译之后,常量提取过程分为基本块提取、语义分析及指令筛选、寄存器恢复、内存单元恢复和内存重组及常量提取几个阶段,如图2所示:
[0062]
基本块提取:在分析过程中,以基本块作为分析的基本单位。虽然函数是程序中功能的基本单位,但是同一函数内可能会使用不同的算法达到同一目的,如果认为每个函数只包含一种密码算法,很容易引起漏报,基本块粒度的分析就能够包含整组短长量而不引起漏报。
[0063]
语义分析及指令筛选:根据指令的语义对基本块之中的指令进行筛选,筛选出向寄存器和内存中写入数据的指令(set_var,store_var),仅对这一部分指令进行进一步的分析。
[0064]
寄存器恢复:该系统在恢复常量时也是首先对寄存器中的常量进行恢复,通过对“set\_var”指令的解析获取到了向各个寄存器中写入的立即数,对写入同一寄存器不同位置的立即数进行合并,并将所有的立即数都作为短常量记录下来。
[0065]
内存单元恢复:将每条

store\_var’指令写入的数据看作一个内存单元,根据相关指令的语义对每个内存单元的数据进行了恢复。
[0066]“store\_var”指令的源数据可以是

var’和

split\_var’,其中“var”为直接的变量,而“split\_var”为将多个变量拼接后的变量。在解析过程中,该系统首先对源数据中的变量进行了追踪,获取到了每个变量对应的值,然后再按照指令的语义对源数据进行了拼接和恢复,恢复出该指令写入内存单元的常量。
[0067]
内存重构与常量提取:在经过以上分析得到许多的短常量之后,该系统将所有寄存器中的常量看做一组短常量进行识别,而对于加载进内存的常量,则根据常量所在的内存地址对常量进行了聚类,优先将存放于连续内存地址的常量看作一组常量。
[0068]
在步骤(4)中,为解决全文件执行困难和动态方法中代码覆盖率低的问题,首先对整个文件的代码进行静态分析筛选,定位到常量计算相关的代码,再通过对目标代码进行模拟执行来计算和提取相关常量。
[0069]
在进行代码筛选的过程中,分析了常量生成算法的特征,利用了代码的控制流图和数据流图进行分析,定位到不依赖外部数据的循环结构,作为目标代码。
[0070]
利用unicorn仅仅对提取到的代码路径进行执行,极大的提高了分析效率和成功率。
[0071]
具体的,在步骤(4)中,本发明对文件中的所有函数进行了分析,通过解析函数的控制流图和数据流图,定位到用于计算常量的独立的算法,提取出相关代码路径。本发明用
于提取的目标代码特征主要有两个:
[0072]
为了计算数组等复杂的常量,需要用到循环等复杂的代码逻辑,这会在函数的控制流图中体现出来。
[0073]
为保证计算结果为常量,过程中不会用到来自外部的变量,这会在函数的数据流图中体现出来。
[0074]
最后,本发明通过对提取出的代码路径进行模拟执行实现了未初始化常量的计算和提取。
[0075]
在本实施例子中,首先通过数据流和控制流对函数中的基本块进行过滤,排除掉与常量生成无关的代码,然后再通过提取出的路径进行模拟执行实现未初始化的常量的提取。其中代码路径提取过程包括控制流图筛选、数据流图筛选和代码路径提取三个部分:
[0076]
控制流图筛选:因为数组的计算是一个复杂的过程,其过程中往往会用到循环逻辑,因此首先通过检测函数是否存在循环结构来筛选函数。该系统的循环检测是在控制流图上进行的,在拿到函数的控制流图之后,从函数的入口点开始通过深度优先搜索对控制流图中的基本块进行遍历,遍历的同时记录当前已经走过的路径,如果新发现的基本块已经在当前的路径中,那么则认定该函数中存在循环,将该函数标记为目标函数。
[0077]
数据流图筛选:目标函数中除了会包含常量的计算过程外,往往还存在着许多其他功能的代码,这些代码在模拟执行过程中不仅会降低执行效率,还会导致许多数据依赖错误,导致执行失败。幸运的是,常量的初始化过程不仅具有相对独立的计算逻辑,因为程序每次运行生成的值都是常量,所以这部分代码逻辑依赖的数据也往往是常量,可以通过这个特点精确的定位到所有生成常量的代码块。该系统的筛选方法如下:从参数开始,对该函数做数据流分析,即对于一个参数,找到并标记所有受该参数影响的指令和变量,然后从标记的指令和变量出发,不断迭代,直到不再产生新的标记为止。最后该系统将所有带有标记的基本块排除掉,把剩下的基本块作为目标基本块的集合。
[0078]
代码路径提取:该系统首先遍历集合中的基本块,根据基本块在控制流图中的前驱和后继关系进行拓扑排序,构建基本块之间的先后关系,将最前端的基本块的起始地址和最后一个基本块的结束地址分别作为路径的起止点,得到计算常量的代码路径。
[0079]
提取出代码路径之后,该系统利用unicorn对目标进行了模拟执行,并记录执行过程中受到影响的内存单元的地址,在执行结束后提取出对应内存单元中的数据,作为提取出的常量。
[0080]
在步骤(5)中,本发明通过匹配和比较,根据(1)中建立的规则,在步骤(2)(3)(4)提取的常量中实现了密码常量的识别,在识别过程中,该系统使用了最大匹配策略来最大限度的减少误报。
[0081]
具体实现时,用yara匹配工具和直接比较的方法对将上述三个常量提取模块提取出的常量与密码常量规则库做匹配实现了密码算法的识别。在识别过程中对于常量有重合的不同密码算法,该系统通过最大匹配策略来最大限度地排除误报。如md5中的初始哈希值为“0x01234567,0x89abcdef,0xfedcba98,0x76543210”;而sha1的初始哈希值为“0x01234567,0x89abcdef,0xfedcba98,0x76543210,0xf0e1d2c3”,因此实现了sha1的函数中也会识别出md5的常量。而该系统的最大匹配策略只会将其识别为sha1算法可以避免常量重合造成的影响。
[0082]
本实施例子中的方法将常量分为标准的常量、编译器拆分的常量和未初始化的常量三种,并针对不同的常量设计了不同的常量恢复和提取方法,从而实现了密码常量的提取和密码算法的识别。
[0083]
本实施例子中通过分析标准密码算法的官方文档与常见的开源密码库,在收集常量的基础上对常量进行了分类,分别建立不同的匹配规则以便于之后的分类检测;提取二进制文件的字节码,来获取直接存在于二进制文件中并可直接识别的标准的常量;对二进制文件进行反编译并转化为中间语言,并通过对语义的解析来恢复其中被编译器拆分的常量;对二进制文件中的函数进行进一步的分析,通过分析函数的控制流图和数据流图定位到进行常量初始化的代码块,然后通过对目标代码进行模拟执行恢复出未初始化的常量;最后通过将提取出的常量与常量规则进行匹配实现了密码算法的识别。与传统的常量检测工具相比,本发明对密码常量进行了更细粒度的分类,并加入了静态的语义分析与动态的模拟执行方法,有针对性地对密码常量进行提取,极大地降低了检测的误报率和漏报率。
[0084]
实施例二
[0085]
本实施例的目的是提供一种计算机装置,包括存储器、处理器及存储在存储器上并可在处理器上运行的计算机程序,所述处理器执行所述程序时实现上述方法的步骤。
[0086]
实施例三
[0087]
本实施例的目的是提供一种计算机可读存储介质。
[0088]
一种计算机可读存储介质,其上存储有计算机程序,该程序被处理器执行时执行上述方法的步骤。
[0089]
实施例四
[0090]
本实施例的目的是提供一种检测二进制文件中密码常量的系统,包括:
[0091]
匹配规则建立模块,被配置为:建立密码常量匹配规则库;
[0092]
标准的常量提取模块,被配置为:提取二进制文件的字节码,提取出了包含相应常量的字节码,来获取直接存在于二进制文件中并可直接识别的标准的常量;提取出了包含相应常量的字节码作为后续识别的目标之一;
[0093]
编译器拆分的常量提取模块,被配置为:对二进制文件进行反编译并对语义进行解析,对拆分的常量进行拼接、恢复和提取,实现通过对汇编指令的解析来恢复其中被编译器拆分的常量;
[0094]
未初始化的常量提取模块,被配置为:对二进制文件中的函数进行进一步的分析,通过分析函数的控制流图和数据流图定位到进行常量初始化的代码块,然后通过对目标代码进行模拟执行恢复出未初始化的常量;
[0095]
常量规则匹配模块,被配置为:将标准的常量、编译器拆分的常量及未初始化的常量进行汇总,并通过与建立的密码常量匹配规则进行匹配实现密码算法的识别。
[0096]
建立密码常量匹配规则库时,根据密码常量的用途和采用的数据结构对密码常量进行了细粒度的划分,能够更好的适合常量匹配过程,提高匹配的准确度。
[0097]
以上实施例二、三和四的装置中涉及的各步骤与方法实施例一相对应,具体实施方式可参见实施例一的相关说明部分。术语“计算机可读存储介质”应该理解为包括一个或多个指令集的单个介质或多个介质;还应当被理解为包括任何介质,所述任何介质能够存储、编码或承载用于由处理器执行的指令集并使处理器执行本发明中的任一方法。
[0098]
本领域技术人员应该明白,上述本发明的各模块或各步骤可以用通用的计算机装置来实现,可选地,它们可以用计算装置可执行的程序代码来实现,从而,可以将它们存储在存储装置中由计算装置来执行,或者将它们分别制作成各个集成电路模块,或者将它们中的多个模块或步骤制作成单个集成电路模块来实现。本发明不限制于任何特定的硬件和软件的结合。
[0099]
上述虽然结合附图对本发明的具体实施方式进行了描述,但并非对本发明保护范围的限制,所属领域技术人员应该明白,在本发明的技术方案的基础上,本领域技术人员不需要付出创造性劳动即可做出的各种修改或变形仍在本发明的保护范围以内。
当前第1页1 2 
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1