基于动态执行的基带固件函数安全性分析*

2022-11-09 00:51曲海鹏吕文杰
关键词:基带固件二进制

曲海鹏, 于 芮, 孙 磊, 吕文杰

(中国海洋大学信息科学与工程学院, 山东 青岛 266100)

基带处理器是移动通信设备的重要组成部分,负责处理与蜂窝网络的通信,拥有独立的RAM和固件。基带固件使用C编写,不使用libc、glibc等通用的函数库,使用静态编译且剥离了调试信息,运行于实时操作系统(RTOS)和ARM处理器上,包含有与蜂窝协议相关的众多功能[1]。虽然基带固件的这些特点给逆向分析和漏洞发掘带来很大困难,但基带固件漏洞近年来还是不断被曝出[2-4]。由于基带固件的闭源性和大量使用内存拷贝操作,我们认为更有针对性的安全分析将可能发现其更多安全漏洞。目前,研发基带处理器的厂商主要包括,高通,三星,华为等。其中,本文研究的是三星Shannon基带芯片,其处理器架构是Armv7-R,提取得到的基带固件大小有36.5 MB,经IDA识别得到的函数达61 535个。

可执行目标文件中的调试信息中包含有函数名称[5],因此针对调试信息剥离的基带固件的安全分析分为函数安全性分析和漏洞发掘两个阶段。函数安全性分析的目标是重新识别基带固件中执行可变长度内存拷贝功能的危险函数,漏洞发掘的目标是发现由于危险函数的不正确使用,导致的缓冲区溢出漏洞。第一阶段的分析方法多使用基于二进制代码相似性[6]比对的函数识别方法,以目前应用最广泛的 Google BinDiff[7-8]为例,通过将目标固件与使用标准函数库编译得到的固件进行比对,可匹配出与标准函数库中危险函数类似的函数。BinDiff通过对比多种语义特征,匹配输入文件之间相似的函数,但因基带固件函数重写、调试信息剥离、静态链接等方式导致只能发现少量危险函数。

2012年RP Weinmann[3]首次系统性的介绍了在基带固件中发现的内存损坏漏洞,并搭建伪基站对漏洞实现了利用。在RP Weinmann的工作中,首先使用二进制文件对比工具BinDiff,对固件中使用的内存拷贝危险函数进行了重新识别,之后,通过分析危险函数处的代码实现和相关协议规范,发现了多个内存破坏缺陷。在之后的国际黑客会议上,针对基带发现的漏洞多是由于固件中的危险函数导致的缓冲区溢出漏洞,例如函数memcpy()[9]和memcpy_s()[2]。

现在已有多种对危险函数进行重写识别的二进制文件对比工具。BinDiff是目前最流行,应用最广泛的对比工具。BinDiff依赖于IDA,并将IDA数据库文件作为输入文件,它忽略汇编层指令的结构,工作在函数的控制流程图和调用关系图层面上,基于图形结构中所包含的语义特征进行相似性检测,具有很好的抗混淆[10-11]特性。BinDiff根据两种图形结构中基本块的数量,基本块间边的数量和子函数调用关系,为每个函数计算得到一个“指纹”,并利用该“指纹”在两个二进制文件中匹配相似的函数。此外,对于一些仅使用以上两种图形结构,无法识别相似性的函数,BinDiff通过比较函数内容的哈希值、函数内循环的次数和函数内引用的字符串等进行更深一步的探索。另外和BinDiff一样,工作在抽象图形模型层面上的二进制对比工具还有Diaphora[12-13],Turbodiff[14],BinKit[15]。近几年,随着机器学习方法的流行,跨学科知识的交叉开始在基于语义特征的相似性检测中得到应用,包括Asm2vec模型[16],SAFE网络[17]等。

