基于KVM虚拟化平台的单向透视防护系统

来源:互联网 发布:淘宝店铺员工提成 编辑:程序博客网 时间:2024/04/28 17:14

  小注: 这是在学校的时候,参加某比赛,而做的一个东西,虽然并不先进,但是当时学到了很多东西。发到这里,当作记录,详细文档可以从这里下载:


doc:https://docs.google.com/open?id=0Bx0lAP-TDpepdEx3SHRCaHZiNGM

PPT  https://docs.google.com/open?id=0Bx0lAP-TDpepR1hkMllibEMzSmc

本系统是基于Linux KVM虚拟化平台的虚拟机安全防护软件。首先,我们通过在KVM内核中增加系统调用,结合安全内核模块实现对虚拟机系统资源的单向透视功能以及对进程的管理功能。在此基础上,安全控制模块使用ClamAV杀毒引擎对各活动虚拟机进行透视病毒扫描。客户可以通过网络模块对自己租用的虚拟机进行安全设置和管理,不需要额外安装任何软件和系统模块。

一        

1.1      系统总体架构

本系统由四个主要模块组成:改造的KVM内核模块、安全内核模块、安全控制模块和网络模块。具体架构如下图:

图3.1 总体架构

  图片贴不出来啊。

1. 改造的KVM内核模块(kvm-kmod):运行在宿主机的Ring0层,在原KVM虚拟化管理器的基础上进行修改,增加透视虚拟机系统资源的函数接口。实现以下功能:

①      第一种虚拟透视技术:提供读取虚拟机内存到主机内核空间的接口(关键技术1)

②     允许其他内核模块在特定VM EXIT(CR3)注册钩子,以实现对进程的监控

      (注:兼容Intel VT和AMD SVM架构)

2. 安全内核模块(av):运行在宿主机的Ring0层,该内核模块通过调用改造的KVM内核模块,获得虚拟机的进程信息,实现以下功能:

①     虚拟机内核对象还原(关键技术2);

②     第二种虚拟透视技术:内存映射(关键技术1);

③     按照扫描策略和进程处理策略,对进程、线程实行以下的控制操作:暂停、恢复、终止;

④     与安全控制模块、sever模块进行netlink通信(通信协议自行设计),以完成进程扫描等功能。

3. 安全控制模块(clamav-host):运行在宿主机的Ring3层, 在clamav杀毒引擎基础上修改实现以下功能:在集成clamav杀毒引擎基础上实现以下功能:

①     与内核模块进行netlink通信,提供第二种虚拟内存透视技术-内存映射的载体;

②     接受扫描命令后,对进程扫描,并将结果报告给安全内核模块,由其进行相应的进程处理;

4. 网络模块(sever/client):包括两个部分,sever和client。

sever——与安全内核模块进行netlink通信,实现对进程的监控;与client模块进行TCP通信(应用层协议自行设计,其中传递的CR3信息为其哈希值);

client——对虚拟机中的进程信息进行控制和管理。

(注:系统在虚拟机中不安装任何软件。Client安装在虚拟机终端中,仅提供显示管理功能,不涉及杀毒,目前采用的是C/S架构,随着系统的应用扩展,可进一步完善为B/S架构。)

 

图中的Qemu进程是具体运行虚拟机的进程,我们不对其进行任何修改。

1.2      系统关键技术及实现原理

1        

2        

3        

3.1        

3.2        

3.2.1       虚拟机内存透视技术

为了保证虚拟机的真实性和透明性,虚拟机内部(下称Guest)与主机之间的通信常通过网络进行,就像两台物理机器一样;Guest和宿主机之间一般不直接交换数据。然而实际上,Guest的所有系统资源(内存、磁盘等)都是VMM进程向主机操作系统申请的,受主机操作系统的控制和调度。因此,只要利用VMM进程的资源信息,将“Guest的资源存放地址”转换为“主机内的真实存放地址”,就可以实现在主机内对Guest系统资源的直接读取;这种技术被称为“虚拟机透视”(VM-Probing)。这种形式的透视,很难被Guest内部的操作系统和进程发现。

在KVM虚拟化平台中,虚拟机的物理内存对应于宿主机上相应的Qemu进程的虚拟内存,要把已知的Guest内存地址(物理或者虚拟)变换成主机的虚拟地址,需要经过如下页图3.2所示的步骤[6]


图3.2 内存虚拟化地址变换原理

在KVM中增加导出函数,可以按照上述转换机制实现虚拟机内存到主机内核空间的变换。这是我们利用的第一种透视技术——内存直接透视

内存的读写难点在于读写的效率,以及在合适的时间完成写。频繁的读取虚拟机内存,将会带来极大的时间和空间的消耗。同时,当清除内存中的恶意代码的时候,不恰当的时机可能导致系统整个崩溃。因此,对于大批量的内存信息读取,我们采用了第二种透视技术——内存映射的方式来减少拷贝虚拟机内存的开销,具体方法为:首先在主机中新建进程空间,将该进程空间的页表直接指向虚拟机进程页表,这样不经过复制,便可实现对虚拟机进程的控制。

