Skip to content

Commit

Permalink
finalize first iteration
Browse files Browse the repository at this point in the history
  • Loading branch information
wbenny committed Aug 17, 2018
1 parent 52e91d2 commit 05554f2
Show file tree
Hide file tree
Showing 116 changed files with 31,677 additions and 2,874 deletions.
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
root = true

[*.{c,h,cpp,hpp}]
[*.{c,h,cpp,hpp,asm}]
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
Expand Down
325 changes: 325 additions & 0 deletions README.md

Large diffs are not rendered by default.

8 changes: 0 additions & 8 deletions TODO.txt

This file was deleted.

Binary file added img/hvppctrl.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/sc-start.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/sc-stop.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/traceview.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
182 changes: 182 additions & 0 deletions src/hvpp/custom_vmexit.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
#include "custom_vmexit.h"

#include "lib/cr3_guard.h"
#include "lib/mp.h"
#include "lib/log.h"

void custom_vmexit_handler::setup(vcpu_t& vp) noexcept
{
vmexit_base_handler::setup(vp);

#if 0
//
// Turn on VM-exit on everything we support.
//

auto procbased_ctls = vp.processor_based_controls();

//
// Since VMWare handles rdtsc(p) instructions by its own magical way, we'll
// disable our own handling. Setting this in VMWare makes the guest OS
// completely bananas.
//
// procbased_ctls.rdtsc_exiting = true;

//
// Use either "use_io_bitmaps" or "unconditional_io_exiting", try to avoid
// using both of them.
//

// procbased_ctls.use_io_bitmaps = true;
procbased_ctls.unconditional_io_exiting = true;
procbased_ctls.mov_dr_exiting = true;
procbased_ctls.cr3_load_exiting = true;
procbased_ctls.cr3_store_exiting = true;
vp.processor_based_controls(procbased_ctls);

auto procbased_ctls2 = vp.processor_based_controls2();
procbased_ctls2.descriptor_table_exiting = true;
vp.processor_based_controls2(procbased_ctls2);

vmx::msr_bitmap_t msr_bitmap{ 0 };
memset(msr_bitmap.data, 0xff, sizeof(msr_bitmap));
vp.msr_bitmap(msr_bitmap);

if (procbased_ctls.use_io_bitmaps)
{
vmx::io_bitmap_t io_bitmap{ 0 };
memset(io_bitmap.data, 0xff, sizeof(io_bitmap));
vp.io_bitmap(io_bitmap);
}

//
// Catch all exceptions.
//
vp.exception_bitmap(vmx::exception_bitmap_t{ ~0ul });

//
// VM-execution control fields include guest/host masks and read shadows for the CR0 and CR4 registers. These
// fields control executions of instructions that access those registers (including CLTS, LMSW, MOV CR, and SMSW).
// They are 64 bits on processors that support Intel 64 architecture and 32 bits on processors that do not.
// In general, bits set to 1 in a guest/host mask correspond to bits "owned" by the host:
// - Guest attempts to set them (using CLTS, LMSW, or MOV to CR) to values differing from the corresponding bits
// in the corresponding read shadow cause VM exits.
// - Guest reads (using MOV from CR or SMSW) return values for these bits from the corresponding read shadow.
// Bits cleared to 0 correspond to bits "owned" by the guest; guest attempts to modify them succeed and guest reads
// return values for these bits from the control register itself.
// (ref: Vol3C[24.6.6(Guest/Host Masks and Read Shadows for CR0 and CR4)])
//
// TL;DR:
// When bit in guest/host mask is set, write to the control register causes VM-exit.
// Mov FROM CR0 and CR4 returns values in the shadow register values.
//
// Note that SHADOW register value and REAL register value may differ. The guest will behave according
// to the REAL control register value. Only read from that register will return the fake (aka "shadow")
// value.
//

vp.cr0_guest_host_mask(cr0_t{ ~0ull });
vp.cr4_guest_host_mask(cr4_t{ ~0ull });
#endif
}

void custom_vmexit_handler::handle_execute_cpuid(vcpu_t& vp) noexcept
{
if (vp.exit_context().eax == 'ppvh')
{
//
// "hello from hvpp\0"
//
vp.exit_context().rax = 'lleh';
vp.exit_context().rbx = 'rf o';
vp.exit_context().rcx = 'h mo';
vp.exit_context().rdx = 'ppv';
}
else
{
vmexit_base_handler::handle_execute_cpuid(vp);
}
}

