百度一下 藏锋者 就能快速找到本站! 每日资讯归档 下载藏锋者到桌面一键访问

当前位置:主页 > 网络安全 > 基于行为监测的Anti-R/Bootkit的研究与实现

基于行为监测的Anti-R/Bootkit的研究与实现

所在栏目:网络安全 时间:04-12 22:28 分享:

论文摘要
Rootkit是一种新型的恶意程序程序或程序集,设计的目的是用来秘密的控制被攻占的计算机的行为。通过隐蔽后门程序或其他类似的工具程序,使得这些工具程序能在指定计算机上长期非法存在;同时当用户查询计算机的当前状况时,通过隐藏相关信息的方法来欺骗用户,使用户相信此计算机未受到侵害。Bootkit是继承自Rootkit内核权限获取和自我痕迹擦除技术的Rootkit高级发展形式,对系统启动和内核准入安全提出了最新挑战。由于Rootkit/Bootkit(R/Bootkit)属于信息安全攻防的新型技术亮点和潜在的危险变种,当前业界和学术界竞相公布出各自富有特色研究项目。
本文的主要工作和特色如下:
1. B/Rootkit行为剖析以及预防监测的技术瓶颈的提出
深入探索当前主流B/Rootkit的危害原理以及技术要点实现,以及主流Anti-R/Bootkit在行为判断上过多依赖用户选择的现状,指出了恶意进驻内核这个行为特征提取是Bootkti/Rootkit防范与检测的技术瓶颈。
2. 行为特征的形式化描述语言的提出
为了统一且完整描述R/Bootkit的各种行为以及子行为彼此间内在的关联关系,我们定义出形式化描述语言规范,以描述出该恶意行为特征。
3. 基于恶意进驻内核行为特征的Anti-R/Bootkit原型系统的设计与实现
在此基础上,利用该形式化描述语言规范和行为策略,我们设计并实现了一个基于恶意进驻内核行为特征的Anti-R/Bootkit原型系统。在和同类商业化的Anti-R/Bootkit系统的比较中,显示出较优的自主识别能力以及较好的未知R/Bootkit预防能力。
本文最后提出了R/Bootkit和Anti-R/Bootkit对抗中新的发展趋势,并介绍了下一步的工作方向。
关键词:Rootkit,Bootkit,行为特征,布控,优先启动,进驻内核,形式化描述,Behavior Detection(BD)


 第 1 章 绪论
1.1 引言
作为成为20世纪最杰出的研究成果之一,Internet改变了人们生活方式和工作方式,改变了全球的经济社会结构,越来越成为人类物质社会的最重要组成部分。开放、灵活、丰富的应用是Internet的特色,但同时潜在地也带来了安全问题。由于越来越多的组织开始利用Internet处理和传输敏感数据,与此同时在Internet上也到处传播和蔓延着攻击方法和恶意代码,使得连入Internet的任何系统都处于将被攻击的风险之中。
在Internet安全事件中,恶意软件/代码造成的危害最为严重。恶意软件(Maleware)是非用户期望运行的、怀有恶意目的或完成恶意功能的完整的程序集合[32] [33] [34]。恶意代码(Malicious Code)含义与恶意软件相近,区别在于所描述的粒度不同, 是指用于描述完成特定恶意功能的代码片段。
恶意代码正在成为信息战、网络战的主要手段,日益严重的恶意代码威胁,新型威胁和组合式威胁的爆炸式增长让防护工作变得复杂起来。例如,AV-Test GmBH表示,1998年安全厂商共收集到1738种独特的威胁样本。那个时候,安全专家监测到近30种签名,因为样本很容易组合形成特征码。10年以后,恶意软件样本数量攀升至177615种,仅仅2008年前两个月就报告了110万种独特样本。
根据趋势科技全球防病毒研发暨技术支持中心TrendLabs的发现,从2005年到2008年为止,TrendLabs报告网络威胁增长了2355%。TrendLabs研究人员也预测,如果威胁数量继续以现在的速度增长,那么2015年将会出现233亿种独特威胁。
Rootkit作为恶意程序的子集,用于实现自身及系统中特定资源和活动的隐藏,破坏可信任计算机的完整性[1]。经常用来隐蔽后门程序或其他类似的工具程序,使这些工具程序能在指定计算机上长期非法存在。当用户查询计算机的当前状况时,通过隐藏相关信息的方法来欺骗用户,使用户相信此计算机未受到侵害。Bootkit是继承自Rootkit内核权限获取和自我痕迹擦除技术的Rootkit高级发展形式。Bootkit通过感染可引导的外设固件和关键系统文件,驻留在整个系统的启动过程,获取系统控制底层权限并且擦除自我存在痕迹,从而为网络恶意代码的进一步攻击行为提供隐蔽、可靠、持久的执行环境。
国际知名的信息安全厂商——卡巴斯基实验室去年发表了题为《卡巴斯基安全公告:2008恶意软件发展情况》的报告,在这个报告中,卡巴斯基表示,2009年度的恶意软件发展情况将持续恶化。2008年对整个反病毒行业以及整个信息安全产业都产生了重大影响的安全事件主要为Rootkit的传播,以及针对在线游戏产生的恶意程序及僵尸网络。
Bootkit这个概念自2005年eEye Digital安全公司的研究人员研究如何在系统启动时利用BIOS接入windows内核的"BootRoot"项目中被第一次提出以后,也越来越为黑客所钟爱,最近更被全球知名的杀毒厂商卡巴斯基在其年度报告中列为2008年度互联网安全的重大挑战。
1.2 研究现状与意义
   Rootkit按照运行环境的不同,主要分为两类 :内核模式Rootkit和用户模式Rootkit。内核模式Rootkit具有内核态的权限,以非常底层的方式存在于操作系统中;用户模式Rootkit则运行在权限较低的用户态中。内核模式Rootkit比用户模式Rootkit更具隐蔽性,更难被检测。按照隐藏的内容来分,Rootkit隐藏的部件包括文件、目录、进程、注册表项、网络端口、设备驱动器等所有使用户判定系统异常的系统模块。
Bootkit是继承自Rootkit内核权限获取和自我痕迹擦除技术的Rootkit高级发展形式,对系统启动和内核准入安全提出了最新挑战。由于Bootkit/Rootkit(R/Bootkit)属于信息安全攻防的新型技术亮点和潜在的危险变种,当前业界和学术界竞相公布出各自富有特色研究项目。如安全人员John Heasman利用ACPI(Advanced Configuration and Power Interface)操作BIOS的新型Rootkit进行过探讨[27],这是一种特殊的利用ACPI机制存在的BIOS Rootkit;Darmawan M S a.k.a Pinczakko 发表过一系列的关于Award BIOS文件进行逆向改造的文章[28];John Heasman还就PCI设备(如显卡、网卡等设备)可能存在的Rootkit(其植入PCI设备中,特性类似于植入BIOS芯片的Rootkit)进行过讨论[29];还有Kris Kaspersky在其专著中[30]也编写专门章节来就BIOS Rootkit的实现原理进行阐述等等。Shawn Ebleton等在文献[31]第一次发表了基于SMM的跟平台无关的bootkit的实现思路;国内的安全研究员Mj0011在文献[26]中实现了基于预启动驱动方式的Tophet Bootkit的思想。
目前针对以恶意程序的预防、检测技术主要有以下几种:
1. 扫描技术:
作为目前商用恶意代码检测软件使用的主要方法之一,特征码扫描是检测己知恶意代码的最简单的方法[24][25]。扫描原理是打开被检测磁盘文件、关键内存区域、网络邮件等,扫描其中是否含有特征数据库中的恶意代码特征串,如果含有,则判断该文件含有恶意代码。其中特征数据库是在确定某个程序是恶意代码后,通过静态反汇编或动态调试,手工提取其中不同于其他程序的指令片断组成的特征数据库。
特征码扫描的主要优点是误报率低,检测准确。但是恶意程序的搜集很困难,面对层出不穷的恶意代码,需要建立一个庞大的恶意代码的搜集网络才能有效搜集;即便得到恶意代码样本,由于其特征码的提取需要专业人士人工完成,费时费力。由于对于未知的不在特征数据库中的恶意代码无能为力,越来越多的恶意代码通过使用变形、加壳、加花、多态等技术可以轻松避过特征码扫描。
2. 检测技术:
针对目前出现的各种R/Bootkit隐藏的非常巧妙的各种内核恶意代码,目前为止没有一种通用的高效方法来进行检测,主要的检测方式有:
(1) 基于特征码的内核内存扫描检测
该方法的检测原理是通过在内核内存中匹配具有特征码的内存块来检测 Rootkit,但它通常只能检测出已知特征码的Rootkit。
(2) 启发式扫描检测
该方法的检测原理是通过发现非常规的系统行为来寻找 Rootkit 的隐藏痕迹。但是由于通常不可避免会挂钩系统频繁调用的关键处理函数,对操作系统性能有较大影响。目前比较成熟的启发式扫描检测的应用实例是 VICE 和 PatchFinder等。
(3) 基于内存完整性校验的检测
该方法的检测原理是假设关键的系统部件譬如Ntoskrnl.exe的磁盘PE文件是可信的、完整的,通过对比磁盘文件中相应部分来校验内存部件的完整性。虽然对于采用挂钩不同层次的 API调用、 挂钩 SSDT(系统服务描述表)以及挂钩IDT等技术的Rootkit具有较好的检测效果,但它一般只能判断Rootkit 的存在,而并不能精确检测出 Rootkit 的位置,也较难区分采用类似技术的安全防护程序和Rootkit。
(4) 基于交叉视图的检测
该方法的检测原理是通过比较不同途径所枚举到的系统信息,譬如文件目录列表、网络连接列表、如进程列表、SSDT、IDT等关键系统部件,根据其中的差异来发现Rootkit的隐藏痕迹。虽然通过枚举系统信息的途径较为可靠通用,但是监测的可靠性依赖于不同途径的可信性。
3. 主动防御技术:
主动防御技术可以在新的未知的安全威胁破坏计算机之前检测到并且排除之。其实现原理在于定义程序执行的威胁程度规则列表,通过由某种应用程序或进程执行的行为序列来辨认一个在计算机中的新威胁。在实际运行过程中,通过全面监控运行在计算机上的系统注册表、系统文件、网络接口、设备等关键系统模块的系统调用行为,每次截获到可疑的潜在进程操作时根据操作所关联的安全属性,查询规则列表来决定此次操作是否被允许或者禁止。用户可以通过增加、删除或编辑规则来修改规则列表来阻拦程序运行或者授予程序执行权限。
而由于缺乏关联行为序列的分析与判断,这种方式存在误报率高和自主识别率的问题。例如:有些恶意程序会伪装成正常干净的程序,进行逃避监控;还有的软件会用到类似恶意程序的方式,进行安装和调用,以获得更高一级的加载权和启动权。因于二者行为的混淆,往往要求用户自己通过经验判断来决定放行还是拒绝,因此容易造成比较高的误报率。
1.3 论文主要工作与组织
目前针对以恶意程序的预防、检测技术或多或少都存在本身固有的缺点,本文通过深入研究主流R/Bootkit的设计思路以及内核准入关键技术剖析,提出基于行为特征监测的Anti-R/Bootkit的设计思路以及实现方式,以有效弥补主流恶意程序预防、检测技术的不足。本文主要工作和创新之处在于:
1. 提出了Bootkti/Rootkit防范与检测的技术瓶颈
本文深入探索当前主流B/Rootkit的危害原理以及技术要点实现,以及主流Anti-R/Bootkit在行为判断上过多依赖用户选择的现状,提出了恶意进驻内核这个行为特征提取是Bootkti/Rootkit防范与检测的技术瓶颈。
2. 提出了形式化描述语言规范
为了统一且完整描述系统运行包括恶意代码的各种行为以及子行为彼此间内在的关联关系,我们参考自然语言叙事逻辑的主语、谓语、宾语结构还有计算机体系中实际的指令格式的定义的操作码、目的操作数、源操作数,提出了一套以执行事务的概念为基础的形式化描述语言规范,完备描述出该恶意行为特征。
3. 设计与实现了基于恶意进驻内核行为特征的Anti-R/Bootkit原型系统
在此基础上,利用该形式化描述语言规范和行为策略,我们设计并实现了一个基于恶意进驻内核行为特征的Anti-R/Bootkit原型系统。在和同类商业化的Anti-R/Bootkit系统的比较中,显示出较优的自主识别能力以及较好的未知R/Bootkit预防能力。
本论文共分为五章,内容组织如下:
第一章绪论。
介绍当前针对以Rootkit/Bootkit为代表的新的网络安全威胁的预防与检测的迫切形势,以及目前学术界的相关项目研究和主流商用产品的对抗方式。
第二章R/Bootkit关键技术研究。
由于R/Bootkit之所以较传统恶意软件更为隐蔽底层难以预防、检测,是在入侵感染技术上有所突破,本章深入研究了R/Bootkit的攻击原理和分类情况以及在实现技术上的关键点。
第三章行为语义抽取&形式化描述研究。
通过剖析典型的Rootkit/Bootkit的入侵感染行为,总结出R/Bootkit恶意进驻内核这个行为特征可以作为行为分析的特征依据,为此定义并使用形式化描述语言描述行为特征。
第四章BD:Anti-R/Bootkit的设计与实现。
设计并实现了一个基于恶意进驻内核行为特征的Anti-R/Bootkit原型系统—BD(Behavior Detection)。在和同类商业化的Anti-R/Bootkit系统的比较中,显示出较优的自主识别能力以及较好的未知R/Bootkit预防能力。
第五章对本文的工作进行了全面的总结,并提出了有待进一步深入研究的几个方面。
 第 2 章 R/Bootkit关键技术研究