为了防止在不恰当的时机修改虚拟机内存,导致虚拟机系统崩溃,我们选择在虚拟机陷入VMM的时候,根据需要对虚拟机内存进行修改,清除内存中的病毒。此时虚拟机处于暂停状态,VMM代其完成某些任务,此时修改其内存数据,不会发生竞争导致系统崩溃。

两种透视技术的比较见下表:

 

表3.1 两种透视技术的比较

透视方法

复制机制

透视获得的信息所在主机空间

适用范围

内存直接透视

将虚拟机相关内存复制一份

内核空间

少量数据,用于进程、线程扫描前期的控制块传递

内存映射

不复制

用户空间

大量数据,用于根据扫描策略对特定进程进行批量扫描

 

3.2.2       系统内核对象还原技术

现代操作系统采用了复杂的数据结构,在内存中保存系统的关键数据。如果不能正确的解析内存数据代表的含义,即使获得内存数据,仍然无法正确的判断和安全的清除病毒。

我们的系统没有在Guest OS内部安装任何辅助软件,而是在VMM层根据Guest OS的特性和x86架构的特点,重新构建Guest OS内核对象。Windows 操作系统用户众多,稳定性好,因此我们选用Windows XP SP3 系统为例,说明如何在VMM层还原系统内核对象。

在Windows系统中,默认约定:当CPU运行在内核态时,FS寄存器指针指向KPRCB结构体,在该结构体中保存了当前运行在CPU的线程和对应的进程的相关信息,如图所示:


图3.3 Windows进程控制块数据结构[7]

 

struct _KTHREAD*CurrentThread //当前线程的KTHREAD结构体,偏移120h

struct _KTHREAD*NextThread   指向下一个要允许的线程

LIST_ENTRYDispatcherReadyListHead[32]  就绪线程队列

LIST_ENTRY  WaitListHead  等待线程队列

当前线程指针CurrentThread保存在KPRCB 偏移0x120的位置。在这个KTHREAD结构体偏移0x44的位置保存有当前线程所属进程的KPROCESS结构指针,此KPROCESS指针等于当前进程EPROCESS结构体指针。通过EPROCESS结构体可以获得当前进程的所有信息。包括:

PVOIDSectionBaseAddress 映像基地址

CHARImageFileName[16]  所执行程序映像的文件名

struct _PEB *Pcb        用户空间进程环境块。

MM_AVL_TABLEVadRoot  指向代表本进程用户空间内存分配的数据结构

在KPROCESS 结构体中保存有

LAGE_INTEGERDirectoryTableBase //本进程页表的物理地址

LIST_ENTRY   ThreadListHead  本进程的线程队列

用户空间的PEB结构体中保存有:

PVOID ImageBaseAddress //程序映像起点

Struct_RTL_USE_PROCESS_PARAMETERS *ProcessParameters 进程参数块,其中保存了当前 CURDIR CurrentDIrectory 当前文件目录。结合映像文件名。即可完整的获得进程所执行的程序在硬盘上的位置。

由此即可以成功的获得当前线程和进程的信息。同时通过PKPCR结构体中的进程链表,可以获得系统中所有已经建立的进程的信息。

当CPU运行在用户态的时候,FS寄存器指针指向当前运行的线程的TEB结构体,通过TEB即可获得该线程所属的进程的位于用户空间的PEB结构体。这样同样可以获得当前线程以及所属进程的所有信息。

上面以获得进程信息为例,展示了通过直接内核对象的读取,可以直接获得Guest OS的各种内核对象,而不会受到虚拟机内部运行的进程的干扰,保证了数据的正确性和完整性。同时做到了完全隐蔽,虚拟机内部的进程无法感知到这一过程的进行。

 

1.3       系统实现

3.3        

3.3.1       改造的KVM内核模块

该内核模块通过略为修改KVM内核,实现获取虚拟机系统信息、透视读写内存的功能,并为安全内核提供接口函数。目前我们在Intel VT架构下具体实现如下:

我们在KVM内核模块添加导出函数kvm_register_vm_av_module,用于向KVM注册一个安全模块,其函数原型如下:

unsigned longkvm_register_vm_av_module(

unsigned long vm_op, unsigned long long vm_event);

其中,第一个参数vm_op是回调函数指针,回调函数原型为:

intav_handle_vm_exit(struct kvm_vcpu * vcpu);

回调参数为一个kvm_vcpu 结构体指针vcpu,代表发生VM Exit事件的虚拟CPU。其中保存有VCPU对应的虚拟机和发生VM Exit事件的原因。

第二个参数vm_event是一个64位无符号整数,定义了回调函数的感兴趣事件。我们规定:第n位为1时,代表回调函数要处理Intel指导手册[8]中对应的第n个VM Exit事件。少量未定义的位在KVM中并没有对应的处理函数,这些VMExit事件并不需要被处理。