void custom_vmexit_handler::handle_execute_vmcall(vcpu_t& vp) noexcept
{
auto& data = data_[mp::cpu_index()];

switch (vp.exit_context().rcx)
{
case 0xc1:
{
cr3_guard _(vp.guest_cr3());

data.page_read = pa_t::from_va(vp.exit_context().rdx_as_pointer);
data.page_exec = pa_t::from_va(vp.exit_context().r8_as_pointer);
}

hvpp_trace("vmcall (hook) EXEC: 0x%p READ: 0x%p", data.page_exec.value(), data.page_read.value());

//
// Set execute-only access.
//
vp.ept().map_4kb(data.page_exec, data.page_exec, epte_t::access_type::execute);
break;

case 0xc2:
hvpp_trace("vmcall (unhook)");

//
// Set back read-write-execute access.
//
vp.ept().map_4kb(data.page_exec, data.page_exec, epte_t::access_type::read_write_execute);
break;

default:
vmexit_base_handler::handle_execute_vmcall(vp);
return;
}

vmx::invept(vmx::invept_t::all_context);
vmx::invvpid(vmx::invvpid_t::all_context);
}

void custom_vmexit_handler::handle_ept_violation(vcpu_t& vp) noexcept
{
auto exit_qualification = vp.exit_qualification().ept_violation;
auto guest_pa = vp.exit_guest_physical_address();
auto guest_la = vp.exit_guest_linear_address();

auto& data = data_[mp::cpu_index()];

if (exit_qualification.data_read || exit_qualification.data_write)
{
//
// Someone requested read or write access to the guest_pa, but the page
// has execute-only access.
// Map the page with "data.page_read" we've saved before in VMCALL handler
// and set the access to RW.
//
hvpp_trace("data_read LA: 0x%p PA: 0x%p", guest_la, guest_pa.value());

vp.ept().map_4kb(data.page_exec, data.page_read, epte_t::access_type::read_write);
}
else if (exit_qualification.data_execute)
{
//
// Someone requested execute access to the guest_pa, but the page has only
// read-write access.
// Map the page with "data.page_execute" we've saved before in VMCALL handler
// and set the access to execute-only.
//
hvpp_trace("data_execute LA: 0x%p PA: 0x%p", guest_la, guest_pa.value());

vp.ept().map_4kb(data.page_exec, data.page_exec, epte_t::access_type::execute);
}

vmx::invept(vmx::invept_t::all_context);
vmx::invvpid(vmx::invvpid_t::all_context);

//
// Make the instruction which fetched the memory to be executed again (this
// time without EPT violation).
//
vp.suppress_rip_adjust();
}
34 changes: 34 additions & 0 deletions src/hvpp/custom_vmexit.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#pragma once
#include "hvpp/config.h"
#include "hvpp/vcpu.h"
#include "hvpp/vmexit.h"
#include "hvpp/vmexit_stats.h"

using namespace ia32;
using namespace hvpp;

#ifdef HVPP_WITH_STATS
using vmexit_base_handler = vmexit_stats_handler;
#else
using vmexit_base_handler = vmexit_handler;
#endif