另一种识别危险函数的二进制文件对比工具IDA FLIRT[18],则基于函数的二进制字节序列进行比对。FLIRT创建了一个包含所有想要识别的库函数的数据库,每个库函数在FLIRT数据库中被表示为一个签名,这个签名是由函数的前32个字节组成的,其中包括所有的变体字节。通过将待识别的函数的字节签名与数据库中的签名进行对比,FLIRT判断其是否为已知的库函数。但是,与使用抽象图形模型的BinDiff对比,FLIRT灵活性较差。

其他的开源的二进制文件对比工具还包括主要应用于微软的补丁分析的eEye Binary Diffing Suite[19];适用于较小的文件比较的IDACompare[20]等。

本文提出了一种基于动态执行的基带固件函数安全性分析方法DEx。DEx方法通过把固件正确映射到内存中,对固件函数实现调用执行。同时,针对危险函数的特征,DEx捕获函数动态执行过程中产生的三种语义信息,包括函数对内存的读写,存储在寄存器R0中的返回值以及函数执行过程中产生的输出内容,并设置优先级排序,以用于后续函数的安全性分析。

动态执行方法DEx与传统的二进制代码相似性方法存在几个重要的不同之处。首先,DEx方法只对基带固件进行分析。与二进制代码相似性方法还需使用到对比文件相比,只需要用到目标固件即可。其次,DEx更加关注危险函数所包含的语义特征。与二进制代码相似性方法所使用的多种的、广泛的特征信息相比,更具针对性。同时,本文基于DEx方法,实现了dyndiff工具,评估结果显示,dyndiff提高了基带固件中危险函数的识别准确率。最后,阐述了本文所做的函数安全性分析工作在后续漏洞发掘工作中的应用。

1 方法和实现

1.1 问题分析

为了降低文件的大小和更好的抵抗逆向分析,基带固件中包括符号表在内的调试信息都是被剥离的。针对调试信息剥离的基带固件的逆向分析首先需要使用二进制补丁对比工具重新识别基带固件中执行内存拷贝的危险函数。因此,通过使用目前应用最广泛的BinDiff将固件与使用标准函数库编译得到的固件进行比对,重新识别了目标固件中使用的strcpy(),strncpy(),strcat(),strncat()等危险函数。但是,在人工分析基带伪代码的过程中,我们发现了多个BinDiff工具未能正确识别的危险函数,如图1(a)所示。与图1(b)中所示的标准库中危险函数相比,其未进行源指针和目的指针所指向的地址是否为空(图1(b)第二行代码)或是否重叠(图1(b)第七行代码)等情况的判断,因此,我们推测该函数是在程序开发过程中由编程人员重新实现的。基带固件的上述特征,特别是函数重写导致的危险函数与标准库中危险函数相比实现太过简单,导致了基于多特征信息进行函数匹配的BinDiff只能发现少量危险函数。由于基带固件中函数个数达6万多个,人工分析以发现全部危险函数显然是不现实的。针对上述问题,本文提出了基于动态执行的DEx方法。

图1 固件中与标准库中危险函数代码对比

1.2 基于动态执行的DEx方法

DEx方法整体流程框架如图2所示。首先,经预处理模块得到基带固件的函数信息和段内容。之后,特征信息收集模块加载基带固件段内容到内存中,根据函数信息动态执行内存中符合条件的函数,并得到函数的语义特征信息。最后,根据函数的语义特征信息,经函数安全性分析模块识别得到危险函数。

图2 DEx方法整体流程

1.2.1 预处理 以三星Shannon基带固件为例,代码中包含多达6万余个函数,为了提高后续动态执行的整体效率,首先经预处理模块过滤掉一部分无关函数。为了确定应该监控并记录基带固件中哪些函数的动态执行时信息,通过对标准函数库中危险函数的分析,DEx方法将执行内存拷贝的危险函数mem_copy分为以下3种类型:

re_val mem_copy(void*dest, [dest_length], void*src, [src_length]);

(1)该函数接收两个指针型参数src和dest,并将源指针src指向内存中的数据复制或追加到目的指针dest指向的内存中。

