虚拟机环境搭建、管理、监控与分析

作者:Diting0x


  • 0x01 全文环境
  • 0x02 虚拟机创建KVM/QEMU
  • 0x03 虚拟机管理Libvirt
  • 0x04 虚拟机监控Libvmi
  • 0x05 虚拟机监控Volatility

本文介绍了一套完整的虚拟化环境搭建与分析工作,包括虚拟机的创建,虚拟机的管理,以及虚拟机的监控与分析。可根据自身需要阅读相关内容。


0x01 全文环境

Ubuntu12.04 + Kvm-kmod-3.8 + Qemu-kvm-1.1.2+ Libvirt 1.3.2 + Libvmi + Volatility

Ox02 虚拟机创建KVM/QEMU

Kvm需要CPU的支持(Intel VT 或者 AMD SVM),在安装KVM之前,可先检查CPU是否支持硬件虚拟化技术。基于Intel的系统,可运行 ‘grep vmx /proc/cpuinfo’ 查看是否含有vmx的关键字,如果有,则表示支持;基于AMD的系统,可运行 ‘grep svm /proc/cpuinfo’ 查看是否含有svm的关键字。
另外,CPU若支持硬件虚拟化,还得确保BLOS开启了VT选项(有些厂商默认是禁用的,如thinkpad t450). 可以下载 cpu-checker 工具(apt-get install cpu-checker),之后运行kvm-ok, 如果提示 kvm acceleration can not be used,则可能是blos禁用了kvm虚拟化,在blos设置中开启即可。

可执行:

modprobe kvm 
modprobe kvm_intel 

开启内核自带的kvm

关于源码安装kvm-kmod以及qemu-kvm的详细过程可参考 上一篇 文章。kvm-kmod安装成功后,运行lsmod | grep kvm, 会显示两个module:

kvm_intel             137721  3 
kvm                   415549  1 kvm_intel

qemu-kvm安装成功后会在/your-confiure-location/bin/qemu-system-x86_64等可执行文件。

安装完KVM/QEMU后,创建虚拟机的时候,虚拟机的网络方式是比较关心的问题,KVM/QEMU有两种网络配置方式。

其一,用户模式(User Networking): 即NAT方式,也是默认的网络模式。让虚拟机访问主机、互联网或本地网络上的资源的简单方法,但是不能从网络或其他的客户机访问客户机。既然无法访问客户机,那宿主机与客户机该如何传输文件呢?默认的,客户机得到的ip空间为10.0.2.0/24,宿主机提供了ip为10.0.2.2的地址让虚拟机访问。可以ssh到宿主机(10.0.2.2),用scp来拷贝文件。

其二,桥接模式(Bridge Networking): 这种模式允许客户机就像一台独立的主机一样拥有网络。这种方式要比用户网络复杂一些,但是设置好后客户机与互联网,客户机与主机之间的通信都很容易。桥接网络需要网卡支持,一般的有线网卡都支持,绝大部分的无线网卡都不支持。

NAT方式是KVM/QEMU提供的默认方式,要设置桥接模式,首先在宿主机上安装桥接相关的包,

apt-get install bridge-utils. 

修改/etc/network/interfaces

auto lo
iface lo inet loopback
auto eth0
iface eth0 inet manual
auto br0
iface br0 inet dhcp
   bridge_ports eth0
   bridge_stp off
   bridge_fd 9
   bridge_hello 2
   bridge_maxwait 0

执行

/etc/init.d/networking restart

配置好后,可运行brctl-show命令,会显示:

bridge name      bridge id              STP enabled interfaces
br0              8000.68f728eddb0d      no          eth0
                                              vnet0

之后在创建虚拟机的时候可添加-net nic -net tap参数,如

/usr/local/bin/qemu-system-x86_64 -hda imgname.img -vnc :1 -m 1024 -net nic -net tap -monitor stdio    

之后创建的虚拟机便工作在网桥模式中。

0x03 虚拟机管理Libvirt

除了用qemu命令行的方式创建与管理虚拟机,也可将一些命令行参数保存为xml配置文件,用libvirt来管理。libvirt是一套管理虚拟机的工具,包括管理虚拟机的API、一个守护进程(libvirtd)和一个命令行工具(virsh). Libvirt 的主要目标是提供一个单一途径以管理多种不同虚拟化方案已经虚拟化主机,包括KVM/QEMU,Xen,LXC等。安装libvirt后,会产生libvirtd进程以及virsh工具,要利用libvirt做开发,可调用其中的API。libvirt, libvirtd 以及virsh的关系如下图:

libvirt-internal

详细介绍可参考:libvirt internals

安装libvirt:

先安装libvirt所依赖的包

apt-get install libnl-dev libxml2 libxml2-dev  libpciaccess-dev libyajl-dev libdevmapper-dev libgnutls-dev

如出现以下错误,都可以检查上述这些包是否安装好

error: Could not find libxml2 anywhere

error: You must install the GnuTLS library in order to compile and run libvirt

error: You must install device-mapper-devel/libdevmapper >= 1.0.0 to compile libvirt

