Page 323 - 《软件学报》2021年第10期
P. 323

陈兴蜀  等:VMOffset:虚拟机自省中一种语义重构改进方法                                                3295


                 次访问 TVM 并手动配置进程偏移量信息;(2)类方法需要安装与 TVM 内核版本一致的 SVM 完成自省;(3)类方
                 法则需要重新分析内核源码,导致系统的通用性及可移植性差,自动化程度低.此外,基于 TVM 的 VMI 方法可能
                 因不具备权限或源码缺失等情况无法加载内核模块,导致自省无法实施.基于 SVM 的 VMI 方法需配置 SVM,
                 对自省环境的要求高,且性能损耗较大.基于内核源码的 VMI 方法需分析及搜索的信息较多,自省效率不高,且
                 分析内存转储文件无法获取运行状态 TVM 的信息.针对这些不足,本文基于 KVM-QEMU 虚拟化平台,提出了
                 一种虚拟机自省中的语义重构改进方法 VMOffset(virtual machine offset),主要贡献如下:
                    (1)  VMOffset 解决了上述 VMI 方法实现过程与 TVM 内核版本相关的问题.在不需要知道 TVM 内核版
                        本的情况下,VMOffset 可基于结构体成员自身属性制定约束条件获取 TVM 的进程偏移量信息.该方
                        法屏蔽了 TVM 内核版本的差异性,无需访问 TVM,对 TVM 无侵入性,且无需额外引入 SVM,具有通
                        用性及可移植性;
                    (2)  VMOffset 在 TVM 启动阶段完成进程偏移量的获取,性能损耗小,且启动阶段不会出现内核 Rootkit
                        等攻击,保障了所得信息的安全性.此外,VMOffset 的实现过程不依赖特定内核源码,TVM 内核源码的
                        修改不会影响结果的正确性与可靠性;
                    (3)  VMOffset 可将所得进程偏移量提供给自研或开源 VMI 工具完成语义重构过程,无需手动进行信息配
                        置,自动化程度高,且可扩展 VMI 开源工具以实现虚拟机隐藏进程检测,进程代码段完整性度量功能,
                        增强虚拟化环境下的安全能力.
                    本文第 1 节介绍 VMOffset 系统的设计及架构.第 2 节阐述关键技术.第 3 节对 VMOffset 进行测试评估.第
                 4 节总结全文.

                 1    VMOffset 系统设计

                    将在 TVM 外部提取的底层状态数据重构为高层语义信息的关键是获取两类信息:(1)  计算机组织、存储
                                                                                                      [2]
                 待重构数据元素的方式,如链表、树等;(2)  待重构数据元素的三元组信息数据元素类型,起始地址,偏移量 .
                 同样地,VMOffset 通过获取这两类信息实现语义重构过程,其设计基于以下前提:(1) Linux 操作系统通常使用链
                 表组织关键信息,如进程、文件、内核模块等;(2)  虽然内核数据结构成员数目及布局会因内核版本的不同而不
                 同,但部分关键属性成员是一直存在的,且其类型不变.以进程为例,如图 1 所示,Linux 内核使用 task_struct 结构
                 体描述单个进程的详细信息,并使用双向循环链表将各个进程的 task_struct 组织起来.该结构体中部分关键成
                 员是一直存在的,如成员 pid 为进程号,用于标识各个进程;成员 comm 可描述进程名称;成员 tasks 用于链接整个
                 进程链表.可知:若得到某个进程 task_struct 结构体的起始地址,根据 pid 及 comm 的偏移量,就可重构出该进程
                 的进程号及进程名;同理,根据 tasks 成员的偏移量,即可通过其链表指针得到下一个进程 tasks 成员的地址,依次
                 遍历可得到 TVM 中的所有进程信息.
                          Process 0                 Process 1                           Process N

                    struct task_struct{      struct task_struct{               struct task_struct{
                        …                        …                                 …
                      struct  list_head tasks;    struct  list_head tasks;       struct  list_head tasks;
                             *next                     *next                            *next
                             *prev                     *prev           …                *prev
                      struct mm_struct *mm;    struct mm_struct *mm;             struct mm_struct *mm;
                      pid_t pid;               pid_t pid;                        pid_t pid;
                      char comm[TASK_COMM_LEN];    char comm[TASK_COMM_LEN];     char comm[TASK_COMM_LEN];
                      …                        …                                 …
                    }                        }                                 }


                                           Fig.1    Structure of process linked list in Linux
                                                  图 1  Linux 进程链表结构
   318   319   320   321   322   323   324   325   326   327   328