KVM循序渐进耳之基础篇 - 一半人生

admin 2021年12月31日15:41:03评论124 views字数 4599阅读15分19秒阅读模式

背景:

  去年利用开源VT框架做简单应用,Windows x64内核实现系统探针(Msr/Ept Hook),VT可以欺骗PG及Rootkit操作。跳出安全视角审视虚拟化一入深似海,业余学习笔记分享。

环境部署:

Os: Linux localhost.localdomain 2.6.18-419.el5 #1 SMP Fri Feb 24 22:47:42 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux,Linux内核 2.6.20以后集成KVM,从最原始来探索虚拟化。

Centos5 install

Source Code Download: https://sourceforge.net/projects/kvm/files/?source=navbar

Centos5 ISO Download: http://mirror.nsc.liu.se/centos-store/5.0/isos/i386/

Centos5 Yum Update: https://github.com/astj/docker-centos5-vault/blob/master/yum.repos.d/CentOS-Base.repo

Centos5key认证:CentOS GPG Keys

VS2017 Remote Debug Gdb Centos5 Event

Cmake项目创建:

1) issues: Finished copying files.CMake version '2.6.0.0' identified on the remote,CMake 3.8.x or above is not available on the remote system.

Cmake版本过低,Cmake升级依赖Gcc(c++11),Gcc 4.8 version以上才可以支持c++11:

2) issues: Current Gcc: gcc version 4.1.2 20080704 (Red Hat 4.1.2-55)

参考:https://www.cnblogs.com/edda/p/13061554.html 这个过程比较耗时间,请多点耐心。

3) issues: 升级至Cmake 3.10,Vs2017远程调试需要3.8.x以上的Cmake,不升级gcc,./bootstarp编译过程中会出现不支持c++11

参考:https://blog.csdn.net/u013714645/article/details/77002555