(2)该函数接收两个指针型参数src、dest和一个数值型参数src_length,并将源指针src指向内存中的src_length个字节的数据复制或追加到目的指针dest指向的内存中。

(3)该函数接收两个指针型参数src、dest和两个数值型参数src_length、dest_length,其中dest_length表示目的地址存储空间的大小。

基于以上对危险函数的分类,预处理模块根据python模块idaapi,idc和idautils中提供的函数得到基带固件的函数信息和段内容。其中函数信息包括函数的参数个数,函数距离基带固件文件头的偏移量,以及对函数指令集的说明,用常数0和1来区分。0表示ARM指令集,1表示Thumb指令集。基带固件的段内容包括每段所包含的字节数量和具体的字节序列内容。

1.2.2 特征信息收集 根据预处理模块得到的基带固件函数信息和段内容,特征信息收集模块主要完成以下两个操作:

(1)加载基带固件段内存到内存中。

(2)根据基带固件的函数信息对内存中的函数实现动态执行,监视并记录函数运行期间产生的语义特征信息。

一旦段内容被正确映射到内存,DEx将控制转移到内存中的函数以对其实现动态执行。在此之前,根据函数信息,对待执行的基带固件函数做如下调用约定:仅执行基带固件中参数个数为两个、三个或四个的函数。

(1)如果该函数的参数个数为两个,约定全部为指针类型。

(2)如果该函数的参数个数为三个,约定两个为指针类型,一个为数字类型。

(3)如果该函数的参数个数为四个,约定两个为指针类型,两个为数字类型。

其中,段内容在内存中的基地址与函数信息中函数的偏移量之和即为函数在内存中的地址,通常,通过把该值传值到调用程序处便可实现对函数的执行。但是,ARMv7-R支持ARM和Thumb两种指令集。ARM指令集的指令长度为32位,Thumb指令集的指令长度为16位或者32位。处于Thumb状态(即正在执行Thumb指令)的处理器可以通过执行BX、BLX等指令进入到ARM状态,更改为执行ARM指令,反之亦然。当处理器在Thumb状态和ARM状态之间切换时,传值到调用程序处的值较正常情况略有差异,除了对待执行的固件函数内存地址的说明,还需说明函数使用的是何种指令集。例如分支指令BLX(register),如果处理器是由ARM状态切换至Thumb状态,传值到调用程序处的值等于段内容在内存中的基地址加上函数的偏移量再加上1,其中“1”表示当前待执行的基带固件函数使用的是Thumb指令集。

在实际运行过程中,为保证对基带固件的调用执行总在合理的时间内终止,对于一个函数的一次执行,我们定义了以下标准用于判断函数是否已经运行结束:

(1)执行到达函数的结尾,函数正常返回。

(2)函数执行出错。

(3)函数的运行时间超过约定的时间。

为了确定某个函数是否是执行可变长度内存拷贝功能的危险函数,特征信息收集模块记录基带固件函数的各种动态运行时信息。在分析了标准库中相关危险函数的实现后,本文选取的特征信息即可捕获各种系统级别信息(例如内存访问),也可获取函数本身可能的输出。同时,对选取的特征信息设置了如下优先级排序以用于后续的函数安全性分析:

(1)第一类优先级是函数对内存的读写。

(2)第二类优先级是存储在寄存器R0中函数的返回值。

(3)第三类优先级是函数运行期间产生的输出内容。

执行内存拷贝功能的危险函数,在运行过程中会对参数指针指向的内存进行读写操作。例如,标准函数库中危险函数

char*strcpy(char*dest,const char*src)。

将指针src指向内存中的字符串复制到指针dest指向的内存中。由于strcpy()函数没有长度参数,无法确定目的缓冲区的大小,不正确的使用可能会导致缓冲区溢出并破坏相邻其他内存。同时,strcpy()函数将指向目标地址的指针作为返回值传递给上层调用者。因此,特征集收集模块捕获基带固件函数执行前后参数指针指向内存中的内容,以及上层调用者得到的返回值。危险函数的返回值既可以是指向目的地址指针的副本,也可以是常数。例如函数memcpy_s(),执行成功返回零,错误返回非零值。

