首页
社区
课程
招聘
[求助]AMD的hypervisor模拟SYSCALL的问题
发表于: 2021-4-20 22:26 6466

[求助]AMD的hypervisor模拟SYSCALL的问题

2021-4-20 22:26
6466

我在搞一个AMD平台虚拟化用来练手的东西,我目前做到了进入退出虚拟机,准备做syscall hook,

但是新windows10有kva shadow情况导致不能跟以前一样改个msr_lstar这个地址了

所以搜索了一会在老外的推荐下,我就看了一下AMD的白皮书有一个是msr_efer.sce的字段,字段作用是控制syscall功能的.如果为0则关闭syscall和sysret,系统再用syscall/sysret的时候就会导致UD异常

这样syscall的时候就会走我的vmexit->svm_handle_exception_ud。现在唯一的问题就是模拟syscall 


intel还好说,老外有现成源码,AMD就惨了,所以我按照amd的白皮书里面的伪码写syscall模拟流程

伪码在

https://www.amd.com/system/files/TechDocs/24594.pdf 470页

uintptr_t msr_value = _huoji_readmsr(amd64_star);
        guest_context->guest_register->Rcx = guest_context->vcpu->svm_stack->guest_vmcb.control.NRip; //RCX.q = next_RIP
        guest_context->guest_register->R11 = guest_context->vcpu->svm_stack->guest_vmcb.state_save.Rflags &~ X86_FLAGS_RF;    // R11.q = RFLAGS    // with rf cleared

        guest_context->vcpu->svm_stack->guest_vmcb.state_save.CsSelector = (UINT16)((msr_value >> 32) & ~3); //MSR_STAR.SYSCALL_CS
        guest_context->vcpu->svm_stack->guest_vmcb.state_save.CsBase = 0;
        guest_context->vcpu->svm_stack->guest_vmcb.state_save.CsLimit = 0xFFFFFFFF;
        guest_context->vcpu->svm_stack->guest_vmcb.state_save.CsAttrib = Tools::get_segment_long_mode2type(guest_context->vcpu->svm_stack->guest_vmcb.state_save.CsSelector, guest_context->vcpu->svm_stack->guest_vmcb.state_save.GdtrBase, 1, 0);

        guest_context->vcpu->svm_stack->guest_vmcb.state_save.SsSelector = (UINT16)(((msr_value >> 32) & ~3) + 8); //MSR_STAR.SYSCALL_CS + 8
        guest_context->vcpu->svm_stack->guest_vmcb.state_save.SsBase = 0;
        guest_context->vcpu->svm_stack->guest_vmcb.state_save.SsLimit = 0xFFFFFFFF;
        guest_context->vcpu->svm_stack->guest_vmcb.state_save.SsAttrib = Tools::get_segment_long_mode2type(guest_context->vcpu->svm_stack->guest_vmcb.state_save.SsSelector, guest_context->vcpu->svm_stack->guest_vmcb.state_save.GdtrBase, 1, 0);

        msr_value = _huoji_readmsr(amd64_sfmask);
        guest_context->vcpu->svm_stack->guest_vmcb.state_save.Rflags &= ~(msr_value | X86_FLAGS_RF); //RFLAGS AND ~MSR_SFMASK , RFLAGS.RF = 0
        msr_value = _huoji_readmsr(amd64_lstar);
        guest_context->vcpu->svm_stack->guest_vmcb.state_save.Rip = msr_value;

其中,MSR_STAR.SYSCALL_CS在amd白皮书里面说明如下(跟intel是一样的)

SYSCALL如下:

  /*
            模拟 SYSCALL:
        */
        uintptr_t msr_value = _huoji_readmsr(amd64_star);
        guest_context->guest_register->Rcx = guest_context->vcpu->svm_stack->guest_vmcb.control.NRip; //RCX.q = next_RIP
        guest_context->guest_register->R11 = guest_context->vcpu->svm_stack->guest_vmcb.state_save.Rflags &~ X86_FLAGS_RF;    // R11.q = RFLAGS    // with rf cleared

        guest_context->vcpu->svm_stack->guest_vmcb.state_save.CsSelector = (UINT16)((msr_value >> 32) & ~3); //MSR_STAR.SYSCALL_CS
        guest_context->vcpu->svm_stack->guest_vmcb.state_save.CsBase = 0;
        guest_context->vcpu->svm_stack->guest_vmcb.state_save.CsLimit = 0xFFFFFFFF;
        guest_context->vcpu->svm_stack->guest_vmcb.state_save.CsAttrib = Tools::get_segment_long_mode2type(guest_context->vcpu->svm_stack->guest_vmcb.state_save.CsSelector, guest_context->vcpu->svm_stack->guest_vmcb.state_save.GdtrBase, 1, 0);

        guest_context->vcpu->svm_stack->guest_vmcb.state_save.SsSelector = (UINT16)(((msr_value >> 32) & ~3) + 8); //MSR_STAR.SYSCALL_CS + 8
        guest_context->vcpu->svm_stack->guest_vmcb.state_save.SsBase = 0;
        guest_context->vcpu->svm_stack->guest_vmcb.state_save.SsLimit = 0xFFFFFFFF;
        guest_context->vcpu->svm_stack->guest_vmcb.state_save.SsAttrib = Tools::get_segment_long_mode2type(guest_context->vcpu->svm_stack->guest_vmcb.state_save.SsSelector, guest_context->vcpu->svm_stack->guest_vmcb.state_save.GdtrBase, 1, 0);

        msr_value = _huoji_readmsr(amd64_sfmask);
        guest_context->vcpu->svm_stack->guest_vmcb.state_save.Rflags &= ~(msr_value | X86_FLAGS_RF); //RFLAGS AND ~MSR_SFMASK , RFLAGS.RF = 0
        msr_value = _huoji_readmsr(amd64_lstar);
        guest_context->vcpu->svm_stack->guest_vmcb.state_save.Rip = msr_value;
        DebugPrint("SYS CALL ! opcode %d == 1 rax %p r11 %p \n", op_code, guest_context->guest_register->Rcx, guest_context->guest_register->R11);

Tools::get_segment_long_mode2type如下:

unsigned short Tools::get_segment_long_mode2type(unsigned short segment_selector, unsigned __int64 gdt_base, unsigned __int16 long_mode, unsigned __int16 dpl)
{
	_segment_descriptor* descriptor = reinterpret_cast<_segment_descriptor*>(gdt_base + (segment_selector & ~3));
	_segment_attribute attribute;
	attribute.Fields.Type = descriptor->fields.type;
	attribute.Fields.System = descriptor->fields.system;
	attribute.Fields.Dpl = dpl;
	attribute.Fields.Present = descriptor->fields.present;
	attribute.Fields.Avl = descriptor->fields.avl;
	attribute.Fields.LongMode = long_mode;
	attribute.Fields.DefaultBit = descriptor->fields.db;
	attribute.Fields.Granularity = descriptor->fields.gran;
	attribute.Fields.Reserved1 = 0;
	return attribute.AsUInt16;
}

炸的位置我认为是cs和ss的attrib字段设置错误,不过实数不懂错在哪了,还请各位大佬指点一下


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 3
支持
分享
最新回复 (1)
雪    币: 137
活跃值: (1380)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
这个问题已经解决
问题比较麻烦 我会在以后单独一篇文章讲述一下AMD的这个坑
2021-5-7 21:28
0
游客
登录 | 注册 方可回帖
返回
//