一种基于隐藏事件触发机制的内存取证方法

2018-10-15 06:49崔超远李勇钢王励成
计算机研究与发展 2018年10期
关键词:链表内核视图

崔超远 李勇钢,2 乌 云 王励成

1(中国科学院合肥物质科学研究院合肥智能机械研究所 合肥 230031)2(中国科学技术大学研究生院科学岛分院 合肥 230027)3(中国科学院合肥物质科学研究院应用技术研究所 合肥 230088)4(北京邮电大学网络空间安全学院 北京 100876)

内存取证包含2个要素:发起取证的时间点和取证对象.传统的内存取证方法均是假设取证操作发生在恶意软件攻击过程中,然后对整个内存空间进行内存转储操作,从而获取全部内存内容[1].此类方法具有取证范围广、实现简单的特点.但是,攻击发起者往往仅是一个进程或一个可加载内核模块(loadable kernel module, LKM),大范围的内存取证虽然能够涵盖攻击发起者的代码信息,却产生了大量的冗余信息.同时,攻击者的攻击发起时间和持续时间具有随机性,且内存本身具有易失性和不可恢复性的特点.换句话说,攻击完成后内存一旦被回收,攻击者的内存痕迹将被彻底清除.因此,若发起内存取证的时间点不在攻击过程中,那么取证内容将不包含攻击行为的特征信息,使得内存取证失去意义.总之,取证时间点和取证对象的确立是成功进行内存取证的关键.但是,恶意内核对象所具有的隐藏性会对取证工具选取取证对象和取证时间点产生干扰,导致取证失败.

Rootkit是一种应用范围最广的隐藏性恶意软件[2].它不仅能够实现自我隐藏,还能与其他恶意软件相结合,实现指定恶意内核对象的隐藏[3].恶意内核对象(如进程或LKM)被隐藏后,能够有效规避安全工具的检测,对操作系统(operating system, OS)安全产生极大的威胁.Rootkit的隐藏技术大致可分为内部指令替换、内核函数重定向、直接内核对象操作(direct kernel object manipulation, DKOM)[4]和容器原语欺骗四大类.其中,指令替换技术很容易通过完整性校验检测到,目前已经很少被使用了.内核函数重定向技术并不对内核代码段做出任何更改,仅对特定内核函数(用于构建语义视图的函数)的引用指针进行重构,使其指向恶意软件自定义的代码段.此类方法并未破坏内核代码段的完整性,因此对内核完整性校验方法具有免疫性,对基于主机的安全工具隐藏效果极强.DKOM型Rootkit的操作对象是内核对象的描述符,它直接更改内核对象的属性.该方法打破了目标内核对象与其他内核对象之间的逻辑连接关系,导致任何依赖于内核对象之间逻辑关系构建语义视图的安全工具失效[5].基于容器原语欺骗技术的Rootkit是Leibowitz在2016年黑帽大会(Black Hat)上提出的一种新型Rootkit,名为Horse Pill[6].它通过感染ramdisk接管整个操作系统,并通过容器原语欺骗系统所有者.在感染过程中,Horse Pill利用操作系统中initrd动态生成的特点向其中注入恶意二进制可执行文件run-init,取代原有的init,以此获取系统的控制权.当操作系统重启之后,run-init会向系统所有者提供提前设计好的虚假语义视图,这类似于将系统所有者圈定在攻击者为其设定的容器内.在容器之外,攻击者可以自由设定后门之类的恶意进程,而这些恶意进程对系统所有者是不可见的.

Rootkit的隐藏性使取证工具在取证对象确定和取证时间点选取上面临巨大挑战.传统的内存取证工具多是基于主机的,与目标OS缺乏足够的隔离性,很容易被具有隐藏特征的Rootkit绕过.目前基于虚拟化技术的取证方法虽然增强了取证工具和目标OS之间的隔离性,但是无法实时地检测到可疑内核对象的隐藏操作,使取证对象和取证时间的选取变得极其困难.尤其是针对DKOM型的Rootkit,当前方法仅能检测到被Rootkit隐藏的内核对象(如进程、文件和网络端口),无法检测到Rootkit本身(即被隐藏的模块).取证对象的不确定性将导致取证范围扩大,影响取证效率;取证时间点的选取错误将直接导致取证数据无效.