2.1 引言
Rootkit是攻击者在入侵系统后用来保持系统的超级用户访问权限,创建后门和隐藏攻击痕迹等常采用的技术,代表了恶意软件在创建后门和隐藏攻击痕迹等高级入侵技术上的新兴发展趋势,而Bootkit则是Rootkit在劫持系统启动技术上的高级发展形式。
由于R/Bootkit之所以较传统恶意软件更为隐蔽底层难以预防、检测,是在入侵感染技术上有所突破,因此分析R/Bootkit的攻击原理、分类R/Bootkit、研究R/Bootkit的关键技术点有助于在R/Bootkit和Anti-R/Bootkit的技术对抗中占据优势。
R/Bootkit已经入侵感染了各个主流的平台譬如Linux、Unix、Mac、Windows等,但考虑到危害的广度和深度等因素,本文优先考虑的是Windows平台下的R/Bootkit技术。
2.2 Rootkit攻击原理
1. 收集目标系统信息
攻击者在攻击某个系统之前,会使用各种社会工程学方法探查目标系统的型号、帐户弱点、系统以及应用程序等未打补丁的漏洞等。
2. 获得超级用户访问权限
攻击者在收集了目标系统的足够信息,检测到了目标系统的可供利用的漏洞后,就会对目标系统发起攻击。为了获得目标系统的超级用户访问权限,攻击者可能先获得普通用户访问权限,然后再利用目标系统的本地漏洞提升到超级用户访问权限;或者直接利用已经查明的网络服务的漏洞获得超级用户访问权限。                                                     
3. 在目标系统上安装R/Bootkit
攻击者在获得超级用户访问权限后,攻击者就可以在目标系统上安装Rootkit从而绕过或者直接关闭防护系统、创建隐蔽通道、隐藏攻击行为。如果是Bootkit的话可能会篡改某些系统部件,然后强制系统重启,从而在系统启动阶段劫持系统。
4. 控制目标系统
攻击者在目标系统上安装R/Bootkit后,就可以持久的控制目标系统,对其进行各种攻击而不被目标系统的管理员察觉。例如:利用目标系统作为傀儡机攻击其它目标系统,使目标系统拒绝提供某些服务等等。
2.3 Rootkit分类
根据Rootkit运行所在的操作系统层次[6][7],可分为应用级Rootkit和内核级Rootkit。
应用级Rootkit是指入侵到操作系统应用层的工作在Ring3级别的Rootkit,通常会替换或修改一些系统工具、信息收集程序等来执行特定攻击任务。比如提取运行的进程、文件系统的内容、网络连接状态等信息,以及安装网络嗅探器(Sniffer ) 来获取一些敏感信息(比如其它系统的用户名和密码等)。目标是重新获得更多的用户访问权限和隐藏攻击痕迹,一般不会对操作系统的其它应用服务造成影响。
内核级Rootkit是指入侵到操作系统内核层的工作在Ring0级别的Rootkit,通常会篡改、过滤任何感兴趣的底层数据结构,比如中断处理函数、系统调用、文件系统、驱动设备、句柄管理器、对象管理器等以伪造虚假的底层系统信息给应用层从而达到隐蔽感染痕迹、维持持久后门等目的。由于拥有对CPU的最高操作权限,可直接操作硬件设备,无内存访问限制,不仅可以实现应用级Rootkit无法完成的隐藏功能,还可以逃避任何应用层的检测,预防和检测的难度更大。
2.4 R/Bootkit技术研究
根据Rootkit 实现隐藏的方法可分为两类[8]:一类是通过修改应用程序调用系统函数的执行路径,劫持正常程序及系统函数调用的执行路径,篡改函数调用函数的返回值以达到向用户隐藏攻击信息的目的;一类是通过修改系统内核数据结构,当用户程序向内核查询信息的时候,内核系统函数查找了被 Rootkit 篡改的内核对象,错误地返回了隐藏攻击信息的结果。
2.4.1 Rootkit 关键Hook技术
2.4.1.1 执行路径劫持
所谓可执行路径就是程序操作从用户态到核心态包括环境切换所执行代码的序列。对于属于某个操作的任何可执行路径(代码序列),理论上都可以通过Hook(钩挂、挂接)技术将控制权导向额外的拦截代码,经过附加处理后再跳转到原来的执行路径。典型的执行路径截获全景图如图2-1所示:
 
图 2 1  执行路径截获
而根据被替换代码在操作系统中所处的优先级级别的不同,可执行路径劫持可分为:用户级Hook 和内核级Hook。
1. 用户态Hook 技术
是指被替换的API 函数处于用户态DLL或者非核心驱动程序中。常见的方式有:
(1) 代理DLL钩挂
代理DLL(也称为“特洛伊DLL” ),工作原理是直接用重写的DLL文件来替换系统中原有的DLL,并将原DLL改名并且保证重写的DLL的IAT(Import Address Table )和原DLL 的EAT(Export Address Table)之间存在一个一一映射。系统调用到需Hook的API,就跳转到代理DLL中相应的API入口,执行了额外的恶意代码截获并处理特定的消息之后跳转到原DLL中的API运行。
(2) 修改Call 指令
采用直接修改代码的方式来实现挂接。其基本思想是,程序装入内存后,通过搜索程序的地址空间,找出调用目标API 函数的CALL指令,然后修改该CALL 指令后的函数地址,从而实现挂接。
(3) 修改函数输入表(IAT,Import Address Table)
该方法基于Windows PE 文件。PE 格式是微软Win32 环境可执行文件(包括.EXE、 .DLL 、.VXD、 .SYS、 .VDM 等)的标准格式,基本结构如图2-2所示:
 
图 2 2  Windows PE 文件格式示意

idata 节中包含函数输入表,IAT中记录着该文件运行中需调用的所有链接库,以及链接库中需调用的所有库函数。PE文件运行时,文件自身和IAT中记录的链接库都加载到内存,将调用导入函数的指令和函数实际所处的地址联系起来,以后就通过 IAT来调用这些函数。
IAT Hook的原理是:在进程加载时修改 IAT,将要 Hook的API函数地址改为自定义函数的地址。这样,进程每次调用此函数时,其实执行的是Rootkit代码,然后再跳转回原来的正常代码。
(4) 修改函数输出表(EAT,Export Address Table)
EAT存在于PE文件中的edata节,保存了可执行文件(如DLL 文件)的导出的可供其他模块来调用的函数和公共变量,包括函数名称和地址等。通过替换Windows 系统某些重要DLL中的输出函数地址,即可实现目标函数的挂接。
(5) 修改API 函数
常见修改API 函数的方法:
a) 通过某个CPU 控制转移指令(如CALL 或JMP) 修改目标API 的头几个字节;具体操作如下[19]:找到目标API 函数在内存中的地址,然后修改这个API 函数前几个字节(修改前需另外开辟空间存储被修改的字节),把它改为跳转到替换API 函数的JMP指令。取消API 函数的挂接时,取出事先保存的字节,并将它们放回挂接函数的开头即可。
b) 通过中断指令(Int 3)代替目标API 第1 个字节。
通过Int 3 产生异常,截获异常实现挂接API。
(6) 其它技术
除了以上技术,用户态布控技术还包括:内存映射技术;dll插入技术,如远程线程插入,内存映射文件插入、调试程序插入等;
2. 内核级Hook[46]
用户级Hook 比较简单,但容易被Rootkit之类的隐藏植入工具轻易绕过。如果将挂接深入到系统内核,使它与检测工具处于相同的运行环境,将极大的提高挂接的深层布控效果。常见的方式有:
(1) 修改系统服务分配表(System Service Description Table,SSDT)
系统调用是操作系统内核向应用程序提供的操作硬件设备、请求内核服务的接口。系统调用接口位于用户态与核心态之间,应用程序通过系统调用向操作系统内核请求服务,操作系统内核完成服务后将结果返回给应用程序。
系统服务调度表中存放了所有系统服务函数的入口地址,在系统服务调用过程中,系统通过服务号到系统服务分配表中查找对应的中断服务过程的地址,到系统服务参数表(System Service Parameter Table,SSPT)中得到调用的参数,然后执行中断服务过程。通过替换系统服务分配表中某些服务号对应的中断服务过程的地址,就可实现对指定API 函数的挂接[20]。
(2) 修改中断描述符表(Interruption Descriptor Table,IDT)
所谓中断,是一个过程,即CPU在正常执行程序的过程中,遇到外部/内部的紧急事件需要处理,暂时中断(中止)当前程序的执行,而转去为事件服务,待服务完毕,再返回到暂停处(断点)继续执行原来的程序。为事件服务的程序称为中断服务程序或中断处理程序。
每个中断用一个0-255 的数字标识,Intel 称这个数字为向量。中断描述符表是一个有256 个入口的线性表,每个IDT的入口是个8字节的中断门描述符指向相应的中断处理过程。当中断发生时,CPU 会根据中断向量和中断描述符表中的值,转移到相应的中断处理程序。
IDT钩挂的原理是:首先保存出特定的中断向量的ISR, 然后直接修改该中断向量的ISR为自定义的函数,每当这个中断向量对应的中断产生时,就会调用自定义的函数。由于我们自定义的函数里面执行完我们的功能后再跳转到原ISR处执行。
(3) SYSENTER指令钩挂
由于之前的int2e系统调用机制,涉及到的Interrupt/Exception Handler的调用都是通过 call/trap/task这一类的gate来实现的,这种方式会进行栈切换,并且系统栈的地址等信息由TSS提供,可能会引起多次内存访问 (来获取这些切换信息),系统开销较大。SYSENTER/SYSEXIT这对指令汇编指令作为快速系统调用机制的一部分是在Pentium® II 处理器及以上处理器中提供的。
SYSENTER指令钩挂的原理是:首先Ntdll 加载相应的请求服务号到EAX 寄存器中,同时EDX 寄存器存贮当前的栈指针ESP,然后Ntdll发出SYSENTER 指令,该指令转移控制权到寄存器IA32_SYSENTER_EIP 存贮的地址中[21],通过修改这个地址,可实现相应的挂接。
(4) 修改IRP (I/O Request Packet) 函数表
Windows驱动程序由一组例程组成,这些例程在处理I/O请求的不同阶段时被调用。其中分发例程(dispatch routines)负责处理不同种类的IRP,实现打开、关闭、读、写 等主要功能。修改驱动程序的函数表,将要Hook的分发例程的入口地址替换为新的IRP处理函数,在其中的Rootkit恶意代码负责截取相应IRP进行额外处理,经过信息过滤之后再调用原来的IRP处理函数。示意的IRP挂接如图2-3所示:

 
图 2 3  IRP挂接
(5) 分层驱动Hook
Windows的驱动程序模型采用分层栈式结构。对设备的访问请求从驱动栈顶开始,处理后再传递到下一层驱动。这就方便了系统的扩展,当需要新功能时,只要编写新的驱动程序,并指定其在驱动栈中的位置即可,无须修改原有系统。而完成例程(completion routines)在下层驱动处理完IRP返回时被调用,把Rootkit代码设置为完成例程,可以在不修改驱动原有函数功能的情况下修改 IRP的返回结果。

2.4.1.2 直接内核对象操作技术(Direct Kernel Object Modify,DKOM)
Windows系统经常要创建、打开和操作各种各样的内核对象,比如存取符号对象、事件对象、文件对象、设备对象、驱动对象、文件映射对象、I/O 完成端口对象、管道对象、进程对象等。每个内核对象只是内核分配的一个内存块,并且只能由该内核访问,应用程序由于特权级别的限制无法在内存中找到内核对象的数据结构,也就不能直接修改它们的内容。操作系统提供的很多具有Ring0特权级别的原始服务API (Native API)都是通过查询相应内核对象,从而返回相应结果的。DKOM的实质就是直接修改Native API 访问的内核对象,影响Native API 的返回结果实现某些隐藏功能。
典型的使用DKOM技术的Rootkit是用来隐藏进程[7]。Windows系统枚举进程使用的是活动进程列表PsActive ProcessList,它是一个双向链表,每个结点对应一个进程的 EPROCESS数据结构,所有结点通过EPROCESS结构中的 ActivePr0cessLinks双向指针链在一起。要隐藏某个进程,只需修改对应 EPROCESS的ActiveProcessLinks,将其从链表中摘除即可。由于系统执行线程调度使用的是线程链表而不进程链表,因此这样的修改不会影响进程运行。
2.4.2 Bootkit启动劫持技术
2.4.2.1 Windows启动流程
Windows启动主要分为:BIOS、MBR、系统引导程序Ntldr、内核初始化。如图2-4所示:
 