error: libnl-devel >= 1.1 is required for macvtap support

下载libvirt1.3.2.tar.gz

tar xvf libvirt1.3.2.tar.gz
./configure
make && make install

安装完成后,执行ldconfig同步链接库,否则会出现以下错误:

virsh: error while loading shared libraries: libvirt.so.0: cannot open shared object file: No such file or directory

执行检查libvirt安装成功

which libvirtd
libvirtd –version
which virsh
virsh –version

若出现此类错误:

error: Failed to reconnect to the hypervisor
error: no valid connection
error: Failed to connect socket to '/usr/local/var/run/libvirt/libvirt-sock': No such file or directory

则很有可能是libvirtd进程没有开启,这时需要手动开启libvirtd,执行libvirtd -d 即可。(libvirtd具体参数可参考:libvirtd manual

另外注意,libvirt从1.3版本后增加了virtlogd特性,需要执行virtlogd -d手动开启virtlogd进程(virtlogd具体参数可参看:virtlogd manual ). 否则会出现以下错误:

error: Failed to connect socket to '/usr/local/var/run/libvirt/virtlogd-sock': No such file or directory

安装好libvirt后,便可配置好xml文件,用virsh来管理。具体virsh命令这里不做介绍,可参考其中一个配置文件:

<domain type='kvm'>
<name>ubuntudemo</name><!--虚拟机名称-->
<memory>1048576</memory><!--最大内存,单位KB-->
<currentMemory>1048576</currentMemory><!--可用内存,单位k-->
<uuid>87d5b3d2-3618-4a59-9efb-aa869ff34999</uuid>

<vcpu>1</vcpu><!--虚拟cpu个数-->
<os>
    <type arch='x86_64',machine='pc'>hvm</type>
    <boot dev='hd'/><!--光盘启动-->
</os>
<features>
    <acpi/>
    <apic/>
    <pae/>
</features>
<clock offset='localtime'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<devices>
    <emulator>/usr/bin/qemu</emulator> <!--先创建好软链接   ln -s /use/local/qemukvm1.1.2/bin/qemu-system-x86_64 /usr/bin/qemu-->
    <disk type='file' device='disk'>
        <driver name='qemu' type='qcow2'/>
        <source file='/home/os.img/server12041.img'/><!--目的镜像路径-->
        <target dev='vda' bus='virtio'/>
    </disk>

    <interface type='bridge'><!--虚拟机网络连接方式-->
        <source bridge='br0'/><!--当前主机网桥的名称-->
        <mac address="00:16:3e:5d:aa:a8"/><!--为虚拟机分配mac地址,务必唯一,否则dhcp获得同样ip,引起冲突-->
    </interface>
    <input type='mouse' bus='ps2'/>
    <!--vnc方式登录,端口号自动分配,自动加1,可以通过virsh vncdisplay ubuntudemo来查询(实际端口为显示结果+5900)--> 
    <graphics type='vnc' port='-1' autoport='yes' listen='0.0.0.0' keymap='en-us'/>
</devices>

0x04 虚拟机监控Libvmi

Libvmi是一套能从底层二进制信息重构虚拟机上层语义的C语言API。由于hypervisor(VMM)获取的全是客户机的二进制比特,用户为了从外部(比如宿主机)监控客户机的行为需要理解客户机上层的语义,比如客户机正在运行的进程列表、模块列表等信息,这种二进制到上层语义之间的gap称之为语义鸿沟(semantic gap),从外部监控客户机的行为称之为虚拟机自省(VM Introspection)。 Libvmi提供的API,能够读取物理内存、虚拟内存、符号表(System.map)、暂停/打开虚拟机、接收内存与寄存器事件的通知等,让用户能很方便的构建插件,来读取进程列表、模块列表等信息(大部分linux原生监控工具都可以通过libvmi来构建).

Libvmi目前支持Intel,AMD64以及ARM系统结构,支持的虚拟机平台包括XEN与KVM/QEMU,支持的被监控系统类型包括windows和linux. Libvmi从Xenaccess发展而来,要了解其详细原理,可参考论文Secure and Flexible Monitoring of Virtual Machines以及官方主页libvmi.

安装libvmi:

先安装其依赖的包,注,这里针对KVM/QEMU,关于XEN依赖的包,会有所不同,可参考libvmi-installation

apt-get install automake autoconf
apt-get install libtool
apt-get install flex bison
apt-get install check

下载libvmi-0.10.1.tar.gz

tar xvf libvmi-0.10.1.tar.gz

安装

cd libvmi-0.10.1
./autogen.sh
./congfigure
make 
make install
ldconfig

libvmi提供了很多plugin examples在/libvmi/examples文件夹中,
要运行其中的plugin(比如process-list,列举客户机中进程信息,类似linux的原生ls命令), 首先要找出客户机符号表中的一些偏移信息. libvmi提供了获取偏移信息的工具在/libvmi/tools/linux-offset-finder/ 文件夹中,将其拷贝到虚拟机中,make编译,生成了一个内核模块findoffset.ko,执行insmod findoffset.ko将其插入内核中,
再执行dmesg 将得到的偏移信息,如:

ostype = "Linux";
//sysmap = "/boot/System.map-3.2.0-29-generic";
linux_name = 0x470;
linux_tasks = 0x248;
linux_mm=0x280;
linux_pid=0x2bc;
linux_pgd=0x58;

写进宿主机的/libvmi/etc/libvmi-example.conf中,将libvmi-example.conf拷贝到/etc/libvmi.conf或者\$HOME/etc/libvmi.conf中,注,这里libvmi会在/etc/libvmi.conf或者\$HOME/etc/libvmi.conf中读取偏移信息。另外,这里的sysmap路径是host主机的路径,需要把guest中的System.map文件拷贝到host主机上。(还发现一个问题,虚拟机的名字不能全以数字命名,比如120432,不然在读取libvmi.conf配置文件时会出错).

之后运行

/libvmi/examples/process-list ubuntudemo 

这里ubuntudemo是创建的虚拟机名字。以下是列出的部分信息:

Process listing for VM ubuntudemo (id=3)
Next list entry is at: ffff88003d638248
[    0] swapper/0 (struct addr:ffffffff81c0d020)
[    1] init (struct addr:ffff88003d638000)
[    2] kthreadd (struct addr:ffff88003d639700)
[    3] ksoftirqd/0 (struct addr:ffff88003d63ae00)
[    6] migration/0 (struct addr:ffff88003d658000)
[    7] watchdog/0 (struct addr:ffff88003d659700)
[    8] cpuset (struct addr:ffff88003d65ae00)
[    9] khelper (struct addr:ffff88003d65c500)
[   10] kdevtmpfs (struct addr:ffff88003d65dc00)
[   11] netns (struct addr:ffff88003d698000)
[   12] sync_supers (struct addr:ffff88003d699700)

Libvmi提供的plugins有限,用户可根据需要编写,也可利用取证工具volatlity做更高层次语义的分析。Libvmi支持python绑定,提供了与volatility绑定的接口,具体可见下文。

###0x05 虚拟机监控Volatility

Volatility是一个用python编写的内存分析工具,与libvmi(利用sysystem.map符号表信息)不同的是,volatility利用可执行文件elf中的调试信息(dwarf格式)以及system.map符号表信息来获取更丰富的变量和函数语义。其支持windows, linux以及mac。 文中以Linux为例。

Get Started:

下载volatility包

git clone https://github.com/volatilityfoundation/volatility.git

创建Linux profile

profile是个zip文件,包含内核数据结构以及调试信息,也就是dwarf文件(volatility称之为vtypes)与system.map的压缩包。

volatility提供了一个内核模块在/volatility/tools/linux文件夹下来获取vtypes信息,将文件夹内容拷贝到要分析的客户机中,编译make,生成module.dwarf文件。在此之前请确保客户机中以及安装dwarfdump (apt-get install dwarfdump)。之后执行 head module.dwarf,会显示以下内容:

.debug_info

<0><0+11><DW_TAG_compile_unit> DW_AT_producer<GNU C 4.6.3> DW_AT_language<DW_LANG_C89>.....

<1><45><DW_TAG_typedef> DW_AT_name<__s8> DW_AT_decl_file<1 include/asm-generic/int-ll64.h>.....

生成

接着将module.dwarf文件以及/boot/System.map-3.2.0-99-generic 文件(不同系统文件名不同)压缩成一个zip文件,如Ubuntu1204.zip。执行:

zip volatility/volatility/plugins/overlays/linux/Ubuntu1204.zip volatility/tools/linux/module.dwarf /boot/System.map-3.2.0-99-generic

使用profile

python vol.py --info | grep Linux 

这时会显示之前创建的profile名,Linuxubuntu1204x64.

LinuxUbuntu1204x64    - A Profile for Linux Ubuntu1204 x64 <=== This is the one we just created

绑定libvmi的python接口

在./volatility/plugins/addrspaces 有针对不同内存快照的物理地址空间,如vmware.py,lime.py,crash.py等。libvmi则提供了pyvmi接口,在/libvmi/tools/pyvmi文件夹中有个pyvmiaddressspace.py文件可供volatility使用,(若需要自己编写python程序,则需要build pyvmi,build过程可参见其中的README文件,若出现编译错误,请确保安装 apt-get install build-essentials, apt-get install python2.7-dev).
将pyvmiaddressspace.py文件拷贝至./volatility/plugins/addrespaces文件夹中便可以利用volatility的plugins来分析虚拟机的内存了。以linux_pslist plugin为例,执行:

python vol.py -l vmi://ubuntudemo --profile=Linuxubuntu1204x64 linux_pslist  

若出现distorm3(反编译库)相关错误,请确保已经安装distorm3

apt-get install python-pip
pip install distorm3

绑定pyvmi接口后,volatility所有的plugins都可以用来分析虚拟机内存。


References

Libvmi

Libvirt

Volatility wiki

Secure and Flexible Monitoring of Virtual Machines


转载本文请务必注明,文章出处:《虚拟化环境搭建、管理、监控与分析》与作者信息:Diting0x