为解决上述问题,本文提出一种基于隐藏事件触发机制的内存取证方法ForenHD.该方法利用虚拟机管理器(virtual machine manager, VMM)实时监视目标虚拟机(target virtual machine, TVM)中内核对象.针对采用DKOM技术隐藏的内核对象,ForenHD实时地监视目标对象与其他对象之间的逻辑连接关系以及运行状态,通过逻辑连接变化和状态异常判定其是否具有隐藏性.针对非DKOM型的内核对象,ForenHD首先通过内核对象占用的物理资源变化实时地捕获正在执行的内核对象,之后与TVM内部视图进行交叉验证以检测该对象是否被隐藏.检测到隐藏对象后,ForenHD对被隐藏的内核对象采用内存映射进行内存取证.ForenHD将隐藏对象的发现作为内存取证的触发事件,以检测到内核对象被隐藏的时刻作为取证时间点,以被隐藏的内核对象作为取证对象.

1 相关工作

关于内存取证技术的研究,研究者们展开了广泛而深入的探索.目前的内存取证技术大致可以分为2类:基于硬件的内存取证和基于软件的内存取证.例如Alessandro 等人[7]和Wang 等人[8]提出的方法都是利用PCI 网卡中的系统管理模式(system management mode, SMM)固件获取物理内存和CPU寄存器内容而tefan[9]则是利用网卡的网络驱动程序接口规范(networkdriver interface specifica-tion, NDIS)来获取物理内存.这些方法都属于基于物理固件的内存拷贝技术,能够随时准确地获取到内存数据.但是这些方法都需要对目标OS中的硬件引入更改,同时对硬件进行重新编程,且容易被基于硬件的Rootkit绕过.此外,它们的取证范围都是对整个内存的完整取证,包含了大量的冗余信息.

基于软件的内存获取方法主要利用软件去获取内核内存区对象,并借助于操作系统的内核数据结构和相关机制去解析重构内存数据.例如Garner开发的Data-Dumper[10]、Klein提出的Process Dumper Utility[11]都是通过用户模式的应用程序读取目标系统中内核内存区对象.这类方法是基于主机取证方法的代表,实现简单快速.但是,这些方法依赖于目标OS的内部语义视图构建函数,存在被绕过的风险.与Data-Dumper不同的是,Mantech 公司的MemoryDD[12]和MoonSols 公司的Windows Memory Toolkit[13]均通过内核模式驱动程序读取目标系统中内核内存区对象.如果攻击者采用 DKOM技术直接修改内存操作函数及其所使用的内核对象,则此类方法获取的内存数据将失真.赵宇韬等人提出的RTMF[14]通过硬件虚拟化技术构建了基于时间触发机制的入侵检测方法,能够及时发现恶意软件对敏感内核对象的篡改操作.但是,该方法仅对静态内核对象有效,无法实时监视进程状态描述符、内核模块状态描述符等动态内核对象的异常变化.因此,对通过DKOM方法实现自我隐藏的进程或模块不具有检测效果,无法实现基于隐藏事件触发的内存取证.KIMBMF[15]针对TOC-TOU攻击,通过采用随机化时间触发的方法弱化其攻击效果.但是,此方法无法确保在恶意软件进行恶意操作时立即进行检测,且存在漏检的可能,这限制了它的推广使用.

为解决上述问题,本文提出了一种基于隐藏事件触发机制的内存取证方法.

2 ForenHD总体设计

ForenHD的总体设计如图1所示.它由实时隐藏监视器Monitor、实时内存取证模块Foren和存储文档file三部分组成.在ForenHD的运行过程中,Monitor实时监视TVM中内核对象的状态变化,若发现隐藏操作则立即通知取证模块Foren.Foren被唤醒后通过内存映射捕获目标对象的内存,并将其存储在文档file中.

Fig. 1 Architecture of ForenHD图1 ForenHD架构设计

ForenHD监视和取证的内核对象包含进程和模块2类.Rootkit对进程的隐藏方法种类繁多,既包括破坏进程间逻辑连接关系的DKOM,也包括函数重定向、系统调用表重构等非DKOM技术;隐藏模块的方法相对单一,均是采用DKOM技术.利用DKOM技术隐藏的进程和模块,其状态描述符中的逻辑连接条目在隐藏过程中发生了改变,因此ForenHD通过实时检测该条目的变化即可实现隐藏检测.与之相比,采用非DKOM技术隐藏进程的Rootkit并不对进程本身做任何更改,而是通过重构语义视图函数实现隐藏目的[16].针对此类隐藏对象,ForenHD需要实时地跟踪进程的真实语义视图,并与Rootkit在TVM内部构建的虚假语义视图进行交叉验证才能检测到被隐藏的进程.