图 2 4  Windows启动流程

1. BIOS启动
在CPU上电之后,若由硬盘启动,则BIOS将硬盘的主引导记录(位于0柱面、0磁道、1扇区)读入物理地址0:7C00处,然后将控制权交给主引导代码。
2. MBR启动
MBR(Master Boot Record )主引导记录包含两部分的内容,前446字节为启动代码及数据,而从446(0x1BE)开始则是分区表,分区表由四个分区项组成,每个分区项数据为16字节,记录了启动时需要的分区参数。
在CPU上电之后,若由硬盘启动,则BIOS将硬盘的主引导记录(位于0柱面、0磁道、1扇区)读入物理地址0:7C00处,然后将控制权交给主引导代码。主引导代码的任务包括:
(1) 扫描分区表,找到一个激活可引导分区(bootable partition);
(2) 找到激活分区的起始扇区(Boot sector);
(3) 将激活分区的引导扇区装载到物理内存7C00处;
(4) 将控制权交给引导扇区代码;
3. OBR(OS Boot Record,系统引导记录)启动
OBR找到Ntldr,把Ntldr读入物理地址2000:0000,Ntldr进32位,加载内核;
4. Ntldr启动
Ntldr是由两部分构成,一部分是被称作Su Module的16位汇编代码,另一部分则是名为Osloader的PE文件。Su module位于Ntldr的头部,Osloader紧随其后。OBR将Ntldr加载到物理地址2000:0000开始的地方,然后跳转到这个地址,将控制权交给Ntldr进行引导,而这个地址也就是Su的入口。
Su的主要功能是为Osloader准备内存环境,包括GDT、IDT、打开保护模式(未分页)和将Osloader按编译时的虚拟地址移动Osloader等等。在MP(多处理器)版本的Ntldr中,Su还负责检测Osloader的完整性,如果它检测到Ntldr被修改,就会中止启动。
至于Osloader,它的作用可以简单归纳为为内核准备执行环境,然后根据Boot.ini的设置将Windows内核、Hal.dll和其它Boot Driver加载进内存。
Osloader最终会调用Osloader!(SystemEntry)(BlLoaderBlock)也即Ntoskrnl!KiSystemStartup真正启动内核。
5. 内核启动
Ntoskrnl和Hal模块作为内核会被加载驻留内存直到操作系统关闭。
2.4.2.2 Bootkit 劫持方式
1. BIOS Hook
当计算机开机时,根据硬件特性就由CPU从主板的BIOS芯片内取得程序代码,用BIOS内部的程序代码获得控制权。从CPU内外部的检测设置、激活DRAM以及针对芯片组与各种外围设备做初始化设置之后,最后驱动软盘或硬盘,直到把操作系统加载成功,BIOS的开机引导工作就此告一段落,转向从事幕后的支持、协调工作,并帮助操作系统或应用程序,来处理外围设备沟通的各种操作。
典型的如eeyebootroot,IceLord等。
2. Ntldr 劫持
Ntldr是Windows NT系列内核的Osloader,当开机以后BIOS载入MBR,MBR载入OBR,然后OBR载入Ntldr,并将执行权转交给Ntldr,最后再来启动内核。理论上讲Ntldr是最接近内核的,而且对Ntldr做Hook,可以避免针对各种外设的编码工作,提高通用性。
3. SMM (System Management Mode)劫持
SMM是Intel在386SL之后引入x86体系结构的一种CPU的执行模式,是IA32架构具备的四种运行模式之一(其他三种模式分别为实模式、V86模式和保护模式)。
为了实现SMM,Intel在其CPU上新增了一个引脚SMI# Pin,当这个引脚上为高电平的时候,CPU会进入该模式。在SMM模式下一切被都屏蔽,包括所有的中断。SMM模式下的执行的程序被称作SMM处理程序,所有的SMM处理程序只能在称作系统管理内存(System Management RAM,SMRAM)的空间内运行。可以通过设置SMBASE的寄存器来设置SMRAM的空间。SMM处理程序只能由系统固件实现。
SMM下可以执行一切特权指令,并且使得一切内存保护均失效。从某种意义上说,SMM是对系统进行监控的终极方法。
SMM漏洞利用的致命之处在于它能将自身隐藏在SMM空间中,SMM权限高于任何其他运行模式,操作系统根本不知道系统何时进入SMM模式,也无法感知SMM模式曾经执行过, 不受任何操作系统控制、关闭或禁用。实际应用中唯一能确认SMM空间中运行代码的方法只有物理性的分离计算机固件。由于SMI优先于任何系统调用,任何操作系统都无法控制或读取SMM,使得SMM RootKit有超强的隐匿性。典型的如SMM PS/2 Keyboard sniffer。
4. 内核劫持
内核属于PE文件,所有针对PE文件镜像的修改技术都可以属于内核劫持。典型的包括IAT Hook,EAT Hook,inline Hook等。
2.5 本章小结
由于R/Bootkit之所以较传统恶意软件更为隐蔽、底层,难以预防和检测,是在入侵感染技术上有所突破,为此本章研究了探索当前主流B/Rootkit的危害原理、分类方式、以及深入分析了其技术要点实现,从而为在R/Bootkit和Anti-R/Bootkit的技术对抗中占据优势提供技术上的支持。
 
 第 3 章 行为语义抽取和形式化描述研究
3.1 引言
为对抗R/Bootkit而发展出来的主动防御技术,可以在新威胁破坏计算机之前检测并消除威胁。但是由于缺乏关联行为序列的分析与判断,这种方式存在误报率较高的问题。例如:有些恶意程序会伪装成正常干净的程序逃避监控;还有的软件会用到类似恶意程序的方式,进行安装和调用,以获得更高一级的加载权和启动权,因此二者行为的混淆,不仅造成主动防御比较高的误报率,同时也增加了识别和判定的难度,从而造成恶意软件入住系统和危及计算机的安全与稳定。
由于主动防御并不能完美发现所有形式的病毒或者攻击(据一些行业数据统计表明它的成功率大概在60%左右),因此很多对于可疑操作放行与拒绝的判定还需要用户必须具备某些高级专业知识来自行判定。缺乏恶意软件行为语义的自主识别能力,带给用户必要的高交互性。
而发现并且提取恶意软件的行为语义,通过截获一系列的潜在恶意行为特征可以有效解决上述问题。
3.2 R/Bootkit行为特征分析
3.2.1 典型Rootkit Klog行为剖析
Klog作为Windows操作系统下当前主流的密码窃取工具之一,属于典型的内核级键盘钩挂Rootkit,在被植入了Klog Rootkit之后的系统上,所有的键盘击键操作所对应的键盘扫描码都会被秘密记录下来保存到特定的日志文件之中,而不管当前的击键操作是否发生在被激活的进程中。由于没有调用任何的Ring3下的编程接口或者操作系统机制,根本无法被Ring3级别的检测工具发现到。
Klog的架构分为App代理部分和内核驱动部分分别运行在Ring3级别和Ring0级别。Klog具体的植入感染过程如图3-1所示:
 
图 3 1  Klog 植入感染示意图
3.2.1.1 植入
App代理一般负责植入、安装Rootkit,一次运行后自我结束并且利用内核驱动的底层隐藏技术隐藏PE磁盘文件痕迹和隐蔽启动保证在下次重启之后存活。Klog的App代理为了安装的快速、隐蔽起见,将App代理和Sys驱动整合为一个可执行文件。Windows PE可执行文件允许在二进制文件中包含多个节(Section),每个节可以看成一个文件夹,使得开发者能够在可执行文件中包含各种对象:图形文件、任意二进制代码等。典型的Rootkit App代理同时包含了Sys文件和Rootkit启动参数的配置文件,更复杂的攻击可以创建和使用配置程序,在加载Rootkit之前动态设置配置选项。
3.2.1.2 加载与通讯
典型的Rootkit驱动的加载方式是使用服务控制器(Service Control Manager,SCM),调用CreateService创建注册表键保存驱动的磁盘文件路径,再调用OpenSerive,StartService开启驱动,此时驱动程序加载入内核。由于通过SCM方式加载确保了所有的内核内存都是非可分页的,意味着驱动里的回调函数、IRP处理函数以及其他重要代码不会从内存中被换页机制调换到内存,从而避免了这些高IRQL权限的代码执行不会因为缺页异常而导致蓝屏,对于Rootkit的隐蔽稳定运行提供了很好的特性。
下面是加载驱动的示例代码:
_snprintf(aPath, 1022, "%s\\%s.sys",  aCurrentDirectory,theDriverName);
/*获取驱动文件路径*/
 SC_HANDLE rh = CreateService(sh,       /*服务控制管理器的句柄* /
                      theDriverName,    /*待安装的驱动服务的名称*/
                      theDriverName,    /*在用户界面上显示的名称*/
                      SERVICE_ALL_ACCESS,       /*请求访问权限*/
                      SERVICE_KERNEL_DRIVER,    /*服务类型*/
                      SERVICE_DEMAND_START,    /*服务启动选项*/
                      SERVICE_ERROR_NORMAL,   /*错误严重性级别*/
                      aPath,       /*服务镜像文件所在路径*/
                   );
       rh = OpenService(sh, theDriverName, SERVICE_ALL_ACCESS);
/*打开刚才创建的驱动服务*/
  if(0 == StartService(rh, 0, NULL));                      /*开启服务*/

典型的App代理和Sys驱动通讯是首先打开驱动文件获取文件句柄,再根据句柄传入不同的IO控制码控制驱动执行不同的操作。
在Windows里驱动是作为文件来处理,每个驱动一般都会在入口函数里创建该驱动驱动对象的外部链接供用户模式下打开文件句柄使用。
3.2.1.3 感染
驱动第一次被加载的时候已经获取到了系统权限,可以访问、运行任何的底层资源,这往往也是大部分Rootkit执行感染的绝好时机。Klog获取所有键盘按键并且记录的原理在于:基本所有的硬件设备包括键盘硬件跟用户态下的硬件数据信息的获取都是通过分层驱动程序来传递;通过分层的驱动程序,在发生击键的硬件中断时,硬件驱动程序的处理函数会将击键转换为I/O请求包(I/O Request Packet IRP),这些IRP会沿着驱动程序链向上或者向下传递经过驱动链的每一层,Klog即是把自己插入到驱动链的顶层从而获取IRP过滤机会。
对于键盘驱动链而言,当发出ReadFile的请求时,I/O管理器会创建一个线程 win32k!RawInputThread 在通过 ReadFile 来要求从键盘读取数据,win32k!RawInputThread 在获得了句柄之后,会以这个句柄为参数,调用 nt!ZwReadFile,向键盘驱动要求读入数据。nt!ZwReadFile 中会交由I/O管理器创建一个 IRP_MJ_READ 的 IRP 发给键盘驱动,告诉键盘驱动要求读入数据。键盘驱动通常会使这个 IRP 处于Pending状态,也就是说这个 IRP_MJ_READ 不会被满足直到来自键盘的数据到来,同时发出这个读请求的线程 win32k!RawInputThread 也会等待,等待着这个读操作的完成。当键盘上有键被按下时,将触发键盘的那个中断,引起中断服务例程的执行,键盘中断的中断服务例程由键盘驱动提供。键盘驱动从端口读取扫描码,经过一系列的处理之后,最后把从键盘得到的数据交给 IRP,然后结束这个 IRP pending。这个 IRP 的结束,将导致win32k!RawInputThread 线程对这个读操作的等待结束。win32k!RawInputThread 线程将会对得到的数据作出处理,分发给合适的进程。一旦把输入数据处理完之后,win32k!RawInputThread 线程会立刻再调用一个 nt!ZwReadFile,向键盘驱动要求读入数据。于是又开始一个等待,等待着键盘上的键被按下。
IRP是由Winodws内核中的I/O管理器进行分配,用于应用程序和驱动、在分层驱动之间传递特有的数据。IRP被初始化后会注册到驱动程序链堆栈上依次从最顶端的驱动对象开始传递给下一个驱动对象直到最低端的驱动对象;最低端驱动对象会在中断发生时将获取到的数据填充给IRP结构,依次向上层驱动对象传递。每次向上传递过程中会回调相应的处理函数从而获取过滤机会。
Klog是在入口函数DriverEntry里创建并且初始化设备对象、驱动对象后,将自己注册为键盘驱动链中的顶层驱动。
CCHAR  ntNameBuffer[64] = "\\Device\\KeyboardClass0";
           /*这是原来键盘驱动设备链的顶层设备*/
                       STRING ntNameString;
           UNICODE_STRING uKeyboardDeviceName;
  RtlInitAnsiString( &ntNameString,ntNameBuffer );
