首页
论坛
课程
招聘
Vmware 嵌套 VT EPT 性能暴降 解决方案
2022-10-30 17:50 14478

Vmware 嵌套 VT EPT 性能暴降 解决方案

2022-10-30 17:50
14478

前言

近段时间在Vmware中使用 VT EPT技术时
发生性能爆降甚至鼠标不能动的现象
检查 VM exit 事件,无任何问题
设置 Vmware 核心数 16 发现比 核心数 4 还卡
设置核心数 1 发现 稳定运行 无卡顿
觉得可能是 EPT 多次寻址问题
HyperPlatform 项目将在每个CPU设置不同的EPT目录
我将代码改为以下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
EptData* g_EptData = 0;
// Builds EPT, allocates pre-allocated entires, initializes and returns EptData
_Use_decl_annotations_ EptData* EptInitialization() {
    PAGED_CODE()
 
        if (g_EptData != 0)//增加
            return g_EptData;//增加
    static const auto kEptPageWalkLevel = 4ul;
 
    // Allocate ept_data
    const auto ept_data = static_cast<EptData*>(ExAllocatePoolWithTag(
        NonPagedPool, sizeof(EptData), kHyperPlatformCommonPoolTag));
    if (!ept_data) {
        return nullptr;
    }
    RtlZeroMemory(ept_data, sizeof(EptData));
 
    //// Allocate EptPointer
    //const auto ept_poiner = reinterpret_cast<EptPointer*>(ExAllocatePoolWithTag(
    //    NonPagedPool, PAGE_SIZE, kHyperPlatformCommonPoolTag));
    //if (!ept_poiner) {
    //    ExFreePoolWithTag(ept_data, kHyperPlatformCommonPoolTag);
    //    return nullptr;
    //}
    //RtlZeroMemory(ept_poiner, PAGE_SIZE);
 
    // Allocate EPT_PML4 and initialize EptPointer
    const auto ept_pml4 = static_cast<EptCommonEntry*>(
        ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, kHyperPlatformCommonPoolTag));
    if (!ept_pml4) {
        ExFreePoolWithTag(ept_data, kHyperPlatformCommonPoolTag);
        return nullptr;
    }
    RtlZeroMemory(ept_pml4, PAGE_SIZE);
 
    ept_data->ept_pointer.all = 0;
    ept_data->ept_pointer.fields.memory_type =
        static_cast<ULONG64>(EptpGetMemoryType(UtilPaFromVa(ept_pml4)));
    ept_data->ept_pointer.fields.page_walk_length = kEptPageWalkLevel - 1;
    ept_data->ept_pointer.fields.pml4_address =
        UtilPfnFromPa(UtilPaFromVa(ept_pml4));
 
    // Initialize all EPT entries for all physical memory pages
    const auto pm_ranges = UtilGetPhysicalMemoryRanges();
    for (auto run_index = 0ul; run_index < pm_ranges->number_of_runs;
        ++run_index) {
        const auto run = &pm_ranges->run[run_index];
        const auto base_addr = run->base_page * PAGE_SIZE;
        for (auto page_index = 0ull; page_index < run->page_count; ++page_index) {
            const auto indexed_addr = base_addr + page_index * PAGE_SIZE;
            const auto ept_pt_entry =
                EptpConstructTables(ept_pml4, 4, indexed_addr, nullptr);
            if (!ept_pt_entry) {
                EptpDestructTables(ept_pml4, 4);
                ExFreePoolWithTag(ept_data, kHyperPlatformCommonPoolTag);
                return nullptr;
            }
        }
    }
 
    // Initialize an EPT entry for APIC_BASE. It is required to allocated it now
    // for some reasons, or else, system hangs.
    const Ia32ApicBaseMsr apic_msr = { UtilReadMsr64(Msr::kIa32ApicBase) };
    if (!EptpConstructTables(ept_pml4, 4, apic_msr.fields.apic_base * PAGE_SIZE,
        nullptr)) {
        EptpDestructTables(ept_pml4, 4);
        ExFreePoolWithTag(ept_data, kHyperPlatformCommonPoolTag);
        return nullptr;
    }
 
    // Allocate preallocated_entries
    const auto preallocated_entries_size =
        sizeof(EptCommonEntry*) * kEptpNumberOfPreallocatedEntries;
    const auto preallocated_entries = static_cast<EptCommonEntry**>(
        ExAllocatePoolWithTag(NonPagedPool, preallocated_entries_size,
            kHyperPlatformCommonPoolTag));
    if (!preallocated_entries) {
        EptpDestructTables(ept_pml4, 4);
        ExFreePoolWithTag(ept_data, kHyperPlatformCommonPoolTag);
        return nullptr;
    }
    RtlZeroMemory(preallocated_entries, preallocated_entries_size);
 
    // And fill preallocated_entries with newly created entries
    for (auto i = 0ul; i < kEptpNumberOfPreallocatedEntries; ++i) {
        const auto ept_entry = EptpAllocateEptEntry(nullptr);
        if (!ept_entry) {
            EptpFreeUnusedPreAllocatedEntries(preallocated_entries, 0);
            EptpDestructTables(ept_pml4, 4);
            ExFreePoolWithTag(ept_data, kHyperPlatformCommonPoolTag);
            return nullptr;
        }
        preallocated_entries[i] = ept_entry;
    }
 
    // Initialization completed
    ept_data->ept_pml4 = ept_pml4;
    ept_data->preallocated_entries = preallocated_entries;
    ept_data->preallocated_entries_count = 0;
 
    g_EptData = ept_data;//增加
    return ept_data;
}