当下发现的DKOM型的Rootkit在进行对象隐藏(隐藏进程)和自我隐藏(隐藏模块)时,均需解除目标对象与其他兄弟对象之间的级联关系.Monitor将目标对象状态描述符中的级联关系成员变量作为监视对象,实时监视其变化.能够引起目标对象中级联关系成员变量产生状态变化的方式有3种:1)目标对象的正常退出操作;2)目标对象相邻节点的加入或删除操作;3)目标对象本身的隐藏操作.前2种操作属于OS的正常操作,第3种操作是DKOM型Rootkit产生的恶意隐藏操作.Monitor通过判断目标对象与相邻节点之间连接关系的变化,以及目标对象自身运行状态的变化可以有效地甄别出正常操作和隐藏操作.

采用非DKOM技术隐藏的进程会对TVM内部指令构建的语义视图保持隐藏,但是仍然会被OS正常地调度执行.为检测此类隐藏进程,ForenHD首先在SVM中实时地监视被TVM调度执行的进程.任何进程的执行都需要获得CPU时间片,并在时间片内独占CPU资源[17].ForenHD实时地捕获TVM中VCPU的上下文信息,通过esp寄存器的变化监视进程内核栈的更新,然后通过栈底的数据结构thread_info→task即可得到当前正在运行的进程.进程的隐藏操作可发生在执行阶段的任意时间点,因此ForenHD需要将每一个捕获的进程与TVM内部的进程语义视图进行交叉验证.由于ForenHD部署在SVM中,无法直接取得TVM的内部语义视图.所以,ForenHD运行前首先向TVM中植入内部视图构建模块.该模块收到视图更新指示后,利用TVM内部指令(如“ps”)构建语义视图,并将所得进程视图存储在共享内存中供ForenHD使用.

当检测到隐藏对象时,ForenHD对目标对象进行内存取证.为防止取证内容被刷新或置换到交换区,本文设计了一种映射页表缓存机制,以减少重复的映射操作,加快映射速度.完成取证后,ForenHD将取证数据存储在文档中保存.

3 内存取证系统实现

3.1 映射页表缓存机制

由于ForenHD部署在SVM中,与TVM之间存在内存隔离,因此不能直接读取TVM的内存数据.ForenHD对TVM的所有读内存操作都需要经过内存映射,在内存映射过程中为取得内存页框,需要完成从页目录到页表再到页框的多级页表映射操作.例如获取32位TVM的单个内存页框需要经历3次内存映射,而64位TVM则需5次.同一进程或模块的不同内存页框之间共用同一页目录,其页表也可能相同.因此,对共用页目录或页表的不同页框的内存映射操作会造成对已映射内存的重复映射.为减少重复映射操作,ForenHD引入了映射页表缓存机制,如图2所示(以32 b地址宽度为例).

Fig. 2 Initialization of page mapping图2 页面映射初始化

映射操作前,ForenHD按照OS中的多级页表分别建立不同等级的映射页表缓存,并对每一缓存页建立管理结构.该结构中包含客户物理地址(GPA)、映射后的内存地址(MMA)、时间戳信息(time)、双向循环链表连接项(list)和下一级缓存首地址(next_init)等信息.各级缓存页表按照时间戳由大到小的顺序构成双向循环链表,由初始节点指向时间戳最大的缓存页.各级缓存的链表连接关系如图3所示.

Fig. 3 Structure of mappedpage table图3 缓存链表结构