RtlAnsiStringToUnicodeString( &uKeyboardDeviceName,
       &ntNameString,
              TRUE );
           IoAttachDevice(pKeyboardDeviceObject,
         &uKeyboardDeviceName,
       &pKeyboardDeviceExtension->pKeyboardDevice);
 
然后再注册驱动的MajorFunction表为DispatchPassDown,负责将所有不感兴趣的IRP请求向直接向下层驱动传递。


for(int i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
     pDriverObject->MajorFunction[i] = DispatchPassDown;
NTSTATUS DispatchPassDown(IN PDEVICE_OBJECT pDeviceObject,
                          IN PIRP pIrp )
{
/*直接将IRP向下传递给下一个对象,不做任何额外操作*/                          IoSkipCurrentIrpStackLocation(pIrp);
IoCallDriver(((PDEVICE_EXTENSION),
pDeviceObject->DeviceExtension)->pKeyboardDevice ,
pIrp);
};

再在本驱动对象中注册IRP_MJ_READ操作的完成处理例程为OnReadCompletion。如下:
/*设置回调例程*/
  IoSetCompletionRoutine(pIrp,
OnReadCompletion,
pDeviceObject,
TRUE,
TRUE,
TRUE);

在OnReadCompletion完成例程中获取当前击键扫描码和状态值封装为Kstate节点放置到QueueListHead开始的节点列表中,由开辟的系统线程负责将QueueListHead队列内容写入固定位置的磁盘文件。
3.2.2 典型Bootkit行为剖析
目前在能够搜索到的公开资料中,IceLord是唯一一个公开发表的BIOS Rootkit。IceLord包含了许多较为前沿的BIOS Rootkit实现技术,我们将对其进行剖解分析,以了解和验证BIOS Rootkit实现的关键技术。
3.2.2.1 BIOS启动分析
以Award BIOS为例,首先分析从BIOS到内核启动的运行流程如下:
Intel8086/8088处理器在CPU加电是所做的第一个动作就是设置CS=DS=ES=SS=0FFFFh及IP=0000h,即是将指令寄存器指向FFFF:0000h,转换成物理地址也就是000FFFF0h,随即开始获取指令码执行。BIOS加载进内存后分布如图3-2所示:
 
图 3 2   BIOS内存布局
从图中我们可以看出:BOOTBLOCK位于000FE000h~000FFFFFh这个区段,而BIOS的入口点却在000FFFF0h。确切的说,在000FFFF0h~000FFFFF这16个字节中存放着一个跳转指令,用于调转到BIOS的执行入口。这句跳转指令可以在BIOS文件的最尾部的16个字节看到。
就主板BIOS而言,依次会执行如下的任务:
(1) POST(Power On Self Test开机自检测)
开机系统将控制权交给BIOS时,它会针对CPU各项寄存器,先检查其是否运行正常,接下来会检查8254 timer(可编程外围计时芯片)、9259A(可编程中断器)、8237 DMA Controller(DMA控制器)的状态。
(2) Initial
BIOS会针对动态内存(DRAM)、主板芯片组、显卡以及相关外围的寄存器做初始化设置,并检测是否能够正常工作。
(3) 记录系统的设置值
BIOS会记录系统的设置值,并且会存贮在非挥发性内存(Non-Volatile RAM),如CMOS或Flash Memory等。
(4) 初始化常驻程序库
BIOS会将常驻程序库(Runtime Program)常驻于某一段内存中。并将其提供给操作系统或应用程序进行调用,如int 10h、int 13h、int 16h等中断调用函数。
这些工作完成以后,BIOS会检查是否存在ISA/PCI附加模块,如果有则加载运行(如以ISA/PCI模块形式存在的BIOS Rootkit)。完成模块加载并成功运行后,BIOS将调用int 19h中断,把磁盘第0柱头0磁道1扇区的系统启动数据,即MBR提取到内存0000:7c00处运行,从此完成BIOS向操作系统的CPU控制权移交工作。
3.2.2.2 劫持原理
IceLord由IceLord.exe、IO_HLPER.SYS、leaving.bin三个文件组成,IceLord是用户态代理模块负责加载IO_HLPER.SYS驱动文件,IO_HLPER.SYS主要作用是辅助IceLord.exe文件对BIOS进行读写工作以便引导BIOS在启动的时候加载ISA模块leaving.bin,而leaving.bin真正完成启动时感染的主体任务。
由于中断int 13h是标准的处理磁盘的BIOS中断类型,在内核加载前的预启动阶段所有的跟磁盘操作都是通过这个中断完成的。leaving.ini是在本身ISA模块被加载获取执行机会的时候通过IVT Hook 钩挂了13h中断方式(将自定义的中断处理函数地址替换IVT中的相应项),在自定义的中断处理函数中根据是否进入32bit保护模式的上下文完成后门安置等恶意行为。
对于中断过程的执行步骤描述如下:
1. 将代码段寄存器CS和指令指针寄存器(EIP)的低16位(IP)压入堆栈。
2. 将标志寄存器EFLAGS的低16位压入堆栈。
3. 清除标志寄存器的IF标志,以禁止其他中断。
4. 清除标志寄存器的TF(Trap Flag)、RF(Resume Flag)、AC(Alignment Check)标志。
5. 使用向量号n作为索引,在IVT中找到对应的表项(n*4+IVT表基地址)。
6. 将表项中的段地址和偏移地址分别装入CS和IP寄存器中,并开始执行对应的代码。
7. 中断例程总是以IRET指令结束。IRET指令会从堆栈中弹出前面保存的CS、IP和标志寄存器值,然后返回执行被中断的程序。
IVT Hook的原理就是,在第6个步骤把我们自行设计的中断处理函数所在的段地址和偏移地址装入CS和IP寄存器中,这样一旦发生13号中断,CPU将会执行自定义的中断处理函数。
3.2.3 行为特征提取
我们经过详细分析典型Rootkit和Bootkit的入侵感染的整个行为,发现R/Bootkit一系列复杂多变的行为特征中必须的行为是恶意进驻内核以获取内核权限,而恶意进驻内核又往往不属于普通应用程序的正常行为范畴,因此可以作为R/Bootkit的典型行为特征加以提取。
通过分析和总结,我们可将恶意进驻内核的行为按照植入时是否处于启动态分为非常规API调用序列方式和启动时恶意进驻方式。
3.2.3.1 非常规API调用序列进驻
1. SysDbgCtl方式
ZwSystemDebugControl(DebugSysWriteBusData,
&bus,sizeof(bus), NULL, 0, NULL)
2. SetSysInfo方式
WCHAR daPath[] = L"\??\d:\samplehello.sys";
RtlInitUnicodeString( &(GregsImage.ModuleName), daPath ); /*驱动路径*/
if( NT_SUCCESS(ZwSetSystemInformation(SystemLoadAndCallImage,&GregsImage,
sizeof(SYSTEM_LOAD_AND_CALL_IMAGE)) ))
3. 打开物理内存方式
status = ZwOpenSection(&hSection,
SECTION_MAP_READ|SECTION_MAP_WRITE,
&objectAttributes);
BaseAddress=MapViewOfFile(hSection,
                 FILE_MAP_READ|FILE_MAP_WRITE,
                 0,mapAddr,(gdt.Limit+1));
4. LoadDriver方式
 LoadDriver("\\Registry\\Machine\\System\\CurrentControlSet\\Services\\*");
其中*代表任意驱动名称。

3.2.3.2 启动时恶意进驻
作为单纯的学术研究,我们通过反汇编并跟踪调试Windows引导执行流程,根据启动顺序还原出正常的windows引导过程图3-3白色框,以及执行流程中加载可执行模块的方式和时机如图3-3灰色框。
 
 图 3 3   Windows引导过程执行流程
整个启动流程可以分为预启动阶段以及内核启动阶段。
其中预启动阶段劫持时机可总结为如下四类[3]:
1. BIOS 劫持
2. MBR劫持
3. Ntldr劫持
4. 内核劫持
这是当前主流的Bootkit钟爱的启动劫持点,具体见2.4.2节中的介绍。
而内核启动阶段劫持时机又可以分为四类,其分别对应上图中的数字5,6,7,8。
5. 可启动驱动
Osloader是预启动过程中最后一个获取引导控制权的可执行模块,由它调用使用内置的文件系统操作加载内核镜像(Ntoskrnl)并调用它KiSystemStartup切入内核,传入的加载参数为LOADER_PARAMETER_BLOCK复杂数据结构。其中的BootDriverListHead保存了所有可以启动的驱动路径的双向链表;在内核启动的phase1阶段初期Phase1Initialization函数会依次调用其所指示的可启动驱动的入口函数DriverEntry,而获取执行机会。
6. Native Application 启动
Windows内核启动后Phase1阶段的初期,调用RtlCreateUserProcess创建会话管理器进程(Smss)。该进程的进程体函数最终会调用SmpExecuteImage加载[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager]下BootExecute指向的Native Application磁盘镜像和传入参数,切入其入口函数NtProcessStartup执行操作。由于此时可以使用Ntdll.dll提供的原始服务(Native API),具有和内核同等的最高执行权限;而且内核尚未初始化完毕,此时的执行环境较为干净,往往是主流杀毒厂商例如卡巴斯基等青睐的启动点。
7. 服务方式
Windows服务是在用户登陆前为拥有用户授权级进行管理的后台程序。内核启动后期创建的Services进程会调用OpenService例程搜索[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services]下的所有服务名,加载Parameters子键中的ServiceDll指向的动态链接库,调用已注册的服务入口函数ServiceMain执行服务任务。主流杀毒厂商往往将自己的Ring3级的Anti-Bootkit功能封装为服务。
8. 注册表相关启动项和系统配置文件
用户登陆后,由explorer进程读取注册表相关启动项和系统配置文件指示的路径执行例程。
四种传统的内核启动时机分别对应图3-3中的数字5、6、7、8所指示的函数调用点,可见传统的启动方式都是在内核已经启动之后的某个阶段被触发的,相比于在BIOS自检、MBR、Ntldr等预启动阶段已经感染劫控了内核镜像的Bootkit来说,已经失去了守方优势。Bootkit很容易通过更改内核入口点、IAT/EAT Hook、inline Hook、SSDT Hook、DKOM等组合的复杂方式[4,5],擦除感染痕迹、安植Ring0后门、绕过或者直接Disable Anti-Bootkit系统而存活下来并伺机窃密。
3.3 形式化描述语言
3.3.1 形式化语言定义
计算机系统的行为从本质上来说定义了一系列空间、时间资源状态以及针对资源的操作行为。即可以理解为不同状态间的迁移,如果用二元式的形式描述系统运行的话可以书写如下:
B=(S,P);
其中S是时间/空间资源状态的集合,P是资源状态迁移操作的集合。
P={p|p=  ,  S,  S};
恶意代码的行为M是B的子集,某种系统的运行之所以被定义为是恶意的是因为其具有恶意行为特征。恶意行为特征可以考虑从以下几个方面取刻画。
从恶意代码攻击意图上可以分作敏感资源的窃取外流行为,计算机正常可用资源的破坏行为。
如果按照计算机系统实现的逻辑,资源可以划分为空间资源和时间资源,操作也可以划分为读,写,执行三类,这样每一种攻击意图可以划分为若干细的行为。例如敏感资源实际是受读保护的空间资源,正常可用资源的破坏又可以分破坏时间资源和破坏空间资源。
从恶意代码本身功能上可以分作自身隐藏行为,恶意意图执行行为,自身传播行为。
从恶意代码施害部件上可以分作针对CPU、BIOS、内存、文件、外设的行为等。
每一种恶意行为必然由一系列的子行为按照特定的序列去完成,一旦在实时运行的环境下按照这种序列在某种粒度(譬如系统调用API级别)检测到各个子行为,就可以断定某种恶意行为发生了。
为了统一且完整描述系统运行包括恶意代码的各种行为以及子行为,我们参考自然语言叙事逻辑:主语、谓语、宾语结构还有计算机体系中实际的指令格式的定义:操作码、目的操作数、源操作数,提出了一套以规则范式元素的概念为基础的规则范式体系(Rule System)描述。
从语法意义上,用四元式表述的行为规则范式体系如下:
T={ , ,R,Q}
其中,
T          规则范式体系
         非终结符(行为或者子行为)
          终结符(规则范式元素)
R          语法产生式的有限集合
Q          规则范式体系的开始点
 , 构成了完整的行为词汇库V(T)=    ,   = ,表征了各个层次不同抽象程度的代码行为。
语法产生式有限集R表述如下:   ,  V(T)。
开始状态集S  ,代表了 中的开始状态点。
从文法以及语义层次,描述规则体系 [23]如下:
由规则范式(Rule Pattern,又可以称作产生式Production),规则脚本(Rule scription),脚本解释(又称脚本语义(Rule Semantics))三大部分组成。
3.3.1.1 规则范式
1. 执行事务(Execute transaction)
将操作系统底层实时执行的指令流切分成具有上层逻辑意义和方便管理控制的指令块就是执行事务。执行事务概念的提出是为了暴露可扩展性良好,粒度无关的接口,是上层的规则范式元素映射的下层具体实现,实际划分的粒度可以小到指令级别也可以大到API、DLL,乃至程序级别。典型的执行事务代表是NtCreateFile,应用层中任何涉及文件创建的操作最终会调用此API来执行。
2. 规则范式(语法产生式)
规则范式包含四元式中的 , ,R,描述底层子行为之间耦合关系以及底层子行为与上层抽象行为之间的归结关系的语法规则。
底层子行为和上层抽象行为的描述,考虑到自然语言叙事逻辑和计算机指令逻辑的自然对应关系,可以从<主体>(Body),<动作>(Action),<空间资源>(Space resources),<时间状语>(Time Related Clause)四大基本组成部分加以刻画。
子行为之间的耦合关系根据是否必须按照特定顺序排列,又可以划分为组合(or)关系与时序(and)关系。
3. 规则范式元素(Rule Pattern Element)
规则范式元素属于四元式中的 ,是截获或者管理的执行事务最基本的上下文(Contex),同时也是规则体系中的终结符(Terminal)。从上层逻辑的角度看,规则范式元素是整个系统检测和控制指令流行为发生的最小逻辑粒度,基于此终结符上层逻辑可以按照既定的规则范式由下至上解析代码行为,并且根据行为判定结果对相应的规则范式元素加以安全策略控制;从下层具体的实现看,在执行事务发生时将控制权引流并从中提取规则范式元素,在上层行为解析结果反馈后规则范式元素会引导执行事务的下一步安全策略操作。
按照我们现在的提出的技术方案,每个规则范式元素抽取并且维护着每个执行事务的执行事务主体、访问、空间资源、时间状语等逻辑成分。
语法产生式的有限规则集合R部分内容如下:
<范式规则> if(<检测类范式规则>) {<控制类范式规则>};<新术语定义选项>
<检测类范式规则> <子行为>
<控制类范式规则> <子行为>
<新术语定义选项> …
<子行为> <执行事务主体><动作><空间资源><时间状语>|<子行为>

<执行事务主体> <线程> <DLL> | 空
<线程> …
<DLL> …
<动作> <监测类动作>|<控制类动作>
<监测类动作> <读>|<写>|<执行>
<控制类动作> <禁止>|<允许>|<截留>

<空间资源> <地址类空间资源>|<内容类空间资源>|<空>
<地址类空间资源> <数据类空间资源>|<代码类空间资源>
<数据类空间资源> …
<代码类空间资源> …
<内容类空间资源> <地址类空间资源>

<时间状语> <频繁>|<时间状语默认>|[<频度>,<频度>]
<频度> <发生次数> per <时间段>
<发生次数> <整数> times
<整数> …
<时间段> <时间数值><时间单位>
<时间数值> <整数>|<默认时间数值>
<默认时间数值> 空
<时间单位> <执行的指令条数>|<时钟周期数>|<标准时间>
<执行的指令条数> …
|<时钟周期数> …
<标准时间> second|minute|hour|day|month|year
<时间状语默认> <一次>
<一次> 空
<频繁> [<最小次数> times per second,]…
<最小次数> 53.3.1.2 规则脚本
规则脚本是按照规则范式组成格式要求,针对特定安全领域(譬如敏感数据流监控,恶意代码发作,间谍类软件扫描,热点(Hot Spot)寻找)的特点的配置脚本。
3.3.1.3 脚本解释
脚本解释是规则范式语言的上层逻辑解析,是对运行时的执行流进行检测和控制,使之按照规则范式的描述要求继续,停止,改变运行方式。
规则范式库框架简图如图3-4所示:
 
图 3 4  规则范式库框架简图
深入分析规则范式库框架的基本组成部分的接口和流程,有助于我们完整细致理解整个规则体系。脚本库和范式库分别是体系中的保存规则范式和规则脚本的模块;而脚本语言范式解析器和脚本解释器则是整个体系执行的引擎模块,其中前者根据规则范式解析出规则脚本定义,而后者又根据此规则脚本定义以及规则脚本输出规则语义。
3.3.2 恶意进驻内核行为特征形式化语言描述
通过引入执行事务和规则范式的语法,符合该语法的脚本可以有效描述恶意进驻内核的行为以及对该行为特征的监控。
Handle * pTempHandle;
路径 csDriverPath;
csDriverPath=” *.sys”;
检测类范式规则 DetectSysAll,AbnormalEnter,Bootkit;
控制类检测类范式规则 Ctl=Deny;
动作 LoadDrv,OpenPhysSec,SetDbgCtl,SetSysInfo;
SSDT主体  ssLdrv=*LoadDriver;
AbnormalEnter=…;
DetectSysAll= LoadDrv | OpenPhysSec | SetDbgCtl | SetSysInfo|;
LoadDrv = ssLdrv Ref csDriverPath as 参数[0];
OpenPhysSec = ZwOpenSection;
SetDbgCtl=*SystemDebugControl ;
SetSysInfo=(*OpenSection Ref pTempHandle as 参数[0] )
and (*MapViewOfFile Ref (*pTempHandle) as 参数[0] ) ;
if (DetectAll) { Deny;}

3.4 本章小结
本章首先指出了主流主动防御式Anti-R/Bootkit对R/Bootkit关联行为序列识别不够,在行为判断上过多依赖用户选择的现状,本文通过剖析典型的Rootkit/Bootkit的入侵感染行为,总结出R/Bootkit恶意进驻内核这个行为特征可以作为行为分析的特征依据,为此定义并使用了形式化描述语言描述行为特征。
 
 第 4 章 基于行为监测的Anti-R/Bootkit的设计与实现
4.1 相关技术基础
4.1.1 进程
Windows下进程的概念牵涉到众多的关键数据结构(譬如工作集,对象句柄,系统内存堆等),经过综合考虑我们选择的事务的主体是进程。
每个Windows进程都是由一个执行体进程(EPROCESS)块来表示的。为了方便使用PROCESS作为主体需要解决两个问题:如何快速找到当前执行事务所在进程以及如何通过进程数据结构某个域找到主体数据结构。
对于前者,Windows使用KPCR (Processor Control Region )这个结构存放当前CPU所正在处理的各种信息,当进行进程调度时系统将根据当前所存活的进程来选择让哪个线程ETHREAD结构来替换KPCR中的ETHREAD,使其变为正在运行的状态。而ETHREAD结构又与EPROCESS结构是相互关联的,通过 KPCR启始地址0xFFDFF000+偏移 就能够快速得到当前正在运行的线程与进程。如下代码所示:
#define KIPCR ((ULONG_PTR)(KADDRESS_BASE + 0xFFFF0000))           
#define PCR ((volatile KPCR * const)KIPCR)
#define KeGetCurrentThread() PCR->CurrentThread
#define PsGetCurrentProcess()
(CONTAINING_RECORD(((KeGetCurrentThread())->ApcState.Process),              EPROCESS,
Pcb))
对于后者,我们通过分析EPROCESS的数据结构,在
(PEPROCESS)(pEprocess)-> Peb.SystemReserved
这个空闲的域来保存主体数据结构的指针。
4.1.2 驱动程序
驱动程序的设计是Anti-R/Bootkit重要组成部分。为了允许驱动开发人员编写跨Windows各个操作系统平台的设备驱动,Microsoft公司提出了WDM(Windows Driver Model)驱动模型,而遵循WDM规则的内核模式驱动被称作为WDM驱动。作为内核模式的驱动程序,WDM一旦被系统加载就拥有了与内核一样的系统内核权限,使得驱动拥有全部的操作系统底层权限和编程资源;这也是主流的Rootkit/Bootkit入侵内核进行内核级别的隐藏、破坏活动的主要方式。
典型的Rootkit/Bootkit包括用户模式的App代理和内核模式的Sys模块如图4-1所示,
 
图 4 1  App-Sys模式的总体设计
前者负责Sys模块的植入、安装、加载等低权限可以完成的任务;Sys模块则利用本身的内核权限完成执行路径劫持和直接修改内核对象等恶意行为。
4.1.2.1 I/O管理器
I/O管理器作为I/O管理系统的核心定义了有序的工作框架(或者称为模型)。在该框架内,I/O请求被提交给设备驱动程序进行处理。Windows 2k及其以后版本的系统中,整个I/O系统是由包驱动(Packet Driven)的。大多数I/O请求用I/O请求包(I/O Request Packet,IRP)表示,它从一个I/O系统组件传递到另一个I/O系统组件(快速I/O是一个特例,它不使用IRP),其所对应的数据结构包含了描述I/O请求的完整信息。I/O管理器创建每个I/O操作的IRP,传递IRP给正确的驱动程序,并且当此I/O操作完成后,处理这个数据包。与之相反,驱动程序接受IRP,执行IRP指定的操作,并且在完成操作后把IRP送回I/O管理器,或为进一步的处理而通过I/O管理器把它送到另一个驱动程序。
除了创建IRP以外,I/O管理器还为不同的驱动程序提供通用服务接口,驱动程序调用这些接口来执行它们的I/O处理。通过在I/O管理器中整合公共服务,单个的驱动程序将变得更加简洁、更加紧凑。I/O管理器还提供灵活的I/O服务,允许环境子系统(譬如Windows和POSIX等)执行它们各自的I/O函数。这些服务包括用于这些服务包括针对异步I/O的高级服务,它们允许开发者建立可扩展的高性能的服务器应用程序。
4.1.2.2 DeviceIoControl()分析
用户态的应用程序通过调用DeviceIoControl()函数来发送I/O控制码(IOCTL)来获取核心态的服务。调用DeviceIoControl会使I/O管理器创建一个IRP_MJ_DEVICE_CONTROL请求并发送到最顶层的驱动程序。发往设备的各种类型的请求,包括读、写数据、创建、撤销等操作请求。由于这里的用户态应用程序并没有涉及到对硬件的读写操作,所以需要逐层把请求传递给下层的设备执行IOCTL操作。应用程序使用标准Win32 A P I函数DeviceIoControl ()来执行这样的操作。
以应用程序的角度看,调用DeviceIoControl()函数可以为驱动程序创建输入和输出缓冲区,其中的lpInBuffer 和nInBufferSize 参数描述了为驱动程序提供数据的缓冲区;以驱动程序的角度看,该区域为驱动程序提供输入数据。lpOutBuffer和nOutBufferSize参数描述了接收驱动程序输出数据的缓冲区。而一个控制操作是否需要输入输出缓冲区要取决于其执行的功能。例如,一个接收驱动程序版本号的IOCTL可能仅需要输出缓冲区;而一个仅用于通知驱动程序Attach到某个应用程序进程地址空间的IOCTL可能仅需要输入缓冲区。有些操作可能同时需要这两种缓冲区,这完全取决于控制操作的具体内容。DeviceIoControl()的dwIoControlCode参数代表控制码,表明应用程序要执行何种控制操作。I/O控制码由系统或用户来定义,用于驱动程序和用户态应用程序之间或者驱动程序之间的通信,来标识I/O控制的不同操作,保存在I/O堆栈的Parameters域中。I/O控制码的具体格式见图4-2:
 
图 4 2  IOCTL码格式
IOCTL中的功能码的低两位来为每个IOCTL指定寻址方式。典型的寻址方式有buffered、direct、neither等。此外,IOCTL中指定的缓冲方式并不影响普通读写IRP的寻址缓冲区。选择哪个缓冲方式基于下面几个因素:buffered方式适合每次请求传输小量的数据,大部分IOCTL操作传输的数据少于一个页,应该使用buffered式;传输超过一个页数据的操作应该使用direct方式,direct方式适合快速读写大量的数据,比如DMA或PIO等;如果没有过滤器驱动程序需要挂起,则可以使用neither方式任意访问用户模式数据。
4.1.2.3 IRP
在核心态的驱动程序中,DeviceIoControl()调用最终会创建一个带有IRP_MJ_DEVICE_CONTROL功能码的IRP,并把该IRP发送到设备堆栈最上层驱动程序的派遣例程。IRP是I/O系统用来存储处理I/O请求所需信息的地方,它是I/O管理器在响应一个I/O请求时从非分页系统内存中分配的一块可变大小的内存,I/O管理器每收到一个来自用户的请求就创建一个该结构。该结构存放有请求的类型、用户缓冲区的首地址、用户请求数据的长度等信息。驱动程序处理完这个请求后,也在该结构中添加处理结果的有关信息,然后调用IoCompletionRequest()将其返回给I/O管理器,用户的请求随即返回。
每一个IRP可以看成由两部分组成:固定部分和一个I/O堆栈。IRP的固定部分包含请求信息,I/O堆栈则包含一系列I/O堆栈单元(I/O Stack Location),单元的数目与驱动程序堆栈中处理这一请求的驱动程序的个数相同,每个单元对应一个将处理该IRP的驱动程序。IRP的结构如图4-3所示:
 
图 4 3  IRP结构

 (a) I/O固定头部
 I/O固定头部的格式如图4-4所示:
 
图 4 4  IRP固定头部

IRP固定域结构中的Associated域是一个三指针Union。其中,与WDM驱动程序相关的指针是AssociatedIRP.SystemBuffer。SystemBuffer指针指向一个内核态下的数据缓冲区,该缓冲区位于内核模式的非分页内存中。作为创建IRP过程的一部分,I/O管理器把用户模式程序发送给驱动程序的数据复制到这个缓冲区。这些数据可以是与WriteFile调用有关的数据,或者是DeviceIoControl()调用中的输入参数。对于读请求,设备驱动程序把读出的数据填到这个缓冲区,然后I/O管理器再把缓冲区的内容复制到用户模式缓冲区。对于指定了neither方式的I/O控制操作,驱动程序把所谓的输出数据放到这个缓冲区,然后I/O管理器再把数据复制到用户模式的输出缓冲区。
当IRP完成时,应该赋值IoStatus.Information域为放入拷贝缓冲区中的输出字节数,然后I/O管理器把数据复制到用户模式缓冲区并设置反馈变量。
Windows2000采用多种方式分割虚拟地址空间:一种方式是基于安全性和完整性,分用户模式地址和内核模式地址;另一种方式基于处理器的分页能力,分分页内存和非分页内存。全部用户模式地址和某些内核模式地址使用分页内存,内存管理器可以在分页内存页帧和磁盘扇区间交换内容;而另一些内核模式地址总是引用物理内存中固定的页帧,必须分配在非分页内存中。比如操作系统中用来支持内存管理器本身的某些代码所在内存是不能被分页的,明显的例子就是,用于处理页故障的代码和数据结构必须常驻内存。
(b)I/O堆栈单元
任何内核模式程序在创建一个IRP时,同时还创建了一个与之关联的IO_STACK_LOCATION结构数组,数组中的每个堆栈单元都对应一个将处理该IRP的驱动程序。过滤器驱动程序会解释某些它们自己的代码,然后把其它 IRP下传。一个了解如何处理IoControl的派遣函数将驻留在驱动程序堆栈的某个地方,最可能是在功能驱动程序中。I/O堆栈单元域结构如图4-5所示:
 
图 4 5  I/O 堆栈单元数据结构
MajorFunction表示该IRP的主功能代码,它指出所要执行的I/O操作类型。
主功能码与驱动程序对象的MajorFunction表中的某个派遣函数指针相对应。
DeviceIoControl操作使用的主功能码是IRP_MJ_DEVICE_CONTROL。MinorFunction表示该IRP的副功能码,它进一步指出该IRP属于哪个主功能类。与DeviceIoControl()相关的另一个重要的域是Parameters,它是几个子结构的联合,每个请求类型都有自己专用的参数。这些子结构包括Create(对应IRP_MJ_CREATE请求)、Read(对应IRP_MJ_READ请求)和DeviceIoControl(对应于IRP_MJ_DEVICE_CONTROL请求)等。其中IRP_MJ_DEVICE_CONTROL保存在堆栈单元参数Parameters.DeviceIoContro中,其结构如下:
struct  DeviceIoControl {
  ULONG OutputBufferLength;
  ULONG POINTER_ALIGNMENT InputBufferLength;
  ULONG POINTER_ALIGNMENT IoControlCode;
  PVOID Type3InputBuffer;};

OutputBufferLength表示用户态输出缓冲区的长度,DeviceIoControl()函数的第六个参数。InputBufferLength表示用户态输入缓冲区的长度,DeviceIoControl()函数的第四个参数。IoControlCode表示控制代码,DeviceIoControl()函数的第二个参数。Type3InputBuffer表示输入缓冲区的用户模式虚拟地址。这些参数用于判断用户态程序与驱动程序之间的数据交换是否超过缓冲区所能承受的范围。
4.1.2.4 设备对象和驱动对象
1. 驱动对象
驱动程序对象为DRIVER_OBJECT结构,如图4-6:
 
图 4 6  驱动程序对象的属性
在操作系统内核模块中代表一个独立的驱动程序,并且为I/O管理器记录每个驱动程序的调度例程的地址(入口点)。I/O管理器使用驱动程序对象来代表每个设备驱动程序。驱动程序对象是部分不透明的,这意味着虽然DDK头中公开了整个结构,但仅能直接访问或修改结构中的某些域。
其中DeviceObject指向一个设备对象链表,每个设备对象代表一个设备。I/O管理器通过维护这个域来把多个设备对象连接起。MajorFunction为一个函数指针表,指向存在于驱动程序中的各个IRP处理函数,它定义了I/O请求如何被驱动程序解释。
2. 设备对象
设备对象以DEVICE_OBJECT结构来描述在系统中代表一个物理的、逻辑的或虚拟的设备并描述该设备的特性,例如它所需要的缓冲区的对齐方式和它用来保存即将到来的I/O请求包的设备队列的位置。图4-7给出了设备对象的格式。WDM驱动程序可以调用IOCreateDevice()函数创建设备对象,但设备对象的管理则由I/O管理器负责。
 
图 4 7  设备对象的数据结构
DriverObject(PDRIVER_OBJECT类型)指向与该设备对象相关的驱动程序对象,通常就是调用IoCreateDevice()函数创建该设备对象的驱动程序对象。过滤器驱动程序有时需要用这个指针来寻找被过滤设备的驱动程序对象。
NextDevice(PDRIVER_OBJECT类型)指向属于同一个驱动程序的下一个设备对象。通过这个域把多个设备对象连接起来,起始点就是驱动程序对象中的DeviceObject成员。
DeviceExtension指向一个由用户定义的数据结构,一般把该结构称为设备扩展(Device Extension),驱动程序可以使用该结构保存每个设备实例的信息。
I/O管理器为设备扩展对象分配空间,但是设备扩展结构的名字和内容完全由用户决定,常见的做法是把设备扩展结构命名为_DEVICE_EXTENSION。为进程的产生和终止定义的设备扩展结构如下所示:
typedef struct _DEVICE-EXTENSION
{
 PDEVICE_OBJECT DeviceObject;      /*设备对象指针*/
 HANDLE hProcessId;         /*新产生或终止进程的ID*/
 PKEVENT ProcessEvent;    /*用来通知用户态应用程序的事件*/
 HANDLE hParentId;            /*父进程的ID*/
   BOOLEAN bCreate;             /*标识进程的产生或终止*/
} DEVICE_EXTENSION,*PDEVICE_EXTENSION;

每当有进程的产生和终止时,通过挂接的回调函数都会将PsSetCreateProcessNotifyRoutine()函数传来的参数写进驱动程序的设备扩展并拷贝到IRP结构的AssociatedIrp.SystemBuffer中,最后通过设置事件通知用户态程序来读取。
DeviceType表示设备对象的设备类型,它由IoCreateDevice()函数初始化,因为这里并没有涉及具体硬件编程,所以初始化为FILE_DEVICE_UNKNOWN。
3. 设备对象和驱动对象的关系
驱动程序对象和设备对象关系密切。当驱动程序被加载到系统中时,I/O管理器将创建一个驱动程序对象,然后调用驱动程序的初始化例程,该例程把驱动程序的入口点放在该驱动程序对象中。初始化例程还创建用于描述每个设备的设备对象,同时使驱动对象和设备对象彼此关联。
一方面,驱动程序对象通常有多个与它相关的设备对象,因此它利用DeviceObject指针指向一个设备对象列表,该列表表示驱动程序可以控制的物理设备、逻辑设备和虚拟设备。例如,硬盘的每个分区都有一个独立的包含具体分区信息的设备对象,然而相同的硬盘驱动程序被用于访问所有的分区。
另一方面,设备对象反过来指向它自己的驱动程序对象,这样I/O管理器就知道在接收一个I/O请求时应该调用哪个驱动程序。它使用设备对象找到代表服务于该设备驱动的驱动程序对象,然后利用在初始化请求中提供的功能码来索引驱动程序对象,而每个功能码都对应一个驱动程序的入口点。当驱动程序收到IOCTL_PROCOBSRV_GET_PROCINFO功能码时会把设备对象中的信息复制到AssociatedIrp.SystemBuffer所指的内核缓冲区,并设置IRP的IoStatus.Information使I/O控制器把内核缓冲区的数据拷贝到用户态的输出缓冲区。
4.2 设计与实现
我们设计的基于行为特征检测的Anti-Rootkit的设计框架图如图4-8所示。左侧的规则编译器模块属于离线模块,负责对符合形式化描述语言定义的规则脚本进行词法分析、语法分析等生成API粒度的描述系统调用和公共变量等关联关系的探针部署库以及描述状态迁移的行为匹配库。前者供探针布控模块引用以对涉及到的所有系统调用预备监视,后者供行为语义模块在每次截获到可疑系统调用时查阅来决定是否发现特定行为特征。优先启动模块则负责在启动阶段优先获取操作系统控制权,提供干净、完备的高权限内核环境来发现、清除Bootkit感染痕迹。
图 4 8  设计框架图
4.2.1 优先启动
在Bootkit感染入侵和Anti-Bootkit检测恢复的攻防策略中,能做到优先启动往往是制胜对方的关键;而目前主流的Anti-Bootkit/Rootkit软件由于固守传统的启动方式,很容易被Bootkit利用固有优势劫控、篡改、移除而形同虚设。
通过反汇编二进制镜像和动态跟踪调试分析Windows预启动过程执行流程,本文分析了选择预启动驱动作为启动方式的原因和可行性,以及实现PBD优先启动方案面临的问题和解决方案。
4.2.1.1 为何选择预启动Osloader阶段以及PBD方式
由于Windows预启动阶段的初期的BIOS、MBR、BootSector、Su(Ntldr的前半部分)的启动执行环境是处于16-bit实模式下,实用的底层功能模块(磁盘操作驱动等)还未能载入内存,因此这些启动位置难以作为劫控对象。
而预启动阶段的后期到内核启动之前,第一次载入并且运行在32-bit保护模式执行环境里的启动模块就是Osloader,更重要的是Osloader会先于内核以及所有基于内核引导的启动点之前加载预启动驱动。
Windows通过将所有的驱动镜像分配在GDT索引为8的DPL=0的段描述符所指示的逻辑段中,使得驱动拥有全部的操作系统底层权限和编程资源,预示着可以作为劫控对象为Anti-Bootkit提供绝佳的布控、检查、还原的内核执行环境。
4.2.1.2 侦测预启动阶段PBD加载并执行的条件与时机
以Windows xp sp2系统的启动流程为例,分析Osloader的执行流程得出的执行步骤用伪代码描述如下:
NtProcessStartup()
/*NtProcessStartup是Osloader入口点函数,在初始化内置内存/文件管理*/
/*系统后,把控制权交给BlStartup函数   完成主体任务。*/
{
    BlMemoryInitialize();                                //初始化内存
    BlIoInitialize();                          //内置文件系统IO初始化
    BlStartup(BootPartitionName);
//*从可启动的分区启动内核*/
}
BlStartup(IN PCHAR PartitionName)
{                                //预启动阶段的设备检测和加载内核
Status = BlOpen(          DriveId,"\\Boot.ini",
                         ArcOpenReadOnly,
                             &BootFileId );
/*BlStartup调用内置文件系统的打开函数读入Boot.ini到内存缓存*/
BlDetectHardware(DriveId, LoadOptions);
/*此处Windows会在预启动阶段第一次加载并执行可执行文件,但是不适合作为劫控点*/
if(!_strnicmp(pItem,"scsi(",5))

/*在这里windows启动全局流程中会第一次加载预启动驱*/
/*Ntbootdd.sys用于scsi型号磁盘IO操作,也是本文选择的劫控时机*/              /*开启条件是当前启动选项的前五个字节是scsi*/
{AEInitializeIo(DriveId); };
/*加载并且初始化SCSI驱动*/
BlOsloader(9,Argv,NULL);
/*初始化内核加载所需环境,加载并执行内核*/
};
AEInitializeIo(IN ULONG DriveId)
{             /*从启动分区加载SCSI启动驱动NtBootdd.sys,并初始化*/
BlLoadImage(DriveId,               MemoryFirmwarePermanent,
                    "\\NTBOOTDD.SYS",
                       TARGET_IMAGE,
 &ImageBase);
/*加载PBD磁盘镜像到内存*/
BlScanOsloaderBoundImportTable(
DriverDataTableEntry);
/*扫描NtBootdd文件头中的导入表初始化Osloader的导入表使之用*/
/*于Osloader的磁盘读写*/
Entry = (PDRIVER_ENTRY)
DriverDataTableEntry->EntryPoint;
/*获取PBD的入口点函数*/
Status = (*Entry)(NULL,NULL);
/*调用PBD入口函数,获取执行机会*/
if (Status == ESUCCESS)
{
  HardDiskInitialize();
                    /*如果PBD初始化成功那么初始化硬盘*/
}
return(Status);                                 //返回操作状态
}

通过对Windows启动流程的全局分析,我们发现NtBootdd.sys是Windows内核加载前的预启动阶段最早加载并且获取到Ring0执行权限的驱动文件,可以作为Anti-Bootkit优先启动的理想Ring0模块载体。PBD的劫控原理如图4-9所示:
 
图 4 9  PBD劫控原理
4.2.1.3 获取最小内存/磁盘操作功能集
由于我们劫控的PBD获得执行权限时内核并没有加载到内存,因此无法使用其提供的原始服务,只有当前供Osloader使用的内置文件/内存管理操作的函数集可以调用。找到这些函数集主要函数的入口地址成为实现Anti-Bootkit的技术焦点。
经过反汇编Ntldr分析发现,虽然内置文件/内存管理操作的函数集随着Osloader被加载到内存并一直提供低级IO操作和内存管理服务直到内核被加载并启动,但是由于Osloader并没有导出相应的操作函数供其他模块调用,因此不能直接在DriverEntry中使用。
但是同时发现内置文件/内存管理操作的函数集在Osloader PE文件的代码节中顺次存放,且入口指令统一,可以作为理想的二进制代码搜索的特征;只要定位到某一个函数的实际线性地址很容易根据入口指令特征寻找到其他函数的实际地址。例如内置文件操作的函数集存放次序依次为      BlIoInitilaze、BlGetFsInfo、BlClose、BlOpen、BlOpen、BlRead、BlSeek、BlWrite、BlGetFileInformation、BlRename、BlReadAtOffset等,入口指令都是
[mov edi,edi],
而该指令在代码节出现的位置恰恰都是内置文件操作函数的入口。
经分析BlClose函数的实际线性地址最容易根据劫控点DriverEntry所在的函数调用堆栈信息得到;反汇编还原出的调用堆栈如图4-10所示:
 
图 4 10  劫控点函数调用堆栈
因为在DriverEntry的二级调用者函数BlStartup调用点位置(也就是AEInitializeIO在BlStartup函数中的返回地址所指指令的上一条)向上第一次出现的内置文件/内存管理操作函数就是BlClose。搜索特征可以定义为
push [ebpBl- 0x10];
call BlClose;
这里的ebpBl指向BlStartup栈帧,搜索起始位置是AEInitializeIO栈帧中存储的返回地址。
由于在函数调用堆栈栈帧中EBP总是指向调用者所在栈帧EBP域,当前EBP寄存器(指向DriverEntry栈帧)所指的DWORD值就是ebpAE,再取ebpAE所指的DWORD值就是ebpBl了。至于待搜索代码块的开始位置,根据栈帧的内部结构定义,取ebpAE+sizeof(DWORD)作为地址,所指向的DWORD值就是开始位置。
4.2.1.4 劫控并回归windows正常的启动流程
为了在PBD加载运行时获取执行机会,在完成主体任务后回归到windows正常的启动流程,我们必须对PBD镜像做适当修改。如图4-11所示,绿色部分是我们修改和添加之处。
 
图 4 11  修改PBD磁盘镜像
由于BlScanOsloaderBoundImportTable会扫描NtBootdd文件头中的导入表(IAT)初始化Osloader的导入表使之用于Osloader的磁盘读写,因此必须保持原文件中的IAT部分和代码节不变。
为此,我们在原来PBD磁盘文件的最后追加了新的代码节存储所有主体任务的代码。同时修改Section头维护所有节的数据结构,修改PE头的EntryPoint域为新代码节中DriverEntry的文件偏移,这样就可以作为PBD的入口点函数被调用了;最后在新的DriverEntry执行主体任务完毕后显示调用了原来的DriverEntry,这样便可以归还给正常的Windows启动流程。此外,我们在主体任务完成后利用内置的文件系统操作来还原Boot.ini的启动项,因为后续的内核启动过程有可能继续使用其中的启动项信息。
4.2.1.5 PBD Anti-Bookit的设计实现与验证

为了验证PBD技术优先启动的有效性,我们设计并实现了PBD Anti-Bootkit模型如图4-12所示:
 
图 4 12  PBD Anti-Rootkit框图
在非启动状态下我们修改并且替换了部分引导相关的启动配置选项文件(Boot.ini)和磁盘驱动文件作为安装模块;这样在Ring0下的引导过程中,会根据启动配置选项导引到加载并执行最早可启动的PBD驱动的分支流程,在驱动中具体劫控内置文件/内存管理系统并且完成还原内核、Ntldr、MBR等磁盘镜像的任务,之后导引回正常的启动执行流程。
我们选取预启动关键引导位置MBR、Boot Sector、Ntldr以及Ntoskrnl作为功能测试对象,结果表明可以正确检查磁盘镜像的完整性。
我们选取卡巴斯基、macfee等主流杀毒软件为优先启动的对比对象,如表4-1所示,第一行是按照启动次序排列的启动点,第一列是对比对象,Y代表对比对象选择的启动点。结果显示BPD Anti-Bootkit可以在它们启动之前优先启动。优先启动的对比结果如表4-1所示。
经过实际的试验测试,BPD Anti-Bootkit可以以预想的启动方式加载并且执行。
表 4 1  优先启动对比结果
  启动
对比  PBD 启动驱动 Native
App 服务 注册表、配置
卡巴   Y Y Y
Macfee    Y Y
PBD Y Y Y Y Y

4.2.2 探针布控
4.2.2.1 系统调用机制
Windows利用现代的大多数微处理器都支持两种模式:用户模式(User/Normal)和内核模式(Kernel/Privileged)来维护可靠性和健壮性。操作系统组件和关键的系统组件处于内核模式,而一般用户模式的程序只能访问私有地址空间和执行非特权等级的指令。如果用户要调用一些内核组件的功能,就得通过系统服务调用来实现。
系统调用是操作系统内核向应用程序提供的操作硬件设备、请求内核服务的接口。系统调用接口位于用户态与核心态之间,应用程序通过系统调用向操作系统内核请求服务,操作系统内核完成服务后将结果返回给应用程序。
为了在不同权限级别的代码之间切换,Windows NT使用了x86系列CPU的Interrupt Gate特性。Interrupt Gate描述子里面包含一个段选择子指向该ISR所在段的段描述子。在Windows NT的系统调用的情况下,段选择子指向的段描述子是在GDT里面。GDT里面包含所有的全局段描述子,也就是说,不是只与某个单独进程相关(换句话说,GDT里面存放的是描述系统的代码以及数据段的段描述子)。图4-13说明了包含"int 2e"命令的中断描述表项(IDT)与对应的ISR所在的GDT表项的关系。
Windows NT的系统调用是由"int 2e"指令(在X86 Pentum II处理器以及更高的处理器上,Windows使用专门的Sysenter指令)的执行引发的。"int"指令导致CPU执行一个软件中断,即它将会从IDT里面索引为2e的项中读取出Interrupt Gate描述子。Interrupt Gate描述子包含了ISR所在段的段描述子,也包含了ISR在段里面的偏移。CPU将会使用此段描述子从GDT或者LDT(根据TI域)里面获取信息。一旦CPU获取了目标段描述子的信息后,将会把目标段描述子信息加载进CPU。CPU会根据Interrupt Gate描述子里面的偏移设置EIP寄存器。这样CPU就准备好了执行在RIng 0代码段里的ISR。
因为所有的Windows NT的系统调用都通过"int 2e"软件中断切换到内核模式里面去,而系统怎么知道执行哪个系统函数呢?答案是在"int 2e"执行前EAX寄存器里面就保存了一个索引。Ring0下面的ISR根据EAX里面的值调用对应的RIng0函数(如果参数也都正确的话)。参数(比如传给OpenFile的参数)都通过ISR传给Ring0的函数。当系统调用完成,CPU就自动使用IRET指令恢复之前的寄存器状态。这个指令会从Ring0的堆栈中退出之前保存的所有值并跳到"int 2e"下面一句继续运行。Windows系统调用机制如图4-13所示:
 
图 4 13  Windows系统调用机制
所有的内核态的系统调用函数(在Windows里称为原始服务)都有一份在用户态下的同名代理函数,这些代理函数的集合就是Ntdll.dll。绝大部分实现系统功能的API(譬如打开进程的OpenProcess)最终都会调用Ntdll里的代理函数来触发系统调用最终完成自身功能。
4.2.2.2 运行态进入内核
由于Rookit/Bookit植入之前必然作为用户态代码来执行,而由于Window为了可靠性和健壮性利用现代的大多数微处理器都支持两种模式:用户模式(User/Normal)和内核模式(Kernel/Privileged)。操作系统组件和关键的系统组件处于内核模式,而一般用户模式的程序只能访问私有地址空间和执行非特权等级的指令。如果R/Bootkit要获取内核组件的系统功能,就必须通过系统服务调用来实现。
恶意非常规进驻内核这个行为特征恰恰是Bootkti/Rootkit感染入侵成功的必须步骤,而正常的应用程序往往不会也没有必要通过非常规途径获取系统权限,因此如何监控非常规进驻内核的行为成为防范R/Bootkit的技术瓶颈。我们选择监控点为潜在的加载系统组件(譬如系统驱动)和执行危险的系统调用函数。
经过调研我们把恶意进驻内核的系统调用操作总结如下:
1. 权限提升方式
HANDLE hToken;
OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES |
TOKEN_QUERY,
&hToken);
EnablePrivilege(hToken,SE_DEBUG_NAME,1);
2. SetSysDbg方式
 typedef enum _DEBUG_CONTROL_CODE {
DebugSysReadIoSpace = 14,
DebugSysWriteIoSpace = 15,
DebugSysReadMsr = 16,
DebugSysWriteMsr = 17,
DebugSysReadBusData = 18,
DebugSysWriteBusData = 19  } DEBUG_CONTROL_CODE;

