文件壳脱壳方法及装置与流程

文档序号:12467687阅读:300来源:国知局
本发明涉及计算机
技术领域
:,具体而言,涉及一种文件壳脱壳方法及装置。
背景技术
::随着Android操作系统的不断发展,Android安全加壳技术也逐步普及,越来越多的Android应用程序开始使用加壳保护自己。加壳服务能够有效保护程序的真实逻辑和完整性,但是这些特点同时很容易被恶意程序利用。随着加壳技术的流行,加壳恶意程序的数量也越来越多。传统的恶意代码检测在加壳应用的逆向分析环节比较薄弱,难以对加壳应用进行检测,这给Android平台的安全发展带来了严峻的挑战Android平台的脱壳技术研究分为Dex脱壳技术和SO(动态链接库)脱壳技术。目前国内外在Dex脱壳方面的研究已经取得了比较明显的成果,出现了数种Dex文件脱壳工具,其中较为常用的有ZjDroid和DexHunter,两者均具有较高的脱壳效率。然而另一方面,在SO脱壳方面的研究才刚刚起步,大多数安全研究者仍采取手动的手段通过静态分析与动态调试进行脱壳,其脱壳效率不高,并且脱壳的成功率也取决于从业者的技术水平,到目前为之,无论是在网络上还是在各类期刊杂志上都找不到一套完整的解决SO脱壳方面的技术理论。因此,目前迫切需要寻找一种在Android平台下切实可行的SO文件壳脱壳方法。技术实现要素:为了克服现有技术中的上述不足,本发明的目的在于提供一种文件壳脱壳方法及装置,其能够有效提高动态链接库文件壳脱壳的效率,脱壳后的动态链接库文件可以正常加载和解析。为了实现上述目的,本发明所采用的技术方案如下:本发明较佳实施例提供一种文件壳脱壳方法,所述方法包括:接收输入的测试样本,所述测试样本中包括动态链接库文件;采用分类模型对所述动态链接库文件进行分类,得到所述测试样本中的所述动态链接库文件的壳状态,所述壳状态包括有壳状态和无壳状态。判断所述动态链接库文件的壳状态;当所述动态链接库文件的壳状态为有壳状态时,加载所述动态链接库文件,寻找程序的入口点,在所述动态链接库文件加载成功后所述程序内存中生成一结构体,所述结构体包括以镜像文件形式存在的所述动态链接库文件的信息;读取所述结构体中的镜像文件,并将所述镜像文件进行保存。本发明较佳实施例还提供一种文件壳脱壳装置,所述装置包括:接收模块,用于接收输入的测试样本,所述测试样本中包括动态链接库文件;分类模块,用于采用所述分类模型对所述动态链接库文件进行分类,得到所述测试样本中的所述动态链接库文件的壳状态,所述壳状态包括有壳状态和无壳状态。判断模块,用于判断所述动态链接库文件的壳状态;加载模块,用于当所述动态链接库文件的壳状态为有壳状态时,加载所述动态链接库文件,寻找所述程序的入口点,其中,加载成功后所述程序内存中出现结构体,所述结构体包括所述动态链接库文件的信息;转存模块,用于读取所述结构体中的镜像文件,并将所述镜像文件转存至所述用户终端;重构模块,用于对所述镜像文件进行重构,得到脱壳后动态链接库文件。本发明提供的文件壳脱壳方法及装置,其能够有效提高动态链接库文件壳脱壳的效率,脱壳后的动态链接库文件可以正常加载和解析,并且无需得知文件壳的具体类型,只需要得知是否加壳,即可完成后续的脱壳工作。附图说明为了更清楚地说明本发明实施例的技术方案,下面将对实施例中所需要使用的附图作简单地介绍,应当理解,以下附图仅示出了本发明的某些实施例,因此不应被看作是对范围的限定,对于本领域普通技术人员来讲,在不付出创造性劳动的前提下,还可以根据这些附图获得其他相关的附图。图1为本发明较佳实施例提供的用户终端的结构框图;图2为本发明实施例提供的文件壳脱壳方法的一种流程示意图;图3为本发明实施例提供的文件壳脱壳方法的另一种流程示意图;图4为图3中步骤S208的子步骤的流程示意图;图5为图2中步骤S260的子步骤的流程示意图;图6为本发明实施例提供的文件壳脱壳装置的功能模块图;图7为本发明实施例提供的文件壳脱壳装置的另一种功能模块图;图8为图7中获取模块208的子模块的功能框图。图标:100-用户终端;110-存储器;120-处理器;130-通信单元;140-存储控制器;200-文件壳脱壳装置;208-获取模块;209-训练模块;210-接收模块;220-分类模块;230-判断模块;240-加载模块;250-转存模块;260-重构模块;2080-提取子模块;2082-筛选子模块;2084-特征集生成子模块。具体实施方式下面将结合本发明实施例中的附图,对本发明实施例中的技术方案进行清楚、完整地描述,显然,所描述的实施例是本发明一部分实施例,而不是全部的实施例。通常在此处附图中描述和示出的本发明实施例的组件可以以各种不同的配置来布置和设计。因此,以下对在附图中提供的本发明的实施例的详细描述并非旨在限制要求保护的本发明的范围,而是仅仅表示本发明的选定实施例。应注意到:相似的标号和字母在下面的附图中表示类似项,因此,一旦某一项在一个附图中被定义,则在随后的附图中不需要对其进行进一步定义和解释。同时,在本发明的描述中,术语“第一”、“第二”等仅用于区分描述,而不能理解为指示或暗示相对重要性。请参阅图1,图1是本发明较佳实施例提供的用户终端100的方框示意图。本发明实施例中所述用户终端100可以为显控类产品,例如,所述用户终端100可以是,但不限于,智能手机、个人电脑(personalcomputer,PC)、平板电脑、个人数字助理(personaldigitalassistant,PDA)、移动上网设备(mobileInternetdevice,MID)等。在本实施例中,所述用户终端100的操作系统可以是,但不限于,安卓(Android)系统等。优选地,本实施例中,所述用户终端100的操作系统为Android系统。所述用户终端100可以执行包含加壳文件的可执行程序,所述可执行程序可在用户终端100的系统平台上运行,例如,所述可执行程序是在用户终端100的Android平台上运行的以“.apk”为名称后缀的文件,即Android系统的安装包。如图1所示,所述用户终端100包括存储器110、处理器120、通信单元130以及存储控制器140。所述存储器110、处理器120、通信单元130以及存储控制器140相互之间直接或间接地电性连接,以实现数据的传输或交互。例如,这些元件相互之间可通过一条或多条通讯总线或信号线实现电性连接。存储器110中存储有文件壳脱壳装置200,所述文件壳脱壳装置200包括至少一个可以软件或固件(firmware)的形式存储于所述存储器110中的软件功能模块,所述处理器120通过运行存储在存储器110内的软件程序以及模块,如本发明实施例中的文件壳脱壳装置200,从而执行各种功能应用以及数据处理,即实现本发明实施例中的文件壳脱壳方法。其中,所述存储器110可以是,但不限于,随机存取存储器(RandomAccessMemory,RAM),只读存储器(ReadOnlyMemory,ROM),可编程只读存储器(ProgrammableRead-OnlyMemory,PROM),可擦除只读存储器(ErasableProgrammableRead-OnlyMemory,EPROM),电可擦除只读存储器(ElectricErasableProgrammableRead-OnlyMemory,EEPROM)等。其中,存储器110用于存储程序,所述处理器120在接收到执行指令后,执行所述程序。进一步地,通信单元130将各种输入/输入装置耦合至处理器120以及存储器110,上述存储器110内的软件程序以及模块还可包括操作系统,其可包括各种用于管理系统任务(例如内存管理、存储设备控制、电源管理等)的软件组件和/或驱动,并可与各种硬件或软件组件相互通讯,从而提供其他软件组件的运行环境。所述处理器120可能是一种集成电路芯片,具有信号的处理能力。上述的处理器120可以是通用处理器,包括中央处理器(CentralProcessingUnit,CPU)、网络处理器(NetworkProcessor,NP)等。还可以是数字信号处理器(DSP))、专用集成电路(ASIC)、现成可编程门阵列(FPGA)或者其他可编程逻辑器件、分立门或者晶体管逻辑器件、分立硬件组件。可以实现或者执行本发明实施例中的公开的各方法、步骤及逻辑框图。通用处理器可以是微处理器或者该处理器120也可以是任何常规的处理器等。所述通信单元130用于建立所述用户终端100与文件壳脱壳装置200二者之间的通信连接。可以理解,图1所示的结构仅为示意,所述用户终端100还可以包括比图1中所示更多或者更少的组件,或者具有与图1所示不同的配置。图1中所示的各组件可以采用硬件、软件或其组合实现。请参阅图2,图2为本发明较佳实施例提供的文件壳脱壳方法的一种流程示意图,所述方法的具体流程如下:步骤S210,接收输入的测试样本,所述测试样本中包括动态链接库文件。具体地,所述测试样本为选定的动态链接库文件的测试样本,其中,所述测试样本不仅限于是一个样本,可以包括多个包括可能加壳或者未加壳的动态链接库文件,所述可能加壳或者未加壳的动态链接库文件的类型可以是多种不同的类型。请参阅图3,图3为本发明实施例提供的文件壳脱壳方法的另一种流程示意图,所述方法还包括:步骤S208,获取所述动态链接库文件的特征集。需要注意的是,在本实施例中,子步骤S208之前还需要对所述动态链接库文件进行有效性的检测,以判断所述动态链接库文件是否为有效的动态链接库文件。具体地,首先查看所述动态链接库文件头部的四个魔术数字(MagicNumber)是否有效,即是否为‘.ELF’;查看所述动态链接库文件头部的第5个字节是否为ELFCLASS32,即判断所述运行平台是否是32位平台;查看所述动态链接库文件头部的第6个字节是否为ELFDATA2LSB,即判断所述动态链接库文件是否采用的小端格式;查看所述动态链接库文件头部的e_version成员的值是否为EV_CURRENT,即判断所述动态链接库文件的版本号是否有效;查看所述动态链接库文件头部的e_type成员的值是否为ET_DYN,即判断文件类型是否为共享库;如果上述所有值全部匹配,则该文件是一个有效的SO文件。在所述动态链接库文件格式中,ELFCLASS32、ELFDATA2LSB、EV_CURRENT、ET_DYN的值分别为1、1、1、3。所述动态链接库文件格式检测的伪代码如下所示,其中header的类型为ELF32_Ehdr结构体。读取所述动态链接库文件头部,并将所述动态链接库文件头部赋给header。请参阅图4,在本实施例中,所述步骤S208可以包括以下子步骤:子步骤S2080,获取所述动态链接库文件的初选特征。根据对所述动态链接库文件的有效性检测,当所述动态链接库文件为有效的动态链接库文件时,解析所述动态链接库文件的结构信息,提取所述动态链接库的初选特征,对所述提起的初选特征简单描述如下:ELF头,选取了除e_ident的前6个字节和除e_type、e_version以外的所有属性,上述几个成员对于每个ELF文件来说都是相同的。PT_LOAD1头,第1个可加载段的程序头,选取了所述程序头部的所有8个属性。PT_LOAD2头,第2个可加载段的程序头,选取了所述程序头部的所有8个属性。.dynstr节头,该节的内容包含了动态链接时所需的全部字符串,选取了该节头部分的所有内容。.dynsym节头,该节的内容包含了动态链接时所需的符号表信息,选取了该节头部分的所有内容。.shstrtab节头,该节的内容包含了所有节的名称字符串,选取了该节头部分的所有内容。.init_array节头,该节用于存放初始化函数地址,选取了该节头部分的所有内容。子步骤S2082,对所述初选特征对筛选,剔除所述初选特征中的冗余特征;上述初选特征中包含了大量的特征属性,其中大部分属性对加壳动态链接库文件检测是无用的,因此本实施例还需要剔除所述初选特征中的冗余特征,以减小计算的复杂度,从而提高后续的分类准确度。优选地,在本实施例中,采用线性判别分析(LinearDiscriminantAnalysis,LDA)算法以达到剔除冗余特征的目的,其原理如下所示:动态链接库文件格式被定义为一个64维向量的特征集,即为本实施例的训练样本集。假设所述训练样本集是x={x1,x2,...,xN},其中x为d维向量,d表示每个训练样本包含了d个特征,N为训练样本集的个数。则w1类样本是w2类的样本是其中w1类代表未加壳训练样本类,w2类代表加壳训练样本类。接下来寻找到一个最佳的投影方向w,使得样本x按照公式yi=wTxi,i=1,2,...,N的线性变换投影到低维度中的y。接下来需要寻找一个最佳的投影方向w,使得样本x按照公式yi=wTxi,i=1,2,...,N的线性变换投影到低维度中的y。具体步骤如下:寻找每类训练样本的均值,按照公式分别计算出w1类的均值和w2类的均值;按照公式s1=Σx∈w1(x-u1)(x-u1)T和s2=∑x∈w2(x-u2)(x-u2)T分别计算出w1类的散列矩阵和w2类的散列矩阵;定义sw=s1+s2,如果sw是可逆的,那么按照公式即可求出最佳的投影方向w。求出w后,挑出最大的p个特征值对应的特征向量作为变换矩阵,即完成了特征变换。子步骤S2084,对筛选后的初选特征进行降维,对降维后的特征进行格式化处理,得到一个适用于分类器的特征集。具体地,所述分类器可以是朴素贝叶斯分类器。通过上述计算,每个动态链接库文件被定义为一个64维向量,通过提取所有的特征向量建立了一个矩阵,使用LDA算法,得到主要特征,最后深入分析主要特征特征,格式化所述特征向量,得到如下动态链接库文件特征集,所述:SO_Info={D,S,N,E,F}具体含义如下:D代表头部部分成员的值是否为默认值。具体含义如下:检测动态链接库文件头部的e_ident、e_entry、e_flags三个成员的值是否为默认值,其中e_ident成员的后10个字节的默认值全为0,e_entry的默认值为0,e_flags的默认值为0x5000000。如果是则D的值为1;否则为0。S代表头部是否包含有效的节信息。具体含义如下:检测动态链接库文件头部的e_shoff、e_shentsize、e_shnum、e_shstrndx四个成员的值是否有效,其中e_shoff成员不应大于文件大小,e_shentsize成员为40,e_shnum成员大于0且不超过50,e_shstrndx成员为e_shnum减1。如果是则S的值为1;否则为0。N代表是否存在奇怪的节名称。具体含义如下:检测所有节数据结构的名称字段是否存在非标准名字、名字不能打印或为空的情况,如果存在,则N的值为1;否则为0。E代表具有可执行属性的段的个数是否超过1个。具体含义如下:检测所有段中具有可执行属性的个数,如果个数超过1则E的值为1;否则为0。F代表具有几个初始化函数。具体含义如下:包括三个类型:init函数;init_array数组中的函数个数;JNI_OnLoad。三种类型均无,则F的值为0;每有1个初始化函数,F的值加1。步骤S209,将所述特征集作为训练样本进行训练得到所述分类模型。将上述得到的动态链接库的特征集作为朴素贝叶斯分类器的训练样本输入,训练成功后,就可以得到贝叶斯公式中先验概率和条件概率,即计算得到训练样本中未加壳动态链接库文件样本和加壳动态链接库文件样本的出现频率,也就是计算所述动态链接库文件各个特征属性分别对未加壳样本和加壳样本的条件概率估计,最后就得到一个可用于动态链接库文件壳检测的朴素贝叶斯分类分类模型。具体地,定义F={f1,f2,...,fn}为一个动态链接库文件样本:其中每个f为F的一个特征属性,共有n个特征属性;定义c={c1,c2}表示所有动态链接库文件样本,其中c1表示未加壳的动态链接库文件样本,c2表示加壳的动态链接库文件样本;若对于一个待分类动态链接库文件样本,则计算其中,p(ci)表示训练样本集中类别为ci的概率,p(fi|ci)表示特征为fi且类别为ci的概率,p(fi)表示特征为fi的概率,p(ci|x)表示x样本的类别为ci的概率。以上公式中的分母的值是固定的,因此只需要计算分子的值,并比较值的大小,若p(c1|x)大于p(c2|x)则待分类动态链接库文件样本为未加壳动态链接库文件,否则为加壳动态链接库文件。请再次参阅图2,步骤S220,采用分类模型对所述动态链接库文件进行分类,得到所述测试样本中的所述动态链接库文件的壳状态,所述壳状态包括有壳状态和无壳状态。在本实施例中,所述分类模型可以是上述得到的朴素贝叶斯分类模型,将所述包括动态链接库文件的测试样本输入到朴素贝叶斯分类模型进行分类,按照上述步骤S209的计算,所述朴素贝叶斯分类模型最后输出所述测试样本中的所述动态链接库文件的壳状态,所述壳状态包括有壳状态和无壳状态。步骤S230,判断所述动态链接库文件的壳状态。根据所述输出所述测试样本中的所述动态链接库文件的壳状态,判断所述动态链接库文件的壳状态,若所述动态链接库文件为有壳状态,则进行下一步脱壳操作。步骤S240,当所述动态链接库文件的壳状态为有壳状态时,加载所述动态链接库文件,寻找程序的入口点,在所述动态链接库文件加载成功后所述程序内存中生成一结构体,所述结构体包括以镜像文件形式存在的所述动态链接库文件的信息。所述程序为可在用户终端100的系统平台上运行的可执行程序,例如,所述可执行程序是在用户终端100的Android平台上运行的以“.apk”为名称后缀的文件,即Android系统的安装包。其中,对所述动态链接库文件的加载包括:壳加载及不带壳的动态链接库文件加载。其中,所述不带壳的动态链接库文件的加载过程包括准备阶段、装载阶段、链接阶段和初始化阶段。所述准备阶段的主要工作如下:扫描apk文件内部的nativeLibrary目录(apk文件的lib目录,/vendor/lib,/system/lib),获得并返回所述动态链接库文件的绝对路径,如果获取失败则返回异常;检查是否已经加载了所述动态链接库文件,如果已经加载过所述动态链接库文件则不再需要重复加载;调用dlopen函数进入所述装载阶段。当Android完成准备阶段之后,就进入了所述装载阶段,装载阶段主要完成对所述动态链接库文件中需要加载的段的内存映射工作。所述装载阶段的主要工作如下:检查是否已经加载了所述动态链接库文件,如果已经加载过则不再需要重复加载,否则继续加载;打开所述动态链接库文件,读取ELF头,并验证所述动态链接库文件是否为有效的所述动态链接库文件,如果验证失败则返回,否则继续;读取程序头,并调用mmap()将所述程序头映射到指定的页中,根据所述程序头的信息,计算出加载所述动态链接库文件的起始地址和所需的总的内存空间大小,并通过mmap()创建足够大的匿名内存空间,以便能够容纳所有可加载的段;将所有PT_LOAD属性的段加载至合适的地址空间,其中代码段与数据段的相对位置与文件的运行域一致;校验程序头是否在内存中;为所述动态链接库文件在共享库链表中分配一个soinfo节点,并根据上述获得的信息,初始化其数据结构,从而生成soinfo结构体,所述结构体由soinfo类型的结构数组组成,所述soinfo结构体包括以镜像文件形式存在的所述动态链接库文件的信息。动态链接库文件属于共享库文件,需要参与动态链接。Android在完成动态链接库文件的装载之后,就会进入所述链接阶段。所述链接阶段的主要工作如下:从程序头中获取.dynamic节信息,并对soinfo结构体的dynamic进行赋值;遍历dynamic数组,根据每个元素的标记信息进行相应的处理;接着依次获取dynamic数组中定义的所述动态链接库文件的soinfo节点;最后遍历重定位节,根据每个元素的重定位类型,对与每个元素相对应的符号进行重定位。Android系统在完成所述动态链接库文件的装载阶段和链接阶段后,就会执行初始化构造函数,即进入所述初始化阶段。所述初始化阶段的主要工作如下:依次执行所述动态链接库文件的初始化构造函数;执行.init节的代码,再执行.init_array节的代码;获取JNI_OnLoad函数的地址,如果存在,则调用JNI_OnLoad。所述壳的加载过程包括:反调试、HOOK-API、解压和解密、交换控制权。具体地,在可执行程序加载过程中,所述文件壳通过修改程序入口地址为壳入口地址会首先获得所述程序的控制权,对于所述动态链接库文件来说,由于没有类似于main函数的程序入口,只存在一个初始化函数队列,Android系统在加载所述动态链接库文件时,在完成装载阶段和链接阶段的工作后,便会执行所述初始化函数队列,即调用位于.init节和.init_array节中的代码以及JNI_OnLoad函数。所述文件壳通过把壳代码放入所述初始化函数队列中,使得在所述动态链接库文件加载时优先获得程序控制权。所述反调试过程:所述壳程序为了对抗脱壳会采取一系列的技术手段,比如:检测模拟器,阻止gdb、IDA等调试工具的附加调试,监控自身内存以防止被第三方程序修改等。所述HOOK-API过程:文件壳会修改原程序的部分API函数的地址,例如:mmap,open、mprotect等。当壳在交还控制权给所述原程序后,仍然能够间接获得所述原程序的控制权。所述解压和解密过程:所述壳程序不能影响原程序的正常执行,即要保证原程序各个函数的应有功能,所以所述壳程序需要对原程序文件的各个区块进行相应的解压和解密工作。所述交换控制权过程:通过上述过程,所述壳程序将控制权交还给原程序,此时原程序可以正常运行。通过上述过程,所述壳程序将控制权交换给原程序,由于壳代码位于所述动态链接库文件的初始化构造函数队列中,也就是位于上述的.init节、.init_array节中的代码以及JNI_OnLoad函数,其中,所述JNI_OnLoad函数是最后被执行的,当所述JNI_OnLoad函数执行完毕时,此时Android系统会执行到所述原程序的入口点(OriginalEntryPoint,OEP),此时壳程序已经完成所有解压和解密工作,即为本实施例脱壳开始的时刻。当所述动态链接库文件装载成功后,所述程序会在Android系统存储空间中中生成soinfo结构体,所述存储空间可以是原程序的文件目录,也可以是,但不限于磁盘、U盘等。所述结构体由soinfo类型的结构数组组成,所述soinfo结构体包括以镜像文件形式存在的所述动态链接库文件的信息,通过解析所述soinfo结构体,可以绕过加壳软件的各种加密算法达到脱壳目的。步骤S250,读取所述结构体中的镜像文件,并将所述镜像文件进行保存。具体地,调用dlopen函数加载所述待脱壳动态链接库文件,从而得到所述soinfo结构体,若dlopen函数返回成功下一步,否则失败退出;调用dlsym函数获取JNI_OnLoad函数地址,若所述动态链接库文件中存在该函数,则执行该函数;解析所述soinfo结构体信息,得到所述soinfo结构体中的成员base和size,即镜像的起始地址和总大小,将所述镜像文件保存到Android系统存储空间中。步骤S260,对所述镜像文件进行重构,得到脱壳后的动态链接库文件。请参阅图5,在本实施例中,所述步骤S260可以包括如下子步骤:子步骤S261,对所述镜像文件头部的固定成员、段相关成员以及节相关成员进行修复。具体地,所述固定成员指的是对于所述动态链接库文件来说固定不变的成员,这些成员描述了系统信息或者校验信息。所述固定成员包含5个成员,分别为:e_ident、e_type、e_version、e_ehsize、e_flags。其中e_ident共有16个字节,前6个字节的值分别为:’7f’,’45’,’4c’,’46’,‘1’,‘1’,后续10个字节全部为0。e_type的值为ET_DYN。e_version的值为EV_CURENT。e_ehsize的值为ELF头所占用的字节数,也就是Elf32_Ehdr结构体的大小。e_flags不用修复。所述段相关成员指的是用于所述装载阶段的成员,这些成员描述了段的相关信息。其包含3个成员,分别为:e_phoff、e_phentsize、e_phnum。其中e_phoff和e_phnum不用修复,e_phenntsize的值为程序头的表项所占用的字节数,也就是Elf32_phdr结构体的大小。所述节相关成员指的是用于所述链接阶段的成员,这些成员描述了节的相关信息。其包含4个成员,分别为:e_shoff、e_shentsize、e_shnum、e_shstrndx。e_shentsize的值为节头的表项所占用的字节数,也就是Elf32_Shdr结构体的大小,e_shoff、e_shnum和e_shstrndx将在后续的重建节头中修复。子步骤S262,将从所述镜像文件的文件头到段的第一个字节的偏移值修改为段的第一个字节映射到程序内存的虚拟地址值。具体地,通过上述对所述动态链接库文件格式的分析,可以知道在程序头中存在两个成员,分别为p_offset和p_vaddr,p_offset指的是从所述镜像的文件头到该段第一个字节的偏移,和p_vaddr指的是段的第一个字节将被映射到内存中的虚拟地址。具体修复步骤如下:解析ELF头部,通过e_phoff成员得到程序头的地址,通过e_phnum成员得到程序头包含的表项个数。遍历所有程序头,将p_offset成员的值修改为p_vaddr成员的值。子步骤S263,对重定位符号的内存地址进行修正。具体地,所述重定位节是由Elf32_Rel类型的结构数组组成,所述类型的结构定义如下:其中r_offset表示应用重定位行为的地址,其指向的值会被重定位。r_info表示具有受重定位影响因素的符号表索引和重定位应用的类型,包含了重定位符号在本地符号表中的索引和重定位类型。重定位发生在所述动态链接库文件的链接阶段,此时已经完成了所述动态连接口库文件的加载工作,因此通过转存的镜像文件是已经完成了重定位工作的,而重定位符号的虚拟地址只是在当时的进程环境下是有效的,因此需要将被重定位的虚拟地址重新修复为偏移地址,这样转存的镜像文件才能被正常加载起来。重定位修复函数的定义如下:reverseRelocate(Elf32_Rel*rel,size_tcount);rel为待修复的重定位节首地址,count为表项个数。其中rel和count的值都可以从soinfo结构体中得到。.rel.dyn表修复:参数rel的值为soinfo结构体中的rel成员,参数count的值为soinfo结构体中的rel_count成员;rel.plt表修复:参数rel的值为soinfo结构体中的plt_rel成员,参数count的值为soinfo结构体中的plt_rel_count成员。reverseRelocate函数的具体流程如下:遍历重定位节,根据重定项的r_info成员获得重定位类型和重定位项对应的符号在符号表中的索引。利用所述动态链接库文件中的.hash表,根据符号名快速地查找所述符号在动态链接库文件中定义。找到所述符号的定义,计算所述符号的地址;根据所述符号的重定位类型,结合所述符号的地址逆向重定位。步骤S264,对所述镜像文件的为每一个节创建对应的节头。具体地,通过上述对所述动态链接库文件的加载过程可知,Android系统在加载所述动态链接库文件时并不需要节头,转存后的所述镜像文件不包含节头,因此需要对转存之后的所述镜像文件的节头进行重建。节头的结构体定义:重建节头具体步骤如下所示:通过base成员得到所述动态链接库文件在内存中的基地址;通过symtab、rel、plt_rel、ARM_exidx、fini_array、init_array、dynamic这7个成员分别得到.dynsym、.rel.dyn、.rel.plt、.ARM_exidx、.fini_array、.init_array、.dynamic这7个节在内存中的虚拟地址,记这个虚拟地址为VA,节的sh_addr成员为VA,而由于内存对齐的原因,节的sh_offset成员可能为VA,也可能为VA-0x1000;通过nchain、rel_count、plt_rel_count、ARM_exidx_count、fini_array_count、init_array_count、dynamic_count这7个成员分别得到.dynsym、.rel.dyn、.rel.plt、.ARM_exidx、.fini_array、.init_array、.dynamic这7个节的表项数目,记所述表项数目为COUNT,表项大小为SIZE。则节的sh_size成员的值为COUNT*SIZE。如果.dynamic节修复成功,则通过解析.dynamic节完成对.dynstr节和.hash节的修复工作。具体修复步骤如下:通过strtab成员得到.dynstr节在内存中的虚拟地址,用虚拟地址减去基地址的值即为.dynstr节的sh_addr和sh_offset,通过解析.dynamic节找到DT_STRSZ,从而得到.dynstr节的sh_size。通过解析.dynamic节找到DT_HASH,从而得到.hash节在内存中的虚拟地址,用虚拟地址减去基地址的值即为.hash节的sh_addr和sh_offset,nbucket成员的值加上nchain成员的值再加上2的总和再乘以4即为.hash节的sh_size。通过搜索前16个字节来确定.plt节的sh_addr和sh_offset,这16个字节为:0xe52de004,0xe59fe004,0xe08fe00e,0xe5bef008。.plt节由固定16字节加上4字节的__global__offset_table变量和需要重定位的函数地址构成,函数地址与.rel.plt节中的结构一一对应,因此,.rel.plt节的表项数目乘以12再加上20即为.plt节的sh_size。.got节存在两种结构,即为{.got,.got_plt}和{.got_plt,.got}。其中,.got节中的项一定出现在.rel节中,.got_plt中的项于.rel_plt中的项是一一对应关系。因此,.got节的重建步骤如下:解析.dynamic节,读取DT_PLTGOT,从而获取__global__offset_table变量,记为plt_got。读取plt_got-4地址的值,在.rel节中进行搜索。如果匹配成功,则说明.got节的结构为{.got,.got_plt},继续向前搜索匹配,直到匹配失败,此处即为.got节的sh_addr和sh_offset。调整搜索位置到got_plt,向后搜索,在.rel_plt节中进行匹配,直到匹配失败,此处即为.got节的末尾,从而可计算得到.got节的sh_size。如果匹配不成功,则说明.got节的结构为{.got_plt,.got},读取plt_got-4地址的值,在.rel_plt节中进行搜索,直到匹配失败,此处即为.got节的sh_addr和sh_offset。调整搜索位置到got_plt,向后搜索,在.rel节中进行匹配,直到匹配失败,此处即为.got节的末尾,从而可计算得到.got节的sh_size。对.shstrtab节进行重建。具体地,.shstrtab节内容存放了所有节的名称字符串,即所有节的sh_name成员均是指向.shstrtab节中字符串的索引,根据所有节的sh_name成员可以构造出所有节的sh_name成员。将上述节头添加至所述动态链接库文件的尾部,修正ELF头部中的e_shoff、e_shnum和e_shstrndx。完成节头重建工作,重建后的动态链接库文件文件可以静态分析和动态调试。步骤S266,清除程序入口的壳程序。在完成上述脱壳工作后,所述动态链接库文件已经完成了解密工作,但是此时的原程序入口仍然位于.init和.init_array节中的壳程序,、此时如果加载所述动态链接库文件,壳程序依然会首先获得原程序控制权,因此需要清除程序入口的壳程序。Android系统调用.init节和.init_array节代码的源代码如下:CallFunction("DT_INIT",init_func);CallArray("DT_INIT_ARRAY",init_array,init_array_count,false);其中,CallFunction函数用于调用.init节的初始化代码,参数init_func为调用地址,若init_func的值为0或-1则不执行初始化代码;CallArray函数用于依次调用.init_array节中的所有初始化代码,参数init_array为初始化代码数组,init_array_count为初始化代码的个数,若参数init_array_count的值为0则不执行初始化代码。本实施例还需要修改所述动态链接库文件的相关信息,使得init_func和init_array_count的值为0。具体步骤如下:通过所述动态链接库文件的soinfo结构体信息,得到.dynamic节信息。遍历.dynamic节,依次找到d_tag成员为DT_INIT(.init节)和DT_INIT_ARRAY(.init_array节)的表项,表项由一个Elf32_Dyn类型的结构体数组构成。将.init节表项中的d_ptr成员修改为0。将.init_array节表项中的d_val成员修改为0。请参阅图6,所述文件壳脱壳装置200包括:接收模块210、分类模块220、判断模块230、加载模块240、转存模块250、重构模块260。所述接收模块210用于接收输入的测试样本,所述测试样本中包括动态链接库文件。所述分类模块220用于采用所述分类模型对所述动态链接库文件进行分类,得到所述测试样本中的所述动态链接库文件的壳状态,所述壳状态包括有壳状态和无壳状态。所述判断模块230用于判断所述动态链接库文件的壳状态。所述加载模块240用于当所述动态链接库文件的壳状态为有壳状态时,加载所述动态链接库文件,寻找所述程序的入口点,其中,加载成功后所述程序内存中出现结构体,所述结构体包括所述动态链接库文件的信息。所述转存模块250用于读取所述结构体中的镜像文件,并将所述镜像文件转存至所述用户终端100。所述重构模块260用于对所述镜像文件进行重构,得到脱壳后动态链接库文件。请参阅图7,所述文件壳脱壳装置200还包括:获取模块208和训练模块209。所述获取模块208用于获取所述动态链接库文件的特征集。所述训练模块209用于将所述特征集作为训练样本进行训练得到分类模型。请参阅图8,所述获取模块208包括:提取子模块2080、筛选子模块2082和特征集生成子模块2084。所述提取子模块2080,用于提取所述动态链接库文件的初选特征。所述筛选子模块2082,用于对所述初选特征对筛选,剔除所述初选特征中的冗余特征。所述特征集生成子模块2084,用于对筛选后的初选特征进行降维,对降维后的特征进行格式化处理,得到一个适用于分类器的特征集。综上所述,本发明提供的文件壳脱壳方法及装置,其能够有效提高动态链接库文件壳脱壳的效率,脱壳后的动态链接库文件可以正常加载和解析,并且无需得知文件壳的具体类型,只需要得知是否加壳,即可完成后续的脱壳工作。在本发明实施例所提供的几个实施例中,应该理解到,所揭露的装置和方法,也可以通过其它的方式实现。以上所描述的装置和方法实施例仅仅是示意性的,例如,附图中的流程图和框图显示了根据本发明的多个实施例的装置、方法和计算机程序产品的可能实现的体系架构、功能和操作。在这点上,流程图或框图中的每个方框可以代表一个模块、程序段或代码的一部分,所述模块、程序段或代码的一部分包含一个或多个用于实现规定的逻辑功能的可执行指令。也应当注意,在有些作为替换的实现方式中,方框中所标注的功能也可以以不同于附图中所标注的顺序发生。例如,两个连续的方框实际上可以基本并行地执行,它们有时也可以按相反的顺序执行,这依所涉及的功能而定。也要注意的是,框图和/或流程图中的每个方框、以及框图和/或流程图中的方框的组合,可以用执行规定的功能或动作的专用的基于硬件的系统来实现,或者可以用专用硬件与计算机指令的组合来实现。另外,在本发明各个实施例中的各功能模块可以集成在一起形成一个独立的部分,也可以是各个模块单独存在,也可以两个或两个以上模块集成形成一个独立的部分。所述功能如果以软件功能模块的形式实现并作为独立的产品销售或使用时,可以存储在一个计算机可读取存储介质中。基于这样的理解,本发明的技术方案本质上或者说对现有技术做出贡献的部分或者该技术方案的部分可以以软件产品的形式体现出来,该计算机软件产品存储在一个存储介质中,包括若干指令用以使得一台计算机设备(可以是个人计算机,电子设备,或者网络设备等)执行本发明各个实施例所述方法的全部或部分步骤。需要说明的是,在本文中,术语“包括”、“包含”或者其任何其他变体意在涵盖非排他性的包含,从而使得包括一系列要素的过程、方法、物品或者设备不仅包括那些要素,而且还包括没有明确列出的其他要素,或者是还包括为这种过程、方法、物品或者设备所固有的要素。在没有更多限制的情况下,由语句“包括一个……”限定的要素,并不排除在包括所述要素的过程、方法、物品或者设备中还存在另外的相同要素。对于本领域技术人员而言,显然本发明不限于上述示范性实施例的细节,而且在不背离本发明的精神或基本特征的情况下,能够以其他的具体形式实现本发明。因此,无论从哪一点来看,均应将实施例看作是示范性的,而且是非限制性的,本发明的范围由所附权利要求而不是上述说明限定,因此旨在将落在权利要求的等同要件的含义和范围内的所有变化囊括在本发明内。不应将权利要求中的任何附图标记视为限制所涉及的权利要求。当前第1页1 2 3 当前第1页1 2 3 
当前第1页1 2 3 
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1