测试发现性能正常 操作流畅 无卡顿 CPU占用降低
so 问题解决
原理是设置CPU核心为同一页表
Vmware 可能某种原因无法识别我们是为那个CPU设置的页表
但是他可以根据 设置的物理地址判断是否为同一个页表结构

 

别忘记卸载时

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Frees all EPT stuff
_Use_decl_annotations_ void EptTermination(EptData* ept_data) {
    if (g_EptData == 0)//增加
        return;
    HYPERPLATFORM_LOG_DEBUG("Used pre-allocated entries  = %2d / %2d",
        ept_data->preallocated_entries_count,
        kEptpNumberOfPreallocatedEntries);
 
    EptpFreeUnusedPreAllocatedEntries(ept_data->preallocated_entries,
        ept_data->preallocated_entries_count);
    EptpDestructTables(ept_data->ept_pml4, 4);
    ExFreePoolWithTag(ept_data, kHyperPlatformCommonPoolTag);
 
    g_EptData = NULL;//增加
}

[招生]科锐逆向工程师培训46期预科班将于 2023年02月09日 正式开班

收藏
点赞9
打赏
分享
最新回复 (14)
雪    币: 1085
活跃值: 活跃值 (250)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
bxb 活跃值 2022-10-30 23:51
2
0
沙发
雪    币: 1187
活跃值: 活跃值 (651)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
program杨 活跃值 2022-10-31 08:27
3
0
相当于每个cpu共享了 ept?
雪    币: 3004
活跃值: 活跃值 (2371)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
caolinkai 活跃值 2022-10-31 08:31
4
0
正常情况都是 每个核心给一个EPT
雪    币: 12044
活跃值: 活跃值 (7257)
能力值: ( LV9,RANK:270 )
在线值:
发帖
回帖
粉丝
hzqst 活跃值 3 2022-10-31 13:29
5
0
6
雪    币: 2126
活跃值: 活跃值 (1147)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
xxxark 活跃值 2022-10-31 16:26
6
0
https://github.com/tandasat/HyperPlatform/commit/c7e2d37d12672e7fabc2c6288cfe08f25dddf142
雪    币: 328
活跃值: 活跃值 (568)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
icey_ 活跃值 2022-10-31 18:11
7
0
所有核心共用一套EPT,多核情况下的EPT HOOK 会造成大量的vmexit吧?
雪    币: 1100
活跃值: 活跃值 (114)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
newmiaoxin 活跃值 2022-11-1 14:30
8
0
这种方式 好像对 MTF Exit有影响
雪    币: 722
活跃值: 活跃值 (1643)
能力值: ( LV3,RANK:25 )
在线值:
发帖
回帖
粉丝
逍遥m 活跃值 2022-11-1 15:13
9
0
newmiaoxin 这种方式 好像对 MTF Exit有影响
多核下可能会出现页目录设置错误逻辑问题
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
Ae0LuS 活跃值 2022-11-2 09:58
10
0
共享ept页在做hook时,MTF权限切换空隙会使得其他core hook失效
雪    币: 722
活跃值: 活跃值 (1643)
能力值: ( LV3,RANK:25 )
在线值:
发帖
回帖
粉丝
逍遥m 活跃值 2022-11-2 11:35
11
0
Ae0LuS 共享ept页在做hook时,MTF权限切换空隙会使得其他core hook失效
是的,但这种概率极小,而且时间片段也很小,有个办法能解决
直接上反汇编引擎,他读什么我给什么直接跳走
雪    币: 215
活跃值: 活跃值 (1159)
能力值: ( LV3,RANK:25 )
在线值:
发帖
回帖
粉丝
劫局丶 活跃值 2022-11-2 14:34
12
0
6
雪    币: 12044
活跃值: 活跃值 (7257)
能力值: ( LV9,RANK:270 )
在线值:
发帖
回帖
粉丝
hzqst 活跃值 3 2022-11-2 15:31
13
0
逍遥m 是的,但这种概率极小,而且时间片段也很小,有个办法能解决 直接上反汇编引擎,他读什么我给什么直接跳走
那不就是KiTpEmulateInstruction
雪    币: 722
活跃值: 活跃值 (1643)
能力值: ( LV3,RANK:25 )
在线值:
发帖
回帖
粉丝
逍遥m 活跃值 2022-11-2 17:22
14
0
hzqst 那不就是KiTpEmulateInstruction

KiTpSetupCompletion is used to finalize registration of a trace point, which first calls KiTpReadImageData based on the instruction size that was specified. An instruction parser (KiTpParseInstructionPrefix, KiTpFetchInstructionBytes) is used, followed by an emulator (KiTpEmulateInstruction, KiTpEmulateMovzx, and many more) are used to determine the instruction size that is required. Once the information is known, the original instructions are copied. For what it’s worth, KiTpReadImageData is a simple function which attaches to the input process and basically does a memcpy of the address and specified bytes.


https://www.alex-ionescu.com/?p=358


大表哥一句话让我查好久 

雪    币: 1187
活跃值: 活跃值 (651)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
program杨 活跃值 2022-11-8 10:32
15
0
逍遥m 是的,但这种概率极小,而且时间片段也很小,有个办法能解决 直接上反汇编引擎,他读什么我给什么直接跳走
他读什么你给什么 , 意思自己取值? 我发现mtf win7共享ept 几乎不会出问题, 但是win10 没几分钟就gg
游客
登录 | 注册 方可回帖
返回