内存映射初始化时,ForenHD首先得到TVM中VCPU的cr3寄存器,并将该寄存器内容和内存映射指令“IOCTL_PRIVCMD_MMAP”通过ioctl传递给驱动privcmd.驱动privcmd收到指令后将cr3寄存器内容对应的页目录映射到SVM中.得到映射页目录后,ForenHD将该映射页目录信息填充到页目录缓存链表中,并建立指向该缓存项的初始节点init_node.在之后进行的内存映射中,ForenHD陆续将各级页表填充到对应的缓存结构中,直到得到虚拟地址对应的内存页框初始化完成.之后,ForenHD在内存映射时从页目录到各级页表,以各自的GPA为键值逐级检索缓存结构.在对每一级缓存进行检索的过程中,ForenHD从next_init指向的时间戳最大的缓存项开始,搜索当前缓存链表中是否存在与GPA相匹配的映射内存.若存在匹配项,则根据虚拟地址中本级页表对应的偏移量(如图3中p1和p2)直接读取下一级页表首地址的GPA,并以该GPA为键值继续搜索下一级缓存链表;若不存在匹配项,则停止本级及之后的缓存检索操作,并从本级开始进行逐级内存映射,直到得到目标缓存页结束.ForenHD通过内存映射得到页表的映射内存后,以该页表的信息更新当前缓存链表中最小时间戳对应的缓存项.若更新项属于页目录缓存链表,则将init_node更新为该项的地址;若更新项属于页表缓存表,则使上一级缓存项中的next_init指向该缓存项.

通过映射缓存机制可以减少对各级页表的重复映射.若缓存链表中不存在对应的缓存项,完成一次内存映射需要进行3次页面映射操作(32位OS);若仅存在页目录映射缓存,则需要进行2次页面映射;如果缓存池中页目录和页表缓存同时存在,则仅需1次页面映射即可.

3.2 隐藏进程的实时检测

在Linux系统中,每个进程在被创建时都会由函数alloc_thread_info分配若干个完整的内存页(8 KB或16 KB)作为内核栈.内核栈采用自顶向下的方式增长,esp寄存器指向栈基址.数据结构thread_info存储在以栈基址为起始地址的一段内存中,它的第一个成员变量即指向进程描述符task_struct[18].进程的切换执行也伴随着CPU寄存器esp所指向的内核栈的切换.ForenHD实时捕获TVM中VCPU上下文信息,并提取出esp寄存器;然后通过esp寄存器的变化判定栈基址的更新;最后通过读取指针thread_info→task得到当前正在执行的进程.由于任何进程的执行都离不开CPU资源,因此利用该方法取得的进程视图能够监视到以任何形式隐藏的进程.

Fig. 4 Monitoring process图4 监视流程

3.2.1 DKOM型隐藏进程的实时检测

目前,采用DKOM技术对进程进行隐藏的技术已经出现,如linuxfu.linuxfu利用DKOM技术将进程状态描述符从它所属的双向循环链表中摘除,以实现隐藏目的.被隐藏的进程对依赖进程间逻辑关系实现检测目的的方法如libvmi[19],vmwatcher[20]等具有极强的隐藏效果.针对此类隐藏进程,ForenHD在监视到VCPU中存在新切换的进程后,检测该进程与该进程的状态描述符中list项所指向的进程之间的连接关系,并通过进程运行状态变化判定是否发生隐藏行为,监视流程如图4所示.

在图4中需要注意的是,在判定隐藏进程的时候不仅需要当前进程的运行信息,还需要核对与该进程的链表相邻进程的指向关系.若相邻节点的list项均不再指向当前进程,或当前进程的list项不再指向任何相邻节点,都判定该进程发生了链表移除操作.此时,若当前进程的状态仍为TASK_RUNNING态,则认定该进程为隐藏进程.

3.2.2 非DKOM型隐藏进程的检测

在当前的各类Rootkit中,采用非DKOM技术隐藏进程的Rootkit仍占多数.此类Rootkit并不会对进程本身做出任何更改,而是将构建进程语义视图的系统接口作为攻击目标,实现对内部进程语义视图的重构.由于进程的自身保持正常,我们很难通过监视进程状态实现隐藏检测.ForenHD在TVM内部部署了一个语义获取模块InerSem,该模块利用TVM指令建立内部进程视图.ForenHD通过Xenstore[21]实现与InerSem之间的消息传递,通过内存映射实现语义视图的传递.初始化时,InerSem将生成的进程视图存储在内存池SemPool中,并将构建视图的时间戳信息存储在SemPool顶部,之后通过Xenstore通知ForenHD将SemPool映射到SVM中.ForenHD将实时捕获的进程与SemPool中的进程视图进行交叉验证即可检测到隐藏的进程.