ZwSystemDebugControl(DebugSysReadBusData,
&bus,
sizeof(bus),
NULL,
0,
DebugSysReadBusData
\*属于DEBUG_CONTROL_CODE*\
NULL);
3. LoadDriver方式
LoadDriver("\\Registry\\Machine\\System\\CurrentControlSet\\Services\\*");
其中*代表任意驱动名称。
标准的驱动程序的加载


4. OpenPysmem
RtlInitUnicodeString(&objName,L"\\Device\\PhysicalMemory");
InitializeObjectAttributes(&objectAttributes,
                     &objName,
                     OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
                     NULL,
                     (PSECURITY_DESCRIPTOR) NULL);
OpenSection(&hSection,
SECTION_MAP_READ|SECTION_MAP_WRITE,
&objectAttributes);
其中objectAttributes中的objName为” \\Device\\PhysicalMemory
5. SetSysInfo
 RtlInitUnicodeString( &(GregsImage。ModuleName),daPath ); 
ZwSetSystemInformation(
SystemLoadAndCallImage,
&GregsImage,
sizeof(SYSTEM_LOAD_AND_CALL_IMAGE));
   其中daPath为驱动文件的绝对路径


4.2.2.3 SSDT(System  Service Descriptor Table) Hook
Windows在内核态维护一份全局唯一的系统服务分配表供系统调用机制来查阅,其数据结构如下:
typedef struct _SERVICE_TABLE_DESCRIPTOR {
   PULONG ServiceTableBase;               /* 函数指针表*/
  PVOID ServiceCounterTable; /*只在CheckedBuild 版本中使用*/
     ULONG NumberOfServices;            /* 表中服务个数*/
     PVOID ParamTableBase;              /* 参数个数表基址*/
} SERVICE_TABLE_DESCRIPTOR,*PSERVICE_TABLE_DESCRIPTOR;