class custom_vmexit_handler
: public vmexit_base_handler
{
public:
void setup(vcpu_t& vp) noexcept override;

void handle_execute_cpuid(vcpu_t& vp) noexcept override;
void handle_execute_vmcall(vcpu_t& vp) noexcept override;
void handle_ept_violation(vcpu_t& vp) noexcept override;

private:
struct per_vcpu_data
{
pa_t page_read;
pa_t page_exec;
};

per_vcpu_data data_[32];
};
43 changes: 38 additions & 5 deletions src/hvpp/hvpp.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -56,27 +56,40 @@
<OutDir>$(SolutionDir)bin\$(PlatformShortName)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)bin\obj\$(PlatformShortName)\$(Configuration)\$(ProjectName)\</IntDir>
<Inf2CatUseLocalTime>true</Inf2CatUseLocalTime>
<EnableInf2cat>false</EnableInf2cat>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<DisableSpecificWarnings>4201;4748;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<LanguageStandard>stdcpplatest</LanguageStandard>
<ObjectFileName>$(IntDir)%(RelativeDir)%(Filename)%(Extension).obj</ObjectFileName>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<SupportJustMyCode>false</SupportJustMyCode>
</ClCompile>
<Inf />
<Inf />
<MASM />
<Link>
<GenerateDebugInformation>DebugFull</GenerateDebugInformation>
</Link>
<PostBuildEvent />
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<DisableSpecificWarnings>4201;4603;4627;4986;4987;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<LanguageStandard>stdcpplatest</LanguageStandard>
<ObjectFileName>$(IntDir)%(RelativeDir)%(Filename)%(Extension).obj</ObjectFileName>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
<WholeProgramOptimization>true</WholeProgramOptimization>
</ClCompile>
<Inf />
<MASM />
<Link>
<GenerateDebugInformation>DebugFull</GenerateDebugInformation>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
</Link>
<PostBuildEvent />
</ItemDefinitionGroup>
<ItemGroup>
<Inf Include="hvpp.inf">
Expand All @@ -90,29 +103,40 @@
<ClCompile Include="hvpp\ept.cpp" />
<ClCompile Include="hvpp\hypervisor.cpp" />
<ClCompile Include="hvpp\vcpu.cpp" />
<ClCompile Include="hvpp\vcpu_vmcs.cpp" />
<ClCompile Include="hvpp\vmexit.cpp">
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)/$(RelativeDir)/%(Filename)%(Extension).obj</ObjectFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)/$(RelativeDir)/%(Filename)%(Extension).obj</ObjectFileName>
</ClCompile>
<ClCompile Include="hvpp\vmexit_stats.cpp" />
<ClCompile Include="ia32\win32\memory.cpp" />
<ClCompile Include="lib\log.cpp" />
<ClCompile Include="lib\mm.cpp" />
<ClCompile Include="lib\vmware\vmware.cpp" />
<ClCompile Include="lib\win32\kernel_cr3.cpp" />
<ClCompile Include="lib\win32\log.cpp" />
<ClCompile Include="lib\win32\mp.cpp" />
<ClCompile Include="lib\win32\tracelog.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="custom_vmexit.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="custom_vmexit.h" />
<ClInclude Include="hvpp\config.h" />
<ClInclude Include="hvpp\ept.h" />
<ClInclude Include="hvpp\hypervisor.h" />
<ClInclude Include="hvpp\vcpu.h" />
<ClInclude Include="hvpp\vmexit.h" />
<ClInclude Include="hvpp\vmexit_stats.h" />
<ClInclude Include="ia32\arch.h" />
<ClInclude Include="ia32\arch\cr.h" />
<ClInclude Include="ia32\arch\dr.h" />
<ClInclude Include="ia32\arch\rflags.h" />
<ClInclude Include="ia32\arch\segment.h" />
<ClInclude Include="ia32\arch\xsave.h" />
<ClInclude Include="ia32\asm.h" />
<ClInclude Include="ia32\cpuid\cpuid_eax_01.h" />
<ClInclude Include="ia32\ept.h" />
<ClInclude Include="ia32\exception.h" />
<ClInclude Include="ia32\interrupt.h" />
<ClInclude Include="ia32\memory.h" />
<ClInclude Include="ia32\msr.h" />
<ClInclude Include="ia32\msr\arch.h" />
Expand All @@ -121,31 +145,40 @@
<ClInclude Include="ia32\mtrr.h" />
<ClInclude Include="ia32\vmx.h" />
<ClInclude Include="ia32\vmx\exception_bitmap.h" />
<ClInclude Include="ia32\vmx\instruction_info.h" />
<ClInclude Include="ia32\vmx\instruction_error.h" />
<ClInclude Include="ia32\vmx\exit_qualification.h" />
<ClInclude Include="ia32\vmx\exit_reason.h" />
<ClInclude Include="ia32\vmx\interrupt.h" />
<ClInclude Include="ia32\vmx\io_bitmap.h" />
<ClInclude Include="ia32\vmx\msr_bitmap.h" />
<ClInclude Include="ia32\vmx\vmcs.h" />
<ClInclude Include="ia32\win32\asm.h" />
<ClInclude Include="ia32\win32\memory.h" />
<ClInclude Include="lib\assert.h" />
<ClInclude Include="lib\bitmap.h" />
<ClInclude Include="lib\enumname.h" />
<ClInclude Include="lib\cr3_guard.h" />
<ClInclude Include="lib\log.h" />
<ClInclude Include="lib\mm.h" />
<ClInclude Include="lib\mp.h" />
<ClInclude Include="lib\noopt.h" />
<ClInclude Include="lib\object.h" />
<ClInclude Include="lib\spinlock.h" />
<ClInclude Include="lib\thread.h" />
<ClInclude Include="lib\typelist.h" />
<ClInclude Include="lib\vmware\vmware.h" />
<ClInclude Include="lib\win32\kernel_cr3.h" />
<ClInclude Include="lib\win32\log.h" />
<ClInclude Include="lib\win32\mp.h" />
<ClInclude Include="lib\win32\tracelog.h" />
</ItemGroup>
<ItemGroup>
<MASM Include="hvpp\vcpu.asm" />
<MASM Include="ia32\context.asm" />
<MASM Include="ia32\asm.asm" />
<MASM Include="lib\noopt.asm" />
<MASM Include="lib\vmware\ioctx.asm" />
</ItemGroup>
<ItemGroup>
<None Include="hvpp\vcpu.inl" />
<None Include="ia32\common.inc" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
Expand Down
Loading

0 comments on commit 05554f2

Please sign in to comment.