经过以上修改的KVM在处理VM Exit的时候的工作流程如下图所示:

图3.4 修改后的VM Exit流程

如果检测到已经注册了安全模块,同时对当前发生的事件感兴趣。则调用注册的回调函数。回调函数处理完成之后,KVM继续进行处理。

在我们的系统实现中,设定的感兴趣事件如下:

表3.2 安全内核感兴趣的VM Exit事件

Intel编号

事件

解释

1

EXIT_REASON_EXCEPTION_NMI

虚拟机发生非屏蔽中断

9

EXIT_REASON_TASK_SWITCH

虚拟机发生任务切换

28

EXIT_REASON_CR_ACCESS

虚拟机访问CR寄存器

48

EXIT_REASON_EPT_VIOLATION

虚拟机发生EPT冲突

49

EXIT_REASON_EPT_MISCONFIG

虚拟机EPT配置出错

另外,我们导出了KVM内核模块中的两个原有的函数,用于在其他内核模块中,读取虚拟机的虚拟内存:

int kvm_read_guest_virt_system(

                                   gva_t addr,

                                   void *val,

                                   unsigned int byte,

                                           structkvm_vcpu *vcpu,

                                           structx86_exception *exception);

 

int kvm_write_guest_virt_system(

                                   gva_t addr,

                                   void *val,

                                   unsigned intbytes,

                                   structkvm_vcpu *vcpu,

                                   structx86_exception *exception);

增加两个导出函数,用于读写虚拟机的寄存器:

unsigned longkvm_vm_register_read(struct kvm_vcpu *vcpu,enum kvm_reg);

voidkvm_vm_register_write(

struct kvm_vcpu *vcpu,enum kvm_reg reg,unsigned long val);

3.3.2       安全内核模块

该内核模块通过第一种透视技术,调用KVM内核模块,获得虚拟机的进程信息,并保存在为每一个虚拟机维护的struct kvm_vm_information 结构体中。同时,使用一个struct kvm_vm_process结构体保存虚拟机中所有的活跃进程。

kvm_vm_information结构体在模块加载或者新建虚拟机时创建,保存该虚拟机对应的宿主机进程pid号、虚拟机操作系统类型、虚拟机内存大小、虚拟机物理内存页对应的宿主机虚拟内存页。当虚拟机发生特殊事件陷入VMM的时候,KVM内核模块将对应的事件报告给安全内核模块,本模块即对28号感兴趣的事件(虚拟机访问CR3)做出反应:

在系统中,每一个不同的CR3寄存器的值代表一个新的进程,通过监控CR3寄存器值变化,可以逐步获得系统中所有的活跃进程,并将其保存到kvm_vm_process结构体中。一旦发现一个新的进程创建,则将其代码段所在内存通过第二种透视技术内存映射的方式映射到安全控制模块,进行进程的查杀,一旦发现可疑进程,按照进程处理策略处理,如下表:

 

表3.3 进程处理策略

事件

动作

可疑进程

暂停进程,计时,等待用户响应

用户终止命令

结束进程

响应超时

结束进程

用户信任命令

放行

对于可疑进程的结束策略如下:

表3.4 可疑进程结束策略

可疑进程所处位置

动作

用户私有进程空间

插入结束代码

用户共享进程DLL空间

备份信息,插入结束代码,进程切换时进行还原,防止影响其他进程

内核空间

暂时不改变

 

3.3.3       安全控制模块——ClamAV杀毒引擎部分

ClamAV全名Clam Anti Virus,是一款 UNIX 下开源的 (GPL) 反病毒工具包,可用于各类场合的反病毒引擎共享库。其使用流程如下页图3.5所示:


图3.5 libclamav 集成流程

因为该杀毒软件只能扫描文件,要对内存中的数据进行查杀,还需要对其进行一定的改进。

3.3.4       安全控制模块——虚拟内存映射部分

该部分主要同安全内核模块一起完成第二种透视技术,实现机制如下:

1.安全内核模块调用改造的KVM内核模块,获得虚拟机进程地址;

2.安全控制模块发送附带进程空间大小信息的建立内存映射命令;

3.安全控制模块申请相应大小的用户空间;

4.安全控制模块申请后向安全内核模块发送回复命令;

5.安全内核模块找到虚拟进程页表;

6.安全内核模块将安全控制模块申请的空间页表指向虚拟进程页表。

3.3.5       网络模块

1.sever模块具有以下功能:

与安全内核模块进行netlink通信,实现对进程的监控;与client模块进行TCP通信(应用层协议自行设计,其中传递的CR3信息为其哈希值)。

2.client模块有以下功能:

连接sever模块,通信协议自行设定;系统进程信息显示,显示正在运行的虚拟机数、各虚拟机当前进程列表和实时扫描结果;结束进程。
原创粉丝点击