ServiceTableBase指向的内存空间为系统调用函数地址表,发生int 2eh 或者 Sysenter 系统调用的时候,执行会陷入内核态的系统调用的处理例程KiSystemService中;该例程会通过Eax寄存器指示的索引查询系统调用函数地址表,得到系统调用地址并且从这里执行。
如图4-14显示了SSDT的钩挂原理:
 
图 4 14  SSDT Hook
我们使用自己的桩函数地址替换潜在的危险系统调用函数所对应的SSDT中的位置里保存的原地址(譬如NtSetSystemInformation),在桩函数里根据探针部署库的格式要求获取相关当前的参数列表和返回值,调用行为语义解析模块来判断当前行为是否允许,根据判断的结果来决定是否调用原来的系统调用函数,从而有效阻止恶意R/Bootkit获取底层权限断绝执行机会。
4.2.3 行为语义解析模块
行为语义解析模块是整个BD设计框架中的关键模块之一,本质上会为每个进程粒度的主体维护各自可疑系统调用行为的行为特征状态迁移图。
任何主体在任何时候都会处于的某个子行为特征状态之中,每当某个特定进程上下文中的相关系统调用发生并被行为截获模块截获到的时候,会将当前系统调用的一次执行或者试图执行作为激励,使得行为特征状态迁移到下一个子特征状态直到进入某个终止状态,从而发现某个完整的行为特征为止。
其整体框架如图4-15所示。现在分析其中的关键部分如下:
 
