刺激战场
六合彩
贵宾厅
  • 1510阅读
  • 1回复

Blue Pill源代码分析(4) [复制链接]

上一主题 下一主题
离线天道酬勤
 

只看楼主 倒序阅读 使用道具 楼主  发表于: 2016-02-02
— 本帖被 天道酬勤 从 驱动保护 移动到本区(2016-05-19) —
HvmInit分别用AMD65和IA32的实现对当前CPU平台进行识别,并确认是否支持VT技术。
HvmSwallowBluepill函数则对当前物理CPU上的所有逻辑CPU,进行虚拟设置,反转到虚拟机的运行状态。
CmDeliverToProcessor 函数调用KeSetSystemAffinityThread将当前线程调度到指定的CPU cProcessorNumber,并将IRQL提升到Dpc Level,调用回调函数CallbackProc,回调返回之后将IRQL降低并调度回原来的CPU。
NTSTATUS NTAPI CmDeliverToProcessor (
  CCHAR cProcessorNumber,
  PCALLBACK_PROC CallbackProc,
  PVOID CallbackParam,
  PNTSTATUS pCallbackStatus
)
HvmSwallowBluepill在调用CmDeliverToProcessor的时候使用了回调函数CmSubvert,该函数使用汇编代码编写。
CmSubvert函数首先保存8个通用寄存器到栈中,接着传递当前栈指针调用HvmSubvertCpu。

NTSTATUS NTAPI HvmSubvertCpu (
  PVOID GuestRsp
)


HvmSubvertCpu 函数再次确认当前CPU实现了VT。紧接着为该CPU在宿主机运行分配栈空间,大小为HOST_STACK_SIZE_IN_PAGES=16 Pages。

在栈底部保留一个结构体struct CPU,保存当前CPU的全局描述符表和中断描述符表等信息。整个栈布局如下:
; Stack layout for vmxVmrun() call:
;
; ^                              ^
; |                              |
; | lots of pages for host stack |
; |                              |
; |------------------------------|   <- HostStackBottom(rcx) points here
; |         struct CPU           |
; --------------------------------
栈和CPU信息块准备好了之后,调用平台相关函数ArchRegisterTraps注册一些导致客户机陷入宿主机的陷阱处理函数,这个函数具体实现在vmxtraps.c或svmtraps.c。
调用ArchInitialize (Cpu, CmSlipIntoMatrix, GuestRsp)初始化客户机的RIP和RSP。在不同的平台具体函数如下:
static NTSTATUS NTAPI VmxInitialize (
  PCPU Cpu,
  PVOID GuestRip,
  PVOID GuestRsp
)

static NTSTATUS NTAPI SvmInitialize (
  PCPU Cpu,
  PVOID GuestRip,
  PVOID GuestRsp
)

而CmSlipIntoMatrix则是客户机运行的入口点,该函数是CmSubvert的逆向操作,具体如下
//x86
; CmSubvert (PVOID  GuestRsp);
CmSubvert PROC StdCall _GuestRsp


CM_SAVE_ALL_NOSEGREGS


mov eax,esp
push eax        ;setup esp to argv[0]
call HvmSubvertCpu@4 ;注意这里是不会返回的
ret

CmSubvert ENDP
; CmSlipIntoMatrix (PVOID  GuestRsp);
CmSlipIntoMatrix PROC StdCall _GuestRsp
pop ebp
call   HvmResumeGuest@0 ;这个函数不进行任何操作,除了log
CM_RESTORE_ALL_NOSEGREGS
ret

CmSlipIntoMatrix ENDP
//x64
CmSubvert PROC


push rax
push rcx
push rdx
push rbx
push rbp
push rsi
push rdi
push r8
push r9
push r10
push r11
push r12
push r13
push r14
push r15

sub rsp, 28h
mov rcx, rsp
call HvmSubvertCpu ;这个函数不返回

CmSubvert ENDP
CmSlipIntoMatrix PROC
call HvmResumeGuest ;空函数
add rsp, 28h
pop r15
pop r14
pop r13
pop r12
pop r11
pop r10
pop r9
pop r8
pop rdi
pop rsi
pop rbp
pop rbx
pop rdx
pop rcx
pop rax
ret
CmSlipIntoMatrix ENDP

最终调用ArchVirtualize()之后,内部分别运行VmxLaunch和SvmVmrun(AMD的x86不支持,直接返回了),这样客户机在虚拟运行模式下从CmSlipIntoMatrix 开始运行了,esp还是原先传入CmSlipIntoMatrix 的esp(rsp),又回到了CmDeliverToProcessor->HvmSwallowBluepill。
static NTSTATUS NTAPI VmxVirtualize (
  PCPU Cpu
)

static NTSTATUS NTAPI SvmVirtualize (
  PCPU Cpu
)


当所有的CPU都运行在虚拟模式下之后,设置驱动的Unload例程,DriverEntry成功返回。当然这中间如果失败就进行善后处理。
所有的CPU都运行在虚拟模式下之后,BP接下来就有的忙了,要处理很多来自客户机的陷阱处理。这后面具体分析,待续...............

离线v2680267313

只看该作者 沙发  发表于: 2016-04-30
用户被禁言,该主题自动屏蔽!
快速回复
限100 字节
如果您在写长篇帖子又不马上发表,建议存为草稿
 
上一个 下一个