ForenHD捕获的进程是当前CPU时间片内正在运行的进程,此时SemPool中的进程视图应在理论上包含此进程才能确保交叉验证操作有效.CPU中所执行的进程既可能是首次执行的“新进程”,也可能是之前尚未执行完毕而被再次调度执行的“老进程”,二者都可能是被Rootkit隐藏的可疑进程.进程的创建、退出和隐藏都会导致TVM内部的进程视图发生改变.由于ForenHD采用存在性验证方式检测进程的隐藏性,因此进程退出并不影响视图交叉验证.但是,我们必须在进程创建或隐藏之后,在交叉验证之前的时间段内重构SemPool中的进程视图,才能确保SemPool中的进程视图的时效性.

触发SemPool更新的方式包括条件触发和无条件触发2种,前者针对“新进程”的隐藏检测,而后者则针对“老进程”的隐藏检测.ForenHD捕获到当前进程后,首先通过该进程的task_struct→real_start_time取得进程的启动时间戳[22],并与SemPool顶部的时间戳信息进行比较.若进程的启动时间戳大于SemPool的时间戳,则说明当前进程是“新进程”,并以该事件作为触发SemPool更新的事件.此外,SemPool也会定时更新,以确保SemPool正确反映“老进程”被隐藏后的进程视图.在整个检测过程中,若进程启动时间戳小于SemPool的时间戳,则将该进程与SemPool中的进程视图进行交叉验证.当前进程的启动时间先于SemPool中进程视图的更新时间,说明理论上SemPool中的进程视图应当包含该进程.因此,若该进程不存在于SemPool中,则可判定该进程为隐藏进程.

3.3 隐藏模块的实时检测

LKM的运行信息,如导出符号、初始函数、代码段等都存储在状态描述符structmodule中.所有的状态描述符被连接成一个双向循环链表(module→list).在该链表中,始终存在一个初始化模块,它本身并不实现具体功能,只作为双向循环链表的一个初始节点,连接着链表中的第1个模块(本文记作“首模块”).任何新增模块在进行内核模块加载时,都需要加载到初始模块后面成为它的下一个节点(即新的“首模块”).

当前的内核级Rootkit均以LKM的形式加载到内核中,因此Rootkit隐藏模块即是自我隐藏.与进程多种多样的隐藏方式不同,Rootkit通常采用DKOM技术解除与其他模块之间的链表连接关系以实现自我隐藏.此外,不同于进程可在执行期间的任意时刻被隐藏,模块的隐藏仅发生在初始化阶段.内核级Rootkit在加载过程中,首先由OS将其连接到双向循环链表中;之后通过自定义的初始化函数执行链表移除操作实现隐藏目的;最后OS再将模块的状态更新为MODULE_STATE_LIVE完成初始化.

引发初始模块list项变化的可能有3种:1)首模块正在被正常卸载;2)有新模块正在被加载;3)首模块正在被隐藏.这3种操作引发的模块状态变化如图5(a)~(c)所示.

Fig. 5 State transition of modules图5 模块状态变化

模块正常加载引发初始模块list项发生变化时,更新前list所指向的模块的状态为MODULE_STATE _LIVE;更新后的list所指向的模块状态为NULL.模块正常卸载引发初始模块list项发生变化时,更新前list所指向的模块状态为MODULE_STATE _GOING;更新后的list所指向的模块状态为MODULE_STATE_LIVE.模块隐藏引发初始模块list项发生变化时,list变化前所指向的模块状态为MODULE_STATE_COMING;更新后的list所指向的模块状态为MODULE_STATE_LIVE.ForenHD在监视到初始模块的list项发生变化时,检测首模块的状态并判断其是否正在发生隐藏操作.需要注意的是,由于list变化后模块的状态可能会在极短的时间内发生改变,所以ForenHD需要在监视到list变化时暂停TVM,防止模块状态尚未被读取就发生改变.

3.4 隐藏对象实时取证

3.4.1 隐藏进程取证

检测到隐藏进程后,ForenHD立即对隐藏进程进行内存取证,取证内容包括进程的执行路径、映射库文件、代码段和数据段.通过对(task_struct→mm→start_code, task_struct→mm→end_code)区间段的内存进行映射读取即可得到进程的代码段.同样地,对(task_struct→mm→start_data, task_struct→mm→end_data)区间段的内存进行映射读取即可得到进程的数据段.