图 4 15  行为语义解析模块
4.2.3.1 TTIndex和私有匹配库
我们将每个进程的主体结构指针放置在对应进程(PEPROCESS)(pEprocess)->Peb.SystemReserved这个空闲的域。通过该指针可以找到根进程关联的两个数据结构:TTIndex和私有匹配库。
TTIndex类似于数组结构,每一个元素代表了一个独立的操作类的终结符,其值是0或者1代表了执行事务对应的操作在当前进程的主体上下文下还没有发生或者已经发生。
4.2.3.2 行为匹配库
行为匹配库其实就是真值表结构,考虑到主体的粒度是进程,行为匹配库划分为每个进程特有行为特征的私有行为匹配库和所有进程的公共行为匹配库。
真值表的每个逻辑变量依次对应探针部署库里的操作,其逻辑为1或者0分别代表当前满足这个执行事务条件的操作是否已经发生;所有逻辑变量的value序列代表了当前状态;每次潜在的操作发生作为状态转移条件更新当前状态,直到执行到某个终结状态即代表发现了某个特定行为特征,如图4-16所示:
 
图 4 16  状态迁移发现行为特征
4.2.3.3 探针部署库
探针部署库描述了所有待监控的执行事务的操作以及操作相关的参数间的依赖关系,分别使用了FunctionList和公共变量符号表。每次潜在的操作发生时,会根据返回值、参数列表搜索探针部署库里,看当前操作是否满足既定的依赖关系条件,根据结果更新对应真值表的逻辑变量的值。
行为语义解析模块是整个模型的关键模块之一。在截获到预设的潜在的危险系统操时会执行以下流程:
每次探针部署库里的系统调用操作发生的时候,会首先执行探针判断操作,t先获取当前的返回值和参数列表然后查阅公共变量符号表,若有匹配项而且变量传递的方向是向内,那么更新该公共变量的内容,为后续引用此公共变量做准备。接着查询探针部署库里该操作相关的所有关系表来决定是否某个执行事务是否发生。然后根据决定的结果更新该执行事务对应操作所对应的TTIndex位是0还是1,再根据更新过的TTIndex查询行为匹配库,判断预定义的特征行为是否发生。行为匹配过程依次查询私有行为匹配库和公共行为匹配库,两库分别代表当前主体特有的行为特征和默认的行为特征。最后根据查询结果是否是1或者0决定是否执行或者跳过原始操作。如图4-17显示了行为解析模块的执行流程:
 