1.2.3 函数安全性分析 根据特征信息收集模块得到的函数特征信息以及设置的优先级排序,如果基带固件函数访问了参数指针指向的内存,并且函数执行完成后目标地址字符串等于或者包含源地址字符串,则认为该函数是执行内存拷贝功能的危险函数。同时,实验过程中,我们发现基带固件中存在某类函数A,A函数只是对危险函数进行了简单调用。安全性分析模块依据第二类优先级,存储在寄存器R0中函数的返回值,对A类函数实现过滤。最后,第三类优先级,函数执行过程中产生的所有输出内容被发送到指定文件并提供给研究人员,以发现其他有趣的部分。

2 实验与结果分析

2.1 实验结果

基于DEx方法,我们实现了dyndiff函数安全性分析工具(https://github.com/xibeiandchangan/dyndiff),并以三星Shannon基带固件为对象进行了对比实验。实验环境为ubuntu linux 18.04.2 LTS系统,安装交叉编译工具链arm-linux-gnueabihf[21]和QEMU虚拟机管理器[22],其中arm-linux-gnueabihf支持x86处理器架构上进行ARM处理器架构可执行代码的交叉编译生成,QEMU用户模式支持在x86处理器架构上进行ARM可执行文件的模拟执行。实验结果如表1所示。

2.2 与BinDiff性能对比

dyndiff重新识别得到固件中22个危险函数,而BinDiff识别结果为4个。其中,图3为本文实现工具dyndiff和BinDiff识别结果对比图。dyndiff比BinDiff表现更好:dyndiff识别得到的危险函数的个数是BinDiff对比工具的5.5倍,其中包括对BinDiff识别结果的全覆盖。

表1 dyndiff识别结果

图3 dyndiff和BinDiff识别结果对比图

2.3 结果分析

在对dyndiff工具的识别结果分析过程中,本文发现一个有趣的现象,即在基带固件中存在多个代码实现完全相同的危险函数,如图4所示。我们推测这可能是由于基带固件源程序是由多个程序开发人员分工合作编写完成,因此出现了对同一功能函数的多次实现。

在3GPP规范中,运行在手机端的GSM协议栈的第3层消息由IEs(Information Elements)组成,而某些IEs被定义为可变长度的。当危险函数将可变长度的IEs复制至本地栈时,不充分的长度检查将导致缓冲区溢出漏洞。因此,本论文进行的函数安全性分析工作,是后续漏洞发掘的基础。基于dyndiff识别结果,通过分析危险函数处的代码实现和与之相对应的协议规范,我们发现了存在的内存破坏缺陷,更深入的利用研究仍在进一步进行。

图4 两个实现完全相同的危险函数

3 结语

本文针对基带固件函数的安全性分析问题,提出了动态执行方法DEx。DEx通过对基带固件函数实现调用执行,并根据其运行过程中产生的语义信息和设置的优先级排序,解决了基带固件中危险函数的识别问题。实验结果表明,dyndiff工具表现出比BinDiff更好的识别效果。由于基带固件中函数数量达6万多个,后续的工作将研究DEx方法的预处理模块,对待执行函数做进一步的筛选,以进一步提高dyndiff的工作效率。本文实现工具dyndiff的下载地址https://github.com/xibeiandchangan/dyndiff。

猜你喜欢
基带固件二进制
尼康旗舰Z9升级新固件延长高速连拍时间
基于国产化IT 基础设施的通用固件安全模型研究
有用的二进制
用Scratch把十进制转为二进制
有趣的进度
苹果推出自研基带芯片要过几道坎?
Intel 5G大动作!PC瞬间飞起
苹果10亿美元为5G买“芯”
英特尔发布免费固件引擎
提取ROM固件中的APP