追溯文件路径和映射库文件的一个关键结构体是struct dentry,其获取方法是逐级读取指针task_struct→mm→mmap→vm_file→file→fpath→dentry.在结构体dentry中含有2个关键的条目,一个是struct dentry*d_parent,指向当前文件或目录的父目录(可为空);另一个是unsigned chard_iname[DNAME_INLINE_LEN],该数组中存放着当前文件或目录的名字.通过由“子”向“父”的不断递推,直到追溯到根目录“/”,并逐级读取文件或目录名,这样就能获取到完整的文件路径.映射文件的偏移量存储在vm_area_struct的vm_pgoffset项中,该项的大小以PAGE_SIZE(本文中大小为4 KB)为单位.

3.4.2 隐藏模块取证

发现隐藏模块之后,ForenHD会对目标LKM的代码段进行内存取证.LKM状态描述符中的module_core项指向LKM的代码段,core_text_size项记录了代码段大小.ForenHD根据这2项通过内存映射即可得到LKM的代码数据,其实现过程如图6所示:

Fig. 6 The memory forensic of modules图6 模块内存取证

4 实验结果与分析

实验环境由物理主机、Xen虚拟化平台、SVM和TVM组成.物理主机为Dell R710机架式服务器,配置为Intel Xeon®E5520@2.27 GHz 16核处理器、16 GB内存、137 GB硬盘.Xen虚拟化平台为Xen 4.1.2.操作系统系统环境配置如表1所示:

Table 1 Experimental Environment表1 实验环境

4.1 隐藏对象实时检测与内存取证

linuxfu是一种利用DKOM技术隐藏进程的典型Rootkit.Diamorphine是一种以LKM形式加载进内核中的内核级Rootkit,它通过解除与其他模块之间的逻辑关系隐藏自身.本节以linuxfu隐藏的进程为例,详细说明ForenHD对隐藏进程的实时检测和内存取证效果,以diamorphine为例验证ForenHD对隐藏模块的隐藏检测和内存取证的检测和取证效果.

4.1.1 隐藏进程检测

Linuxfu感染TVM后,会以LKM的形式加载到内核空间,从而获得root权限.通过将目标进程从双向循环链表中移除,linuxfu可以实现对进程的隐藏.ForenHD对linuxfu所隐藏进程的检测结果,以及与libVMI进行的对比如图7所示.图7(a)是ForenHD在SVM中对进程加载执行的实时监视.图7(b)和(c)分别是TVM中未运行linuxfu和运行linuxfu时,利用libVMI在SVM中得到的TVM进程视图,通过对比发现,libVMI无法检测到linuxfu的隐藏进程test.图7(a)显示,当linuxfu隐藏进程test时,ForenHD能够实时地检测到linuxfu对test的隐藏操作,如图7(a)横线部分.

Fig. 7 Hidden process detectionof Linuxfu Rootkit图7 Linuxfu隐藏进程检测

Fig. 8 Execution path and map library file of hidden process图8 隐藏进程执行路径及映射库文件

4.1.2 隐藏进程取证

ForenHD对隐藏进程的执行路径和映射库文件的取证结果图8所示.图8(a)是ForenHD的取证结果,图8(b)是在TVM中使用指令“pmap”得到的test的映射库文件视图.从图8中可以看出,ForenHD能够检测到隐藏进程test的完整映射库文件及其偏移量.其中,左侧窗口横线部分就是隐藏进程的执行路径.

图9是ForenHD对隐藏进程test取证所得的代码段信息(图9(a))与利用指令“objdump-S test”在TVM中得到的test代码段(图9(b))的对比结果.对比显示:ForenHD的取整数据与test代码段完全一致.

4.1.3 隐藏模块检测

ForenHD对LKM的隐藏事件检测如图10所示,分别是ForenHD的检测视图和TVM的内部指令视图.从图10可以看出,diamorphine隐藏后,无论是模块的外部语意视图(图10(a)中MODULE LIST)还是其内部指令视图(图10(b)中lsmod)均无法检测到它的存在.但是,ForenHD能够检测到diamorphine的隐藏事件操作,如图10(a)横线部分所示.

4.1.4 隐藏模块取证

图11是ForenHD对diamorphine的取证结果,图11(a)和(b)分别是ForenHD的取证数据和利用指令“objdump -S diamorphine.ko”所得的静态代码数据.需要注意的是,未加载的LKM因为尚未完成符号重定向等操作,所以部分数据为初始值0.ForenHD的取证对象是运行态的LKM,此时LKM已完成初始化操作,因此原来为0的静态数据可能已发生变化.抛开静态数据0产生的差异,可以发现ForenHD的取整数据与静态代码完全一致.