图 4 17  行为解析模块执行流程

4.2.4 编译器模块
编译模块的架构如图4-18所示:
 
图 4 18  编译器模块
利用lex和yacc解析脚本,以函数操作为粒度,为每一个出现的函数构建探针部署库,包括函数返回值、参数列表以及彼此间的比较关系;每次规约完一个if语句,那么根据其中涉及到的函数操作和主体更新行为匹配库。
4.3 实验结果评估
4.3.1 评估思路
BD(Behavior Detector)设计的目标是利用恶意进驻内核的R/Bootkit典型行为特征来预防R/Bootkit的植入,在保证同等程度的系统开销和误报、虚报率的基础上,相比于同类的Anti-R/Bootkit系统显示出较好未知R/Bootkit预防能力和高度灵活可以配置性。
实验的目的如下:
1. 评估BD在已知R/Bootkit上的误报和虚报率;
2. 评估BD与用户交互度和配置量;
3. 评估BD针对未知R/Bootkit的预防能力;
4.3.2 实验环境
Virtual PC作为主流的虚拟机软件功能丰富,能够模拟出来的硬件包括:主板、内存、硬盘(IDE和SCSI)、DVD/CD-ROM、软驱、网卡、声卡、串口、并口和USB口等。使用Virutal PC可以方便模拟、复制特定性能的机器配置,同时可以有效避免重启、死机、破坏操作系统正常运行等在真实机上测试经常出现、耗时、费力的问题。机器配置如表4-2所示:

表 4 2  机器配置
  CPU 主频 内存 操作系统
Virtual pc 2007 -- -- 512MB Windows XP
Sp2
宿主机 Intel(R)Core(TM)2 Duo CPU E8200  2.66GHz 1.95GB
物理地址扩展 Windows XP Sp2
如表4-3所示列出了与BD进行横向比较的五款主流的Anti-R/Bootkit商业化产品。为了更加合理的进行横向对比,我们选择了这几款主流R/Bookit的最新版本。同时由于这几款主流的Anti-R/Bootkit产品并不是特定R/Bootkit的专杀工具,而是集成了Anti-R/Bootit子功能,为此在相关功能说明项中列出了已经开启的有关Anti-R/Bookit的功能集合。

表 4 3  横向比较对象
软件名称 版本 相关功能说明
Kaspersky Internet Security 2009 保护计算机免遭木马、病毒、间谍软件以及其他恶意软件的威胁。
狙剑(SnipeSword 2008-0224 主动防御的相关规则包括程序运行控制、钩子安装控制、程序写入控制、进程注入控制等。
360安全卫士 V5.0.0.1032 木马云查杀,发现未知木马,排除潜在威胁;系统实时保护。
Avast V4.8.1335 Home 病毒隔离区,实时监控,系统结合。
4.3.3 功能评估
注:  
 数字:  
代表提示用户的次数 ;
 N(无反应,No Reflect):  
表示该款产品没有发现恶意威胁;
 N(无反应,No Reflect):  
表示该款产品没有发现恶意威胁;
 L(提前锁定,Lock Ahead):  
表示该被测程序被扫描引擎提前扫描到根本无法执行;
 C(不能运行,Can not Run):  
表示运行失败;
 S(死机,Shut Down):  
表示被测程序的运行引起系统崩溃;
4.3.3.1 已知R/Bootkit评估
已知R/Bootkit的评估结果表4-4所示:
表 4 4  已知R/Bootkit评估
已知R/Bootkit
Anti-R/Bootkit Hxdef100 MigBot  FUTo
Enhanced Nt
GodMode HE4
Hook VICE 漏报率 虚报率
狙剑 3 1 2 2 1 2  0 36%
卡巴斯基 3 C N L N C 33% 45%
360安全卫士 3 N S/N N 1 N 66% 17%
Avast 3 C N L N N 50% 22%
BD 1 1 1 1 1 1 0 0

分析:为了验证BD相比起同类主动防御式商业产品对已知Rootkit的有效检测程度,我们选择了五款典型的Rootkit实地对比。这五款R/Bootkit各代表了不同隐蔽方式和危害方式。由于当前被测的对象确实是R/Bootkit,所以提前锁定和死机等算能识别出危险。
根据
虚报率=(1-   /(6-无反应次数))*100%
漏报率=无反应次数/6
计算可知
从漏报率角度看:狙剑=BD<卡巴<Avast<360安全卫士
从虚报率角度看:BD<360安全卫士<Avast<狙剑<卡巴斯基
结论:
从表格中可以看到相比于其他产品要么不能正常检测要么报告次数偏多,BD对R/Bootkit具有较低的虚报率和漏报率。
4.3.3.2 非R/Bootkit评估
非R\Bootkit的评估结果如表4-5所示:

表 4 5  非R\Bootkit评估
非R/Bootkit
Anti-R/Bootkit Vs2005 Ethereal安装 Register
Monitor 虚报率
狙剑 7 6 3 80%
卡巴斯基 N N N 0
360安全卫士 N 2 N 63%
Avast N N N 0
BD N 1 1 33%
分析:为了验证BD相比起同类主动防御式商业产品对非Rootkit的有效检测程度,我们选择了具有潜在危害但是非R/Bootkit的软件实地对比。这三种非R/Bootkit分别代表了编译连接、安装程序、内核检测类程序。
根据
虚报率=(1- )*100%
计算可知
从虚报率角度看:卡巴斯基=Avast<BD<360安全卫士<狙剑
结论:
从表格中可以看到相比于其他产品要么,BD对非R/Bootkit具有一般的虚报率。
4.3.3.3 未知R/Bootkit发现
未知R/Bootkit的评估结果如表4-6所示:
表 4 6  不同加载方式评估
未知R/Bootkit
Anti-R/Bootkit 
SysDbgCtl 
SetSysInfo  Physmem 
Misc 
LoadDrv 漏报率 虚报率
狙剑 1 2 3 2 1 0 33%
卡巴斯基 S N N N/S 1 60% 0
360安全卫士 N N N N 1 80% 0
Avast N N N N 1 80% 0
BD 1 1 1 1 1 0 0
分析:为了验证BD相比起同类主动防御式商业产品对未知Rootkit的有效检测程度,我们构造了具有R/Bootkit功能的自定义的程序实地对比。这五种R/Bootkit分别代表入侵内核的不同方式。由于当前被测的对象确实是R/Bootkit,所以提前锁定和死机等可认为是识别出了危险。
根据
漏报率=无反应次数/5
虚报率=
计算可知:
从漏报率角度看:狙剑=BD<卡巴<Avast=360安全卫士
从虚报率角度看:BD=360安全卫士=Avast=卡巴斯基<狙剑
结论:
从表格中可以看到相比于其他产品要么不能正常检测要么报告次数偏多,BD针对未知R/Bootkit检测发现上有较优表现。
4.4 本章小结
本章利用形式化描述语言规范和行为策略设计并实现了一个基于恶意进驻内核行为特征的Anti-R/Bootkit原型系统—BD(Behavior Detection)。首先介绍了内核编程所必须的背景知识,然后分模块依次介绍了优先启动、探针布控、行为语义解析、编译器等模块的设计与实现,最后再通过实验评估,证实该系统与同类商业化的Anti-R/Bootkit系统的比较中,显示出较优的自主识别能力以及较好的未知R/Bootkit预防能力。
 
 第 5 章 全文总结
R/Bootkit和Anti-R/Bootkit作为团体利益在信息安全领域之争的必然结果,在技术上的抗衡是无止境的,最近提出的基于虚拟机、硬件检测技术的Anti-R/Bootkit就代表了对抗会朝着更加广泛、深入、隐蔽的方向发展的趋势。
5.1 主要工作和特色
本文做到的工作主要有以下几个方面:
1. 提出了Bootkti/Rootkit防范与检测的技术瓶颈
本文深入探索当前主流B/Rootkit的危害原理以及技术要点实现,以及主流Anti-R/Bootkit在行为判断上过多依赖用户选择的现状,提出了恶意进驻内核这个行为特征提取是Bootkti/Rootkit防范与检测的技术瓶颈。
2. 提出了形式化描述语言规范
为了统一且完整描述系统运行包括恶意代码的各种行为以及子行为彼此间内在的关联关系,我们参考自然语言叙事逻辑:主语、谓语、宾语结构还有计算机体系中实际的指令格式的定义:操作码、目的操作数、源操作数,提出了一套以执行事务的概念为基础的形式化描述语言规范,完备描述出该恶意行为特征。
3. 设计与实现了基于恶意进驻内核行为特征的Anti-R/Bootkit原型系统
在此基础上,利用该形式化描述语言规范和行为策略,我们设计并实现了一个基于恶意进驻内核行为特征的Anti-R/Bootkit原型系统。在和同类商业化的Anti-R/Bootkit系统的比较中,显示出较优的自主识别能力以及较好的未知R/Bootkit预防能力。
5.2 后续工作研究
本文后续的研究工作包括:
1. 完善形式化描述语言的词法分析、语法分析和语义定义部分,支持功能更为强大的行为特征描述;加入UI配置功能。
2. 对恶意行为和非恶意行为建模,加入行为序列自学习功能,以便减少筛选、提取行为特征时的用户交互。
3. 拓展底层布控模块的布控深度和广度、加入自我保护功能等,以便扩展为功能完备的主动防御产品。
 

致谢
为了本人这篇分量有限的毕业论文成稿,不知道耽搁多少科大老师朋友的时间和心思。感谢周老师和陈香兰老师为小论文大论文的审稿而付出的时光。感谢同实验的徐军同学为Ozone底层防御搭起来框架供师弟师妹继续开展项目研究,供我收益。感谢胡大磊、李星、李奇、薛辉、晓丹在论文构架和技术实现上耐心的交流和思路闪光点。感谢软院的师弟师妹和研二的师弟们在安全加固项目上的投入,尤其是邱寅峰同学在Native App 优先启动方面的补充、陈辉在网络socket方面的调研以及裴建国在Windows 启动上的总结文档。最后至诚感谢杨寿保等评审老师的认真审阅与回复,希望答辩的时候能再聆听指教。

基于行为监测的Anti-R/Bootkit的研究与实现 免费邮件订阅: 邮件订阅

图片推荐

热点排行榜

CopyRight? 2013 www.cangfengzhe.com All rights reserved