4) issues: make过程中遇到openssl.c:(.text+0xf7a): undefined reference to `EVP_PKEY_id'问题:

参考:升级Openssl(也要安装openssl-devel):https://www.cnblogs.com/madsnotes/articles/6285727.html

CMake工程页面大致如下,配置文件CMakeSettings.json。

Linux项目创建:

工程项目下会有readme\readme.html,操作即可:

Centos5从默认gcc 4.1.8,gcc 4.8或更高支持c++11,这里先不用c11以上的标准,用99/89.

1) Issues: error : unrecognized command line option "-Wempty-body",低版本不支持这个参数/删除:

如下图所示,删除%(CppAdditionalWarning)和empty-body即可:

2) Issues: /usr/bin/ld : error : cannot find -lGL

sudo yum install mesa-libGL-devel mesa-libGLU-devel
sudo yum install freeglut-devel

编译/执行如下:

VS远程调试微软官方文档:

  1. https://docs.microsoft.com/en-us/cpp/linux/cmake-linux-project?view=msvc-160
  2. https://devblogs.microsoft.com/cppblog/visual-c-for-linux-development-with-cmake/

KVM编译:

KVM1.0 Download:

https://sourceforge.net/projects/kvm/files/kvm/1/kvm-module-1.tar.gz/download

  Cmake方式会出现问题,Centos5原生Gcc是顺利编译成功(kvm1.0),升级gcc编译会出现问题,不过比较好解决,自行谷歌即可。

编译成功生成kvm.ko:

最终文章环境如下:

  Centos5.0 + gcc 4.1.x + Vs2017(Linux) + KVM.ko(1.0) + libKvm(1.0),编译完成之后,编写r3来调用kvm.ko探索使用,参考libkvm学习。

LibKVM/KVM 源码分析:

Libkvm/Kernel:

libkvm_main分为详细分析四个函数,kvm_init & kvm_create & kvm_show_regs & kvm_run

kvm_init

  初始化R3负责打开驱动kvm文件,获取句柄。申请kvm_context_t结构提内存(保存上线文环境),测试回调赋值及返回kvm结构。

kvm_create:

1) r = ioctl(fd, KVM_SET_MEMORY_REGION, &low_memory);

case KVM_SET_MEMORY_REGION: {
​    struct kvm_memory_region kvm_mem;
​    r = -EFAULT;
​    // 首先将 用户态数据拷贝内核态
​    if (copy_from_user(&kvm_mem, (void *)arg, sizeof kvm_mem))
​      goto out;
​    // 分配内存
​    r = kvm_dev_ioctl_set_memory_region(kvm, &kvm_mem);
​    if (r)
​      goto out;
​    break;
  }

用户态对应Kernel:

内核态:

  Vcpu_load里面会做Vmcs的write操作,其实就是不同状态Exit时候处理用到,后面再对vmcs做相关介绍。

分别设置了如下状态:

HostGdtrBase = 0x00006c0c,
    // HostIdtrBase = 0x00006c0e,
    HostTrBase = 0x00006c0a,
    HostIa32SysenterEsp = 0x00006c10,

2) r = ioctl(fd, KVM_CREATE_VCPU, 0);

用户态
  // 发送KVM_CREATE_VCPU
  r = ioctl(fd, KVM_CREATE_VCPU, 0);
  if (r == -1) {
​    printf("kvm_create_vcpu: %m\n");
​    exit(1);
  }

内核态:

  创建vcpu精髓是vmcs申请/填充,kvm_vcpu_setup()函数的主要的工作。这部分在成熟的框架里面很庞大,16bit/32bit/64bit不同的区域都有填充,kvm1.0代码量就会小很多,后面做详细的填充介绍。

)

vmcs_writel(HOST_RIP, (unsigned long)kvm_vmx_return); / 22.2.5 /,kvm_vmx_return入口函数.

kvm_show_regs

r = ioctl(fd, KVM_GET_REGS, &regs);

从内核态获取寄存器状态等操作

case KVM_GET_REGS: {
​    struct kvm_regs kvm_regs;
​    r = -EFAULT;
​    if (copy_from_user(&kvm_regs, (void *)arg, sizeof kvm_regs))
​      goto out;
​    r = kvm_dev_ioctl_get_regs(kvm, &kvm_regs);
​    if (r)
​      goto out;
​    r = -EFAULT;
​    if (copy_to_user((void *)arg, &kvm_regs, sizeof kvm_regs))
​      goto out;
​    r = 0;
​    break;
  }
kvm_run

r = ioctl(fd, KVM_RUN, &kvm_run);

负责读取Guest和进入虚拟机等操作

KVM循序渐进耳之基础篇 -  一半人生
kvm_do_inject_irq() --> inject_rmode_irq() --> kvm_read_guest()

下面就是进入vm汇编代码

#endif
​    /* Enter guest mode */
​    "jne launched \n\t"
​   //  进入
​    "vmlaunch \n\t"
​    "jmp kvm_vmx_return \n\t"
​   // 退出
​    "launched: vmresume \n\t"
​    ".globl kvm_vmx_return \n\t"
​    "kvm_vmx_return: "
​    /* Save guest registers, load host registers, keep flags */

KVM循序渐进耳之基础篇 -  一半人生
1.0的代码启动还是有__asm内联汇编

梳理libkvm如下:

在进入调试内核环节之前,Libkvm用于观察学习,虚拟机中要开启嵌套虚化,如下:

KVM循序渐进耳之基础篇 -  一半人生
使用insmod kvm.ko来加载内核,lsmod | grep kvm 加载成功,/dev/kvm如下所示:

KVM循序渐进耳之基础篇 -  一半人生

这时候可以远程Debug Libkvm或者编写的R3程序了:

Intelx86_x64,Kvm原理性检测一致列举部分如下:

1) cpu_has_kvm_support()

检测CPUID.1:ECX.VMX[bit 5] 是否支持vt

2) vmx_disabled_by_bios

读取msr_ia32_feature_control 检测 lock

3) kvm_init_debug

创建debugfs目录kvm

4) setup_vmcs_descriptor

virtual machine control structure

rdmsr msr_ia32_vmx_basic_msr

高位 size = vmx_msr_high & 1fff

revision_id 要和msr版本一致等等

Vt初始化过程,原来再博客写过一点笔记:https://blog.51cto.com/u_13352079/2545416

虚拟化书籍推荐:

《Intel白皮书》

https://software.intel.com/content/www/us/en/develop/articles/intel-sdm.html

《处理器虚拟化技术》邓志 Windows

《深度探索Linux系统虚拟化》王柏生 谢广军 Linux

其它Blog:

  1. https://www.wilderssecurity.com/forums/sandboxing-virtualization.98/
  2. https://bbs.pediy.com/thread-257190.htm
  3. https://www.bookstack.cn/books/learn-kvm
后记:

  有想过根据Intel手册学习抄写vt虚拟化框架,尝试两次都以失败告终。能力不行除外,参考项目过于庞大(别人维护了很多年),给人感觉成熟量大的项目越难二次开发,从Win转Linux学习的时候,都是用老古董来入门研究,麻雀虽小五脏俱全。

  希望本系笔记能够和大家一起交流进步(有错误之处请指出更正)。

BY:先知论坛

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2021年12月31日15:41:03
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   KVM循序渐进耳之基础篇 - 一半人生http://cn-sec.com/archives/712218.html

发表评论

匿名网友 填写信息