除linuxfu和diamorphine外,实验中还对多种其他类型的Rootkit进行了实验,实验结果汇总如表2所示.从表2中可以看出,ForenHD能够检测到各种类型Rootkit隐藏的内核对象并对内核对象进行内存取证.

Fig. 11 Code forensic of hidden module图11 隐藏模块代码取证

RootkitNameProcessModuleDetectionForensicDetectionForensicadore-ng√√√√horsepill√√brootus√√diamorphine√√√√z-Rootkit√√√√linuxfu√√xingyiquan√√kbeast√√√√mak_it√√

TVM内部工具(如ps,top等指令)在构建进程视图时,必须要借助TVM提供的进程视图构建函数.Rootkit(如adore-ng,z-Rootkit等)侵入TVM后会重构或重定向这些函数,导致内部进程视图失真.诸如libVMI类的外部视图构建工具,虽然通过虚拟机之间的隔离性避免了使用TVM内部不可信函数,但其构建进程视图的过程依赖于进程之间的逻辑关系.一旦某种Rootkit(如linuxfu)打破了进程之间的逻辑关系,此类工具得到的进程视图将变得不可信.

与libVMI等安全工具不同是,ForenHD构建进程的真实视图时既不依赖于TVM的内部函数,也不依赖于进程之间的逻辑连接关系.ForenHD首先根据VCPU中esp所指向的内核栈的更新判定进程的切换执行,然后通过内核栈中的数据结构取得VCPU中正在运行的进程.由于任何进程的执行都需要获得CPU、内核栈等物理资源,因此ForenHD通过监视物理资源变化构建的进程视图能够涵盖各类Rootkit隐藏的进程.ForenHD实时地捕获每一个在CPU中执行的进程,并检测所捕获进程与其他进程的逻辑连接关系是否遭到破坏.与此同时,ForenHD还搜索该进程是否存在于InerSem构建的TVM内部进程视图中.因此,ForenHD能够检测到以任何形式被隐藏的进程.

无论是内部工具还是外部工具,在构建模块视图时都依赖于模块之间的逻辑连接关系.所以Rootkit只需将LKM从双向循环链表中移除即可实现隐藏目的.模块的隐藏操作均发生在加载期间初始化函数的调用过程中,且在加载完成之前就已经实现了隐藏目的.因此ForenHD实时地监视初始模块的链表更新,并通过首模块的状态变化甄别LKM的加载、卸载和隐藏行为.所以当Rootkit进行隐藏操作时,会被ForenHD实时地检测到.

4.2 内存取证性能分析

4.2.1 运行时间

本实验以目标对象的隐藏检测作为时间起点,测试完成隐藏检测和取证总共所需的时间.取证操作所需时间与取证的内存数量相关,实验中逐渐增加目标对象的体积并测量检测和取证总共所需的时间,结果如图12所示:

Fig. 12 Performance overhead of memory forensic图12 内存取证性能开销

从图12中可以看出,ForenHD对进程和模块的检测及取证所需时间几乎相同,均与取证内存的数量成正相关.此外,可以发现映射第一个内存页时耗时较多.这是由于ForenHD对内存映射引入了映射页表缓存机制,在进行首次映射时需要完成对多级页表的映射并建立缓存.之后进行内存映射时,ForenHD会首先对页表缓存进行搜索,若存在存根则直接读取,这可以减少对已映射页表的重复映射,提高映射速度.

Fig. 13 Time proportion of detection and forensic图13 检测与取证的时间占比

以4 KB内存数量为例,测量隐藏进程检测、隐藏模块检测、进程取证和模块取证4部分的耗时百分比,结果如图13所示:

对比发现,对进程的隐藏检测耗时最多,对模块的隐藏检测耗时最少.因为在监视进程时,需要实时地捕获vcpu上下文信息,然后通过内存映射得到内核栈,之后再次通过内存映射得到进程描述符,最后解析进程的状态描述符并进行隐藏性校验.而对模块的监视只需要映射得到LKM状态描述符后检测模块状态即可.因此,ForenHD对进程的隐藏检测耗时较多.

4.2.2 性能开销

本节利用Linux系统性能测试工具nbench[23]测试ForenHD对SVM和TVM产生的性能影响.Nbench的测试结果共有10项,每项测试表示每秒能够完成的测试个数,进行多次测试取平均值,数值越大表明处理速度越快.实验中分别测试了ForenHD对SVM和TVM的影响,包括进程隐藏性检测(P-Monitor)、模块隐藏性检测(M-Monitor)和内存取证(Foren)各自造成的性能开销,以及总的性能开销.

Fig. 14 Influence of ForenHD modules on SVM performance图14 ForenHD各功能模块对SVM的性能影响

测试结果如图14~16所示.图中各项结果均以系统中不运行ForenHD的性能表现作为标准做了归一化处理,横坐标表示测试类型,纵坐标表示性能损耗.可以看出,P-Monitor,M-Monitor和Foren对SVM引入的平均性能开销分别为2.9%,1.0%和1.9%,总计为5.8%;对TVM引入平均性能开销分别为1.4%,0.4%和1.0%,总计为2.8%.对比发现,ForenHD对SVM影响较大,同时各功能模块中又以进程检测引入的性能开销最大.

Fig. 15 Influence of ForenHD modules on TVM performance图15 ForenHD各功能模块对TVM的性能影响

由于ForenHD部署在SVM中,其主要计算资源和存储资源均来自SVM,因此它的运行将对SVM产生的影响较大;对TVM的影响则主要来源于其对整体资源占用造成的影响以、运行过程中对TVM的短暂暂停以及内部进程视图的生成3部分.

ForenHD为实时地捕获CPU中执行的进程,首先获取TVM中VCPU上文信息,然后通过esp寄存器的变化识别内核栈的更新.紧接着通过内核栈中的thread_info→task得到当前进程的状态描述符,最后通过进程描述符解析进程的状态,如进程名、进程号、启动时间和逻辑连接关系等.之后,为检测当前进程的隐藏性ForenHD需要将其与TVM的内部进程视图进行交叉验证.若检测到该进程为新进程,则需等待TVM内部进程视图更新后再进行验证.整个进程的检测过程需要依次取得并解析TVM的VCPU上下文、进程内核栈的内存映射和进程描述符的内存映射,且进程切换频率较高.因此进程检测会引入较大的性能开销.模块检测的性能开销主要来自于初始模块的实时监视和新增模块的状态检测2部分.与进程切换相比,模块的加载和卸载频率较低,所以引入的性能开销较小.内存取证的产生的性能开销则来自内存映射、内存读取和内存转储3部分.

5 总 结

本文提出了一种基于隐藏事件触发机制的内存取证技术ForenHD.它能够实时地检测到被隐藏的进程和模块,并完成对目标对象进行内存取证.ForenHD以发现隐藏对象的时刻作为取证时间点,确保了该时刻的内存中包含了表征目标对象恶意行为的代码段信息.与RTMF等软件方法相比,ForenHD以隐藏事件作为内存取证的触发条件,在恶意软件进行隐藏动作时即可实现内存取证. 同时,ForenHD的取证对象并非是TVM的全部内存,而是仅对被隐藏的内核对象进行取证. 与基于硬件的内存取证方法相比,该方法在最大程度上减少了取证的冗余信息.通过实验验证,ForenHD能够实时地检测到被各类Rootkit隐藏的进程和模块,并快速捕获其内存证据.ForenHD对SVM和TVM分别引入了5.8%和2.8%的性能开销.

但是,ForenHD仍存在一些局限性.首先,ForenHD假设虚拟化平台和SVM是绝对安全的.目前针对hypervisor和特权域的恶意软件已经出现,如何确保它们的安全显得尤为重要.其次,ForenHD仅对正在加载的Rootkit进行取证有效,而对于运行前已完成加载的Rootkit无法取证.最后,ForenHD仍采用以已知的内核语义知识为模板解析TVM内部语义的方式克服语义鸿沟问题,一方面会影响系统执行速率[24],另一方面也未考虑地址随机化[25]造成的语义模板多样化的问题.这些问题都将作为我们后续的研究重点展开.

猜你喜欢
链表内核视图
多内核操作系统综述①
强化『高新』内核 打造农业『硅谷』
蒙特卡罗模拟中基于双向链表的元胞链表方法
活化非遗文化 承启设计内核
如何用链表实现一元多项式相加
微软发布新Edge浏览器预览版下载换装Chrome内核
跟麦咭学编程
视图
Y—20重型运输机多视图
SA2型76毫米车载高炮多视图