├── FU_Hypervisor.VC.db ├── FU_Hypervisor.sln ├── FU_Hypervisor.suo ├── FU_Hypervisor ├── FU_Hypervisor.cpp ├── FU_Hypervisor.h ├── FU_Hypervisor.vcxproj ├── FU_Hypervisor.vcxproj.filters ├── FU_Hypervisor.vcxproj.user ├── FU_Hypervisor.vcxproj.vspscc ├── fake_page.cpp └── fake_page.h ├── HyperPlatform ├── Documents │ └── UserDocument.odt ├── HyperPlatform.doxyfile ├── HyperPlatform.sln ├── HyperPlatform │ ├── Arch │ │ ├── x64 │ │ │ └── x64.asm │ │ └── x86 │ │ │ └── x86.asm │ ├── HyperPlatform.inf │ ├── HyperPlatform.vcxproj │ ├── HyperPlatform.vcxproj.filters │ ├── asm.h │ ├── common.h │ ├── driver.cpp │ ├── driver.h │ ├── ept.cpp │ ├── ept.h │ ├── global_object.cpp │ ├── global_object.h │ ├── hotplug_callback.cpp │ ├── hotplug_callback.h │ ├── ia32_type.h │ ├── kernel_stl.cpp │ ├── log.cpp │ ├── log.h │ ├── perf_counter.h │ ├── performance.cpp │ ├── performance.h │ ├── power_callback.cpp │ ├── power_callback.h │ ├── util.cpp │ ├── util.h │ ├── util_page_constants.h │ ├── vm.cpp │ ├── vm.h │ ├── vmm.cpp │ └── vmm.h ├── LICENSE ├── README.md └── clean.bat ├── README.md └── x64 ├── Debug ├── FU_Hypervisor.cer ├── FU_Hypervisor.pdb ├── FU_Hypervisor.sys └── FU_Hypervisor │ ├── FU_Hypervisor.sys │ └── WdfCoinstaller01009.dll └── Release ├── FU_Hypervisor.cer ├── FU_Hypervisor.pdb ├── FU_Hypervisor.sys └── FU_Hypervisor ├── FU_Hypervisor.sys └── WdfCoinstaller01009.dll /FU_Hypervisor.VC.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bb33bb/r3epthook/2ab806c04fbb6456eccae32d4374959f5116a05b/FU_Hypervisor.VC.db -------------------------------------------------------------------------------- /FU_Hypervisor.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28010.2016 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FU_Hypervisor", "FU_Hypervisor\FU_Hypervisor.vcxproj", "{108B26EA-C225-476E-B763-975A409A252F}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{CF7F7666-5330-481C-AE37-02DA46B66650}" 9 | ProjectSection(SolutionItems) = preProject 10 | .clang-format = .clang-format 11 | .gitattributes = .gitattributes 12 | .gitignore = .gitignore 13 | .gitmodules = .gitmodules 14 | clean.bat = clean.bat 15 | README.md = README.md 16 | EndProjectSection 17 | EndProject 18 | Global 19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 20 | Debug|x64 = Debug|x64 21 | Debug|x86 = Debug|x86 22 | Release|x64 = Release|x64 23 | Release|x86 = Release|x86 24 | EndGlobalSection 25 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 26 | {108B26EA-C225-476E-B763-975A409A252F}.Debug|x64.ActiveCfg = Debug|x64 27 | {108B26EA-C225-476E-B763-975A409A252F}.Debug|x64.Build.0 = Debug|x64 28 | {108B26EA-C225-476E-B763-975A409A252F}.Debug|x64.Deploy.0 = Debug|x64 29 | {108B26EA-C225-476E-B763-975A409A252F}.Debug|x86.ActiveCfg = Debug|Win32 30 | {108B26EA-C225-476E-B763-975A409A252F}.Debug|x86.Build.0 = Debug|Win32 31 | {108B26EA-C225-476E-B763-975A409A252F}.Debug|x86.Deploy.0 = Debug|Win32 32 | {108B26EA-C225-476E-B763-975A409A252F}.Release|x64.ActiveCfg = Release|x64 33 | {108B26EA-C225-476E-B763-975A409A252F}.Release|x64.Build.0 = Release|x64 34 | {108B26EA-C225-476E-B763-975A409A252F}.Release|x64.Deploy.0 = Release|x64 35 | {108B26EA-C225-476E-B763-975A409A252F}.Release|x86.ActiveCfg = Release|Win32 36 | {108B26EA-C225-476E-B763-975A409A252F}.Release|x86.Build.0 = Release|Win32 37 | {108B26EA-C225-476E-B763-975A409A252F}.Release|x86.Deploy.0 = Release|Win32 38 | EndGlobalSection 39 | GlobalSection(SolutionProperties) = preSolution 40 | HideSolutionNode = FALSE 41 | EndGlobalSection 42 | GlobalSection(ExtensibilityGlobals) = postSolution 43 | SolutionGuid = {B2E34F47-467C-4242-BE98-BA659681DA10} 44 | EndGlobalSection 45 | GlobalSection(TeamFoundationVersionControl) = preSolution 46 | SccNumberOfProjects = 2 47 | SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} 48 | SccTeamFoundationServer = https://dev.azure.com/1174258612 49 | SccLocalPath0 = . 50 | SccProjectUniqueName1 = FU_Hypervisor\\FU_Hypervisor.vcxproj 51 | SccProjectName1 = FU_Hypervisor 52 | SccLocalPath1 = FU_Hypervisor 53 | EndGlobalSection 54 | EndGlobal 55 | -------------------------------------------------------------------------------- /FU_Hypervisor.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bb33bb/r3epthook/2ab806c04fbb6456eccae32d4374959f5116a05b/FU_Hypervisor.suo -------------------------------------------------------------------------------- /FU_Hypervisor/FU_Hypervisor.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2018, Satoshi Tanda. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | /// @file 6 | /// Implements FU functions. 7 | 8 | #include "FU_Hypervisor.h" 9 | #include 10 | #define NTSTRSAFE_NO_CB_FUNCTIONS 11 | #include 12 | #include "../HyperPlatform/HyperPlatform/common.h" 13 | #include "../HyperPlatform/HyperPlatform/log.h" 14 | #include "../HyperPlatform/HyperPlatform/util.h" 15 | #include "../HyperPlatform/HyperPlatform/ept.h" 16 | 17 | extern "C" { 18 | //////////////////////////////////////////////////////////////////////////////// 19 | // 20 | // macro utilities 21 | // 22 | 23 | //////////////////////////////////////////////////////////////////////////////// 24 | // 25 | // constants and macros 26 | // 27 | 28 | //////////////////////////////////////////////////////////////////////////////// 29 | // 30 | // types 31 | // 32 | 33 | //////////////////////////////////////////////////////////////////////////////// 34 | // 35 | // prototypes 36 | // 37 | 38 | _IRQL_requires_max_(PASSIVE_LEVEL) static void FupCreateProcessNotifyRoutine( 39 | _In_ HANDLE parent_pid, _In_ HANDLE pid, _In_ BOOLEAN create); 40 | 41 | #if defined(ALLOC_PRAGMA) 42 | #pragma alloc_text(INIT, FuInitialization) 43 | #pragma alloc_text(PAGE, FuTermination) 44 | #pragma alloc_text(PAGE, FupCreateProcessNotifyRoutine) 45 | #endif 46 | 47 | //////////////////////////////////////////////////////////////////////////////// 48 | // 49 | // variables 50 | // 51 | 52 | //////////////////////////////////////////////////////////////////////////////// 53 | // 54 | // implementations 55 | // 56 | 57 | _Use_decl_annotations_ NTSTATUS FuInitialization() { 58 | PAGED_CODE(); 59 | 60 | auto status = 61 | PsSetCreateProcessNotifyRoutine(FupCreateProcessNotifyRoutine, FALSE); 62 | return status; 63 | } 64 | 65 | _Use_decl_annotations_ void FuTermination() { 66 | PAGED_CODE(); 67 | 68 | PsSetCreateProcessNotifyRoutine(FupCreateProcessNotifyRoutine, TRUE); 69 | } 70 | 71 | _Use_decl_annotations_ static void FupCreateProcessNotifyRoutine( 72 | HANDLE parent_pid, HANDLE pid, BOOLEAN create) { 73 | PAGED_CODE(); 74 | UNREFERENCED_PARAMETER(parent_pid); 75 | UNREFERENCED_PARAMETER(pid); 76 | 77 | if (create) { 78 | return; 79 | } 80 | 81 | UtilForEachProcessor( 82 | [](void* context) { 83 | UNREFERENCED_PARAMETER(context); 84 | return UtilVmCall(HypercallNumber::kApiMonDisableConcealment, nullptr); 85 | }, 86 | nullptr); 87 | 88 | UtilVmCall(HypercallNumber::kApiMonDeleteConcealment, nullptr); 89 | } 90 | 91 | } // extern "C" 92 | -------------------------------------------------------------------------------- /FU_Hypervisor/FU_Hypervisor.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2018, Satoshi Tanda. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | /// @file 6 | /// Declares interfaces to FU functions. 7 | 8 | #ifndef FU_HYPERVISOR_FU_HYPERVISOR_H_ 9 | #define FU_HYPERVISOR_FU_HYPERVISOR_H_ 10 | 11 | #include 12 | 13 | extern "C" { 14 | //////////////////////////////////////////////////////////////////////////////// 15 | // 16 | // macro utilities 17 | // 18 | 19 | //////////////////////////////////////////////////////////////////////////////// 20 | // 21 | // constants and macros 22 | // 23 | 24 | //////////////////////////////////////////////////////////////////////////////// 25 | // 26 | // types 27 | // 28 | 29 | struct EptData; 30 | struct ProcessorFakePageData; 31 | struct SharedFakePageData; 32 | 33 | //////////////////////////////////////////////////////////////////////////////// 34 | // 35 | // prototypes 36 | // 37 | 38 | _IRQL_requires_max_(PASSIVE_LEVEL) EXTERN_C NTSTATUS FuInitialization(); 39 | 40 | _IRQL_requires_max_(PASSIVE_LEVEL) EXTERN_C void FuTermination(); 41 | 42 | //////////////////////////////////////////////////////////////////////////////// 43 | // 44 | // variables 45 | // 46 | 47 | //////////////////////////////////////////////////////////////////////////////// 48 | // 49 | // implementations 50 | // 51 | 52 | } // extern "C" 53 | 54 | #endif // FU_HYPERVISOR_FU_HYPERVISOR_H_ 55 | -------------------------------------------------------------------------------- /FU_Hypervisor/FU_Hypervisor.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {108B26EA-C225-476E-B763-975A409A252F} 23 | {1bc93793-694f-48fe-9372-81e2b05556fd} 24 | v4.5.2 25 | 12.0 26 | Debug 27 | Win32 28 | FU_Hypervisor 29 | 10.0.17134.0 30 | SAK 31 | SAK 32 | SAK 33 | SAK 34 | 35 | 36 | 37 | Windows7 38 | true 39 | WindowsKernelModeDriver10.0 40 | Driver 41 | KMDF 42 | Desktop 43 | 44 | 45 | Windows7 46 | false 47 | WindowsKernelModeDriver10.0 48 | Driver 49 | KMDF 50 | Desktop 51 | 52 | 53 | Windows7 54 | true 55 | WindowsKernelModeDriver10.0 56 | Driver 57 | KMDF 58 | Desktop 59 | 60 | 61 | Windows7 62 | false 63 | WindowsKernelModeDriver10.0 64 | Driver 65 | KMDF 66 | Desktop 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | DbgengKernelDebugger 78 | $(VC_IncludePath);$(IncludePath) 79 | 80 | 81 | DbgengKernelDebugger 82 | $(VC_IncludePath);$(IncludePath) 83 | 84 | 85 | DbgengKernelDebugger 86 | $(VC_IncludePath);$(IncludePath) 87 | 88 | 89 | DbgengKernelDebugger 90 | $(VC_IncludePath);$(IncludePath) 91 | 92 | 93 | 94 | false 95 | false 96 | 97 | 98 | 99 | 100 | true 101 | 102 | 103 | Level3 104 | 105 | 106 | 107 | 108 | Level4 109 | false 110 | 111 | 112 | /SAFESEH:NO %(AdditionalOptions) 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | true 156 | true 157 | 158 | 159 | true 160 | true 161 | true 162 | true 163 | 164 | 165 | 166 | 167 | 168 | -------------------------------------------------------------------------------- /FU_Hypervisor/FU_Hypervisor.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {8E41214B-6785-4CFE-B992-037D68949A14} 18 | inf;inv;inx;mof;mc; 19 | 20 | 21 | 22 | 23 | Source Files 24 | 25 | 26 | Source Files 27 | 28 | 29 | Source Files 30 | 31 | 32 | Source Files 33 | 34 | 35 | Source Files 36 | 37 | 38 | Source Files 39 | 40 | 41 | Source Files 42 | 43 | 44 | Source Files 45 | 46 | 47 | Source Files 48 | 49 | 50 | Source Files 51 | 52 | 53 | Source Files 54 | 55 | 56 | Source Files 57 | 58 | 59 | Source Files 60 | 61 | 62 | 63 | 64 | Header Files 65 | 66 | 67 | Header Files 68 | 69 | 70 | Header Files 71 | 72 | 73 | Header Files 74 | 75 | 76 | Header Files 77 | 78 | 79 | Header Files 80 | 81 | 82 | Header Files 83 | 84 | 85 | Header Files 86 | 87 | 88 | Header Files 89 | 90 | 91 | Header Files 92 | 93 | 94 | Header Files 95 | 96 | 97 | Header Files 98 | 99 | 100 | Header Files 101 | 102 | 103 | Header Files 104 | 105 | 106 | Header Files 107 | 108 | 109 | Header Files 110 | 111 | 112 | Header Files 113 | 114 | 115 | Header Files 116 | 117 | 118 | 119 | 120 | Source Files 121 | 122 | 123 | Source Files 124 | 125 | 126 | -------------------------------------------------------------------------------- /FU_Hypervisor/FU_Hypervisor.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | TestSign 5 | 6 | -------------------------------------------------------------------------------- /FU_Hypervisor/FU_Hypervisor.vcxproj.vspscc: -------------------------------------------------------------------------------- 1 | "" 2 | { 3 | "FILE_VERSION" = "9237" 4 | "ENLISTMENT_CHOICE" = "NEVER" 5 | "PROJECT_FILE_RELATIVE_PATH" = "" 6 | "NUMBER_OF_EXCLUDED_FILES" = "0" 7 | "ORIGINAL_PROJECT_FILE_PATH" = "" 8 | "NUMBER_OF_NESTED_PROJECTS" = "0" 9 | "SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER" 10 | } 11 | -------------------------------------------------------------------------------- /FU_Hypervisor/fake_page.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bb33bb/r3epthook/2ab806c04fbb6456eccae32d4374959f5116a05b/FU_Hypervisor/fake_page.cpp -------------------------------------------------------------------------------- /FU_Hypervisor/fake_page.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2018, Satoshi Tanda. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | /// @file 6 | /// Declares interfaces to fake page functions. 7 | 8 | #ifndef FU_HYPERVISOR_FAKE_PAGE_H_ 9 | #define FU_HYPERVISOR_FAKE_PAGE_H_ 10 | 11 | #include 12 | 13 | //////////////////////////////////////////////////////////////////////////////// 14 | // 15 | // macro utilities 16 | // 17 | 18 | //////////////////////////////////////////////////////////////////////////////// 19 | // 20 | // constants and macros 21 | // 22 | 23 | //////////////////////////////////////////////////////////////////////////////// 24 | // 25 | // types 26 | // 27 | 28 | struct EptData; 29 | struct ProcessorFakePageData; 30 | struct SharedFakePageData; 31 | 32 | /// @copydoc IoInstQualification 33 | 34 | //////////////////////////////////////////////////////////////////////////////// 35 | // 36 | // prototypes 37 | // 38 | 39 | _IRQL_requires_max_(PASSIVE_LEVEL) EXTERN_C 40 | ProcessorFakePageData* FpAllocateProcessorData(); 41 | 42 | _IRQL_requires_max_(PASSIVE_LEVEL) EXTERN_C 43 | void FpFreeProcessorData(_In_ ProcessorFakePageData* processor_fp_data); 44 | 45 | _IRQL_requires_max_(PASSIVE_LEVEL) EXTERN_C 46 | SharedFakePageData* FpAllocateSharedProcessorData(); 47 | 48 | _IRQL_requires_max_(PASSIVE_LEVEL) EXTERN_C 49 | void FpFreeSharedProcessorData(_In_ SharedFakePageData* shared_fp_data); 50 | 51 | _IRQL_requires_min_(DISPATCH_LEVEL) void FpHandleMonitorTrapFlag( 52 | _In_ ProcessorFakePageData* processor_fp_data, 53 | _In_ const SharedFakePageData* shared_fp_data, _In_ EptData* ept_data); 54 | 55 | _IRQL_requires_min_(DISPATCH_LEVEL) void FpHandleEptViolation( 56 | _In_ ProcessorFakePageData* processor_fp_data, 57 | _In_ const SharedFakePageData* shared_fp_data, _In_ EptData* ept_data, 58 | _In_ void* fault_va, ULONG64 fault_pa 59 | ); 60 | 61 | _IRQL_requires_max_(PASSIVE_LEVEL) bool FpVmCallCreateFakePage( 62 | _In_ SharedFakePageData* shared_fp_data, _In_ void* context); 63 | 64 | _IRQL_requires_min_(DISPATCH_LEVEL) NTSTATUS 65 | FpVmCallEnableFakePages(_In_ EptData* ept_data, 66 | _In_ const SharedFakePageData* shared_fp_data); 67 | 68 | _IRQL_requires_min_(DISPATCH_LEVEL) void FpVmCallDisableFakePages( 69 | _In_ EptData* ept_data, _In_ SharedFakePageData* shared_fp_data); 70 | 71 | _IRQL_requires_min_(DISPATCH_LEVEL) void FpVmCallDeleteFakePages( 72 | _In_ SharedFakePageData* shared_fp_data); 73 | 74 | _IRQL_requires_min_(PASSIVE_LEVEL) EXTERN_C 75 | void SaveCpuinfo( 76 | SharedFakePageData* sharedata); 77 | _IRQL_requires_min_(PASSIVE_LEVEL) EXTERN_C 78 | int* FpHandleCpuid(SharedFakePageData* sharedata, int index, int subfun); 79 | 80 | //////////////////////////////////////////////////////////////////////////////// 81 | // 82 | // variables 83 | // 84 | 85 | //////////////////////////////////////////////////////////////////////////////// 86 | // 87 | // implementations 88 | // 89 | 90 | #endif // FU_HYPERVISOR_FAKE_PAGE_H_ 91 | -------------------------------------------------------------------------------- /HyperPlatform/Documents/UserDocument.odt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bb33bb/r3epthook/2ab806c04fbb6456eccae32d4374959f5116a05b/HyperPlatform/Documents/UserDocument.odt -------------------------------------------------------------------------------- /HyperPlatform/HyperPlatform.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.24720.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HyperPlatform", "HyperPlatform\HyperPlatform.vcxproj", "{4C048BB2-7E8D-43BF-B29D-942461275023}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{9D6567E8-2030-4700-805F-D44CB292A667}" 9 | ProjectSection(SolutionItems) = preProject 10 | .clang-format = .clang-format 11 | .gitattributes = .gitattributes 12 | .gitignore = .gitignore 13 | clean.bat = clean.bat 14 | README.md = README.md 15 | EndProjectSection 16 | EndProject 17 | Global 18 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 19 | Debug|x64 = Debug|x64 20 | Debug|x86 = Debug|x86 21 | Release|x64 = Release|x64 22 | Release|x86 = Release|x86 23 | EndGlobalSection 24 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 25 | {4C048BB2-7E8D-43BF-B29D-942461275023}.Debug|x64.ActiveCfg = Debug|x64 26 | {4C048BB2-7E8D-43BF-B29D-942461275023}.Debug|x64.Build.0 = Debug|x64 27 | {4C048BB2-7E8D-43BF-B29D-942461275023}.Debug|x64.Deploy.0 = Debug|x64 28 | {4C048BB2-7E8D-43BF-B29D-942461275023}.Debug|x86.ActiveCfg = Debug|Win32 29 | {4C048BB2-7E8D-43BF-B29D-942461275023}.Debug|x86.Build.0 = Debug|Win32 30 | {4C048BB2-7E8D-43BF-B29D-942461275023}.Debug|x86.Deploy.0 = Debug|Win32 31 | {4C048BB2-7E8D-43BF-B29D-942461275023}.Release|x64.ActiveCfg = Release|x64 32 | {4C048BB2-7E8D-43BF-B29D-942461275023}.Release|x64.Build.0 = Release|x64 33 | {4C048BB2-7E8D-43BF-B29D-942461275023}.Release|x64.Deploy.0 = Release|x64 34 | {4C048BB2-7E8D-43BF-B29D-942461275023}.Release|x86.ActiveCfg = Release|Win32 35 | {4C048BB2-7E8D-43BF-B29D-942461275023}.Release|x86.Build.0 = Release|Win32 36 | {4C048BB2-7E8D-43BF-B29D-942461275023}.Release|x86.Deploy.0 = Release|Win32 37 | EndGlobalSection 38 | GlobalSection(SolutionProperties) = preSolution 39 | HideSolutionNode = FALSE 40 | EndGlobalSection 41 | EndGlobal 42 | -------------------------------------------------------------------------------- /HyperPlatform/HyperPlatform/Arch/x64/x64.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (c) 2015-2017, Satoshi Tanda. All rights reserved. 2 | ; Use of this source code is governed by a MIT-style license that can be 3 | ; found in the LICENSE file. 4 | 5 | ; 6 | ; This module implements all assembler code 7 | ; 8 | 9 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 10 | ; 11 | ; References to C functions 12 | ; 13 | EXTERN VmmVmExitHandler : PROC 14 | EXTERN VmmVmxFailureHandler : PROC 15 | EXTERN UtilDumpGpRegisters : PROC 16 | 17 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 18 | ; 19 | ; constants 20 | ; 21 | .CONST 22 | 23 | VMX_OK EQU 0 24 | VMX_ERROR_WITH_STATUS EQU 1 25 | VMX_ERROR_WITHOUT_STATUS EQU 2 26 | 27 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 28 | ; 29 | ; macros 30 | ; 31 | 32 | ; Saves all general purpose registers to the stack 33 | PUSHAQ MACRO 34 | push rax 35 | push rcx 36 | push rdx 37 | push rbx 38 | push -1 ; dummy for rsp 39 | push rbp 40 | push rsi 41 | push rdi 42 | push r8 43 | push r9 44 | push r10 45 | push r11 46 | push r12 47 | push r13 48 | push r14 49 | push r15 50 | ENDM 51 | 52 | ; Loads all general purpose registers from the stack 53 | POPAQ MACRO 54 | pop r15 55 | pop r14 56 | pop r13 57 | pop r12 58 | pop r11 59 | pop r10 60 | pop r9 61 | pop r8 62 | pop rdi 63 | pop rsi 64 | pop rbp 65 | add rsp, 8 ; dummy for rsp 66 | pop rbx 67 | pop rdx 68 | pop rcx 69 | pop rax 70 | ENDM 71 | 72 | ; Dumps all general purpose registers and a flag register. 73 | ASM_DUMP_REGISTERS MACRO 74 | pushfq 75 | PUSHAQ ; -8 * 16 76 | mov rcx, rsp ; guest_context 77 | mov rdx, rsp 78 | add rdx, 8*17 ; stack_pointer 79 | 80 | sub rsp, 28h ; 28h for alignment 81 | call UtilDumpGpRegisters ; UtilDumpGpRegisters(guest_context, stack_pointer); 82 | add rsp, 28h 83 | 84 | POPAQ 85 | popfq 86 | ENDM 87 | 88 | 89 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 90 | ; 91 | ; implementations 92 | ; 93 | .CODE 94 | 95 | ; bool __stdcall AsmInitializeVm( 96 | ; _In_ void (*vm_initialization_routine)(_In_ ULONG_PTR, _In_ ULONG_PTR, 97 | ; _In_opt_ void *), 98 | ; _In_opt_ void *context); 99 | AsmInitializeVm PROC 100 | ; RSP is not 16 bit aligned when it gets called, but the following odd 101 | ; number (17 times) of push makes RSP 16 bit aligned. 102 | pushfq 103 | PUSHAQ ; -8 * 16 104 | 105 | mov rax, rcx 106 | mov r8, rdx 107 | mov rdx, asmResumeVm 108 | mov rcx, rsp 109 | 110 | sub rsp, 20h 111 | call rax ; vm_initialization_routine(rsp, asmResumeVm, context) 112 | add rsp, 20h 113 | 114 | POPAQ 115 | popfq 116 | xor rax, rax ; return false 117 | ret 118 | 119 | ; This is where the virtualized guest start to execute after successful 120 | ; vmlaunch. 121 | asmResumeVm: 122 | nop ; keep this nop for ease of debugging 123 | POPAQ 124 | popfq 125 | 126 | sub rsp, 8 ; align RSP 127 | ASM_DUMP_REGISTERS 128 | add rsp, 8 ; restore RSP 129 | 130 | xor rax, rax 131 | inc rax ; return true 132 | ret 133 | AsmInitializeVm ENDP 134 | 135 | ; void __stdcall AsmVmmEntryPoint(); 136 | AsmVmmEntryPoint PROC 137 | ; No need to save the flag registers since it is restored from the VMCS at 138 | ; the time of vmresume. 139 | PUSHAQ ; -8 * 16 140 | mov rcx, rsp 141 | 142 | ; save volatile XMM registers 143 | sub rsp, 60h 144 | movaps xmmword ptr [rsp + 0h], xmm0 145 | movaps xmmword ptr [rsp + 10h], xmm1 146 | movaps xmmword ptr [rsp + 20h], xmm2 147 | movaps xmmword ptr [rsp + 30h], xmm3 148 | movaps xmmword ptr [rsp + 40h], xmm4 149 | movaps xmmword ptr [rsp + 50h], xmm5 150 | 151 | sub rsp, 20h 152 | call VmmVmExitHandler ; bool vm_continue = VmmVmExitHandler(guest_context); 153 | add rsp, 20h 154 | 155 | ; restore XMM registers 156 | movaps xmm0, xmmword ptr [rsp + 0h] 157 | movaps xmm1, xmmword ptr [rsp + 10h] 158 | movaps xmm2, xmmword ptr [rsp + 20h] 159 | movaps xmm3, xmmword ptr [rsp + 30h] 160 | movaps xmm4, xmmword ptr [rsp + 40h] 161 | movaps xmm5, xmmword ptr [rsp + 50h] 162 | add rsp, 60h 163 | 164 | test al, al 165 | jz exitVm ; if (!vm_continue) jmp exitVm 166 | 167 | POPAQ 168 | vmresume 169 | jmp vmxError 170 | 171 | exitVm: 172 | ; Executes vmxoff and ends virtualization 173 | ; rax = Guest's rflags 174 | ; rdx = Guest's rsp 175 | ; rcx = Guest's rip for the next instruction 176 | POPAQ 177 | vmxoff 178 | jz vmxError ; if (ZF) jmp 179 | jc vmxError ; if (CF) jmp 180 | push rax 181 | popfq ; rflags <= GurstFlags 182 | mov rsp, rdx ; rsp <= GuestRsp 183 | push rcx 184 | ret ; jmp AddressToReturn 185 | 186 | vmxError: 187 | ; Diagnose a critical error 188 | pushfq 189 | PUSHAQ ; -8 * 16 190 | mov rcx, rsp ; all_regs 191 | 192 | sub rsp, 28h ; 28h for alignment 193 | call VmmVmxFailureHandler ; VmmVmxFailureHandler(all_regs); 194 | add rsp, 28h 195 | int 3 196 | AsmVmmEntryPoint ENDP 197 | 198 | ; unsigned char __stdcall AsmVmxCall(_In_ ULONG_PTR hypercall_number, 199 | ; _In_opt_ void *context); 200 | AsmVmxCall PROC 201 | vmcall ; vmcall(hypercall_number, context) 202 | jz errorWithCode ; if (ZF) jmp 203 | jc errorWithoutCode ; if (CF) jmp 204 | xor rax, rax ; return VMX_OK 205 | ret 206 | 207 | errorWithoutCode: 208 | mov rax, VMX_ERROR_WITHOUT_STATUS 209 | ret 210 | 211 | errorWithCode: 212 | mov rax, VMX_ERROR_WITH_STATUS 213 | ret 214 | AsmVmxCall ENDP 215 | 216 | ; void __stdcall AsmWriteGDT(_In_ const GDTR *gdtr); 217 | AsmWriteGDT PROC 218 | lgdt fword ptr [rcx] 219 | ret 220 | AsmWriteGDT ENDP 221 | 222 | ; void __stdcall AsmReadGDT(_Out_ GDTR *gdtr); 223 | AsmReadGDT PROC 224 | sgdt [rcx] 225 | ret 226 | AsmReadGDT ENDP 227 | 228 | ; void __stdcall AsmWriteLDTR(_In_ USHORT local_segmeng_selector); 229 | AsmWriteLDTR PROC 230 | lldt cx 231 | ret 232 | AsmWriteLDTR ENDP 233 | 234 | ; USHORT __stdcall AsmReadLDTR(); 235 | AsmReadLDTR PROC 236 | sldt ax 237 | ret 238 | AsmReadLDTR ENDP 239 | 240 | ; void __stdcall AsmWriteTR(_In_ USHORT task_register); 241 | AsmWriteTR PROC 242 | ltr cx 243 | ret 244 | AsmWriteTR ENDP 245 | 246 | ; USHORT __stdcall AsmReadTR(); 247 | AsmReadTR PROC 248 | str ax 249 | ret 250 | AsmReadTR ENDP 251 | 252 | ; void __stdcall AsmWriteES(_In_ USHORT segment_selector); 253 | AsmWriteES PROC 254 | mov es, cx 255 | ret 256 | AsmWriteES ENDP 257 | 258 | ; USHORT __stdcall AsmReadES(); 259 | AsmReadES PROC 260 | mov ax, es 261 | ret 262 | AsmReadES ENDP 263 | 264 | ; void __stdcall AsmWriteCS(_In_ USHORT segment_selector); 265 | AsmWriteCS PROC 266 | mov cs, cx 267 | ret 268 | AsmWriteCS ENDP 269 | 270 | ; USHORT __stdcall AsmReadCS(); 271 | AsmReadCS PROC 272 | mov ax, cs 273 | ret 274 | AsmReadCS ENDP 275 | 276 | ; void __stdcall AsmWriteSS(_In_ USHORT segment_selector); 277 | AsmWriteSS PROC 278 | mov ss, cx 279 | ret 280 | AsmWriteSS ENDP 281 | 282 | ; USHORT __stdcall AsmReadSS(); 283 | AsmReadSS PROC 284 | mov ax, ss 285 | ret 286 | AsmReadSS ENDP 287 | 288 | ; void __stdcall AsmWriteDS(_In_ USHORT segment_selector); 289 | AsmWriteDS PROC 290 | mov ds, cx 291 | ret 292 | AsmWriteDS ENDP 293 | 294 | ; USHORT __stdcall AsmReadDS(); 295 | AsmReadDS PROC 296 | mov ax, ds 297 | ret 298 | AsmReadDS ENDP 299 | 300 | ; void __stdcall AsmWriteFS(_In_ USHORT segment_selector); 301 | AsmWriteFS PROC 302 | mov fs, cx 303 | ret 304 | AsmWriteFS ENDP 305 | 306 | ; USHORT __stdcall AsmReadFS(); 307 | AsmReadFS PROC 308 | mov ax, fs 309 | ret 310 | AsmReadFS ENDP 311 | 312 | ; void __stdcall AsmWriteGS(_In_ USHORT segment_selector); 313 | AsmWriteGS PROC 314 | mov gs, cx 315 | ret 316 | AsmWriteGS ENDP 317 | 318 | ; USHORT __stdcall AsmReadGS(); 319 | AsmReadGS PROC 320 | mov ax, gs 321 | ret 322 | AsmReadGS ENDP 323 | 324 | ; ULONG_PTR __stdcall AsmLoadAccessRightsByte(_In_ ULONG_PTR segment_selector); 325 | AsmLoadAccessRightsByte PROC 326 | lar rax, rcx 327 | ret 328 | AsmLoadAccessRightsByte ENDP 329 | 330 | ; void __stdcall AsmInvalidateInternalCaches(); 331 | AsmInvalidateInternalCaches PROC 332 | invd 333 | ret 334 | AsmInvalidateInternalCaches ENDP 335 | 336 | ; void __stdcall AsmWriteCR2(_In_ ULONG_PTR cr2_value); 337 | AsmWriteCR2 PROC 338 | mov cr2, rcx 339 | ret 340 | AsmWriteCR2 ENDP 341 | 342 | ; unsigned char __stdcall AsmInvept( 343 | ; _In_ InvEptType invept_type, 344 | ; _In_ const InvEptDescriptor *invept_descriptor); 345 | AsmInvept PROC 346 | ; invept ecx, oword ptr [rdx] 347 | db 66h, 0fh, 38h, 80h, 0ah 348 | jz errorWithCode ; if (ZF) jmp 349 | jc errorWithoutCode ; if (CF) jmp 350 | xor rax, rax ; return VMX_OK 351 | ret 352 | 353 | errorWithoutCode: 354 | mov rax, VMX_ERROR_WITHOUT_STATUS 355 | ret 356 | 357 | errorWithCode: 358 | mov rax, VMX_ERROR_WITH_STATUS 359 | ret 360 | AsmInvept ENDP 361 | 362 | ; unsigned char __stdcall AsmInvvpid( 363 | ; _In_ InvVpidType invvpid_type, 364 | ; _In_ const InvVpidDescriptor *invvpid_descriptor); 365 | AsmInvvpid PROC 366 | ; invvpid ecx, oword ptr [rdx] 367 | db 66h, 0fh, 38h, 81h, 0ah 368 | jz errorWithCode ; if (ZF) jmp 369 | jc errorWithoutCode ; if (CF) jmp 370 | xor rax, rax ; return VMX_OK 371 | ret 372 | 373 | errorWithoutCode: 374 | mov rax, VMX_ERROR_WITHOUT_STATUS 375 | ret 376 | 377 | errorWithCode: 378 | mov rax, VMX_ERROR_WITH_STATUS 379 | ret 380 | AsmInvvpid ENDP 381 | 382 | 383 | PURGE PUSHAQ 384 | PURGE POPAQ 385 | PURGE ASM_DUMP_REGISTERS 386 | END 387 | -------------------------------------------------------------------------------- /HyperPlatform/HyperPlatform/Arch/x86/x86.asm: -------------------------------------------------------------------------------- 1 | ; Copyright (c) 2015-2017, Satoshi Tanda. All rights reserved. 2 | ; Use of this source code is governed by a MIT-style license that can be 3 | ; found in the LICENSE file. 4 | 5 | ; 6 | ; This module implements all assembler code 7 | ; 8 | .686p 9 | .model flat, stdcall 10 | .MMX 11 | .XMM 12 | 13 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 14 | ; 15 | ; References to C functions 16 | ; 17 | EXTERN VmmVmExitHandler@4 : PROC 18 | EXTERN VmmVmxFailureHandler@4 : PROC 19 | EXTERN UtilDumpGpRegisters@8 : PROC 20 | 21 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 22 | ; 23 | ; constants 24 | ; 25 | .CONST 26 | 27 | VMX_OK EQU 0 28 | VMX_ERROR_WITH_STATUS EQU 1 29 | VMX_ERROR_WITHOUT_STATUS EQU 2 30 | 31 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 32 | ; 33 | ; macros 34 | ; 35 | 36 | ; Dumps all general purpose registers and a flag register. 37 | ASM_DUMP_REGISTERS MACRO 38 | pushfd 39 | pushad ; -4 * 8 40 | mov ecx, esp ; all_regs 41 | mov edx, esp 42 | add edx, 4*9 ; stack_pointer 43 | 44 | push ecx 45 | push edx 46 | call UtilDumpGpRegisters@8 ; UtilDumpGpRegisters(all_regs, stack_pointer); 47 | 48 | popad 49 | popfd 50 | ENDM 51 | 52 | 53 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 54 | ; 55 | ; implementations 56 | ; 57 | .CODE 58 | 59 | ; bool __stdcall AsmInitializeVm( 60 | ; _In_ void (*vm_initialization_routine)(_In_ ULONG_PTR, _In_ ULONG_PTR, 61 | ; _In_opt_ void *), 62 | ; _In_opt_ void *context); 63 | AsmInitializeVm PROC vm_initialization_routine, context 64 | pushfd 65 | pushad ; -4 * 8 66 | 67 | mov ecx, esp ; esp 68 | 69 | ; vm_initialization_routine(rsp, asmResumeVm, context) 70 | push context 71 | push asmResumeVm 72 | push ecx 73 | call vm_initialization_routine 74 | 75 | popad 76 | popfd 77 | xor eax, eax ; return false 78 | ret 79 | 80 | ; This is where the virtualized guest start to execute after successful 81 | ; vmlaunch. 82 | asmResumeVm: 83 | nop ; keep this nop for ease of debugging 84 | popad 85 | popfd 86 | ASM_DUMP_REGISTERS 87 | xor eax, eax 88 | inc eax ; return true 89 | ret 90 | AsmInitializeVm ENDP 91 | 92 | ; void __stdcall AsmVmmEntryPoint(); 93 | AsmVmmEntryPoint PROC 94 | ; No need to save the flag registers since it is restored from the VMCS at 95 | ; the time of vmresume. 96 | pushad ; -4 * 8 97 | mov eax, esp 98 | 99 | ; save volatile XMM registers 100 | sub esp, 68h ; +8 for alignment 101 | mov ecx, cr0 102 | mov edx, ecx ; save original CR0 103 | and cl, 0f1h ; clear MP, EM, TS bits for floating point access 104 | mov cr0, ecx ; update CR0 105 | movaps xmmword ptr [esp + 0h], xmm0 106 | movaps xmmword ptr [esp + 10h], xmm1 107 | movaps xmmword ptr [esp + 20h], xmm2 108 | movaps xmmword ptr [esp + 30h], xmm3 109 | movaps xmmword ptr [esp + 40h], xmm4 110 | movaps xmmword ptr [esp + 50h], xmm5 111 | mov cr0, edx ; restore the original CR0 112 | 113 | push eax 114 | call VmmVmExitHandler@4 ; bool vm_continue = VmmVmExitHandler(guest_context); 115 | 116 | ; restore XMM registers 117 | mov ecx, cr0 118 | mov edx, ecx ; save original CR0 119 | and cl, 0f1h ; clear MP, EM, TS bits for floating point access 120 | mov cr0, ecx ; update CR0 121 | movaps xmm0, xmmword ptr [esp + 0h] 122 | movaps xmm1, xmmword ptr [esp + 10h] 123 | movaps xmm2, xmmword ptr [esp + 20h] 124 | movaps xmm3, xmmword ptr [esp + 30h] 125 | movaps xmm4, xmmword ptr [esp + 40h] 126 | movaps xmm5, xmmword ptr [esp + 50h] 127 | mov cr0, edx ; restore the original CR0 128 | add esp, 68h ; +8 for alignment 129 | 130 | test al, al 131 | jz exitVm ; if (!vm_continue) jmp exitVm 132 | 133 | popad 134 | vmresume 135 | jmp vmxError 136 | 137 | exitVm: 138 | ; Executes vmxoff and ends virtualization 139 | ; eax = Guest's eflags 140 | ; edx = Guest's esp 141 | ; ecx = Guest's eip for the next instruction 142 | popad 143 | vmxoff 144 | jz vmxError ; if (ZF) jmp 145 | jc vmxError ; if (CF) jmp 146 | push eax 147 | popfd ; eflags <= GurstFlags 148 | mov esp, edx ; esp <= GuestRsp 149 | push ecx 150 | ret ; jmp AddressToReturn 151 | 152 | vmxError: 153 | ; Diagnose a critical error 154 | pushfd 155 | pushad ; -4 * 8 156 | mov ecx, esp ; all_regs 157 | push ecx 158 | call VmmVmxFailureHandler@4 ; VmmVmxFailureHandler(all_regs); 159 | int 3 160 | AsmVmmEntryPoint ENDP 161 | 162 | ; unsigned char __stdcall AsmVmxCall(_In_ ULONG_PTR hypercall_number, 163 | ; _In_opt_ void *context); 164 | AsmVmxCall PROC hypercall_number, context 165 | mov ecx, hypercall_number 166 | mov edx, context 167 | vmcall ; vmcall(hypercall_number, context) 168 | jz errorWithCode ; if (ZF) jmp 169 | jc errorWithoutCode ; if (CF) jmp 170 | xor eax, eax ; return VMX_OK 171 | ret 172 | 173 | errorWithoutCode: 174 | mov eax, VMX_ERROR_WITHOUT_STATUS 175 | ret 176 | 177 | errorWithCode: 178 | mov eax, VMX_ERROR_WITH_STATUS 179 | ret 180 | AsmVmxCall ENDP 181 | 182 | ; void __stdcall AsmWriteGDT(_In_ const GDTR *gdtr); 183 | AsmWriteGDT PROC gdtr 184 | mov ecx, gdtr 185 | lgdt fword ptr [ecx] 186 | ret 187 | AsmWriteGDT ENDP 188 | 189 | ; void __stdcall AsmReadGDT(_Out_ GDTR *gdtr); 190 | AsmReadGDT PROC gdtr 191 | mov ecx, gdtr 192 | sgdt [ecx] 193 | ret 194 | AsmReadGDT ENDP 195 | 196 | ; void __stdcall AsmWriteLDTR(_In_ USHORT local_segmeng_selector); 197 | AsmWriteLDTR PROC local_segmeng_selector 198 | mov ecx, local_segmeng_selector 199 | lldt cx 200 | ret 201 | AsmWriteLDTR ENDP 202 | 203 | ; USHORT __stdcall AsmReadLDTR(); 204 | AsmReadLDTR PROC 205 | sldt ax 206 | ret 207 | AsmReadLDTR ENDP 208 | 209 | ; void __stdcall AsmWriteTR(_In_ USHORT task_register); 210 | AsmWriteTR PROC task_register 211 | mov ecx, task_register 212 | ltr cx 213 | ret 214 | AsmWriteTR ENDP 215 | 216 | ; USHORT __stdcall AsmReadTR(); 217 | AsmReadTR PROC 218 | str ax 219 | ret 220 | AsmReadTR ENDP 221 | 222 | ; void __stdcall AsmWriteES(_In_ USHORT segment_selector); 223 | AsmWriteES PROC segment_selector 224 | mov ecx, segment_selector 225 | mov es, cx 226 | ret 227 | AsmWriteES ENDP 228 | 229 | ; USHORT __stdcall AsmReadES(); 230 | AsmReadES PROC 231 | mov ax, es 232 | ret 233 | AsmReadES ENDP 234 | 235 | ; void __stdcall AsmWriteCS(_In_ USHORT segment_selector); 236 | AsmWriteCS PROC segment_selector 237 | mov ecx, segment_selector 238 | mov cs, cx 239 | ret 240 | AsmWriteCS ENDP 241 | 242 | ; USHORT __stdcall AsmReadCS(); 243 | AsmReadCS PROC 244 | mov ax, cs 245 | ret 246 | AsmReadCS ENDP 247 | 248 | ; void __stdcall AsmWriteSS(_In_ USHORT segment_selector); 249 | AsmWriteSS PROC segment_selector 250 | mov ecx, segment_selector 251 | mov ss, cx 252 | ret 253 | AsmWriteSS ENDP 254 | 255 | ; USHORT __stdcall AsmReadSS(); 256 | AsmReadSS PROC 257 | mov ax, ss 258 | ret 259 | AsmReadSS ENDP 260 | 261 | ; void __stdcall AsmWriteDS(_In_ USHORT segment_selector); 262 | AsmWriteDS PROC segment_selector 263 | mov ecx, segment_selector 264 | mov ds, cx 265 | ret 266 | AsmWriteDS ENDP 267 | 268 | ; USHORT __stdcall AsmReadDS(); 269 | AsmReadDS PROC 270 | mov ax, ds 271 | ret 272 | AsmReadDS ENDP 273 | 274 | ; void __stdcall AsmWriteFS(_In_ USHORT segment_selector); 275 | AsmWriteFS PROC segment_selector 276 | mov ecx, segment_selector 277 | mov fs, cx 278 | ret 279 | AsmWriteFS ENDP 280 | 281 | ; USHORT __stdcall AsmReadFS(); 282 | AsmReadFS PROC 283 | mov ax, fs 284 | ret 285 | AsmReadFS ENDP 286 | 287 | ; void __stdcall AsmWriteGS(_In_ USHORT segment_selector); 288 | AsmWriteGS PROC segment_selector 289 | mov ecx, segment_selector 290 | mov gs, cx 291 | ret 292 | AsmWriteGS ENDP 293 | 294 | ; USHORT __stdcall AsmReadGS(); 295 | AsmReadGS PROC 296 | mov ax, gs 297 | ret 298 | AsmReadGS ENDP 299 | 300 | ; ULONG_PTR __stdcall AsmLoadAccessRightsByte( 301 | ; _In_ ULONG_PTR segment_selector); 302 | AsmLoadAccessRightsByte PROC segment_selector 303 | mov ecx, segment_selector 304 | lar eax, ecx 305 | ret 306 | AsmLoadAccessRightsByte ENDP 307 | 308 | ; void __stdcall AsmInvalidateInternalCaches(); 309 | AsmInvalidateInternalCaches PROC 310 | invd 311 | ret 312 | AsmInvalidateInternalCaches ENDP 313 | 314 | ; void __stdcall AsmWriteCR2(_In_ ULONG_PTR cr2_value); 315 | AsmWriteCR2 PROC cr2_value 316 | mov ecx, cr2_value 317 | mov cr2, ecx 318 | ret 319 | AsmWriteCR2 ENDP 320 | 321 | ; unsigned char __stdcall AsmInvept( 322 | ; _In_ InvEptType invept_type, 323 | ; _In_ const InvEptDescriptor *invept_descriptor); 324 | AsmInvept PROC invept_type, invept_descriptor 325 | mov ecx, invept_type 326 | mov edx, invept_descriptor 327 | ; invept ecx, oword ptr [edx] 328 | db 66h, 0fh, 38h, 80h, 0ah 329 | jz errorWithCode ; if (ZF) jmp 330 | jc errorWithoutCode ; if (CF) jmp 331 | xor eax, eax ; return VMX_OK 332 | ret 333 | 334 | errorWithoutCode: 335 | mov eax, VMX_ERROR_WITHOUT_STATUS 336 | ret 337 | 338 | errorWithCode: 339 | mov eax, VMX_ERROR_WITH_STATUS 340 | ret 341 | AsmInvept ENDP 342 | 343 | ; unsigned char __stdcall AsmInvvpid( 344 | ; _In_ InvVpidType invvpid_type, 345 | ; _In_ const InvVpidDescriptor *invvpid_descriptor); 346 | AsmInvvpid PROC invvpid_type, invvpid_descriptor 347 | mov ecx, invvpid_type 348 | mov edx, invvpid_descriptor 349 | ; invvpid ecx, oword ptr [rdx] 350 | db 66h, 0fh, 38h, 81h, 0ah 351 | jz errorWithCode ; if (ZF) jmp 352 | jc errorWithoutCode ; if (CF) jmp 353 | xor eax, eax ; return VMX_OK 354 | ret 355 | 356 | errorWithoutCode: 357 | mov eax, VMX_ERROR_WITHOUT_STATUS 358 | ret 359 | 360 | errorWithCode: 361 | mov eax, VMX_ERROR_WITH_STATUS 362 | ret 363 | AsmInvvpid ENDP 364 | 365 | 366 | PURGE ASM_DUMP_REGISTERS 367 | END 368 | -------------------------------------------------------------------------------- /HyperPlatform/HyperPlatform/HyperPlatform.inf: -------------------------------------------------------------------------------- 1 | ; 2 | ; HyperPlatform.inf 3 | ; 4 | 5 | [Version] 6 | Signature="$WINDOWS NT$" 7 | Class=Sample ; TODO: edit Class 8 | ClassGuid={78A1C341-4539-11d3-B88D-00C04FAD5171} ; TODO: edit ClassGuid 9 | Provider=%ManufacturerName% 10 | CatalogFile=HyperPlatform.cat 11 | DriverVer= ; TODO: set DriverVer in stampinf property pages 12 | 13 | [DestinationDirs] 14 | DefaultDestDir = 12 15 | HyperPlatform_Device_CoInstaller_CopyFiles = 11 16 | 17 | ; ================= Class section ===================== 18 | 19 | [ClassInstall32] 20 | Addreg=SampleClassReg 21 | 22 | [SampleClassReg] 23 | HKR,,,0,%ClassName% 24 | HKR,,Icon,,-5 25 | 26 | [SourceDisksNames] 27 | 1 = %DiskName%,,,"" 28 | 29 | [SourceDisksFiles] 30 | HyperPlatform.sys = 1,, 31 | WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll=1 ; make sure the number matches with SourceDisksNames 32 | 33 | ;***************************************** 34 | ; Install Section 35 | ;***************************************** 36 | 37 | [Manufacturer] 38 | %ManufacturerName%=Standard,NT$ARCH$ 39 | 40 | [Standard.NT$ARCH$] 41 | %HyperPlatform.DeviceDesc%=HyperPlatform_Device, Root\HyperPlatform ; TODO: edit hw-id 42 | 43 | [HyperPlatform_Device.NT] 44 | CopyFiles=Drivers_Dir 45 | 46 | [Drivers_Dir] 47 | HyperPlatform.sys 48 | 49 | ;-------------- Service installation 50 | [HyperPlatform_Device.NT.Services] 51 | AddService = HyperPlatform,%SPSVCINST_ASSOCSERVICE%, HyperPlatform_Service_Inst 52 | 53 | ; -------------- HyperPlatform driver install sections 54 | [HyperPlatform_Service_Inst] 55 | DisplayName = %HyperPlatform.SVCDESC% 56 | ServiceType = 1 ; SERVICE_KERNEL_DRIVER 57 | StartType = 3 ; SERVICE_DEMAND_START 58 | ErrorControl = 1 ; SERVICE_ERROR_NORMAL 59 | ServiceBinary = %12%\HyperPlatform.sys 60 | 61 | ; 62 | ;--- HyperPlatform_Device Coinstaller installation ------ 63 | ; 64 | 65 | [HyperPlatform_Device.NT.CoInstallers] 66 | AddReg=HyperPlatform_Device_CoInstaller_AddReg 67 | CopyFiles=HyperPlatform_Device_CoInstaller_CopyFiles 68 | 69 | [HyperPlatform_Device_CoInstaller_AddReg] 70 | HKR,,CoInstallers32,0x00010000, "WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll,WdfCoInstaller" 71 | 72 | [HyperPlatform_Device_CoInstaller_CopyFiles] 73 | WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll 74 | 75 | [HyperPlatform_Device.NT.Wdf] 76 | KmdfService = HyperPlatform, HyperPlatform_wdfsect 77 | [HyperPlatform_wdfsect] 78 | KmdfLibraryVersion = $KMDFVERSION$ 79 | 80 | [Strings] 81 | SPSVCINST_ASSOCSERVICE= 0x00000002 82 | ManufacturerName="" ;TODO: Replace with your manufacturer name 83 | ClassName="Samples" ; TODO: edit ClassName 84 | DiskName = "HyperPlatform Installation Disk" 85 | HyperPlatform.DeviceDesc = "HyperPlatform Device" 86 | HyperPlatform.SVCDESC = "HyperPlatform Service" 87 | -------------------------------------------------------------------------------- /HyperPlatform/HyperPlatform/HyperPlatform.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {4C048BB2-7E8D-43BF-B29D-942461275023} 23 | {497e31cb-056b-4f31-abb8-447fd55ee5a5} 24 | v4.5 25 | 12.0 26 | Debug 27 | Win32 28 | HyperPlatform 29 | 30 | 31 | 32 | Windows7 33 | true 34 | WindowsKernelModeDriver10.0 35 | Driver 36 | KMDF 37 | Desktop 38 | 39 | 40 | Windows7 41 | false 42 | WindowsKernelModeDriver10.0 43 | Driver 44 | KMDF 45 | Desktop 46 | 47 | 48 | Windows7 49 | true 50 | WindowsKernelModeDriver10.0 51 | Driver 52 | KMDF 53 | Desktop 54 | 55 | 56 | Windows7 57 | false 58 | WindowsKernelModeDriver10.0 59 | Driver 60 | KMDF 61 | Desktop 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | DbgengKernelDebugger 73 | true 74 | 75 | 76 | DbgengKernelDebugger 77 | true 78 | 79 | 80 | DbgengKernelDebugger 81 | true 82 | 83 | 84 | DbgengKernelDebugger 85 | true 86 | 87 | 88 | 89 | true 90 | trace.h 91 | true 92 | 93 | 94 | 95 | 96 | 97 | true 98 | trace.h 99 | true 100 | 101 | 102 | 103 | 104 | 105 | true 106 | trace.h 107 | true 108 | 109 | 110 | 111 | 112 | 113 | true 114 | trace.h 115 | true 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | true 155 | true 156 | 157 | 158 | true 159 | true 160 | true 161 | true 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | -------------------------------------------------------------------------------- /HyperPlatform/HyperPlatform/HyperPlatform.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {8E41214B-6785-4CFE-B992-037D68949A14} 18 | inf;inv;inx;mof;mc; 19 | 20 | 21 | 22 | 23 | Driver Files 24 | 25 | 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | Source Files 38 | 39 | 40 | Source Files 41 | 42 | 43 | Source Files 44 | 45 | 46 | Source Files 47 | 48 | 49 | Source Files 50 | 51 | 52 | Source Files 53 | 54 | 55 | Source Files 56 | 57 | 58 | Source Files 59 | 60 | 61 | 62 | 63 | Header Files 64 | 65 | 66 | Header Files 67 | 68 | 69 | Header Files 70 | 71 | 72 | Header Files 73 | 74 | 75 | Header Files 76 | 77 | 78 | Header Files 79 | 80 | 81 | Header Files 82 | 83 | 84 | Header Files 85 | 86 | 87 | Header Files 88 | 89 | 90 | Header Files 91 | 92 | 93 | Header Files 94 | 95 | 96 | Header Files 97 | 98 | 99 | Header Files 100 | 101 | 102 | Header Files 103 | 104 | 105 | Header Files 106 | 107 | 108 | 109 | 110 | Source Files 111 | 112 | 113 | Source Files 114 | 115 | 116 | -------------------------------------------------------------------------------- /HyperPlatform/HyperPlatform/asm.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2017, Satoshi Tanda. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | /// @file 6 | /// Declares interfaces to assembly functions. 7 | 8 | #ifndef HYPERPLATFORM_ASM_H_ 9 | #define HYPERPLATFORM_ASM_H_ 10 | 11 | #include "ia32_type.h" 12 | 13 | extern "C" { 14 | //////////////////////////////////////////////////////////////////////////////// 15 | // 16 | // macro utilities 17 | // 18 | 19 | //////////////////////////////////////////////////////////////////////////////// 20 | // 21 | // constants and macros 22 | // 23 | 24 | //////////////////////////////////////////////////////////////////////////////// 25 | // 26 | // types 27 | // 28 | 29 | //////////////////////////////////////////////////////////////////////////////// 30 | // 31 | // prototypes 32 | // 33 | 34 | /// A wrapper for vm_initialization_routine. 35 | /// @param vm_initialization_routine A function pointer for entering VMX-mode 36 | /// @param context A context parameter for vm_initialization_routine 37 | /// @return true if vm_initialization_routine was successfully executed 38 | bool __stdcall AsmInitializeVm( 39 | _In_ void (*vm_initialization_routine)(_In_ ULONG_PTR, _In_ ULONG_PTR, 40 | _In_opt_ void *), 41 | _In_opt_ void *context); 42 | 43 | /// An entry point of VMM where gets called whenever VM-exit occurred. 44 | void __stdcall AsmVmmEntryPoint(); 45 | 46 | /// Executes VMCALL with the given hypercall number and a context. 47 | /// @param hypercall_number A hypercall number 48 | /// @param context A context parameter for VMCALL 49 | /// @return Equivalent to #VmxStatus 50 | unsigned char __stdcall AsmVmxCall(_In_ ULONG_PTR hypercall_number, 51 | _In_opt_ void *context); 52 | 53 | /// Writes to GDT 54 | /// @param gdtr A value to write 55 | void __stdcall AsmWriteGDT(_In_ const Gdtr *gdtr); 56 | 57 | /// Reads SGDT 58 | /// @param gdtr A pointer to read GDTR 59 | void __stdcall AsmReadGDT(_Out_ Gdtr *gdtr); 60 | 61 | /// Reads SLDT 62 | /// @return LDT 63 | USHORT __stdcall AsmReadLDTR(); 64 | 65 | /// Writes to TR 66 | /// @param task_register A value to write 67 | void __stdcall AsmWriteTR(_In_ USHORT task_register); 68 | 69 | /// Reads STR 70 | /// @return TR 71 | USHORT __stdcall AsmReadTR(); 72 | 73 | /// Writes to ES 74 | /// @param segment_selector A value to write 75 | void __stdcall AsmWriteES(_In_ USHORT segment_selector); 76 | 77 | /// Reads ES 78 | /// @return ES 79 | USHORT __stdcall AsmReadES(); 80 | 81 | /// Writes to CS 82 | /// @param segment_selector A value to write 83 | void __stdcall AsmWriteCS(_In_ USHORT segment_selector); 84 | 85 | /// Reads CS 86 | /// @return CS 87 | USHORT __stdcall AsmReadCS(); 88 | 89 | /// Writes to SS 90 | /// @param segment_selector A value to write 91 | void __stdcall AsmWriteSS(_In_ USHORT segment_selector); 92 | 93 | /// Reads SS 94 | /// @return SS 95 | USHORT __stdcall AsmReadSS(); 96 | 97 | /// Writes to DS 98 | /// @param segment_selector A value to write 99 | void __stdcall AsmWriteDS(_In_ USHORT segment_selector); 100 | 101 | /// Reads DS 102 | /// @return DS 103 | USHORT __stdcall AsmReadDS(); 104 | 105 | /// Writes to FS 106 | /// @param segment_selector A value to write 107 | void __stdcall AsmWriteFS(_In_ USHORT segment_selector); 108 | 109 | /// Reads FS 110 | /// @return FS 111 | USHORT __stdcall AsmReadFS(); 112 | 113 | /// Writes to GS 114 | /// @param segment_selector A value to write 115 | void __stdcall AsmWriteGS(_In_ USHORT segment_selector); 116 | 117 | /// Reads GS 118 | /// @return GS 119 | USHORT __stdcall AsmReadGS(); 120 | 121 | /// Loads access rights byte 122 | /// @param segment_selector A value to get access rights byte 123 | /// @return An access rights byte 124 | ULONG_PTR __stdcall AsmLoadAccessRightsByte(_In_ ULONG_PTR segment_selector); 125 | 126 | /// Invalidates internal caches 127 | void __stdcall AsmInvalidateInternalCaches(); 128 | 129 | /// Writes to CR2 130 | /// @param cr2_value A value to write 131 | void __stdcall AsmWriteCR2(_In_ ULONG_PTR cr2_value); 132 | 133 | /// Invalidates translations derived from EPT 134 | /// @param invept_type A type of invalidation 135 | /// @param invept_descriptor A reference to EPTP to invalidate 136 | /// @return 0 on success, 1 w/ an error code or 2 w/o an error code on failure 137 | unsigned char __stdcall AsmInvept( 138 | _In_ InvEptType invept_type, 139 | _In_ const InvEptDescriptor *invept_descriptor); 140 | 141 | /// Invalidate translations based on VPID 142 | /// @param invvpid_type A type of invalidation 143 | /// @param invvpid_descriptor A description of translations to invalidate 144 | /// @return 0 on success, 1 w/ an error code or 2 w/o an error code on failure 145 | unsigned char __stdcall AsmInvvpid( 146 | _In_ InvVpidType invvpid_type, 147 | _In_ const InvVpidDescriptor *invvpid_descriptor); 148 | 149 | //////////////////////////////////////////////////////////////////////////////// 150 | // 151 | // variables 152 | // 153 | 154 | //////////////////////////////////////////////////////////////////////////////// 155 | // 156 | // implementations 157 | // 158 | 159 | /// Writes to GDT 160 | /// @param gdtr A value to write 161 | inline void __sgdt(_Out_ void *gdtr) { AsmReadGDT(static_cast(gdtr)); } 162 | 163 | /// Reads SGDT 164 | /// @param gdtr A pointer to read GDTR 165 | inline void __lgdt(_In_ void *gdtr) { AsmWriteGDT(static_cast(gdtr)); } 166 | 167 | // Followings are oringal implementations of Microsoft VMX intrinsic functions 168 | // which are not avaiable on x86. 169 | #if defined(_X86_) 170 | 171 | /// Activates virtual machine extensions (VMX) operation in the processor 172 | /// @param vms_support_physical_address A pointer to a 64 bit physical address 173 | /// that points to a virtual machine control structure(VMCS) 174 | /// @return Equivalent to #VmxStatus 175 | inline unsigned char __vmx_on( 176 | _In_ unsigned __int64 *vms_support_physical_address) { 177 | FlagRegister flags = {}; 178 | PHYSICAL_ADDRESS physical_address = {}; 179 | physical_address.QuadPart = *vms_support_physical_address; 180 | __asm { 181 | push physical_address.HighPart 182 | push physical_address.LowPart 183 | 184 | _emit 0xF3 185 | _emit 0x0F 186 | _emit 0xC7 187 | _emit 0x34 188 | _emit 0x24 // VMXON [ESP] 189 | 190 | pushfd 191 | pop flags.all 192 | 193 | add esp, 8 194 | } 195 | if (flags.fields.cf) { 196 | return 2; 197 | } 198 | if (flags.fields.zf) { 199 | return 1; 200 | } 201 | return 0; 202 | } 203 | 204 | /// Initializes the specified VMCS and sets its launch state to Clear 205 | /// @param vmcs_physical_address A pointer to a 64-bit memory location that 206 | /// contains the physical address of the VMCS to clear 207 | /// @return Equivalent to #VmxStatus 208 | inline unsigned char __vmx_vmclear( 209 | _In_ unsigned __int64 *vmcs_physical_address) { 210 | FlagRegister flags = {}; 211 | PHYSICAL_ADDRESS physical_address = {}; 212 | physical_address.QuadPart = *vmcs_physical_address; 213 | __asm { 214 | push physical_address.HighPart 215 | push physical_address.LowPart 216 | 217 | _emit 0x66 218 | _emit 0x0F 219 | _emit 0xc7 220 | _emit 0x34 221 | _emit 0x24 // VMCLEAR [ESP] 222 | 223 | pushfd 224 | pop flags.all 225 | 226 | add esp, 8 227 | } 228 | if (flags.fields.cf) { 229 | return 2; 230 | } 231 | if (flags.fields.zf) { 232 | return 1; 233 | } 234 | return 0; 235 | } 236 | 237 | /// Places the calling application in VMX non-root operation state (VM enter) 238 | /// @return Equivalent to #VmxStatus 239 | inline unsigned char __vmx_vmlaunch() { 240 | FlagRegister flags = {}; 241 | __asm { 242 | _emit 0x0f 243 | _emit 0x01 244 | _emit 0xc2 // VMLAUNCH 245 | 246 | pushfd 247 | pop flags.all 248 | } 249 | if (flags.fields.cf) { 250 | return 2; 251 | } 252 | if (flags.fields.zf) { 253 | return 1; 254 | } 255 | /* UNREACHABLE */ 256 | return 0; 257 | } 258 | 259 | /// Loads the pointer to the current VMCS from the specified address 260 | /// @param vmcs_physical_address The address where the VMCS pointer is stored 261 | /// @return Equivalent to #VmxStatus 262 | inline unsigned char __vmx_vmptrld( 263 | _In_ unsigned __int64 *vmcs_physical_address) { 264 | FlagRegister flags = {}; 265 | PHYSICAL_ADDRESS physical_address = {}; 266 | physical_address.QuadPart = *vmcs_physical_address; 267 | __asm { 268 | push physical_address.HighPart 269 | push physical_address.LowPart 270 | 271 | _emit 0x0F 272 | _emit 0xC7 273 | _emit 0x34 274 | _emit 0x24 // VMPTRLD [ESP] 275 | 276 | pushfd 277 | pop flags.all 278 | 279 | add esp, 8 280 | } 281 | if (flags.fields.cf) { 282 | return 2; 283 | } 284 | if (flags.fields.zf) { 285 | return 1; 286 | } 287 | return 0; 288 | } 289 | 290 | /// Reads a specified field from the current VMCS 291 | /// @param field The VMCS field to read 292 | /// @param field_value A pointer to the location to store the value read from 293 | /// the VMCS field specified by the Field parameter 294 | /// @return Equivalent to #VmxStatus 295 | inline unsigned char __vmx_vmread(_In_ size_t field, 296 | _Out_ size_t *field_value) { 297 | FlagRegister flags = {}; 298 | __asm { 299 | pushad 300 | mov eax, field 301 | 302 | _emit 0x0F 303 | _emit 0x78 304 | _emit 0xC3 // VMREAD EBX, EAX 305 | 306 | pushfd 307 | pop flags.all 308 | 309 | mov eax, field_value 310 | mov [eax], ebx 311 | popad 312 | } 313 | if (flags.fields.cf) { 314 | return 2; 315 | } 316 | if (flags.fields.zf) { 317 | return 1; 318 | } 319 | return 0; 320 | } 321 | 322 | /// Writes the specified value to the specified field in the current VMCS 323 | /// @param field The VMCS field to write 324 | /// @param field_value The value to write to the VMCS field 325 | /// @return Equivalent to #VmxStatus 326 | inline unsigned char __vmx_vmwrite(_In_ size_t field, _In_ size_t field_value) { 327 | FlagRegister flags = {}; 328 | __asm { 329 | pushad 330 | push field_value 331 | mov eax, field 332 | 333 | _emit 0x0F 334 | _emit 0x79 335 | _emit 0x04 336 | _emit 0x24 // VMWRITE EAX, [ESP] 337 | 338 | pushfd 339 | pop flags.all 340 | 341 | add esp, 4 342 | popad 343 | } 344 | if (flags.fields.cf) { 345 | return 2; 346 | } 347 | if (flags.fields.zf) { 348 | return 1; 349 | } 350 | return 0; 351 | } 352 | 353 | #endif 354 | 355 | } // extern "C" 356 | 357 | #endif // HYPERPLATFORM_ASM_H_ 358 | -------------------------------------------------------------------------------- /HyperPlatform/HyperPlatform/common.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2017, Satoshi Tanda. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | /// @file 6 | /// Declares and implements common things across the project 7 | 8 | /// @mainpage 9 | /// @section whats About 10 | /// These pages serve as a programmer's reference manual for HyperPlatform and 11 | /// were automatically generated from the source using Doxygen. 12 | /// 13 | /// For compilation and installation of HyperPlatform, see the HyperPlatform 14 | /// project page. For more general information about development using 15 | /// HyperPlatform, see User's Documents in the project page. 16 | /// @li https://github.com/tandasat/HyperPlatform 17 | /// 18 | /// Some of good places to start are the files page that provides a brief 19 | /// description of each files, the DriverEntry() function where is an entry 20 | /// point 21 | /// of HyperPlatform, and the VmmVmExitHandler() function, a high-level entry 22 | /// point of VM-exit handlers. 23 | /// 24 | /// @subsection links External Document 25 | /// This document often refers to the Intel 64 and IA-32 Architectures Software 26 | /// Developer Manuals (Intel SDM). Any descriptions like 27 | /// "See: CONTROL REGISTERS" implies that details are explained in a page or a 28 | /// table titled as "CONTROL REGISTERS" in the Intel SDM. 29 | /// @li 30 | /// http://www.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html 31 | /// 32 | /// @copyright Use of this source code is governed by a MIT-style license that 33 | /// can be found in the LICENSE file. 34 | 35 | #ifndef HYPERPLATFORM_COMMON_H_ 36 | #define HYPERPLATFORM_COMMON_H_ 37 | 38 | #include 39 | 40 | // C30030: Calling a memory allocating function and passing a parameter that 41 | // indicates executable memory 42 | // 43 | // Disable C30030 since POOL_NX_OPTIN + ExInitializeDriverRuntime is in place. 44 | // This warning is false positive and can be seen when Target Platform Version 45 | // equals to 10.0.14393.0. 46 | #pragma prefast(disable : 30030) 47 | 48 | //////////////////////////////////////////////////////////////////////////////// 49 | // 50 | // macro utilities 51 | // 52 | 53 | /// Sets a break point that works only when a debugger is present 54 | #if !defined(HYPERPLATFORM_COMMON_DBG_BREAK) 55 | #define HYPERPLATFORM_COMMON_DBG_BREAK() \ 56 | if (KD_DEBUGGER_NOT_PRESENT) { \ 57 | } else { \ 58 | __debugbreak(); \ 59 | } \ 60 | reinterpret_cast(0) 61 | #endif 62 | 63 | /// Issues a bug check 64 | /// @param hp_bug_check_code Type of a bug 65 | /// @param param1 1st parameter for KeBugCheckEx() 66 | /// @param param2 2nd parameter for KeBugCheckEx() 67 | /// @param param3 3rd parameter for KeBugCheckEx() 68 | #if !defined(HYPERPLATFORM_COMMON_BUG_CHECK) 69 | #define HYPERPLATFORM_COMMON_BUG_CHECK(hp_bug_check_code, param1, param2, \ 70 | param3) \ 71 | HYPERPLATFORM_COMMON_DBG_BREAK(); \ 72 | const HyperPlatformBugCheck code = (hp_bug_check_code); \ 73 | KeBugCheckEx(MANUALLY_INITIATED_CRASH, static_cast(code), (param1), \ 74 | (param2), (param3)) 75 | #endif 76 | 77 | //////////////////////////////////////////////////////////////////////////////// 78 | // 79 | // constants and macros 80 | // 81 | 82 | /// Enable or disable performance monitoring globally 83 | /// 84 | /// Enables #HYPERPLATFORM_PERFORMANCE_MEASURE_THIS_SCOPE() which measures 85 | /// an elapsed time of the scope when set to non 0. Enabling it introduces 86 | /// negative performance impact. 87 | #define HYPERPLATFORM_PERFORMANCE_ENABLE_PERFCOUNTER 1 88 | 89 | /// A pool tag 90 | static const ULONG kHyperPlatformCommonPoolTag = 'PpyH'; 91 | 92 | //////////////////////////////////////////////////////////////////////////////// 93 | // 94 | // types 95 | // 96 | 97 | /// BugCheck codes for #HYPERPLATFORM_COMMON_BUG_CHECK(). 98 | enum class HyperPlatformBugCheck : ULONG { 99 | kUnspecified, //!< An unspecified bug occurred 100 | kUnexpectedVmExit, //!< An unexpected VM-exit occurred 101 | kTripleFaultVmExit, //!< A triple fault VM-exit occurred 102 | kExhaustedPreallocatedEntries, //!< All pre-allocated entries are used 103 | kCriticalVmxInstructionFailure, //!< VMRESUME or VMXOFF has failed 104 | kEptMisconfigVmExit, //!< EPT misconfiguration VM-exit occurred 105 | kCritialPoolAllocationFailure, //!< Critical pool allocation failed 106 | }; 107 | 108 | //////////////////////////////////////////////////////////////////////////////// 109 | // 110 | // prototypes 111 | // 112 | 113 | //////////////////////////////////////////////////////////////////////////////// 114 | // 115 | // variables 116 | // 117 | 118 | //////////////////////////////////////////////////////////////////////////////// 119 | // 120 | // implementations 121 | // 122 | 123 | /// Checks if a system is x64 124 | /// @return true if a system is x64 125 | constexpr bool IsX64() { 126 | #if defined(_AMD64_) 127 | return true; 128 | #else 129 | return false; 130 | #endif 131 | } 132 | 133 | /// Checks if the project is compiled as Release 134 | /// @return true if the project is compiled as Release 135 | constexpr bool IsReleaseBuild() { 136 | #if defined(DBG) 137 | return false; 138 | #else 139 | return true; 140 | #endif 141 | } 142 | 143 | #endif // HYPERPLATFORM_COMMON_H_ 144 | -------------------------------------------------------------------------------- /HyperPlatform/HyperPlatform/driver.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2017, Satoshi Tanda. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | /// @file 6 | /// Implements an entry point of the driver. 7 | 8 | #ifndef POOL_NX_OPTIN 9 | #define POOL_NX_OPTIN 1 10 | #endif 11 | #include "driver.h" 12 | #include "common.h" 13 | #include "global_object.h" 14 | #include "hotplug_callback.h" 15 | #include "log.h" 16 | #include "power_callback.h" 17 | #include "util.h" 18 | #include "vm.h" 19 | #include "performance.h" 20 | 21 | #include "../../FU_Hypervisor/FU_Hypervisor.h" 22 | 23 | extern "C" { 24 | //////////////////////////////////////////////////////////////////////////////// 25 | // 26 | // macro utilities 27 | // 28 | 29 | //////////////////////////////////////////////////////////////////////////////// 30 | // 31 | // constants and macros 32 | // 33 | 34 | //////////////////////////////////////////////////////////////////////////////// 35 | // 36 | // types 37 | // 38 | 39 | //////////////////////////////////////////////////////////////////////////////// 40 | // 41 | // prototypes 42 | // 43 | 44 | DRIVER_INITIALIZE DriverEntry; 45 | 46 | static DRIVER_UNLOAD DriverpDriverUnload; 47 | 48 | _IRQL_requires_max_(PASSIVE_LEVEL) bool DriverpIsSuppoetedOS(); 49 | 50 | #if defined(ALLOC_PRAGMA) 51 | #pragma alloc_text(INIT, DriverEntry) 52 | #pragma alloc_text(PAGE, DriverpDriverUnload) 53 | #pragma alloc_text(INIT, DriverpIsSuppoetedOS) 54 | #endif 55 | 56 | 57 | //////////////////////////////////////////////////////////////////////////////// 58 | // 59 | // implementations 60 | // 61 | 62 | // A driver entry point 63 | _Use_decl_annotations_ NTSTATUS DriverEntry(PDRIVER_OBJECT driver_object, 64 | PUNICODE_STRING registry_path) { 65 | UNREFERENCED_PARAMETER(registry_path); 66 | PAGED_CODE(); 67 | 68 | 69 | 70 | static const wchar_t kLogFilePath[] = L"\\SystemRoot\\mydri.log"; 71 | static const auto kLogLevel = 72 | (IsReleaseBuild()) ? kLogPutLevelInfo | kLogOptDisableFunctionName 73 | : kLogPutLevelDebug | kLogOptDisableFunctionName; 74 | 75 | auto status = STATUS_UNSUCCESSFUL; 76 | driver_object->DriverUnload = DriverpDriverUnload; 77 | HYPERPLATFORM_COMMON_DBG_BREAK(); 78 | 79 | /* pDriverObject = driver_object; 80 | HideDriver(driver_object);*/ 81 | 82 | // Request NX Non-Paged Pool when available 83 | ExInitializeDriverRuntime(DrvRtPoolNxOptIn); 84 | 85 | // Initialize log functions 86 | bool need_reinitialization = false; 87 | status = LogInitialization(kLogLevel, kLogFilePath); 88 | if (status == STATUS_REINITIALIZATION_NEEDED) { 89 | need_reinitialization = true; 90 | } else if (!NT_SUCCESS(status)) { 91 | return status; 92 | } 93 | 94 | // Test if the system is supported 95 | if (!DriverpIsSuppoetedOS()) { 96 | LogTermination(); 97 | return STATUS_CANCELLED; 98 | } 99 | 100 | // Initialize global variables 101 | status = GlobalObjectInitialization(); 102 | if (!NT_SUCCESS(status)) { 103 | LogTermination(); 104 | return status; 105 | } 106 | 107 | // Initialize perf functions 108 | status = PerfInitialization(); 109 | if (!NT_SUCCESS(status)) { 110 | GlobalObjectTermination(); 111 | LogTermination(); 112 | return status; 113 | } 114 | 115 | // Initialize utility functions 116 | status = UtilInitialization(driver_object); 117 | if (!NT_SUCCESS(status)) { 118 | PerfTermination(); 119 | GlobalObjectTermination(); 120 | LogTermination(); 121 | return status; 122 | } 123 | 124 | // Initialize power callback 125 | status = PowerCallbackInitialization(); 126 | if (!NT_SUCCESS(status)) { 127 | UtilTermination(); 128 | PerfTermination(); 129 | GlobalObjectTermination(); 130 | LogTermination(); 131 | return status; 132 | } 133 | 134 | // Initialize hot-plug callback 135 | status = HotplugCallbackInitialization(); 136 | if (!NT_SUCCESS(status)) { 137 | PowerCallbackTermination(); 138 | UtilTermination(); 139 | PerfTermination(); 140 | GlobalObjectTermination(); 141 | LogTermination(); 142 | return status; 143 | } 144 | 145 | //Virtualize all processors 146 | status = VmInitialization(); 147 | if (!NT_SUCCESS(status)) { 148 | HotplugCallbackTermination(); 149 | PowerCallbackTermination(); 150 | UtilTermination(); 151 | PerfTermination(); 152 | GlobalObjectTermination(); 153 | LogTermination(); 154 | return status; 155 | } 156 | 157 | // Initialize FU components 158 | status = FuInitialization(); 159 | if (!NT_SUCCESS(status)) { 160 | VmTermination(); 161 | UtilTermination(); 162 | PerfTermination(); 163 | GlobalObjectTermination(); 164 | LogTermination(); 165 | return status; 166 | } 167 | 168 | // Register re-initialization for the log functions if needed 169 | if (need_reinitialization) { 170 | LogRegisterReinitialization(driver_object); 171 | } 172 | 173 | HYPERPLATFORM_LOG_INFO("The VMM has been installed."); 174 | return status; 175 | } 176 | 177 | // Unload handler 178 | _Use_decl_annotations_ static void DriverpDriverUnload( 179 | PDRIVER_OBJECT driver_object) { 180 | UNREFERENCED_PARAMETER(driver_object); 181 | PAGED_CODE(); 182 | 183 | HYPERPLATFORM_COMMON_DBG_BREAK(); 184 | 185 | FuTermination(); 186 | VmTermination(); 187 | HotplugCallbackTermination(); 188 | PowerCallbackTermination(); 189 | UtilTermination(); 190 | PerfTermination(); 191 | GlobalObjectTermination(); 192 | LogTermination(); 193 | } 194 | 195 | // Test if the system is one of supported OS versions 196 | _Use_decl_annotations_ bool DriverpIsSuppoetedOS() { 197 | PAGED_CODE(); 198 | 199 | RTL_OSVERSIONINFOW os_version = {}; 200 | auto status = RtlGetVersion(&os_version); 201 | if (!NT_SUCCESS(status)) { 202 | return false; 203 | } 204 | if (os_version.dwMajorVersion != 6 && os_version.dwMajorVersion != 10) { 205 | return false; 206 | } 207 | // 4-gigabyte tuning (4GT) should not be enabled 208 | if (!IsX64() && 209 | reinterpret_cast(MmSystemRangeStart) != 0x80000000) { 210 | return false; 211 | } 212 | return true; 213 | } 214 | 215 | } // extern "C" 216 | -------------------------------------------------------------------------------- /HyperPlatform/HyperPlatform/driver.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2017, Satoshi Tanda. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | /// @file 6 | /// @brief Declares interfaces to driver functions. 7 | 8 | #ifndef HYPERPLATFORM_DRIVER_H_ 9 | #define HYPERPLATFORM_DRIVER_H_ 10 | 11 | extern "C" { 12 | //////////////////////////////////////////////////////////////////////////////// 13 | // 14 | // macro utilities 15 | // 16 | 17 | //////////////////////////////////////////////////////////////////////////////// 18 | // 19 | // constants and macros 20 | // 21 | 22 | //////////////////////////////////////////////////////////////////////////////// 23 | // 24 | // types 25 | // 26 | 27 | //////////////////////////////////////////////////////////////////////////////// 28 | // 29 | // prototypes 30 | // 31 | 32 | //////////////////////////////////////////////////////////////////////////////// 33 | // 34 | // variables 35 | // 36 | 37 | //////////////////////////////////////////////////////////////////////////////// 38 | // 39 | // implementations 40 | // 41 | 42 | } // extern "C" 43 | 44 | #endif // HYPERPLATFORM_DRIVER_H_ 45 | -------------------------------------------------------------------------------- /HyperPlatform/HyperPlatform/ept.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2017, Satoshi Tanda. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | /// @file 6 | /// Declares interfaces to EPT functions. 7 | 8 | #ifndef HYPERPLATFORM_EPT_H_ 9 | #define HYPERPLATFORM_EPT_H_ 10 | 11 | #include 12 | 13 | extern "C" { 14 | //////////////////////////////////////////////////////////////////////////////// 15 | // 16 | // macro utilities 17 | // 18 | 19 | //////////////////////////////////////////////////////////////////////////////// 20 | // 21 | // constants and macros 22 | // 23 | 24 | //////////////////////////////////////////////////////////////////////////////// 25 | // 26 | // types 27 | // 28 | 29 | struct EptData; 30 | struct ProcessorFakePageData; 31 | struct SharedFakePageData; 32 | 33 | /// A structure made up of mutual fields across all EPT entry types 34 | union EptCommonEntry { 35 | ULONG64 all; 36 | struct { 37 | ULONG64 read_access : 1; //!< [0] 38 | ULONG64 write_access : 1; //!< [1] 39 | ULONG64 execute_access : 1; //!< [2] 40 | ULONG64 memory_type : 3; //!< [3:5] 41 | ULONG64 reserved1 : 6; //!< [6:11] 42 | ULONG64 physial_address : 36; //!< [12:48-1] 43 | ULONG64 reserved2 : 16; //!< [48:63] 44 | } fields; 45 | }; 46 | static_assert(sizeof(EptCommonEntry) == 8, "Size check"); 47 | 48 | //////////////////////////////////////////////////////////////////////////////// 49 | // 50 | // prototypes 51 | // 52 | 53 | /// Checks if the system supports EPT technology sufficient enough 54 | /// @return true if the system supports EPT 55 | _IRQL_requires_max_(PASSIVE_LEVEL) bool EptIsEptAvailable(); 56 | 57 | /// Returns an EPT pointer from \a ept_data 58 | /// @param ept_data EptData to get an EPT pointer 59 | /// @return An EPT pointer 60 | ULONG64 EptGetEptPointer(_In_ EptData* ept_data); 61 | 62 | /// Reads and stores all MTRRs to set a correct memory type for EPT 63 | _IRQL_requires_max_(PASSIVE_LEVEL) void EptInitializeMtrrEntries(); 64 | 65 | /// Builds EPT, allocates pre-allocated entires, initializes and returns EptData 66 | /// @return An allocated EptData on success, or nullptr 67 | /// 68 | /// A driver must call EptTermination() with a returned value when this function 69 | /// succeeded. 70 | _IRQL_requires_max_(PASSIVE_LEVEL) EptData* EptInitialization(); 71 | 72 | /// De-allocates \a ept_data and all resources referenced in it 73 | /// @param ept_data A returned value of EptInitialization() 74 | void EptTermination(_In_ EptData* ept_data); 75 | 76 | /// Handles VM-exit triggered by EPT violation 77 | /// @param ept_data EptData to get an EPT pointer 78 | _IRQL_requires_min_(DISPATCH_LEVEL) void EptHandleEptViolation( 79 | _In_ EptData* ept_data, _In_ ProcessorFakePageData* fp_data, 80 | _In_ SharedFakePageData* shared_fp_data); 81 | 82 | /// Returns an EPT entry corresponds to \a physical_address 83 | /// @param ept_data EptData to get an EPT entry 84 | /// @param physical_address Physical address to get an EPT entry 85 | /// @return An EPT entry, or nullptr if not allocated yet 86 | EptCommonEntry* EptGetEptPtEntry(_In_ EptData* ept_data, 87 | _In_ ULONG64 physical_address); 88 | 89 | //////////////////////////////////////////////////////////////////////////////// 90 | // 91 | // variables 92 | // 93 | 94 | //////////////////////////////////////////////////////////////////////////////// 95 | // 96 | // implementations 97 | // 98 | 99 | } // extern "C" 100 | 101 | #endif // HYPERPLATFORM_EPT_H_ 102 | -------------------------------------------------------------------------------- /HyperPlatform/HyperPlatform/global_object.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2017, Satoshi Tanda. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | /// @file 6 | /// Implements global object functions. 7 | 8 | #include "global_object.h" 9 | 10 | // .CRT section is required to invoke ctors and dtors. This pragma embeds a .CRT 11 | // section into the .rdata section. Or else, a LNK warning would be raised. 12 | #pragma comment(linker, "/merge:.CRT=.rdata") 13 | 14 | // Create two sections that are used by MSVC to place an array of ctors at a 15 | // compile time. It is important to be ordered in alphabetical order. 16 | #pragma section(".CRT$XCA", read) 17 | #pragma section(".CRT$XCZ", read) 18 | 19 | extern "C" { 20 | //////////////////////////////////////////////////////////////////////////////// 21 | // 22 | // macro utilities 23 | // 24 | 25 | //////////////////////////////////////////////////////////////////////////////// 26 | // 27 | // constants and macros 28 | // 29 | 30 | /// A pool tag for this module 31 | static const ULONG kGlobalObjectpPoolTag = 'jbOG'; 32 | 33 | //////////////////////////////////////////////////////////////////////////////// 34 | // 35 | // types 36 | // 37 | 38 | using Destructor = void(__cdecl *)(); 39 | 40 | struct DestructorEntry { 41 | Destructor dtor; 42 | SINGLE_LIST_ENTRY list_entry; 43 | }; 44 | 45 | //////////////////////////////////////////////////////////////////////////////// 46 | // 47 | // prototypes 48 | // 49 | 50 | #if defined(ALLOC_PRAGMA) 51 | #pragma alloc_text(INIT, GlobalObjectInitialization) 52 | #pragma alloc_text(INIT, atexit) 53 | #pragma alloc_text(PAGE, GlobalObjectTermination) 54 | #endif 55 | 56 | //////////////////////////////////////////////////////////////////////////////// 57 | // 58 | // variables 59 | // 60 | 61 | // Place markers pointing to the beginning and end of the ctors arrays embedded 62 | // by MSVC. 63 | __declspec(allocate(".CRT$XCA")) static Destructor g_gop_ctors_begin[1] = {}; 64 | __declspec(allocate(".CRT$XCZ")) static Destructor g_gop_ctors_end[1] = {}; 65 | 66 | // Stores pointers to dtors to be called at the exit. 67 | static SINGLE_LIST_ENTRY g_gop_dtors_list_head = {}; 68 | 69 | //////////////////////////////////////////////////////////////////////////////// 70 | // 71 | // implementations 72 | // 73 | 74 | // Calls all constructors and register all destructor 75 | _Use_decl_annotations_ NTSTATUS GlobalObjectInitialization() { 76 | PAGED_CODE(); 77 | 78 | // Call all constructors 79 | for (auto ctor = g_gop_ctors_begin + 1; ctor < g_gop_ctors_end; ++ctor) { 80 | (*ctor)(); 81 | } 82 | return STATUS_SUCCESS; 83 | } 84 | 85 | // Calls all registered destructors 86 | _Use_decl_annotations_ void GlobalObjectTermination() { 87 | PAGED_CODE(); 88 | 89 | auto entry = PopEntryList(&g_gop_dtors_list_head); 90 | while (entry) { 91 | const auto element = CONTAINING_RECORD(entry, DestructorEntry, list_entry); 92 | element->dtor(); 93 | ExFreePoolWithTag(element, kGlobalObjectpPoolTag); 94 | entry = PopEntryList(&g_gop_dtors_list_head); 95 | } 96 | } 97 | 98 | // Registers destructor; this is called through a call to constructor 99 | _IRQL_requires_max_(PASSIVE_LEVEL) int __cdecl atexit(_In_ Destructor dtor) { 100 | PAGED_CODE(); 101 | 102 | const auto element = 103 | reinterpret_cast(ExAllocatePoolWithTag( 104 | PagedPool, sizeof(DestructorEntry), kGlobalObjectpPoolTag)); 105 | if (!element) { 106 | return 1; 107 | } 108 | element->dtor = dtor; 109 | PushEntryList(&g_gop_dtors_list_head, &element->list_entry); 110 | return 0; 111 | } 112 | 113 | } // extern "C" 114 | -------------------------------------------------------------------------------- /HyperPlatform/HyperPlatform/global_object.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2017, Satoshi Tanda. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | /// @file 6 | /// Declares interfaces to global object functions. 7 | 8 | #ifndef HYPERPLATFORM_GLOBAL_OBJECT_H_ 9 | #define HYPERPLATFORM_GLOBAL_OBJECT_H_ 10 | 11 | #include 12 | 13 | extern "C" { 14 | //////////////////////////////////////////////////////////////////////////////// 15 | // 16 | // macro utilities 17 | // 18 | 19 | //////////////////////////////////////////////////////////////////////////////// 20 | // 21 | // constants and macros 22 | // 23 | 24 | //////////////////////////////////////////////////////////////////////////////// 25 | // 26 | // types 27 | // 28 | 29 | //////////////////////////////////////////////////////////////////////////////// 30 | // 31 | // prototypes 32 | // 33 | 34 | /// Calls all constructors and register all destructor 35 | /// @return STATUS_SUCCESS on success 36 | _IRQL_requires_max_(PASSIVE_LEVEL) NTSTATUS GlobalObjectInitialization(); 37 | 38 | /// Calls all destructors 39 | _IRQL_requires_max_(PASSIVE_LEVEL) void GlobalObjectTermination(); 40 | 41 | //////////////////////////////////////////////////////////////////////////////// 42 | // 43 | // variables 44 | // 45 | 46 | //////////////////////////////////////////////////////////////////////////////// 47 | // 48 | // implementations 49 | // 50 | 51 | } // extern "C" 52 | 53 | #endif // HYPERPLATFORM_GLOBAL_OBJECT_H_ 54 | -------------------------------------------------------------------------------- /HyperPlatform/HyperPlatform/hotplug_callback.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2017, Satoshi Tanda. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | /// @file 6 | /// Implements hot-plug callback functions. 7 | 8 | #include "hotplug_callback.h" 9 | #include "common.h" 10 | #include "log.h" 11 | #include "vm.h" 12 | 13 | extern "C" { 14 | //////////////////////////////////////////////////////////////////////////////// 15 | // 16 | // macro utilities 17 | // 18 | 19 | //////////////////////////////////////////////////////////////////////////////// 20 | // 21 | // constants and macros 22 | // 23 | 24 | //////////////////////////////////////////////////////////////////////////////// 25 | // 26 | // types 27 | // 28 | 29 | //////////////////////////////////////////////////////////////////////////////// 30 | // 31 | // prototypes 32 | // 33 | 34 | static PROCESSOR_CALLBACK_FUNCTION HotplugCallbackpCallbackRoutine; 35 | 36 | #if defined(ALLOC_PRAGMA) 37 | #pragma alloc_text(INIT, HotplugCallbackInitialization) 38 | #pragma alloc_text(PAGE, HotplugCallbackTermination) 39 | #pragma alloc_text(PAGE, HotplugCallbackpCallbackRoutine) 40 | #endif 41 | 42 | //////////////////////////////////////////////////////////////////////////////// 43 | // 44 | // variables 45 | // 46 | 47 | static PVOID g_hpp_callback_handle = nullptr; 48 | 49 | //////////////////////////////////////////////////////////////////////////////// 50 | // 51 | // implementations 52 | // 53 | 54 | // Registers power callback 55 | _Use_decl_annotations_ NTSTATUS HotplugCallbackInitialization() { 56 | PAGED_CODE(); 57 | 58 | auto callback_handle = KeRegisterProcessorChangeCallback( 59 | HotplugCallbackpCallbackRoutine, nullptr, 0); 60 | if (!callback_handle) { 61 | return STATUS_UNSUCCESSFUL; 62 | } 63 | 64 | g_hpp_callback_handle = callback_handle; 65 | return STATUS_SUCCESS; 66 | } 67 | 68 | // Unregister power callback 69 | _Use_decl_annotations_ void HotplugCallbackTermination() { 70 | PAGED_CODE(); 71 | 72 | if (g_hpp_callback_handle) { 73 | KeDeregisterProcessorChangeCallback(g_hpp_callback_handle); 74 | } 75 | } 76 | 77 | _Use_decl_annotations_ static void HotplugCallbackpCallbackRoutine( 78 | PVOID callback_context, PKE_PROCESSOR_CHANGE_NOTIFY_CONTEXT change_context, 79 | PNTSTATUS operation_status) { 80 | PAGED_CODE(); 81 | UNREFERENCED_PARAMETER(callback_context); 82 | UNREFERENCED_PARAMETER(operation_status); 83 | 84 | if (change_context->State != KeProcessorAddCompleteNotify) { 85 | return; 86 | } 87 | 88 | HYPERPLATFORM_LOG_DEBUG("A new processor %hu:%hu has been added.", 89 | change_context->ProcNumber.Group, 90 | change_context->ProcNumber.Number); 91 | HYPERPLATFORM_COMMON_DBG_BREAK(); 92 | 93 | auto status = VmHotplugCallback(change_context->ProcNumber); 94 | if (!NT_SUCCESS(status)) { 95 | HYPERPLATFORM_LOG_ERROR("Failed to virtualize the new processors."); 96 | } 97 | } 98 | 99 | } // extern "C" 100 | -------------------------------------------------------------------------------- /HyperPlatform/HyperPlatform/hotplug_callback.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2017, Satoshi Tanda. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | /// @file 6 | /// @brief Declares interfaces to hot-plug functions. 7 | 8 | #ifndef HYPERPLATFORM_HOTPLUG_CALLBACK_H_ 9 | #define HYPERPLATFORM_HOTPLUG_CALLBACK_H_ 10 | 11 | #include 12 | 13 | extern "C" { 14 | //////////////////////////////////////////////////////////////////////////////// 15 | // 16 | // macro utilities 17 | // 18 | 19 | //////////////////////////////////////////////////////////////////////////////// 20 | // 21 | // constants and macros 22 | // 23 | 24 | //////////////////////////////////////////////////////////////////////////////// 25 | // 26 | // types 27 | // 28 | 29 | //////////////////////////////////////////////////////////////////////////////// 30 | // 31 | // prototypes 32 | // 33 | 34 | _IRQL_requires_max_(PASSIVE_LEVEL) NTSTATUS HotplugCallbackInitialization(); 35 | 36 | _IRQL_requires_max_(PASSIVE_LEVEL) void HotplugCallbackTermination(); 37 | 38 | //////////////////////////////////////////////////////////////////////////////// 39 | // 40 | // variables 41 | // 42 | 43 | //////////////////////////////////////////////////////////////////////////////// 44 | // 45 | // implementations 46 | // 47 | 48 | } // extern "C" 49 | 50 | #endif // HYPERPLATFORM_HOTPLUG_CALLBACK_H_ 51 | -------------------------------------------------------------------------------- /HyperPlatform/HyperPlatform/kernel_stl.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2017, Satoshi Tanda. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | /// @file 6 | /// Implements code to use STL in a driver project 7 | 8 | #include 9 | #undef _HAS_EXCEPTIONS 10 | #define _HAS_EXCEPTIONS 0 11 | 12 | // See common.h for details 13 | #pragma prefast(disable : 30030) 14 | 15 | //////////////////////////////////////////////////////////////////////////////// 16 | // 17 | // macro utilities 18 | // 19 | 20 | //////////////////////////////////////////////////////////////////////////////// 21 | // 22 | // constants and macros 23 | // 24 | 25 | /// A pool tag for this module 26 | static const ULONG kKstlpPoolTag = 'LTSK'; 27 | 28 | //////////////////////////////////////////////////////////////////////////////// 29 | // 30 | // types 31 | // 32 | 33 | //////////////////////////////////////////////////////////////////////////////// 34 | // 35 | // prototypes 36 | // 37 | 38 | //////////////////////////////////////////////////////////////////////////////// 39 | // 40 | // variables 41 | // 42 | 43 | //////////////////////////////////////////////////////////////////////////////// 44 | // 45 | // implementations 46 | // 47 | 48 | // An alternative implementation of a C++ exception handler. Issues a bug check. 49 | DECLSPEC_NORETURN static void KernelStlpRaiseException( 50 | _In_ ULONG bug_check_code) { 51 | KdBreakPoint(); 52 | #pragma warning(push) 53 | #pragma warning(disable : 28159) 54 | KeBugCheck(bug_check_code); 55 | #pragma warning(pop) 56 | } 57 | 58 | DECLSPEC_NORETURN void __cdecl _invalid_parameter_noinfo_noreturn() { 59 | KernelStlpRaiseException(KMODE_EXCEPTION_NOT_HANDLED); 60 | } 61 | 62 | namespace std { 63 | 64 | DECLSPEC_NORETURN void __cdecl _Xbad_alloc() { 65 | KernelStlpRaiseException(KMODE_EXCEPTION_NOT_HANDLED); 66 | } 67 | DECLSPEC_NORETURN void __cdecl _Xinvalid_argument(_In_z_ const char *) { 68 | KernelStlpRaiseException(KMODE_EXCEPTION_NOT_HANDLED); 69 | } 70 | DECLSPEC_NORETURN void __cdecl _Xlength_error(_In_z_ const char *) { 71 | KernelStlpRaiseException(KMODE_EXCEPTION_NOT_HANDLED); 72 | } 73 | DECLSPEC_NORETURN void __cdecl _Xout_of_range(_In_z_ const char *) { 74 | KernelStlpRaiseException(KMODE_EXCEPTION_NOT_HANDLED); 75 | } 76 | DECLSPEC_NORETURN void __cdecl _Xoverflow_error(_In_z_ const char *) { 77 | KernelStlpRaiseException(KMODE_EXCEPTION_NOT_HANDLED); 78 | } 79 | DECLSPEC_NORETURN void __cdecl _Xruntime_error(_In_z_ const char *) { 80 | KernelStlpRaiseException(KMODE_EXCEPTION_NOT_HANDLED); 81 | } 82 | 83 | } // namespace std 84 | 85 | // An alternative implementation of the new operator 86 | _IRQL_requires_max_(DISPATCH_LEVEL) void *__cdecl operator new( 87 | _In_ size_t size) { 88 | if (size == 0) { 89 | size = 1; 90 | } 91 | 92 | const auto p = ExAllocatePoolWithTag(NonPagedPool, size, kKstlpPoolTag); 93 | if (!p) { 94 | KernelStlpRaiseException(MUST_SUCCEED_POOL_EMPTY); 95 | } 96 | return p; 97 | } 98 | 99 | // An alternative implementation of the new operator 100 | _IRQL_requires_max_(DISPATCH_LEVEL) void __cdecl operator delete(_In_ void *p) { 101 | if (p) { 102 | ExFreePoolWithTag(p, kKstlpPoolTag); 103 | } 104 | } 105 | 106 | // An alternative implementation of the new operator 107 | _IRQL_requires_max_(DISPATCH_LEVEL) void __cdecl operator delete( 108 | _In_ void *p, _In_ size_t size) { 109 | UNREFERENCED_PARAMETER(size); 110 | if (p) { 111 | ExFreePoolWithTag(p, kKstlpPoolTag); 112 | } 113 | } 114 | 115 | // An alternative implementation of __stdio_common_vsprintf_s 116 | _Success_(return >= 0) EXTERN_C inline int __cdecl __stdio_common_vsprintf_s( 117 | _In_ unsigned __int64 _Options, _Out_writes_z_(_BufferCount) char *_Buffer, 118 | _In_ size_t _BufferCount, 119 | _In_z_ _Printf_format_string_params_(2) char const *_Format, 120 | _In_opt_ _locale_t _Locale, va_list _ArgList) { 121 | UNREFERENCED_PARAMETER(_Options); 122 | UNREFERENCED_PARAMETER(_Locale); 123 | 124 | // Calls _vsnprintf exported by ntoskrnl 125 | using _vsnprintf_type = int __cdecl(char *, size_t, const char *, va_list); 126 | static _vsnprintf_type *local__vsnprintf = nullptr; 127 | if (!local__vsnprintf) { 128 | UNICODE_STRING proc_name_U = {}; 129 | RtlInitUnicodeString(&proc_name_U, L"_vsnprintf"); 130 | local__vsnprintf = reinterpret_cast<_vsnprintf_type *>( 131 | MmGetSystemRoutineAddress(&proc_name_U)); 132 | } 133 | 134 | return local__vsnprintf(_Buffer, _BufferCount, _Format, _ArgList); 135 | } 136 | 137 | // An alternative implementation of __stdio_common_vswprintf_s 138 | _Success_(return >= 0) _Check_return_opt_ EXTERN_C 139 | inline int __cdecl __stdio_common_vswprintf_s( 140 | _In_ unsigned __int64 _Options, 141 | _Out_writes_z_(_BufferCount) wchar_t *_Buffer, _In_ size_t _BufferCount, 142 | _In_z_ _Printf_format_string_params_(2) wchar_t const *_Format, 143 | _In_opt_ _locale_t _Locale, va_list _ArgList) { 144 | UNREFERENCED_PARAMETER(_Options); 145 | UNREFERENCED_PARAMETER(_Locale); 146 | 147 | // Calls _vsnwprintf exported by ntoskrnl 148 | using _vsnwprintf_type = 149 | int __cdecl(wchar_t *, size_t, const wchar_t *, va_list); 150 | static _vsnwprintf_type *local__vsnwprintf = nullptr; 151 | if (!local__vsnwprintf) { 152 | UNICODE_STRING proc_name_U = {}; 153 | RtlInitUnicodeString(&proc_name_U, L"_vsnwprintf"); 154 | local__vsnwprintf = reinterpret_cast<_vsnwprintf_type *>( 155 | MmGetSystemRoutineAddress(&proc_name_U)); 156 | } 157 | 158 | return local__vsnwprintf(_Buffer, _BufferCount, _Format, _ArgList); 159 | } 160 | -------------------------------------------------------------------------------- /HyperPlatform/HyperPlatform/log.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2017, Satoshi Tanda. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | /// @file 6 | /// Implements logging functions. 7 | 8 | #include "log.h" 9 | #define NTSTRSAFE_NO_CB_FUNCTIONS 10 | #include 11 | 12 | // See common.h for details 13 | #pragma prefast(disable : 30030) 14 | 15 | extern "C" { 16 | //////////////////////////////////////////////////////////////////////////////// 17 | // 18 | // macro utilities 19 | // 20 | 21 | //////////////////////////////////////////////////////////////////////////////// 22 | // 23 | // constant and macro 24 | // 25 | 26 | // A size for log buffer in NonPagedPool. Two buffers are allocated with this 27 | // size. Exceeded logs are ignored silently. Make it bigger if a buffered log 28 | // size often reach this size. 29 | static const auto kLogpBufferSizeInPages = 16ul; 30 | 31 | // An actual log buffer size in bytes. 32 | static const auto kLogpBufferSize = PAGE_SIZE * kLogpBufferSizeInPages; 33 | 34 | // A size that is usable for logging. Minus one because the last byte is kept 35 | // for \0. 36 | static const auto kLogpBufferUsableSize = kLogpBufferSize - 1; 37 | 38 | // An interval to flush buffered log entries into a log file. 39 | static const auto kLogpLogFlushIntervalMsec = 50; 40 | 41 | static const ULONG kLogpPoolTag = ' gol'; 42 | 43 | //////////////////////////////////////////////////////////////////////////////// 44 | // 45 | // types 46 | // 47 | 48 | struct LogBufferInfo { 49 | // A pointer to buffer currently used. It is either log_buffer1 or 50 | // log_buffer2. 51 | volatile char *log_buffer_head; 52 | 53 | // A pointer to where the next log should be written. 54 | volatile char *log_buffer_tail; 55 | 56 | char *log_buffer1; 57 | char *log_buffer2; 58 | 59 | // Holds the biggest buffer usage to determine a necessary buffer size. 60 | SIZE_T log_max_usage; 61 | 62 | HANDLE log_file_handle; 63 | KSPIN_LOCK spin_lock; 64 | ERESOURCE resource; 65 | bool resource_initialized; 66 | volatile bool buffer_flush_thread_should_be_alive; 67 | volatile bool buffer_flush_thread_started; 68 | HANDLE buffer_flush_thread_handle; 69 | wchar_t log_file_path[200]; 70 | }; 71 | 72 | //////////////////////////////////////////////////////////////////////////////// 73 | // 74 | // prototypes 75 | // 76 | 77 | NTKERNELAPI UCHAR *NTAPI PsGetProcessImageFileName(_In_ PEPROCESS process); 78 | 79 | _IRQL_requires_max_(PASSIVE_LEVEL) static NTSTATUS 80 | LogpInitializeBufferInfo(_In_ const wchar_t *log_file_path, 81 | _Inout_ LogBufferInfo *info); 82 | 83 | _IRQL_requires_max_(PASSIVE_LEVEL) static NTSTATUS 84 | LogpInitializeLogFile(_Inout_ LogBufferInfo *info); 85 | 86 | static DRIVER_REINITIALIZE LogpReinitializationRoutine; 87 | 88 | _IRQL_requires_max_(PASSIVE_LEVEL) static void LogpFinalizeBufferInfo( 89 | _In_ LogBufferInfo *info); 90 | 91 | static NTSTATUS LogpMakePrefix(_In_ ULONG level, 92 | _In_z_ const char *function_name, 93 | _In_z_ const char *log_message, 94 | _Out_ char *log_buffer, 95 | _In_ SIZE_T log_buffer_length); 96 | 97 | static const char *LogpFindBaseFunctionName(_In_z_ const char *function_name); 98 | 99 | static NTSTATUS LogpPut(_In_z_ char *message, _In_ ULONG attribute); 100 | 101 | _IRQL_requires_max_(PASSIVE_LEVEL) static NTSTATUS 102 | LogpFlushLogBuffer(_Inout_ LogBufferInfo *info); 103 | 104 | _IRQL_requires_max_(PASSIVE_LEVEL) static NTSTATUS 105 | LogpWriteMessageToFile(_In_z_ const char *message, 106 | _In_ const LogBufferInfo &info); 107 | 108 | static NTSTATUS LogpBufferMessage(_In_z_ const char *message, 109 | _Inout_ LogBufferInfo *info); 110 | 111 | static void LogpDoDbgPrint(_In_z_ char *message); 112 | 113 | static bool LogpIsLogFileEnabled(_In_ const LogBufferInfo &info); 114 | 115 | static bool LogpIsLogFileActivated(_In_ const LogBufferInfo &info); 116 | 117 | static bool LogpIsLogNeeded(_In_ ULONG level); 118 | 119 | static bool LogpIsDbgPrintNeeded(); 120 | 121 | static KSTART_ROUTINE LogpBufferFlushThreadRoutine; 122 | 123 | _IRQL_requires_max_(PASSIVE_LEVEL) static NTSTATUS 124 | LogpSleep(_In_ LONG millisecond); 125 | 126 | static void LogpSetPrintedBit(_In_z_ char *message, _In_ bool on); 127 | 128 | static bool LogpIsPrinted(_In_z_ char *message); 129 | 130 | static void LogpDbgBreak(); 131 | 132 | #if defined(ALLOC_PRAGMA) 133 | #pragma alloc_text(INIT, LogInitialization) 134 | #pragma alloc_text(INIT, LogpInitializeBufferInfo) 135 | #pragma alloc_text(PAGE, LogpInitializeLogFile) 136 | #pragma alloc_text(INIT, LogRegisterReinitialization) 137 | #pragma alloc_text(PAGE, LogpReinitializationRoutine) 138 | #pragma alloc_text(PAGE, LogIrpShutdownHandler) 139 | #pragma alloc_text(PAGE, LogTermination) 140 | #pragma alloc_text(PAGE, LogpFinalizeBufferInfo) 141 | #pragma alloc_text(PAGE, LogpBufferFlushThreadRoutine) 142 | #pragma alloc_text(PAGE, LogpSleep) 143 | #endif 144 | 145 | //////////////////////////////////////////////////////////////////////////////// 146 | // 147 | // variables 148 | // 149 | 150 | static auto g_logp_debug_flag = kLogPutLevelDisable; 151 | static LogBufferInfo g_logp_log_buffer_info = {}; 152 | 153 | //////////////////////////////////////////////////////////////////////////////// 154 | // 155 | // implementations 156 | // 157 | 158 | _Use_decl_annotations_ NTSTATUS 159 | LogInitialization(ULONG flag, const wchar_t *log_file_path) { 160 | PAGED_CODE(); 161 | 162 | auto status = STATUS_SUCCESS; 163 | 164 | g_logp_debug_flag = flag; 165 | 166 | // Initialize a log file if a log file path is specified. 167 | bool need_reinitialization = false; 168 | if (log_file_path) { 169 | status = LogpInitializeBufferInfo(log_file_path, &g_logp_log_buffer_info); 170 | if (status == STATUS_REINITIALIZATION_NEEDED) { 171 | need_reinitialization = true; 172 | } else if (!NT_SUCCESS(status)) { 173 | return status; 174 | } 175 | } 176 | 177 | // Test the log. 178 | status = HYPERPLATFORM_LOG_INFO("Log has been %sinitialized.", 179 | (need_reinitialization ? "partially " : "")); 180 | if (!NT_SUCCESS(status)) { 181 | goto Fail; 182 | } 183 | HYPERPLATFORM_LOG_DEBUG("Info= %p, Buffer= %p %p, File= %S", 184 | &g_logp_log_buffer_info, 185 | g_logp_log_buffer_info.log_buffer1, 186 | g_logp_log_buffer_info.log_buffer2, log_file_path); 187 | return (need_reinitialization ? STATUS_REINITIALIZATION_NEEDED 188 | : STATUS_SUCCESS); 189 | 190 | Fail:; 191 | if (log_file_path) { 192 | LogpFinalizeBufferInfo(&g_logp_log_buffer_info); 193 | } 194 | return status; 195 | } 196 | 197 | // Initialize a log file related code such as a flushing thread. 198 | _Use_decl_annotations_ static NTSTATUS LogpInitializeBufferInfo( 199 | const wchar_t *log_file_path, LogBufferInfo *info) { 200 | PAGED_CODE(); 201 | NT_ASSERT(log_file_path); 202 | NT_ASSERT(info); 203 | 204 | KeInitializeSpinLock(&info->spin_lock); 205 | 206 | auto status = RtlStringCchCopyW( 207 | info->log_file_path, RTL_NUMBER_OF_FIELD(LogBufferInfo, log_file_path), 208 | log_file_path); 209 | if (!NT_SUCCESS(status)) { 210 | return status; 211 | } 212 | 213 | status = ExInitializeResourceLite(&info->resource); 214 | if (!NT_SUCCESS(status)) { 215 | return status; 216 | } 217 | info->resource_initialized = true; 218 | 219 | // Allocate two log buffers on NonPagedPool. 220 | info->log_buffer1 = reinterpret_cast( 221 | ExAllocatePoolWithTag(NonPagedPool, kLogpBufferSize, kLogpPoolTag)); 222 | if (!info->log_buffer1) { 223 | LogpFinalizeBufferInfo(info); 224 | return STATUS_INSUFFICIENT_RESOURCES; 225 | } 226 | 227 | info->log_buffer2 = reinterpret_cast( 228 | ExAllocatePoolWithTag(NonPagedPool, kLogpBufferSize, kLogpPoolTag)); 229 | if (!info->log_buffer2) { 230 | LogpFinalizeBufferInfo(info); 231 | return STATUS_INSUFFICIENT_RESOURCES; 232 | } 233 | 234 | // Initialize these buffers 235 | RtlFillMemory(info->log_buffer1, kLogpBufferSize, 0xff); // for diagnostic 236 | info->log_buffer1[0] = '\0'; 237 | info->log_buffer1[kLogpBufferSize - 1] = '\0'; // at the end 238 | 239 | RtlFillMemory(info->log_buffer2, kLogpBufferSize, 0xff); // for diagnostic 240 | info->log_buffer2[0] = '\0'; 241 | info->log_buffer2[kLogpBufferSize - 1] = '\0'; // at the end 242 | 243 | // Buffer should be used is log_buffer1, and location should be written logs 244 | // is the head of the buffer. 245 | info->log_buffer_head = info->log_buffer1; 246 | info->log_buffer_tail = info->log_buffer1; 247 | 248 | status = LogpInitializeLogFile(info); 249 | if (status == STATUS_OBJECT_PATH_NOT_FOUND) { 250 | HYPERPLATFORM_LOG_INFO("The log file needs to be activated later."); 251 | status = STATUS_REINITIALIZATION_NEEDED; 252 | } else if (!NT_SUCCESS(status)) { 253 | LogpFinalizeBufferInfo(info); 254 | } 255 | return status; 256 | } 257 | 258 | // Initializes a log file and starts a log buffer thread. 259 | _Use_decl_annotations_ static NTSTATUS LogpInitializeLogFile( 260 | LogBufferInfo *info) { 261 | PAGED_CODE(); 262 | 263 | if (info->log_file_handle) { 264 | return STATUS_SUCCESS; 265 | } 266 | 267 | // Initialize a log file 268 | UNICODE_STRING log_file_path_u = {}; 269 | RtlInitUnicodeString(&log_file_path_u, info->log_file_path); 270 | 271 | OBJECT_ATTRIBUTES oa = {}; 272 | InitializeObjectAttributes(&oa, &log_file_path_u, 273 | OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, nullptr, 274 | nullptr); 275 | 276 | IO_STATUS_BLOCK io_status = {}; 277 | auto status = ZwCreateFile( 278 | &info->log_file_handle, FILE_APPEND_DATA | SYNCHRONIZE, &oa, &io_status, 279 | nullptr, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN_IF, 280 | FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE, nullptr, 0); 281 | if (!NT_SUCCESS(status)) { 282 | return status; 283 | } 284 | 285 | // Initialize a log buffer flush thread. 286 | info->buffer_flush_thread_should_be_alive = true; 287 | status = PsCreateSystemThread(&info->buffer_flush_thread_handle, GENERIC_ALL, 288 | nullptr, nullptr, nullptr, 289 | LogpBufferFlushThreadRoutine, info); 290 | if (!NT_SUCCESS(status)) { 291 | ZwClose(info->log_file_handle); 292 | info->log_file_handle = nullptr; 293 | info->buffer_flush_thread_should_be_alive = false; 294 | return status; 295 | } 296 | 297 | // Wait until the thread has started 298 | while (!info->buffer_flush_thread_started) { 299 | LogpSleep(100); 300 | } 301 | return status; 302 | } 303 | 304 | // Registers LogpReinitializationRoutine() for re-initialization. 305 | _Use_decl_annotations_ void LogRegisterReinitialization( 306 | PDRIVER_OBJECT driver_object) { 307 | PAGED_CODE(); 308 | IoRegisterBootDriverReinitialization( 309 | driver_object, LogpReinitializationRoutine, &g_logp_log_buffer_info); 310 | HYPERPLATFORM_LOG_INFO("The log file will be activated later."); 311 | } 312 | 313 | // Initializes a log file at the re-initialization phase. 314 | _Use_decl_annotations_ VOID static LogpReinitializationRoutine( 315 | _DRIVER_OBJECT *driver_object, PVOID context, ULONG count) { 316 | PAGED_CODE(); 317 | UNREFERENCED_PARAMETER(driver_object); 318 | UNREFERENCED_PARAMETER(count); 319 | NT_ASSERT(context); 320 | 321 | auto info = reinterpret_cast(context); 322 | auto status = LogpInitializeLogFile(info); 323 | NT_ASSERT(NT_SUCCESS(status)); 324 | if (NT_SUCCESS(status)) { 325 | HYPERPLATFORM_LOG_INFO("The log file has been activated."); 326 | } 327 | } 328 | 329 | // Terminates the log functions without releasing resources. 330 | _Use_decl_annotations_ void LogIrpShutdownHandler() { 331 | PAGED_CODE(); 332 | 333 | HYPERPLATFORM_LOG_DEBUG("Flushing... (Max log usage = %Iu/%lu bytes)", 334 | g_logp_log_buffer_info.log_max_usage, 335 | kLogpBufferSize); 336 | HYPERPLATFORM_LOG_INFO("Bye!"); 337 | g_logp_debug_flag = kLogPutLevelDisable; 338 | 339 | // Wait until the log buffer is emptied. 340 | auto &info = g_logp_log_buffer_info; 341 | while (info.log_buffer_head[0]) { 342 | LogpSleep(kLogpLogFlushIntervalMsec); 343 | } 344 | } 345 | 346 | // Terminates the log functions. 347 | _Use_decl_annotations_ void LogTermination() { 348 | PAGED_CODE(); 349 | 350 | HYPERPLATFORM_LOG_DEBUG("Finalizing... (Max log usage = %Iu/%lu bytes)", 351 | g_logp_log_buffer_info.log_max_usage, 352 | kLogpBufferSize); 353 | HYPERPLATFORM_LOG_INFO("Bye!"); 354 | g_logp_debug_flag = kLogPutLevelDisable; 355 | LogpFinalizeBufferInfo(&g_logp_log_buffer_info); 356 | } 357 | 358 | // Terminates a log file related code. 359 | _Use_decl_annotations_ static void LogpFinalizeBufferInfo(LogBufferInfo *info) { 360 | PAGED_CODE(); 361 | NT_ASSERT(info); 362 | 363 | // Closing the log buffer flush thread. 364 | if (info->buffer_flush_thread_handle) { 365 | info->buffer_flush_thread_should_be_alive = false; 366 | auto status = 367 | ZwWaitForSingleObject(info->buffer_flush_thread_handle, FALSE, nullptr); 368 | if (!NT_SUCCESS(status)) { 369 | LogpDbgBreak(); 370 | } 371 | ZwClose(info->buffer_flush_thread_handle); 372 | info->buffer_flush_thread_handle = nullptr; 373 | } 374 | 375 | // Cleaning up other things. 376 | if (info->log_file_handle) { 377 | ZwClose(info->log_file_handle); 378 | info->log_file_handle = nullptr; 379 | } 380 | if (info->log_buffer2) { 381 | ExFreePoolWithTag(info->log_buffer2, kLogpPoolTag); 382 | info->log_buffer2 = nullptr; 383 | } 384 | if (info->log_buffer1) { 385 | ExFreePoolWithTag(info->log_buffer1, kLogpPoolTag); 386 | info->log_buffer1 = nullptr; 387 | } 388 | 389 | if (info->resource_initialized) { 390 | ExDeleteResourceLite(&info->resource); 391 | info->resource_initialized = false; 392 | } 393 | } 394 | 395 | // Actual implementation of logging API. 396 | _Use_decl_annotations_ NTSTATUS LogpPrint(ULONG level, 397 | const char *function_name, 398 | const char *format, ...) { 399 | auto status = STATUS_SUCCESS; 400 | 401 | 402 | if (!LogpIsLogNeeded(level)) { 403 | return status; 404 | } 405 | // return status; 406 | va_list args; 407 | va_start(args, format); 408 | char log_message[412]; 409 | status = RtlStringCchVPrintfA(log_message, RTL_NUMBER_OF(log_message), format, 410 | args); 411 | va_end(args); 412 | if (!NT_SUCCESS(status)) { 413 | LogpDbgBreak(); 414 | return status; 415 | } 416 | if (log_message[0] == '\0') { 417 | LogpDbgBreak(); 418 | return STATUS_INVALID_PARAMETER; 419 | } 420 | 421 | const auto pure_level = level & 0xf0; 422 | const auto attribute = level & 0x0f; 423 | 424 | // A single entry of log should not exceed 512 bytes. See 425 | // Reading and Filtering Debugging Messages in MSDN for details. 426 | char message[512]; 427 | static_assert(RTL_NUMBER_OF(message) <= 512, 428 | "One log message should not exceed 512 bytes."); 429 | status = LogpMakePrefix(pure_level, function_name, log_message, message, 430 | RTL_NUMBER_OF(message)); 431 | if (!NT_SUCCESS(status)) { 432 | LogpDbgBreak(); 433 | return status; 434 | } 435 | 436 | status = LogpPut(message, attribute); 437 | if (!NT_SUCCESS(status)) { 438 | LogpDbgBreak(); 439 | } 440 | return status; 441 | } 442 | 443 | // Concatenates meta information such as the current time and a process ID to 444 | // user given log message. 445 | _Use_decl_annotations_ static NTSTATUS LogpMakePrefix( 446 | ULONG level, const char *function_name, const char *log_message, 447 | char *log_buffer, SIZE_T log_buffer_length) { 448 | char const *level_string = nullptr; 449 | switch (level) { 450 | case kLogpLevelDebug: 451 | level_string = "DBG\t"; 452 | break; 453 | case kLogpLevelInfo: 454 | level_string = "INF\t"; 455 | break; 456 | case kLogpLevelWarn: 457 | level_string = "WRN\t"; 458 | break; 459 | case kLogpLevelError: 460 | level_string = "ERR\t"; 461 | break; 462 | default: 463 | return STATUS_INVALID_PARAMETER; 464 | } 465 | 466 | auto status = STATUS_SUCCESS; 467 | 468 | char time_buffer[20] = {}; 469 | if ((g_logp_debug_flag & kLogOptDisableTime) == 0) { 470 | // Want the current time. 471 | TIME_FIELDS time_fields; 472 | LARGE_INTEGER system_time, local_time; 473 | KeQuerySystemTime(&system_time); 474 | ExSystemTimeToLocalTime(&system_time, &local_time); 475 | RtlTimeToTimeFields(&local_time, &time_fields); 476 | 477 | status = RtlStringCchPrintfA(time_buffer, RTL_NUMBER_OF(time_buffer), 478 | "%02u:%02u:%02u.%03u\t", time_fields.Hour, 479 | time_fields.Minute, time_fields.Second, 480 | time_fields.Milliseconds); 481 | if (!NT_SUCCESS(status)) { 482 | return status; 483 | } 484 | } 485 | 486 | // Want the function name 487 | char function_name_buffer[50] = {}; 488 | if ((g_logp_debug_flag & kLogOptDisableFunctionName) == 0) { 489 | const auto base_function_name = LogpFindBaseFunctionName(function_name); 490 | status = RtlStringCchPrintfA(function_name_buffer, 491 | RTL_NUMBER_OF(function_name_buffer), "%-40s\t", 492 | base_function_name); 493 | if (!NT_SUCCESS(status)) { 494 | return status; 495 | } 496 | } 497 | 498 | // Want the processor number 499 | char processro_number[10] = {}; 500 | if ((g_logp_debug_flag & kLogOptDisableProcessorNumber) == 0) { 501 | status = 502 | RtlStringCchPrintfA(processro_number, RTL_NUMBER_OF(processro_number), 503 | "#%lu\t", KeGetCurrentProcessorNumberEx(nullptr)); 504 | if (!NT_SUCCESS(status)) { 505 | return status; 506 | } 507 | } 508 | 509 | // It uses PsGetProcessId(PsGetCurrentProcess()) instead of 510 | // PsGetCurrentThreadProcessId() because the later sometimes returns 511 | // unwanted value, for example: 512 | // PID == 4 but its image name != ntoskrnl.exe 513 | // The author is guessing that it is related to attaching processes but 514 | // not quite sure. The former way works as expected. 515 | status = RtlStringCchPrintfA( 516 | log_buffer, log_buffer_length, "%s%s%s%5Iu\t%5Iu\t%-15s\t%s%s\r\n", 517 | time_buffer, level_string, processro_number, 518 | reinterpret_cast(PsGetProcessId(PsGetCurrentProcess())), 519 | reinterpret_cast(PsGetCurrentThreadId()), 520 | PsGetProcessImageFileName(PsGetCurrentProcess()), function_name_buffer, 521 | log_message); 522 | return status; 523 | } 524 | 525 | // Returns the function's base name, for example, 526 | // NamespaceName::ClassName::MethodName will be returned as MethodName. 527 | _Use_decl_annotations_ static const char *LogpFindBaseFunctionName( 528 | const char *function_name) { 529 | if (!function_name) { 530 | return nullptr; 531 | } 532 | 533 | auto ptr = function_name; 534 | auto name = function_name; 535 | while (*(ptr++)) { 536 | if (*ptr == ':') { 537 | name = ptr + 1; 538 | } 539 | } 540 | return name; 541 | } 542 | 543 | // Logs the entry according to attribute and the thread condition. 544 | _Use_decl_annotations_ static NTSTATUS LogpPut(char *message, ULONG attribute) { 545 | auto status = STATUS_SUCCESS; 546 | 547 | auto do_DbgPrint = ((attribute & kLogpLevelOptSafe) == 0 && 548 | KeGetCurrentIrql() < CLOCK_LEVEL); 549 | 550 | // Log the entry to a file or buffer. 551 | auto &info = g_logp_log_buffer_info; 552 | if (LogpIsLogFileEnabled(info)) { 553 | // Can it log it to a file now? 554 | if (((attribute & kLogpLevelOptSafe) == 0) && 555 | KeGetCurrentIrql() == PASSIVE_LEVEL && LogpIsLogFileActivated(info)) { 556 | #pragma warning(push) 557 | #pragma warning(disable : 28123) 558 | if (!KeAreAllApcsDisabled()) { 559 | // Yes, it can. Do it. 560 | LogpFlushLogBuffer(&info); 561 | status = LogpWriteMessageToFile(message, info); 562 | } 563 | #pragma warning(pop) 564 | } else { 565 | // No, it cannot. Set the printed bit if needed, and then buffer it. 566 | if (do_DbgPrint) { 567 | LogpSetPrintedBit(message, true); 568 | } 569 | status = LogpBufferMessage(message, &info); 570 | LogpSetPrintedBit(message, false); 571 | } 572 | } 573 | 574 | // Can it safely be printed? 575 | if (do_DbgPrint) { 576 | LogpDoDbgPrint(message); 577 | } 578 | return status; 579 | } 580 | 581 | // Switches the current log buffer, saves the contents of old buffer to the log 582 | // file, and prints them out as necessary. This function does not flush the log 583 | // file, so code should call LogpWriteMessageToFile() or ZwFlushBuffersFile() 584 | // later. 585 | _Use_decl_annotations_ static NTSTATUS LogpFlushLogBuffer(LogBufferInfo *info) { 586 | NT_ASSERT(info); 587 | NT_ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); 588 | 589 | auto status = STATUS_SUCCESS; 590 | 591 | // Enter a critical section and acquire a reader lock for info in order to 592 | // write a log file safely. 593 | ExEnterCriticalRegionAndAcquireResourceExclusive(&info->resource); 594 | 595 | // Acquire a spin lock for info.log_buffer(s) in order to switch its head 596 | // safely. 597 | KLOCK_QUEUE_HANDLE lock_handle = {}; 598 | KeAcquireInStackQueuedSpinLock(&info->spin_lock, &lock_handle); 599 | const auto old_log_buffer = const_cast(info->log_buffer_head); 600 | if (old_log_buffer[0]) { 601 | info->log_buffer_head = (old_log_buffer == info->log_buffer1) 602 | ? info->log_buffer2 603 | : info->log_buffer1; 604 | info->log_buffer_head[0] = '\0'; 605 | info->log_buffer_tail = info->log_buffer_head; 606 | } 607 | KeReleaseInStackQueuedSpinLock(&lock_handle); 608 | 609 | // Write all log entries in old log buffer. 610 | IO_STATUS_BLOCK io_status = {}; 611 | for (auto current_log_entry = old_log_buffer; current_log_entry[0]; /**/) { 612 | // Check the printed bit and clear it 613 | const auto printed_out = LogpIsPrinted(current_log_entry); 614 | LogpSetPrintedBit(current_log_entry, false); 615 | 616 | const auto current_log_entry_length = strlen(current_log_entry); 617 | status = ZwWriteFile(info->log_file_handle, nullptr, nullptr, nullptr, 618 | &io_status, current_log_entry, 619 | static_cast(current_log_entry_length), nullptr, 620 | nullptr); 621 | if (!NT_SUCCESS(status)) { 622 | // It could happen when you did not register IRP_SHUTDOWN and call 623 | // LogIrpShutdownHandler() and the system tried to log to a file after 624 | // a file system was unmounted. 625 | LogpDbgBreak(); 626 | } 627 | 628 | // Print it out if requested and the message is not already printed out 629 | if (!printed_out) { 630 | LogpDoDbgPrint(current_log_entry); 631 | } 632 | 633 | current_log_entry += current_log_entry_length + 1; 634 | } 635 | old_log_buffer[0] = '\0'; 636 | 637 | ExReleaseResourceAndLeaveCriticalRegion(&info->resource); 638 | return status; 639 | } 640 | 641 | // Logs the current log entry to and flush the log file. 642 | _Use_decl_annotations_ static NTSTATUS LogpWriteMessageToFile( 643 | const char *message, const LogBufferInfo &info) { 644 | NT_ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); 645 | 646 | IO_STATUS_BLOCK io_status = {}; 647 | auto status = 648 | ZwWriteFile(info.log_file_handle, nullptr, nullptr, nullptr, &io_status, 649 | const_cast(message), 650 | static_cast(strlen(message)), nullptr, nullptr); 651 | if (!NT_SUCCESS(status)) { 652 | // It could happen when you did not register IRP_SHUTDOWN and call 653 | // LogIrpShutdownHandler() and the system tried to log to a file after 654 | // a file system was unmounted. 655 | LogpDbgBreak(); 656 | } 657 | status = ZwFlushBuffersFile(info.log_file_handle, &io_status); 658 | return status; 659 | } 660 | 661 | // Buffer the log entry to the log buffer. 662 | _Use_decl_annotations_ static NTSTATUS LogpBufferMessage(const char *message, 663 | LogBufferInfo *info) { 664 | NT_ASSERT(info); 665 | 666 | // Acquire a spin lock to add the log safely. 667 | KLOCK_QUEUE_HANDLE lock_handle = {}; 668 | const auto old_irql = KeGetCurrentIrql(); 669 | if (old_irql < DISPATCH_LEVEL) { 670 | KeAcquireInStackQueuedSpinLock(&info->spin_lock, &lock_handle); 671 | } else { 672 | KeAcquireInStackQueuedSpinLockAtDpcLevel(&info->spin_lock, &lock_handle); 673 | } 674 | NT_ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL); 675 | 676 | // Copy the current log to the buffer. 677 | SIZE_T used_buffer_size = info->log_buffer_tail - info->log_buffer_head; 678 | auto status = 679 | RtlStringCchCopyA(const_cast(info->log_buffer_tail), 680 | kLogpBufferUsableSize - used_buffer_size, message); 681 | 682 | // Update info.log_max_usage if necessary. 683 | if (NT_SUCCESS(status)) { 684 | const auto message_length = strlen(message) + 1; 685 | info->log_buffer_tail += message_length; 686 | used_buffer_size += message_length; 687 | if (used_buffer_size > info->log_max_usage) { 688 | info->log_max_usage = used_buffer_size; // Update 689 | } 690 | } else { 691 | info->log_max_usage = kLogpBufferSize; // Indicates overflow 692 | } 693 | *info->log_buffer_tail = '\0'; 694 | 695 | if (old_irql < DISPATCH_LEVEL) { 696 | KeReleaseInStackQueuedSpinLock(&lock_handle); 697 | } else { 698 | KeReleaseInStackQueuedSpinLockFromDpcLevel(&lock_handle); 699 | } 700 | return status; 701 | } 702 | 703 | // Calls DbgPrintEx() while converting \r\n to \n\0 704 | _Use_decl_annotations_ static void LogpDoDbgPrint(char *message) { 705 | if (!LogpIsDbgPrintNeeded()) { 706 | return; 707 | } 708 | const auto location_of_cr = strlen(message) - 2; 709 | message[location_of_cr] = '\n'; 710 | message[location_of_cr + 1] = '\0'; 711 | DbgPrintEx(DPFLTR_DEFAULT_ID, DPFLTR_ERROR_LEVEL, "%s", message); 712 | } 713 | 714 | // Returns true when a log file is enabled. 715 | _Use_decl_annotations_ static bool LogpIsLogFileEnabled( 716 | const LogBufferInfo &info) { 717 | if (info.log_buffer1) { 718 | NT_ASSERT(info.log_buffer2); 719 | NT_ASSERT(info.log_buffer_head); 720 | NT_ASSERT(info.log_buffer_tail); 721 | return true; 722 | } 723 | NT_ASSERT(!info.log_buffer2); 724 | NT_ASSERT(!info.log_buffer_head); 725 | NT_ASSERT(!info.log_buffer_tail); 726 | return false; 727 | } 728 | 729 | // Returns true when a log file is opened. 730 | _Use_decl_annotations_ static bool LogpIsLogFileActivated( 731 | const LogBufferInfo &info) { 732 | if (info.buffer_flush_thread_should_be_alive) { 733 | NT_ASSERT(info.buffer_flush_thread_handle); 734 | NT_ASSERT(info.log_file_handle); 735 | return true; 736 | } 737 | NT_ASSERT(!info.buffer_flush_thread_handle); 738 | NT_ASSERT(!info.log_file_handle); 739 | return false; 740 | } 741 | 742 | // Returns true when logging is necessary according to the log's severity and 743 | // a set log level. 744 | _Use_decl_annotations_ static bool LogpIsLogNeeded(ULONG level) { 745 | return !!(g_logp_debug_flag & level); 746 | } 747 | 748 | // Returns true when DbgPrint is requested 749 | /*_Use_decl_annotations_*/ static bool LogpIsDbgPrintNeeded() { 750 | return (g_logp_debug_flag & kLogOptDisableDbgPrint) == 0; 751 | } 752 | 753 | // A thread runs as long as info.buffer_flush_thread_should_be_alive is true and 754 | // flushes a log buffer to a log file every kLogpLogFlushIntervalMsec msec. 755 | _Use_decl_annotations_ static VOID LogpBufferFlushThreadRoutine( 756 | void *start_context) { 757 | PAGED_CODE(); 758 | auto status = STATUS_SUCCESS; 759 | auto info = reinterpret_cast(start_context); 760 | info->buffer_flush_thread_started = true; 761 | HYPERPLATFORM_LOG_DEBUG("Log thread started (TID= %p).", 762 | PsGetCurrentThreadId()); 763 | 764 | while (info->buffer_flush_thread_should_be_alive) { 765 | NT_ASSERT(LogpIsLogFileActivated(*info)); 766 | if (info->log_buffer_head[0]) { 767 | NT_ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); 768 | NT_ASSERT(!KeAreAllApcsDisabled()); 769 | status = LogpFlushLogBuffer(info); 770 | // Do not flush the file for overall performance. Even a case of 771 | // bug check, we should be able to recover logs by looking at both 772 | // log buffers. 773 | } 774 | LogpSleep(kLogpLogFlushIntervalMsec); 775 | } 776 | PsTerminateSystemThread(status); 777 | } 778 | 779 | // Sleep the current thread's execution for milliseconds. 780 | _Use_decl_annotations_ static NTSTATUS LogpSleep(LONG millisecond) { 781 | PAGED_CODE(); 782 | 783 | LARGE_INTEGER interval = {}; 784 | interval.QuadPart = -(10000ll * millisecond); // msec 785 | return KeDelayExecutionThread(KernelMode, FALSE, &interval); 786 | } 787 | 788 | // Marks the message as it is already printed out, or clears the printed bit and 789 | // restores it to the original 790 | _Use_decl_annotations_ static void LogpSetPrintedBit(char *message, bool on) { 791 | if (on) { 792 | message[0] |= 0x80; 793 | } else { 794 | message[0] &= 0x7f; 795 | } 796 | } 797 | 798 | // Tests if the printed bit is on 799 | _Use_decl_annotations_ static bool LogpIsPrinted(char *message) { 800 | return (message[0] & 0x80) != 0; 801 | } 802 | 803 | // Sets a break point that works only when a debugger is present 804 | /*_Use_decl_annotations_*/ static void LogpDbgBreak() { 805 | if (!KD_DEBUGGER_NOT_PRESENT) { 806 | __debugbreak(); 807 | } 808 | } 809 | 810 | // Provides an implementation of _vsnprintf as it fails to link when a include 811 | // directory setting is modified for using STL 812 | _Success_(return >= 0) _Check_return_opt_ int __cdecl __stdio_common_vsprintf( 813 | _In_ unsigned __int64 _Options, 814 | _Out_writes_opt_z_(_BufferCount) char *_Buffer, _In_ size_t _BufferCount, 815 | _In_z_ _Printf_format_string_params_(2) char const *_Format, 816 | _In_opt_ _locale_t _Locale, va_list _ArgList) { 817 | UNREFERENCED_PARAMETER(_Options); 818 | UNREFERENCED_PARAMETER(_Locale); 819 | 820 | // Calls _vsnprintf exported by ntoskrnl 821 | using _vsnprintf_type = int __cdecl(char *, size_t, const char *, va_list); 822 | static _vsnprintf_type *local__vsnprintf = nullptr; 823 | if (!local__vsnprintf) { 824 | UNICODE_STRING proc_name_U = {}; 825 | RtlInitUnicodeString(&proc_name_U, L"_vsnprintf"); 826 | local__vsnprintf = reinterpret_cast<_vsnprintf_type *>( 827 | MmGetSystemRoutineAddress(&proc_name_U)); 828 | } 829 | return local__vsnprintf(_Buffer, _BufferCount, _Format, _ArgList); 830 | } 831 | 832 | // Provides an implementation of _vsnwprintf as it fails to link when a include 833 | // directory setting is modified for using STL 834 | _Success_(return >= 0) _Check_return_opt_ int __cdecl __stdio_common_vswprintf( 835 | _In_ unsigned __int64 _Options, 836 | _Out_writes_opt_z_(_BufferCount) wchar_t *_Buffer, _In_ size_t _BufferCount, 837 | _In_z_ _Printf_format_string_params_(2) wchar_t const *_Format, 838 | _In_opt_ _locale_t _Locale, va_list _ArgList) { 839 | UNREFERENCED_PARAMETER(_Options); 840 | UNREFERENCED_PARAMETER(_Locale); 841 | 842 | // Calls _vsnwprintf exported by ntoskrnl 843 | using _vsnwprintf_type = 844 | int __cdecl(wchar_t *, size_t, const wchar_t *, va_list); 845 | static _vsnwprintf_type *local__vsnwprintf = nullptr; 846 | if (!local__vsnwprintf) { 847 | UNICODE_STRING proc_name_U = {}; 848 | RtlInitUnicodeString(&proc_name_U, L"_vsnwprintf"); 849 | local__vsnwprintf = reinterpret_cast<_vsnwprintf_type *>( 850 | MmGetSystemRoutineAddress(&proc_name_U)); 851 | } 852 | 853 | return local__vsnwprintf(_Buffer, _BufferCount, _Format, _ArgList); 854 | } 855 | 856 | } // extern "C" 857 | -------------------------------------------------------------------------------- /HyperPlatform/HyperPlatform/log.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2017, Satoshi Tanda. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | /// @file 6 | /// Declares interfaces to logging functions. 7 | 8 | #ifndef HYPERPLATFORM_LOG_H_ 9 | #define HYPERPLATFORM_LOG_H_ 10 | 11 | #include 12 | 13 | extern "C" { 14 | //////////////////////////////////////////////////////////////////////////////// 15 | // 16 | // macro utilities 17 | // 18 | 19 | /// Logs a message as respective severity 20 | /// @param format A format string 21 | /// @return STATUS_SUCCESS on success 22 | /// 23 | /// Debug prints or buffers a log message with information about current 24 | /// execution context such as time, PID and TID as respective severity. 25 | /// Here are some guide lines to decide which level is appropriate: 26 | /// @li DEBUG: info for only developers. 27 | /// @li INFO: info for all users. 28 | /// @li WARN: info may require some attention but does not prevent the program 29 | /// working properly. 30 | /// @li ERROR: info about issues may stop the program working properly. 31 | /// 32 | /// A message should not exceed 512 bytes after all string construction is 33 | /// done; otherwise this macro fails to log and returns non STATUS_SUCCESS. 34 | #define HYPERPLATFORM_LOG_DEBUG(format, ...) \ 35 | LogpPrint(kLogpLevelDebug, __FUNCTION__, (format), __VA_ARGS__) 36 | 37 | /// @see HYPERPLATFORM_LOG_DEBUG 38 | #define HYPERPLATFORM_LOG_INFO(format, ...) \ 39 | LogpPrint(kLogpLevelInfo, __FUNCTION__, (format), __VA_ARGS__) 40 | 41 | /// @see HYPERPLATFORM_LOG_DEBUG 42 | #define HYPERPLATFORM_LOG_WARN(format, ...) \ 43 | LogpPrint(kLogpLevelWarn, __FUNCTION__, (format), __VA_ARGS__) 44 | 45 | /// @see HYPERPLATFORM_LOG_DEBUG 46 | #define HYPERPLATFORM_LOG_ERROR(format, ...) \ 47 | LogpPrint(kLogpLevelError, __FUNCTION__, (format), __VA_ARGS__) 48 | 49 | /// Buffers a message as respective severity 50 | /// @param format A format string 51 | /// @return STATUS_SUCCESS on success 52 | /// 53 | /// Buffers the log to buffer and neither calls DbgPrint() nor writes to a file. 54 | /// It is strongly recommended to use it when a status of a system is not 55 | /// expectable in order to avoid system instability. 56 | /// @see HYPERPLATFORM_LOG_DEBUG 57 | #define HYPERPLATFORM_LOG_DEBUG_SAFE(format, ...) \ 58 | LogpPrint(kLogpLevelDebug | kLogpLevelOptSafe, __FUNCTION__, (format), \ 59 | __VA_ARGS__) 60 | 61 | /// @see HYPERPLATFORM_LOG_DEBUG_SAFE 62 | #define HYPERPLATFORM_LOG_INFO_SAFE(format, ...) \ 63 | LogpPrint(kLogpLevelInfo | kLogpLevelOptSafe, __FUNCTION__, (format), \ 64 | __VA_ARGS__) 65 | 66 | /// @see HYPERPLATFORM_LOG_DEBUG_SAFE 67 | #define HYPERPLATFORM_LOG_WARN_SAFE(format, ...) \ 68 | LogpPrint(kLogpLevelWarn | kLogpLevelOptSafe, __FUNCTION__, (format), \ 69 | __VA_ARGS__) 70 | 71 | /// @see HYPERPLATFORM_LOG_DEBUG_SAFE 72 | #define HYPERPLATFORM_LOG_ERROR_SAFE(format, ...) \ 73 | LogpPrint(kLogpLevelError | kLogpLevelOptSafe, __FUNCTION__, (format), \ 74 | __VA_ARGS__) 75 | 76 | //////////////////////////////////////////////////////////////////////////////// 77 | // 78 | // constants and macros 79 | // 80 | 81 | /// Save this log to buffer and not try to write to a log file. 82 | static const auto kLogpLevelOptSafe = 0x1ul; 83 | 84 | static const auto kLogpLevelDebug = 0x10ul; //!< Bit mask for DEBUG level logs 85 | static const auto kLogpLevelInfo = 0x20ul; //!< Bit mask for INFO level logs 86 | static const auto kLogpLevelWarn = 0x40ul; //!< Bit mask for WARN level logs 87 | static const auto kLogpLevelError = 0x80ul; //!< Bit mask for ERROR level logs 88 | 89 | /// For LogInitialization(). Enables all levels of logs 90 | static const auto kLogPutLevelDebug = 91 | kLogpLevelError | kLogpLevelWarn | kLogpLevelInfo | kLogpLevelDebug; 92 | 93 | /// For LogInitialization(). Enables ERROR, WARN and INFO levels of logs 94 | static const auto kLogPutLevelInfo = 95 | kLogpLevelError | kLogpLevelWarn | kLogpLevelInfo; 96 | 97 | /// For LogInitialization(). Enables ERROR and WARN levels of logs 98 | static const auto kLogPutLevelWarn = kLogpLevelError | kLogpLevelWarn; 99 | 100 | /// For LogInitialization(). Enables an ERROR level of logs 101 | static const auto kLogPutLevelError = kLogpLevelError; 102 | 103 | /// For LogInitialization(). Disables all levels of logs 104 | static const auto kLogPutLevelDisable = 0x00ul; 105 | 106 | /// For LogInitialization(). Do not log a current time 107 | static const auto kLogOptDisableTime = 0x100ul; 108 | 109 | /// For LogInitialization(). Do not log a current function name 110 | static const auto kLogOptDisableFunctionName = 0x200ul; 111 | 112 | /// For LogInitialization(). Do not log a current processor number 113 | static const auto kLogOptDisableProcessorNumber = 0x400ul; 114 | 115 | /// For LogInitialization(). Do not log to debug buffer 116 | static const auto kLogOptDisableDbgPrint = 0x800ul; 117 | 118 | //////////////////////////////////////////////////////////////////////////////// 119 | // 120 | // types 121 | // 122 | 123 | //////////////////////////////////////////////////////////////////////////////// 124 | // 125 | // prototypes 126 | // 127 | 128 | /// Initializes the log system. 129 | /// @param flag A OR-ed flag to control a log level and options 130 | /// @param file_path A log file path 131 | /// @return STATUS_SUCCESS on success, STATUS_REINITIALIZATION_NEEDED when 132 | /// re-initialization with LogRegisterReinitialization() is required, or else on 133 | /// failure. 134 | /// 135 | /// Allocates internal log buffers, initializes related resources, starts a 136 | /// log flush thread and creates a log file if requested. This function returns 137 | /// STATUS_REINITIALIZATION_NEEDED if a file-system is not initialized yet. In 138 | /// that case, a driver must call LogRegisterReinitialization() for completing 139 | /// initialization. 140 | /// 141 | /// \a flag is a OR-ed value of kLogPutLevel* and kLogOpt*. For example, 142 | /// kLogPutLevelDebug | kLogOptDisableFunctionName. 143 | _IRQL_requires_max_(PASSIVE_LEVEL) NTSTATUS 144 | LogInitialization(_In_ ULONG flag, _In_opt_ const wchar_t *file_path); 145 | 146 | /// Registers re-initialization. 147 | /// @param driver_object A driver object being loaded 148 | /// 149 | /// A driver must call this function, or call LogTermination() and return non 150 | /// STATUS_SUCCESS from DriverEntry() if LogInitialization() returned 151 | /// STATUS_REINITIALIZATION_NEEDED. If this function is called, DriverEntry() 152 | /// must return STATUS_SUCCESS. 153 | _IRQL_requires_max_(PASSIVE_LEVEL) void LogRegisterReinitialization( 154 | _In_ PDRIVER_OBJECT driver_object); 155 | 156 | /// Terminates the log system. Should be called from an IRP_MJ_SHUTDOWN handler. 157 | _IRQL_requires_max_(PASSIVE_LEVEL) void LogIrpShutdownHandler(); 158 | 159 | /// Terminates the log system. Should be called from a DriverUnload routine. 160 | _IRQL_requires_max_(PASSIVE_LEVEL) void LogTermination(); 161 | 162 | /// Logs a message; use HYPERPLATFORM_LOG_*() macros instead. 163 | /// @param level Severity of a message 164 | /// @param function_name A name of a function called this function 165 | /// @param format A format string 166 | /// @return STATUS_SUCCESS on success 167 | /// @see HYPERPLATFORM_LOG_DEBUG 168 | /// @see HYPERPLATFORM_LOG_DEBUG_SAFE 169 | NTSTATUS LogpPrint(_In_ ULONG level, _In_z_ const char *function_name, 170 | _In_z_ _Printf_format_string_ const char *format, ...); 171 | 172 | //////////////////////////////////////////////////////////////////////////////// 173 | // 174 | // variables 175 | // 176 | 177 | //////////////////////////////////////////////////////////////////////////////// 178 | // 179 | // implementations 180 | // 181 | 182 | } // extern "C" 183 | 184 | #endif // HYPERPLATFORM_LOG_H_ 185 | -------------------------------------------------------------------------------- /HyperPlatform/HyperPlatform/perf_counter.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2017, Satoshi Tanda. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | /// @file 6 | /// Declares interfaces to performance measurement primitives. 7 | /// 8 | /// @warning 9 | /// All exposed interfaces but #HYPERPLATFORM_PERFCOUNTER_MEASURE_TIME are meant 10 | /// to be for internal use only. Also, the macro is only used by a wrapper code. 11 | /// 12 | /// @see performance.h 13 | 14 | #ifndef HYPERPLATFORM_PERF_COUNTER_H_ 15 | #define HYPERPLATFORM_PERF_COUNTER_H_ 16 | 17 | #include 18 | 19 | //////////////////////////////////////////////////////////////////////////////// 20 | // 21 | // macro utilities 22 | // 23 | 24 | #define HYPERPLATFORM_PERFCOUNTER_P_JOIN2(x, y) x##y 25 | #define HYPERPLATFORM_PERFCOUNTER_P_JOIN1(x, y) \ 26 | HYPERPLATFORM_PERFCOUNTER_P_JOIN2(x, y) 27 | 28 | /// Concatinates two tokens 29 | /// @param x 1st token 30 | /// @param y 2nd token 31 | #define HYPERPLATFORM_PERFCOUNTER_P_JOIN(x, y) \ 32 | HYPERPLATFORM_PERFCOUNTER_P_JOIN1(x, y) 33 | 34 | #define HYPERPLATFORM_PERFCOUNTER_P_TO_STRING1(n) #n 35 | 36 | /// Converts a token to a string literal 37 | /// @param n A token to convert to a string literal 38 | #define HYPERPLATFORM_PERFCOUNTER_P_TO_STRING(n) \ 39 | HYPERPLATFORM_PERFCOUNTER_P_TO_STRING1(n) 40 | 41 | /// Creates an instance of PerfCounter to measure an elapsed time of this scope 42 | /// @param collector A pointer to a PerfCollector instance 43 | /// @param query_time_routine A function pointer to get an elapsed time 44 | /// @see HYPERPLATFORM_PERFCOUNTER_MEASURE_TIME 45 | /// 46 | /// This macro should not be used directly. Instead use 47 | /// #HYPERPLATFORM_PERFCOUNTER_MEASURE_TIME. 48 | /// 49 | /// This macro creates an instance of PerfCounter named perf_obj_N where N is 50 | /// a sequential number starting at 0. A current function name and a source line 51 | /// number are converted into a string literal and passed to the instance to 52 | /// uniquely identify a location of measurement. The instance gets "counters" in 53 | // its constructor and destructor with \a query_time_routine, calculates an 54 | /// elapsed time and passes it to \a collector as well as the created string 55 | /// literal. In pseudo code, for example: 56 | /// 57 | /// @code{.cpp} 58 | /// Hello.cpp:233 | { 59 | /// Hello.cpp:234 | HYPERPLATFORM_PERFCOUNTER_MEASURE_TIME(collector, fn); 60 | /// Hello.cpp:235 | // do stuff 61 | /// Hello.cpp:236 | } 62 | /// @endcode 63 | /// 64 | /// This works as if below: 65 | /// 66 | /// @code{.cpp} 67 | /// { 68 | /// begin_time = fn(); //perf_obj_0.ctor(); 69 | /// // do stuff 70 | /// elapsed_time = fn(); //perf_obj_0.dtor(); 71 | /// collector->AddTime(elapsed_time, "Hello.cpp(234)"); 72 | /// } 73 | /// @endcode 74 | /// 75 | /// @warning 76 | /// Do not use this macro in where going to be unavailable at the time of a 77 | /// call of PerfCollector::Terminate(). This causes access violation because 78 | /// this macro builds a string literal in a used section, and the string is 79 | /// referenced in the PerfCollector::Terminate(), while it is no longer 80 | /// accessible if the section is already destroyed. In other words, do not use 81 | /// it in any functions in the INIT section. 82 | #define HYPERPLATFORM_PERFCOUNTER_MEASURE_TIME(collector, query_time_routine) \ 83 | const PerfCounter HYPERPLATFORM_PERFCOUNTER_P_JOIN(perf_obj_, __COUNTER__)( \ 84 | (collector), (query_time_routine), \ 85 | __FUNCTION__ "(" HYPERPLATFORM_PERFCOUNTER_P_TO_STRING(__LINE__) ")") 86 | 87 | //////////////////////////////////////////////////////////////////////////////// 88 | // 89 | // constants and macros 90 | // 91 | 92 | //////////////////////////////////////////////////////////////////////////////// 93 | // 94 | // types 95 | // 96 | 97 | //////////////////////////////////////////////////////////////////////////////// 98 | // 99 | // prototypes 100 | // 101 | 102 | //////////////////////////////////////////////////////////////////////////////// 103 | // 104 | // variables 105 | // 106 | 107 | //////////////////////////////////////////////////////////////////////////////// 108 | // 109 | // implementations 110 | // 111 | 112 | /// Responsible for collecting and saving data supplied by PerfCounter. 113 | class PerfCollector { 114 | public: 115 | /// A function type for printing out a header line of results 116 | using InitialOutputRoutine = void(_In_opt_ void* output_context); 117 | 118 | /// A function type for printing out a footer line of results 119 | using FinalOutputRoutine = void(_In_opt_ void* output_context); 120 | 121 | /// A function type for printing out results 122 | using OutputRoutine = void(_In_ const char* location_name, 123 | _In_ ULONG64 total_execution_count, 124 | _In_ ULONG64 total_elapsed_time, 125 | _In_opt_ void* output_context); 126 | 127 | /// A function type for acquiring and releasing a lock 128 | using LockRoutine = void(_In_opt_ void* lock_context); 129 | 130 | /// Constructor; call this only once before any other code in this module runs 131 | /// @param output_routine A function pointer for printing out results 132 | /// @param initial_output_routine A function pointer for printing a header 133 | /// line of results 134 | /// @param final_output_routine A function pointer for printing a footer 135 | /// line of results 136 | /// @param lock_enter_routine A function pointer for acquiring a lock 137 | /// @param lock_leave_routine A function pointer for releasing a lock 138 | /// @param lock_context An arbitrary parameter for \a lock_enter_routine and 139 | /// \a lock_leave_routine 140 | /// @param output_context An arbitrary parameter for \a output_routine, 141 | /// \a initial_output_routine and \a final_output_routine. 142 | void Initialize( 143 | _In_ OutputRoutine* output_routine, 144 | _In_opt_ InitialOutputRoutine* initial_output_routine = NoOutputRoutine, 145 | _In_opt_ FinalOutputRoutine* final_output_routine = NoOutputRoutine, 146 | _In_opt_ LockRoutine* lock_enter_routine = NoLockRoutine, 147 | _In_opt_ LockRoutine* lock_leave_routine = NoLockRoutine, 148 | _In_opt_ void* lock_context = nullptr, 149 | _In_opt_ void* output_context = nullptr) { 150 | initial_output_routine_ = initial_output_routine; 151 | final_output_routine_ = final_output_routine; 152 | output_routine_ = output_routine; 153 | lock_enter_routine_ = lock_enter_routine; 154 | lock_leave_routine_ = lock_leave_routine; 155 | lock_context_ = lock_context; 156 | output_context_ = output_context; 157 | memset(data_, 0, sizeof(data_)); 158 | } 159 | 160 | /// Destructor; prints out accumulated performance results. 161 | void Terminate() { 162 | if (data_[0].key) { 163 | initial_output_routine_(output_context_); 164 | } 165 | 166 | for (auto i = 0ul; i < kMaxNumberOfDataEntries; i++) { 167 | if (data_[i].key == nullptr) { 168 | break; 169 | } 170 | 171 | output_routine_(data_[i].key, data_[i].total_execution_count, 172 | data_[i].total_elapsed_time, output_context_); 173 | } 174 | if (data_[0].key) { 175 | final_output_routine_(output_context_); 176 | } 177 | } 178 | 179 | /// Saves performance data taken by PerfCounter. 180 | bool AddData(_In_ const char* location_name, _In_ ULONG64 elapsed_time) { 181 | ScopedLock lock(lock_enter_routine_, lock_leave_routine_, lock_context_); 182 | 183 | const auto data_index = GetPerfDataIndex(location_name); 184 | if (data_index == kInvalidDataIndex) { 185 | return false; 186 | } 187 | 188 | data_[data_index].total_execution_count++; 189 | data_[data_index].total_elapsed_time += elapsed_time; 190 | return true; 191 | } 192 | 193 | private: 194 | static const ULONG kInvalidDataIndex = MAXULONG; 195 | static const ULONG kMaxNumberOfDataEntries = 200; 196 | 197 | /// Represents performance data for each location 198 | struct PerfDataEntry { 199 | const char* key; //!< Identifies a subject matter location 200 | ULONG64 total_execution_count; //!< How many times executed 201 | ULONG64 total_elapsed_time; //!< An accumulated elapsed time 202 | }; 203 | 204 | /// Scoped lock 205 | class ScopedLock { 206 | public: 207 | /// Acquires a lock using \a lock_routine. 208 | /// @param lock_routine A function pointer for acquiring a lock 209 | /// @param leave_routine A function pointer for releasing a lock 210 | /// @param lock_context An arbitrary parameter for \a lock_enter_routine 211 | /// and \a lock_leave_routine 212 | ScopedLock(_In_ LockRoutine* lock_routine, _In_ LockRoutine* leave_routine, 213 | _In_opt_ void* lock_context) 214 | : lock_routine_(lock_routine), 215 | leave_routine_(leave_routine), 216 | lock_context_(lock_context) { 217 | lock_routine_(lock_context_); 218 | } 219 | 220 | /// Releases a lock using ScopedLock::leave_routine_. 221 | ~ScopedLock() { leave_routine_(lock_context_); } 222 | 223 | private: 224 | LockRoutine* lock_routine_; 225 | LockRoutine* leave_routine_; 226 | void* lock_context_; 227 | }; 228 | 229 | /// Default empty output routine 230 | /// @param output_context Ignored 231 | static void NoOutputRoutine(_In_opt_ void* output_context) { 232 | UNREFERENCED_PARAMETER(output_context); 233 | } 234 | 235 | /// Default empty lock and release routine 236 | /// @param lock_context Ignored 237 | static void NoLockRoutine(_In_opt_ void* lock_context) { 238 | UNREFERENCED_PARAMETER(lock_context); 239 | } 240 | 241 | /// Returns an index of data corresponds to the location_name. 242 | /// @param key A location to get an index of corresponding data entry 243 | /// @return An index of data or kInvalidDataIndex 244 | /// 245 | /// It adds a new entry when the key is not found in existing entries. Returns 246 | /// kInvalidDataIndex if a corresponding entry is not found and there is no 247 | /// room to add a new entry. 248 | ULONG GetPerfDataIndex(_In_ const char* key) { 249 | if (!key) { 250 | return false; 251 | } 252 | 253 | for (auto i = 0ul; i < kMaxNumberOfDataEntries; i++) { 254 | if (data_[i].key == key) { 255 | return i; 256 | } 257 | 258 | if (data_[i].key == nullptr) { 259 | data_[i].key = key; 260 | return i; 261 | } 262 | } 263 | return kInvalidDataIndex; 264 | } 265 | 266 | InitialOutputRoutine* initial_output_routine_; 267 | FinalOutputRoutine* final_output_routine_; 268 | OutputRoutine* output_routine_; 269 | LockRoutine* lock_enter_routine_; 270 | LockRoutine* lock_leave_routine_; 271 | void* lock_context_; 272 | void* output_context_; 273 | PerfDataEntry data_[kMaxNumberOfDataEntries]; 274 | }; 275 | 276 | /// Measure elapsed time of the scope 277 | class PerfCounter { 278 | public: 279 | using QueryTimeRoutine = ULONG64(); 280 | 281 | /// Gets the current time using \a query_time_routine. 282 | /// @param collector PerfCollector instance to store performance data 283 | /// @param query_time_routine A function pointer for getting times 284 | /// @param location_name A function name where being measured 285 | /// 286 | /// #HYPERPLATFORM_PERFCOUNTER_MEASURE_TIME() should be used to create an 287 | /// instance of this class. 288 | PerfCounter(_In_ PerfCollector* collector, 289 | _In_opt_ QueryTimeRoutine* query_time_routine, 290 | _In_ const char* location_name) 291 | : collector_(collector), 292 | query_time_routine_((query_time_routine) ? query_time_routine : RdTsc), 293 | location_name_(location_name), 294 | before_time_(query_time_routine_()) {} 295 | 296 | /// Measures an elapsed time and stores it to PerfCounter::collector_. 297 | ~PerfCounter() { 298 | if (collector_) { 299 | const auto elapsed_time = query_time_routine_() - before_time_; 300 | collector_->AddData(location_name_, elapsed_time); 301 | } 302 | } 303 | 304 | private: 305 | /// Gets the current time using the RDTSC instruction 306 | /// @return the current time 307 | static ULONG64 RdTsc() { return __rdtsc(); } 308 | 309 | PerfCollector* collector_; 310 | QueryTimeRoutine* query_time_routine_; 311 | const char* location_name_; 312 | const ULONG64 before_time_; 313 | }; 314 | 315 | #endif // HYPERPLATFORM_PERF_COUNTER_H_ 316 | -------------------------------------------------------------------------------- /HyperPlatform/HyperPlatform/performance.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2017, Satoshi Tanda. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | /// @file 6 | /// Implements performance measurement functions. 7 | 8 | #include "performance.h" 9 | #include "common.h" 10 | #include "log.h" 11 | 12 | //////////////////////////////////////////////////////////////////////////////// 13 | // 14 | // macro utilities 15 | // 16 | 17 | //////////////////////////////////////////////////////////////////////////////// 18 | // 19 | // constants and macros 20 | // 21 | 22 | //////////////////////////////////////////////////////////////////////////////// 23 | // 24 | // types 25 | // 26 | 27 | //////////////////////////////////////////////////////////////////////////////// 28 | // 29 | // prototypes 30 | // 31 | 32 | static PerfCollector::InitialOutputRoutine PerfpInitialOutputRoutine; 33 | static PerfCollector::OutputRoutine PerfpOutputRoutine; 34 | static PerfCollector::FinalOutputRoutine PerfpFinalOutputRoutine; 35 | 36 | #if defined(ALLOC_PRAGMA) 37 | #pragma alloc_text(INIT, PerfInitialization) 38 | #pragma alloc_text(PAGE, PerfTermination) 39 | #endif 40 | 41 | //////////////////////////////////////////////////////////////////////////////// 42 | // 43 | // variables 44 | // 45 | 46 | PerfCollector* g_performance_collector; 47 | 48 | //////////////////////////////////////////////////////////////////////////////// 49 | // 50 | // implementations 51 | // 52 | 53 | _Use_decl_annotations_ NTSTATUS PerfInitialization() { 54 | PAGED_CODE(); 55 | auto status = STATUS_SUCCESS; 56 | 57 | const auto perf_collector = 58 | reinterpret_cast(ExAllocatePoolWithTag( 59 | NonPagedPool, sizeof(PerfCollector), kHyperPlatformCommonPoolTag)); 60 | if (!perf_collector) { 61 | return STATUS_MEMORY_NOT_ALLOCATED; 62 | } 63 | 64 | // No lock to avoid calling kernel APIs from VMM and race condition here is 65 | // not an issue. 66 | perf_collector->Initialize(PerfpOutputRoutine, PerfpInitialOutputRoutine, 67 | PerfpFinalOutputRoutine); 68 | 69 | g_performance_collector = perf_collector; 70 | return status; 71 | } 72 | 73 | _Use_decl_annotations_ void PerfTermination() { 74 | PAGED_CODE(); 75 | 76 | if (g_performance_collector) { 77 | g_performance_collector->Terminate(); 78 | ExFreePoolWithTag(g_performance_collector, kHyperPlatformCommonPoolTag); 79 | g_performance_collector = nullptr; 80 | } 81 | } 82 | 83 | /*_Use_decl_annotations_*/ ULONG64 PerfGetTime() { 84 | LARGE_INTEGER counter = KeQueryPerformanceCounter(nullptr); 85 | return static_cast(counter.QuadPart); 86 | } 87 | 88 | _Use_decl_annotations_ static void PerfpInitialOutputRoutine( 89 | void* output_context) { 90 | UNREFERENCED_PARAMETER(output_context); 91 | HYPERPLATFORM_LOG_INFO("%-45s,%-20s,%-20s", "FunctionName(Line)", 92 | "Execution Count", "Elapsed Time"); 93 | } 94 | 95 | _Use_decl_annotations_ static void PerfpOutputRoutine( 96 | const char* location_name, ULONG64 total_execution_count, 97 | ULONG64 total_elapsed_time, void* output_context) { 98 | UNREFERENCED_PARAMETER(output_context); 99 | HYPERPLATFORM_LOG_INFO("%-45s,%20I64u,%20I64u,", location_name, 100 | total_execution_count, total_elapsed_time); 101 | } 102 | 103 | _Use_decl_annotations_ static void PerfpFinalOutputRoutine( 104 | void* output_context) { 105 | UNREFERENCED_PARAMETER(output_context); 106 | } 107 | -------------------------------------------------------------------------------- /HyperPlatform/HyperPlatform/performance.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2017, Satoshi Tanda. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | /// @file 6 | /// Declares interfaces to performance measurement functions. 7 | 8 | #ifndef HYPERPLATFORM_PERFORMANCE_H_ 9 | #define HYPERPLATFORM_PERFORMANCE_H_ 10 | 11 | #include "perf_counter.h" 12 | 13 | extern "C" { 14 | //////////////////////////////////////////////////////////////////////////////// 15 | // 16 | // macro utilities 17 | // 18 | 19 | #if (HYPERPLATFORM_PERFORMANCE_ENABLE_PERFCOUNTER != 0) 20 | 21 | /// Measures an elapsed time from execution of this macro to the end of a scope 22 | /// 23 | /// @warning 24 | /// This macro cannot be called from an INIT section. See 25 | /// #HYPERPLATFORM_PERFCOUNTER_MEASURE_TIME() for details. 26 | #define HYPERPLATFORM_PERFORMANCE_MEASURE_THIS_SCOPE() \ 27 | HYPERPLATFORM_PERFCOUNTER_MEASURE_TIME(g_performance_collector, PerfGetTime) 28 | 29 | #else 30 | #define HYPERPLATFORM_PERFORMANCE_MEASURE_THIS_SCOPE() 31 | #endif 32 | 33 | //////////////////////////////////////////////////////////////////////////////// 34 | // 35 | // constants and macros 36 | // 37 | 38 | //////////////////////////////////////////////////////////////////////////////// 39 | // 40 | // types 41 | // 42 | 43 | //////////////////////////////////////////////////////////////////////////////// 44 | // 45 | // prototypes 46 | // 47 | 48 | /// Makes #HYPERPLATFORM_PERFORMANCE_MEASURE_THIS_SCOPE() ready for use 49 | /// @return STATUS_SUCCESS on success 50 | _IRQL_requires_max_(PASSIVE_LEVEL) NTSTATUS PerfInitialization(); 51 | 52 | /// Ends performance monitoring and outputs its results 53 | _IRQL_requires_max_(PASSIVE_LEVEL) void PerfTermination(); 54 | 55 | /// Returns the current "time" for performance measurement. 56 | /// @return Current performance counter 57 | /// 58 | /// It should only be used by #HYPERPLATFORM_PERFORMANCE_MEASURE_THIS_SCOPE(). 59 | ULONG64 PerfGetTime(); 60 | 61 | //////////////////////////////////////////////////////////////////////////////// 62 | // 63 | // variables 64 | // 65 | 66 | /// Stores all performance data collected by 67 | /// #HYPERPLATFORM_PERFORMANCE_MEASURE_THIS_SCOPE(). 68 | extern PerfCollector* g_performance_collector; 69 | 70 | //////////////////////////////////////////////////////////////////////////////// 71 | // 72 | // implementations 73 | // 74 | 75 | } // extern "C" 76 | 77 | #endif // HYPERPLATFORM_PERFORMANCE_H_ 78 | -------------------------------------------------------------------------------- /HyperPlatform/HyperPlatform/power_callback.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2017, Satoshi Tanda. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | /// @file 6 | /// Implements power callback functions. 7 | 8 | #include "power_callback.h" 9 | #include "common.h" 10 | #include "log.h" 11 | #include "vm.h" 12 | 13 | extern "C" { 14 | //////////////////////////////////////////////////////////////////////////////// 15 | // 16 | // macro utilities 17 | // 18 | 19 | //////////////////////////////////////////////////////////////////////////////// 20 | // 21 | // constants and macros 22 | // 23 | 24 | //////////////////////////////////////////////////////////////////////////////// 25 | // 26 | // types 27 | // 28 | 29 | //////////////////////////////////////////////////////////////////////////////// 30 | // 31 | // prototypes 32 | // 33 | 34 | static CALLBACK_FUNCTION PowerCallbackpCallbackRoutine; 35 | 36 | #if defined(ALLOC_PRAGMA) 37 | #pragma alloc_text(INIT, PowerCallbackInitialization) 38 | #pragma alloc_text(PAGE, PowerCallbackTermination) 39 | #pragma alloc_text(PAGE, PowerCallbackpCallbackRoutine) 40 | #endif 41 | 42 | //////////////////////////////////////////////////////////////////////////////// 43 | // 44 | // variables 45 | // 46 | 47 | static PCALLBACK_OBJECT g_pcp_callback_object = nullptr; 48 | static PVOID g_pcp_registration = nullptr; 49 | 50 | //////////////////////////////////////////////////////////////////////////////// 51 | // 52 | // implementations 53 | // 54 | 55 | // Registers power callback 56 | _Use_decl_annotations_ NTSTATUS PowerCallbackInitialization() { 57 | PAGED_CODE(); 58 | 59 | UNICODE_STRING name = RTL_CONSTANT_STRING(L"\\Callback\\PowerState"); 60 | OBJECT_ATTRIBUTES oa = 61 | RTL_CONSTANT_OBJECT_ATTRIBUTES(&name, OBJ_CASE_INSENSITIVE); 62 | 63 | auto status = ExCreateCallback(&g_pcp_callback_object, &oa, FALSE, TRUE); 64 | if (!NT_SUCCESS(status)) { 65 | return status; 66 | } 67 | 68 | g_pcp_registration = ExRegisterCallback( 69 | g_pcp_callback_object, PowerCallbackpCallbackRoutine, nullptr); 70 | if (!g_pcp_registration) { 71 | ObDereferenceObject(g_pcp_callback_object); 72 | g_pcp_callback_object = nullptr; 73 | return STATUS_UNSUCCESSFUL; 74 | } 75 | return status; 76 | } 77 | 78 | // Unregister power callback 79 | _Use_decl_annotations_ void PowerCallbackTermination() { 80 | PAGED_CODE(); 81 | 82 | if (g_pcp_registration) { 83 | ExUnregisterCallback(g_pcp_registration); 84 | } 85 | if (g_pcp_callback_object) { 86 | ObDereferenceObject(g_pcp_callback_object); 87 | } 88 | } 89 | 90 | // Power callback routine dealing with hibernate and sleep 91 | _Use_decl_annotations_ static void PowerCallbackpCallbackRoutine( 92 | PVOID callback_context, PVOID argument1, PVOID argument2) { 93 | UNREFERENCED_PARAMETER(callback_context); 94 | PAGED_CODE(); 95 | 96 | HYPERPLATFORM_LOG_DEBUG("PowerCallback %p:%p", argument1, argument2); 97 | 98 | if (argument1 != reinterpret_cast(PO_CB_SYSTEM_STATE_LOCK)) { 99 | return; 100 | } 101 | 102 | HYPERPLATFORM_COMMON_DBG_BREAK(); 103 | 104 | if (argument2) { 105 | // the computer has just reentered S0. 106 | HYPERPLATFORM_LOG_INFO("Resuming the system..."); 107 | auto status = VmInitialization(); 108 | if (!NT_SUCCESS(status)) { 109 | HYPERPLATFORM_LOG_ERROR( 110 | "Failed to re-virtualize processors. Please unload the driver."); 111 | } 112 | } else { 113 | // the computer is about to exit system power state S0 114 | HYPERPLATFORM_LOG_INFO("Suspending the system..."); 115 | VmTermination(); 116 | } 117 | } 118 | 119 | } // extern "C" 120 | -------------------------------------------------------------------------------- /HyperPlatform/HyperPlatform/power_callback.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2017, Satoshi Tanda. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | /// @file 6 | /// @brief Declares interfaces to power functions. 7 | 8 | #ifndef HYPERPLATFORM_POWER_CALLBACK_H_ 9 | #define HYPERPLATFORM_POWER_CALLBACK_H_ 10 | 11 | #include 12 | 13 | extern "C" { 14 | //////////////////////////////////////////////////////////////////////////////// 15 | // 16 | // macro utilities 17 | // 18 | 19 | //////////////////////////////////////////////////////////////////////////////// 20 | // 21 | // constants and macros 22 | // 23 | 24 | //////////////////////////////////////////////////////////////////////////////// 25 | // 26 | // types 27 | // 28 | 29 | //////////////////////////////////////////////////////////////////////////////// 30 | // 31 | // prototypes 32 | // 33 | 34 | _IRQL_requires_max_(PASSIVE_LEVEL) NTSTATUS PowerCallbackInitialization(); 35 | 36 | _IRQL_requires_max_(PASSIVE_LEVEL) void PowerCallbackTermination(); 37 | 38 | //////////////////////////////////////////////////////////////////////////////// 39 | // 40 | // variables 41 | // 42 | 43 | //////////////////////////////////////////////////////////////////////////////// 44 | // 45 | // implementations 46 | // 47 | 48 | } // extern "C" 49 | 50 | #endif // HYPERPLATFORM_POWER_CALLBACK_H_ 51 | -------------------------------------------------------------------------------- /HyperPlatform/HyperPlatform/util.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2017, Satoshi Tanda. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | /// @file 6 | /// Declares interfaces to utility functions. 7 | 8 | #ifndef HYPERPLATFORM_UTIL_H_ 9 | #define HYPERPLATFORM_UTIL_H_ 10 | 11 | #include "ia32_type.h" 12 | 13 | extern "C" { 14 | //////////////////////////////////////////////////////////////////////////////// 15 | // 16 | // macro utilities 17 | // 18 | 19 | //////////////////////////////////////////////////////////////////////////////// 20 | // 21 | // constants and macros 22 | // 23 | 24 | //////////////////////////////////////////////////////////////////////////////// 25 | // 26 | // types 27 | // 28 | 29 | /// Represents ranges of addresses 30 | struct PhysicalMemoryRun { 31 | ULONG_PTR base_page; //!< A base address / PAGE_SIZE (ie, 0x1 for 0x1000) 32 | ULONG_PTR page_count; //!< A number of pages 33 | }; 34 | #if defined(_AMD64_) 35 | static_assert(sizeof(PhysicalMemoryRun) == 0x10, "Size check"); 36 | #else 37 | static_assert(sizeof(PhysicalMemoryRun) == 0x8, "Size check"); 38 | #endif 39 | 40 | /// Represents a physical memory ranges of the system 41 | struct PhysicalMemoryDescriptor { 42 | PFN_COUNT number_of_runs; //!< A number of PhysicalMemoryDescriptor::run 43 | PFN_NUMBER number_of_pages; //!< A physical memory size in pages 44 | PhysicalMemoryRun run[1]; //!< ranges of addresses 45 | }; 46 | #if defined(_AMD64_) 47 | static_assert(sizeof(PhysicalMemoryDescriptor) == 0x20, "Size check"); 48 | #else 49 | static_assert(sizeof(PhysicalMemoryDescriptor) == 0x10, "Size check"); 50 | #endif 51 | 52 | /// Indicates a result of VMX-instructions 53 | /// 54 | /// This convention was taken from the VMX-intrinsic functions by Microsoft. 55 | enum class VmxStatus : unsigned __int8 { 56 | kOk = 0, //!< Operation succeeded 57 | kErrorWithStatus = 1, //!< Operation failed with extended status available 58 | kErrorWithoutStatus = 2, //!< Operation failed without status available 59 | }; 60 | 61 | /// Provides |= operator for VmxStatus 62 | constexpr VmxStatus operator|=(_In_ VmxStatus lhs, _In_ VmxStatus rhs) { 63 | return static_cast(static_cast(lhs) | 64 | static_cast(rhs)); 65 | } 66 | 67 | /// Available command numbers for VMCALL 68 | enum class HypercallNumber : unsigned __int32 { 69 | kTerminateVmm, //!< Terminates VMM 70 | kPingVmm, //!< Sends ping to the VMM 71 | kGetSharedProcessorData, //!< Terminates VMM 72 | kApiMonCreateConcealment = 0x11223300, 73 | kApiMonEnableConcealment, 74 | kApiMonDisableConcealment, 75 | kApiMonDeleteConcealment, 76 | }; 77 | 78 | //////////////////////////////////////////////////////////////////////////////// 79 | // 80 | // prototypes 81 | // 82 | 83 | /// Makes the Util functions ready for use 84 | /// @param driver_object The current driver's driver object 85 | /// @return STATUS_SUCCESS on success 86 | _IRQL_requires_max_(PASSIVE_LEVEL) NTSTATUS 87 | UtilInitialization(_In_ PDRIVER_OBJECT driver_object); 88 | 89 | /// Frees all resources allocated for the sake of the Util functions 90 | _IRQL_requires_max_(PASSIVE_LEVEL) void UtilTermination(); 91 | 92 | /// Returns a module base address of \a address 93 | /// @param address An address to get a base address 94 | /// @return A base address of a range \a address belongs to, or nullptr 95 | void *UtilPcToFileHeader(_In_ void *address); 96 | 97 | /// Returns ranges of physical memory on the system 98 | /// @return Physical memory ranges; never fails 99 | const PhysicalMemoryDescriptor *UtilGetPhysicalMemoryRanges(); 100 | 101 | /// Executes \a callback_routine on each processor 102 | /// @param callback_routine A function to execute 103 | /// @param context An arbitrary parameter for \a callback_routine 104 | /// @return STATUS_SUCCESS when \a returned STATUS_SUCCESS on all processors 105 | _IRQL_requires_max_(APC_LEVEL) NTSTATUS 106 | UtilForEachProcessor(_In_ NTSTATUS (*callback_routine)(void *), 107 | _In_opt_ void *context); 108 | 109 | /// Queues \a deferred_routine on all processors 110 | /// @param deferred_routine A DPC routine to be queued 111 | /// @param context An arbitrary parameter for \a deferred_routine 112 | /// @return STATUS_SUCCESS when DPC was queued to all processors 113 | /// 114 | /// \a deferred_routine must free the pointer to a DPC structure like this: 115 | /// ExFreePoolWithTag(dpc, kHyperPlatformCommonPoolTag). 116 | _IRQL_requires_max_(DISPATCH_LEVEL) NTSTATUS 117 | UtilForEachProcessorDpc(_In_ PKDEFERRED_ROUTINE deferred_routine, 118 | _In_opt_ void *context); 119 | 120 | /// Suspends the execution of the current thread 121 | /// @param millisecond Time to suspend in milliseconds 122 | /// @return STATUS_SUCCESS on success 123 | _IRQL_requires_max_(APC_LEVEL) NTSTATUS UtilSleep(_In_ LONG millisecond); 124 | 125 | /// Searches a byte pattern from a given address range 126 | /// @param search_base An address to start search 127 | /// @param search_size A length to search in bytes 128 | /// @param pattern A byte pattern to search 129 | /// @param pattern_size A size of \a pattern 130 | /// @return An address of the first occurrence of the patten if found, or 131 | /// nullptr 132 | void *UtilMemMem(_In_ const void *search_base, _In_ SIZE_T search_size, 133 | _In_ const void *pattern, _In_ SIZE_T pattern_size); 134 | 135 | /// Get an address of an exported symbol by the kernel or HAL 136 | /// @param proc_name A name of a symbol to locate an address 137 | /// @return An address of the symbol or nullptr 138 | void *UtilGetSystemProcAddress(_In_ const wchar_t *proc_name); 139 | 140 | /// Checks if the system is a PAE-enabled x86 system 141 | /// @return true if the system is a PAE-enabled x86 system 142 | bool UtilIsX86Pae(); 143 | 144 | /// Checks is the address is present on physical memory 145 | /// @param address A virtual address to test 146 | /// @return true if the \a address is present on physical memory 147 | bool UtilIsAccessibleAddress(_In_ void *address); 148 | 149 | /// VA -> PA 150 | /// @param va A virtual address to get its physical address 151 | /// @return A physical address of \a va, or nullptr 152 | /// 153 | /// @warning 154 | /// It cannot be used for a virtual address managed by a prototype PTE. 155 | ULONG64 UtilPaFromVa(_In_ void *va); 156 | 157 | /// VA -> PFN 158 | /// @param va A virtual address to get its physical address 159 | /// @return A page frame number of \a va, or 0 160 | /// 161 | /// @warning 162 | /// It cannot be used for a virtual address managed by a prototype PTE. 163 | PFN_NUMBER UtilPfnFromVa(_In_ void *va); 164 | 165 | /// PA -> PFN 166 | /// @param pa A physical address to get its page frame number 167 | /// @return A page frame number of \a pa, or 0 168 | PFN_NUMBER UtilPfnFromPa(_In_ ULONG64 pa); 169 | 170 | /// PA -> VA 171 | /// @param pa A physical address to get its virtual address 172 | /// @return A virtual address \a pa, or 0 173 | void *UtilVaFromPa(_In_ ULONG64 pa); 174 | 175 | /// PNF -> PA 176 | /// @param pfn A page frame number to get its physical address 177 | /// @return A physical address of \a pfn 178 | ULONG64 UtilPaFromPfn(_In_ PFN_NUMBER pfn); 179 | 180 | /// PNF -> VA 181 | /// @param pfn A page frame number to get its virtual address 182 | /// @return A virtual address of \a pfn 183 | void *UtilVaFromPfn(_In_ PFN_NUMBER pfn); 184 | 185 | /// Allocates continuous physical memory 186 | /// @param number_of_bytes A size to allocate 187 | /// @return A base address of an allocated memory or nullptr 188 | /// 189 | /// A returned value must be freed with UtilFreeContiguousMemory(). 190 | _Must_inspect_result_ _IRQL_requires_max_(DISPATCH_LEVEL) void 191 | *UtilAllocateContiguousMemory(_In_ SIZE_T number_of_bytes); 192 | 193 | /// Frees an address allocated by UtilAllocateContiguousMemory() 194 | /// @param base_address A return value of UtilAllocateContiguousMemory() to free 195 | _IRQL_requires_max_(DISPATCH_LEVEL) void UtilFreeContiguousMemory( 196 | _In_ void *base_address); 197 | 198 | /// Executes VMCALL 199 | /// @param hypercall_number A command number 200 | /// @param context An arbitrary parameter 201 | /// @return STATUS_SUCCESS if VMXON instruction succeeded 202 | NTSTATUS UtilVmCall(_In_ HypercallNumber hypercall_number, 203 | _In_opt_ void *context); 204 | 205 | /// Debug prints registers 206 | /// @param all_regs Registers to print out 207 | /// @param stack_pointer A stack pointer before calling this function 208 | void UtilDumpGpRegisters(_In_ const AllRegisters *all_regs, 209 | _In_ ULONG_PTR stack_pointer); 210 | 211 | /// Reads natural-width VMCS 212 | /// @param field VMCS-field to read 213 | /// @return read value 214 | ULONG_PTR UtilVmRead(_In_ VmcsField field); 215 | 216 | /// Reads 64bit-width VMCS 217 | /// @param field VMCS-field to read 218 | /// @return read value 219 | ULONG64 UtilVmRead64(_In_ VmcsField field); 220 | 221 | /// Writes natural-width VMCS 222 | /// @param field VMCS-field to write 223 | /// @param field_value A value to write 224 | /// @return A result of the VMWRITE instruction 225 | VmxStatus UtilVmWrite(_In_ VmcsField field, _In_ ULONG_PTR field_value); 226 | 227 | /// Writes 64bit-width VMCS 228 | /// @param field VMCS-field to write 229 | /// @param field_value A value to write 230 | /// @return A result of the VMWRITE instruction 231 | VmxStatus UtilVmWrite64(_In_ VmcsField field, _In_ ULONG64 field_value); 232 | 233 | /// Reads natural-width MSR 234 | /// @param msr MSR to read 235 | /// @return read value 236 | ULONG_PTR UtilReadMsr(_In_ Msr msr); 237 | 238 | /// Reads 64bit-width MSR 239 | /// @param msr MSR to read 240 | /// @return read value 241 | ULONG64 UtilReadMsr64(_In_ Msr msr); 242 | 243 | /// Writes natural-width MSR 244 | /// @param msr MSR to write 245 | /// @param value A value to write 246 | void UtilWriteMsr(_In_ Msr msr, _In_ ULONG_PTR value); 247 | 248 | /// Writes 64bit-width MSR 249 | /// @param msr MSR to write 250 | /// @param value A value to write 251 | void UtilWriteMsr64(_In_ Msr msr, _In_ ULONG64 value); 252 | 253 | /// Executes the INVEPT instruction and invalidates EPT entry cache 254 | /// @return A result of the INVEPT instruction 255 | VmxStatus UtilInveptGlobal(); 256 | 257 | /// Executes the INVVPID instruction (type 0) 258 | /// @return A result of the INVVPID instruction 259 | VmxStatus UtilInvvpidIndividualAddress(_In_ USHORT vpid, _In_ void *address); 260 | 261 | /// Executes the INVVPID instruction (type 1) 262 | /// @return A result of the INVVPID instruction 263 | VmxStatus UtilInvvpidSingleContext(_In_ USHORT vpid); 264 | 265 | /// Executes the INVVPID instruction (type 2) 266 | /// @return A result of the INVVPID instruction 267 | VmxStatus UtilInvvpidAllContext(); 268 | 269 | /// Executes the INVVPID instruction (type 3) 270 | /// @return A result of the INVVPID instruction 271 | VmxStatus UtilInvvpidSingleContextExceptGlobal(_In_ USHORT vpid); 272 | 273 | /// Loads the PDPTE registers from CR3 to VMCS 274 | /// @param cr3_value CR3 value to retrieve PDPTEs 275 | void UtilLoadPdptes(_In_ ULONG_PTR cr3_value); 276 | 277 | /// Does RtlCopyMemory safely even if destination is a read only region 278 | /// @param destination A destination address 279 | /// @param source A source address 280 | /// @param length A size to copy in bytes 281 | /// @return STATUS_SUCCESS if successful 282 | _IRQL_requires_max_(DISPATCH_LEVEL) NTSTATUS 283 | UtilForceCopyMemory(_In_ void *destination, _In_ const void *source, 284 | _In_ SIZE_T length); 285 | 286 | //////////////////////////////////////////////////////////////////////////////// 287 | // 288 | // variables 289 | // 290 | 291 | //////////////////////////////////////////////////////////////////////////////// 292 | // 293 | // implementations 294 | // 295 | 296 | } // extern "C" 297 | 298 | /// Tests if \a value is in between \a min and \a max 299 | /// @param value A value to test 300 | /// @param min A minimum acceptable value 301 | /// @param max A maximum acceptable value 302 | /// @return true if \a value is in between \a min and \a max 303 | template 304 | constexpr bool UtilIsInBounds(_In_ const T &value, _In_ const T &min, 305 | _In_ const T &max) { 306 | return (min <= value) && (value <= max); 307 | } 308 | 309 | #endif // HYPERPLATFORM_UTIL_H_ 310 | -------------------------------------------------------------------------------- /HyperPlatform/HyperPlatform/util_page_constants.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2017, Satoshi Tanda. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | /// @file 6 | /// Defines page table related constants 7 | /// 8 | /// This file defines platform dependent constants and is included only from a 9 | /// function where initializes g_utilp_p*e_base, g_utilp_p*i_shift and 10 | /// g_utilp_p*i_mask global variables. 11 | 12 | #ifndef HYPERPLATFORM_UTIL_CONSTANT_H_ 13 | #define HYPERPLATFORM_UTIL_CONSTANT_H_ 14 | 15 | // Virtual Address Interpretation For Handling PTEs 16 | // 17 | // -- On x64 18 | // Sign extension 16 bits 19 | // Page map level 4 selector 9 bits 20 | // Page directory pointer selector 9 bits 21 | // Page directory selector 9 bits 22 | // Page table selector 9 bits 23 | // Byte within page 12 bits 24 | // 11111111 11111111 11111000 10000000 00000011 01010011 00001010 00011000 25 | // ^^^^^^^^ ^^^^^^^^ ~~~~~~~~ ~^^^^^^^ ^^~~~~~~ ~~~^^^^^ ^^^^~~~~ ~~~~~~~~ 26 | // Sign extension PML4 PDPT PD PT Offset 27 | // 28 | // -- On x86(PAE) 29 | // Page directory pointer selector 2 bits 30 | // Page directory selector 9 bits 31 | // Page table selector 9 bits 32 | // Byte within page 12 bits 33 | // 10 000011011 000001101 001001110101 34 | // ^^ ~~~~~~~~~ ^^^^^^^^^ ~~~~~~~~~~~~ 35 | // PDPT PD PT Offset 36 | // 37 | // -- On x86 and ARM 38 | // Page directory selector 10 bits 39 | // Page table selector 10 bits 40 | // Byte within page 12 bits 41 | // 1000001101 1000001101 001001110101 42 | // ~~~~~~~~~~ ^^^^^^^^^^ ~~~~~~~~~~~~ 43 | // PD PT Offset 44 | // 45 | // 46 | // x64 x86(PAE) x86 ARM 47 | // Page map level 4 selector 9 - - - 48 | // Page directory pointer selector 9 2 - - 49 | // Page directory selector 9 9 10 10 50 | // Page table selector 9 9 10 10 51 | // Byte within page 12 12 12 12 52 | // 53 | // 6666555555555544444444443333333333222222222211111111110000000000 54 | // 3210987654321098765432109876543210987654321098765432109876543210 55 | // ---------------------------------------------------------------- 56 | // aaaaaaaaaaaaaaaabbbbbbbbbcccccccccdddddddddeeeeeeeeeffffffffffff x64 57 | // ................................ccdddddddddeeeeeeeeeffffffffffff x86(PAE) 58 | // ................................ddddddddddeeeeeeeeeeffffffffffff x86 59 | // ................................ddddddddddeeeeeeeeeeffffffffffff ARM 60 | // 61 | // a = Sign extension, b = PML4, c = PDPT, d = PD, e = PT, f = Offset 62 | 63 | #if defined(_AMD64_) 64 | 65 | // Base addresses of page structures. Use !pte to obtain them. 66 | static auto kUtilpPxeBase = 0xfffff6fb7dbed000ull; 67 | static auto kUtilpPpeBase = 0xfffff6fb7da00000ull; 68 | static auto kUtilpPdeBase = 0xfffff6fb40000000ull; 69 | static auto kUtilpPteBase = 0xfffff68000000000ull; 70 | 71 | // Get the highest 25 bits 72 | static const auto kUtilpPxiShift = 39ull; 73 | 74 | // Get the highest 34 bits 75 | static const auto kUtilpPpiShift = 30ull; 76 | 77 | // Get the highest 43 bits 78 | static const auto kUtilpPdiShift = 21ull; 79 | 80 | // Get the highest 52 bits 81 | static const auto kUtilpPtiShift = 12ull; 82 | 83 | // Use 9 bits; 0b0000_0000_0000_0000_0000_0000_0001_1111_1111 84 | static const auto kUtilpPxiMask = 0x1ffull; 85 | 86 | // Use 18 bits; 0b0000_0000_0000_0000_0011_1111_1111_1111_1111 87 | static const auto kUtilpPpiMask = 0x3ffffull; 88 | 89 | // Use 27 bits; 0b0000_0000_0111_1111_1111_1111_1111_1111_1111 90 | static const auto kUtilpPdiMask = 0x7ffffffull; 91 | 92 | // Use 36 bits; 0b1111_1111_1111_1111_1111_1111_1111_1111_1111 93 | static const auto kUtilpPtiMask = 0xfffffffffull; 94 | 95 | #elif defined(_X86_) 96 | 97 | // Base addresses of page structures. Use !pte to obtain them. 98 | static auto kUtilpPdeBase = 0xc0300000; 99 | static auto kUtilpPteBase = 0xc0000000; 100 | 101 | // Get the highest 10 bits 102 | static const auto kUtilpPdiShift = 22; 103 | 104 | // Get the highest 20 bits 105 | static const auto kUtilpPtiShift = 12; 106 | 107 | // Use 10 bits; 0b0000_0000_0000_0000_0000_0000_0011_1111_1111 108 | static const auto kUtilpPdiMask = 0x3ff; 109 | 110 | // Use 20 bits; 0b0000_0000_0000_0000_1111_1111_1111_1111_1111 111 | static const auto kUtilpPtiMask = 0xfffff; 112 | 113 | // unused but defined to compile without ifdef 114 | 115 | static auto kUtilpPxeBase = 0; 116 | static auto kUtilpPpeBase = 0; 117 | static const auto kUtilpPxiShift = 0; 118 | static const auto kUtilpPpiShift = 0; 119 | static const auto kUtilpPxiMask = 0; 120 | static const auto kUtilpPpiMask = 0; 121 | 122 | #endif 123 | 124 | // Base addresses of page structures. Use !pte to obtain them. 125 | static const auto kUtilpPdeBasePae = 0xc0600000; 126 | static const auto kUtilpPteBasePae = 0xc0000000; 127 | 128 | // Get the highest 11 bits 129 | static const auto kUtilpPdiShiftPae = 21; 130 | 131 | // Get the highest 20 bits 132 | static const auto kUtilpPtiShiftPae = 12; 133 | 134 | // Use 11 bits; 0b0000_0000_0000_0000_0000_0000_0111_1111_1111 135 | static const auto kUtilpPdiMaskPae = 0x7ff; 136 | 137 | // Use 20 bits; 0b0000_0000_0000_0000_1111_1111_1111_1111_1111 138 | static const auto kUtilpPtiMaskPae = 0xfffff; 139 | 140 | #endif // HYPERPLATFORM_UTIL_H_ 141 | -------------------------------------------------------------------------------- /HyperPlatform/HyperPlatform/vm.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bb33bb/r3epthook/2ab806c04fbb6456eccae32d4374959f5116a05b/HyperPlatform/HyperPlatform/vm.cpp -------------------------------------------------------------------------------- /HyperPlatform/HyperPlatform/vm.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2017, Satoshi Tanda. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | /// @file 6 | /// Declares interfaces to VMM initialization functions 7 | 8 | #ifndef HYPERPLATFORM_VM_H_ 9 | #define HYPERPLATFORM_VM_H_ 10 | 11 | #include 12 | 13 | extern "C" { 14 | //////////////////////////////////////////////////////////////////////////////// 15 | // 16 | // macro utilities 17 | // 18 | 19 | //////////////////////////////////////////////////////////////////////////////// 20 | // 21 | // constants and macros 22 | // 23 | 24 | //////////////////////////////////////////////////////////////////////////////// 25 | // 26 | // types 27 | // 28 | 29 | //////////////////////////////////////////////////////////////////////////////// 30 | // 31 | // prototypes 32 | // 33 | 34 | /// Virtualizes all processors 35 | /// @return STATUS_SUCCESS on success 36 | /// 37 | /// Initializes a VMCS region and virtualizes (ie, enters the VMX non-root 38 | /// operation mode) for each processor. Returns non STATUS_SUCCESS value if any 39 | /// of processors failed to do so. In that case, this function de-virtualize 40 | /// already virtualized processors. 41 | _IRQL_requires_max_(PASSIVE_LEVEL) NTSTATUS VmInitialization(); 42 | 43 | /// De-virtualize all processors 44 | _IRQL_requires_max_(PASSIVE_LEVEL) void VmTermination(); 45 | 46 | /// Virtualizes the specified processor 47 | /// @param proc_num A processor number to virtualize 48 | /// @return STATUS_SUCCESS on success 49 | /// 50 | /// The processor 0 must have already been virtualized, or it fails. 51 | _IRQL_requires_max_(PASSIVE_LEVEL) NTSTATUS 52 | VmHotplugCallback(const PROCESSOR_NUMBER& proc_num); 53 | 54 | //////////////////////////////////////////////////////////////////////////////// 55 | // 56 | // variables 57 | // 58 | 59 | //////////////////////////////////////////////////////////////////////////////// 60 | // 61 | // implementations 62 | // 63 | 64 | } // extern "C" 65 | 66 | #endif // HYPERPLATFORM_VM_H_ 67 | -------------------------------------------------------------------------------- /HyperPlatform/HyperPlatform/vmm.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bb33bb/r3epthook/2ab806c04fbb6456eccae32d4374959f5116a05b/HyperPlatform/HyperPlatform/vmm.cpp -------------------------------------------------------------------------------- /HyperPlatform/HyperPlatform/vmm.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2017, Satoshi Tanda. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | 5 | /// @file 6 | /// Declares interfaces to VMM functions. 7 | 8 | #ifndef HYPERPLATFORM_VMM_H_ 9 | #define HYPERPLATFORM_VMM_H_ 10 | 11 | #include 12 | 13 | //////////////////////////////////////////////////////////////////////////////// 14 | // 15 | // macro utilities 16 | // 17 | 18 | //////////////////////////////////////////////////////////////////////////////// 19 | // 20 | // constants and macros 21 | // 22 | 23 | //////////////////////////////////////////////////////////////////////////////// 24 | // 25 | // types 26 | // 27 | 28 | /// Represents VMM related data shared across all processors 29 | struct SharedProcessorData { 30 | volatile long reference_count; //!< Number of processors sharing this data 31 | void* msr_bitmap; //!< Bitmap to activate MSR I/O VM-exit 32 | void* io_bitmap_a; //!< Bitmap to activate IO VM-exit (~ 0x7FFF) 33 | void* io_bitmap_b; //!< Bitmap to activate IO VM-exit (~ 0xffff) 34 | 35 | struct SharedFakePageData* shared_fp_data; ///< Shared fake page data 36 | }; 37 | 38 | /// Represents VMM related data associated with each processor 39 | struct ProcessorData { 40 | SharedProcessorData* shared_data; //!< Shared data 41 | void* vmm_stack_limit; //!< A head of VA for VMM stack 42 | struct VmControlStructure* vmxon_region; //!< VA of a VMXON region 43 | struct VmControlStructure* vmcs_region; //!< VA of a VMCS region 44 | struct EptData* ept_data; //!< A pointer to EPT related data 45 | struct ProcessorFakePageData* fp_data; ///< Per-processor fake page data 46 | }; 47 | 48 | //////////////////////////////////////////////////////////////////////////////// 49 | // 50 | // prototypes 51 | // 52 | 53 | //////////////////////////////////////////////////////////////////////////////// 54 | // 55 | // variables 56 | // 57 | 58 | //////////////////////////////////////////////////////////////////////////////// 59 | // 60 | // implementations 61 | // 62 | 63 | #endif // HYPERPLATFORM_VMM_H_ 64 | -------------------------------------------------------------------------------- /HyperPlatform/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Satoshi Tanda 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /HyperPlatform/README.md: -------------------------------------------------------------------------------- 1 | HyperPlatform 2 | ============== 3 | 4 | Introduction 5 | ------------- 6 | HyperPlatform is an Intel VT-x based hypervisor (a.k.a. virtual machine monitor) 7 | aiming to provide a thin platform for research on Windows. HyperPlatform is 8 | capable of monitoring a wide range of events, including but not limited to, 9 | access to virtual/physical memory and system registers, occurrences of interrupts 10 | and execution of certain instructions. 11 | 12 | Researchers are free to selectively enable and/or disable any of those event 13 | monitoring and implement their own logic on the top of HyperPlatform. Some 14 | potential applications are: 15 | - Analyzing kernel mode rootkit 16 | - Implementing virtual-machine-based intrusion prevention system (VIPS) 17 | - Reverse-engineering the Windows kernel 18 | 19 | A simplified implementation of those ideas are available: 20 | - MemoryMon detecting execution of kernel memory for rootkit analysis 21 | - https://github.com/tandasat/MemoryMon 22 | - EopMon spotting a successful elevation of privilege (EoP) exploit 23 | - https://github.com/tandasat/EopMon 24 | - DdiMon monitoring and controlling kernel API calls with stealth hook using EPT 25 | - https://github.com/tandasat/DdiMon 26 | - GuardMon observing some of PatchGuard activities 27 | - https://github.com/tandasat/GuardMon 28 | 29 | 30 | Advantages 31 | ----------- 32 | HyperPlatform is designed to be easy to read and extend by researchers, 33 | especially those who are familiar with Windows. For instance: 34 | - HyperPlatform runs on Windows 7, 8.1 and 10 in both 32 and 64 bit architectures 35 | without any special configuration (except for enabling Intel-VT technology). 36 | - HyperPlatform compiles in Visual Studio and can be debugged though Windbg 37 | just like a regular software driver. 38 | - Source code of HyperPlatform is written and formatted in existing styles 39 | (Google C++ Style Guide and clang-format), and well commented. 40 | - HyperPlatform has no dependencies, supports use of STL and is released under 41 | a relaxed license. 42 | 43 | For more details, see the HyperPlatform User Document and Programmer's Reference. 44 | - http://tandasat.github.io/HyperPlatform/userdocument/ 45 | - http://tandasat.github.io/HyperPlatform/doxygen/ 46 | 47 | 48 | Build 49 | ------ 50 | To build HyperPlatform, the following are required. 51 | - Visual Studio Community 2015 Update 3 52 | - https://beta.visualstudio.com/downloads/ 53 | - Windows Software Development Kit (SDK) for Windows 10 (10.0.10586.0 or later) 54 | - https://developer.microsoft.com/en-us/windows/downloads/windows-10-sdk 55 | - Windows Driver Kit (WDK) 10 (10.0.10586.0 or later) 56 | - https://developer.microsoft.com/en-us/windows/hardware/windows-driver-kit 57 | 58 | 59 | Installation and Uninstallation 60 | -------------------------------- 61 | Clone full source code from Github with a below command and compile it on Visual 62 | Studio. 63 | 64 | $ git clone --recursive https://github.com/tandasat/HyperPlatform.git 65 | 66 | On the x64 platform, you have to enable test signing to install the driver. 67 | To do that, open the command prompt with the administrator privilege and type 68 | the following command, and then restart the system to activate the change: 69 | 70 | >bcdedit /set testsigning on 71 | 72 | To install and uninstall the driver, use the 'sc' command. For installation: 73 | 74 | >sc create HyperPlatform type= kernel binPath= C:\Users\user\Desktop\HyperPlatform.sys 75 | >sc start HyperPlatform 76 | 77 | For uninstallation: 78 | 79 | >sc stop HyperPlatform 80 | >sc delete HyperPlatform 81 | >bcdedit /deletevalue testsigning 82 | 83 | 84 | Note that the system must support the Intel VT-x and EPT technology to 85 | successfully install the driver. 86 | 87 | To install the driver on a virtual machine on VMware Workstation, see an "Using 88 | VMware Workstation" section in the HyperPlatform User Document. 89 | - http://tandasat.github.io/HyperPlatform/userdocument/ 90 | 91 | 92 | Output 93 | ------- 94 | All logs are printed out to DbgView and saved in C:\Windows\HyperPlatform.log. 95 | 96 | 97 | Supported Platforms 98 | -------------------- 99 | - x86 and x64 Windows 7, 8.1 and 10 100 | - The system must support the Intel VT-x and EPT technology 101 | 102 | 103 | Related Project(s) 104 | -------------------- 105 | - SimpleVisor 106 | - http://ionescu007.github.io/SimpleVisor/ 107 | 108 | SimpleVisor is a very (very) simple and readable Windows-specific hypervisor made 109 | up of only 1700 lines of code. I would recommend taking a look at the project to 110 | learn VT-x if you are new to hypervisor development. It should give you a clearer 111 | view of how a hypervisor is initialized and executed. 112 | 113 | - ksm 114 | - https://github.com/asamy/ksm 115 | 116 | ksm is other simple and lightweight x64 hypervisor written in C for Windows for 117 | Intel processors. It is just a half size of HyperPlatform in lines of code while 118 | demonstrating usage of EPT, as well as #VE and VMFUNC where HyperPlatform does 119 | not include. 120 | 121 | - Bareflank Hypervisor 122 | - http://bareflank.github.io/hypervisor/ 123 | 124 | Bareflank Hypervisor is an actively developed open source, lightweight hypervisor. 125 | It comes with rich documents, tests, and comments, supports Linux on Intel 64bit, 126 | and also aims to support Windows, OS X, and UEFI as well as ARM and AMD platforms. 127 | While a size of code is larger than that of HyperPlatform, ones look for a more 128 | complihensive yet still lightweight hypervisor will find it interesting. 129 | 130 | 131 | License 132 | -------- 133 | This software is released under the MIT License, see LICENSE. 134 | -------------------------------------------------------------------------------- /HyperPlatform/clean.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | del *.sdf 3 | del *.VC.db 4 | del /s *.aps 5 | del /a:h *.suo 6 | rmdir /s /q .vs 7 | rmdir /s /q ipch 8 | rmdir /s /q x64 9 | rmdir /s /q Debug 10 | rmdir /s /q Release 11 | rmdir /s /q HyperPlatform\x64 12 | rmdir /s /q HyperPlatform\Debug 13 | rmdir /s /q HyperPlatform\Release 14 | rmdir /s /q doxygen 15 | pause 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # r3epthook 2 | 使用vt进行无痕hook,支持r3 3 | -------------------------------------------------------------------------------- /x64/Debug/FU_Hypervisor.cer: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bb33bb/r3epthook/2ab806c04fbb6456eccae32d4374959f5116a05b/x64/Debug/FU_Hypervisor.cer -------------------------------------------------------------------------------- /x64/Debug/FU_Hypervisor.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bb33bb/r3epthook/2ab806c04fbb6456eccae32d4374959f5116a05b/x64/Debug/FU_Hypervisor.pdb -------------------------------------------------------------------------------- /x64/Debug/FU_Hypervisor.sys: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bb33bb/r3epthook/2ab806c04fbb6456eccae32d4374959f5116a05b/x64/Debug/FU_Hypervisor.sys -------------------------------------------------------------------------------- /x64/Debug/FU_Hypervisor/FU_Hypervisor.sys: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bb33bb/r3epthook/2ab806c04fbb6456eccae32d4374959f5116a05b/x64/Debug/FU_Hypervisor/FU_Hypervisor.sys -------------------------------------------------------------------------------- /x64/Debug/FU_Hypervisor/WdfCoinstaller01009.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bb33bb/r3epthook/2ab806c04fbb6456eccae32d4374959f5116a05b/x64/Debug/FU_Hypervisor/WdfCoinstaller01009.dll -------------------------------------------------------------------------------- /x64/Release/FU_Hypervisor.cer: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bb33bb/r3epthook/2ab806c04fbb6456eccae32d4374959f5116a05b/x64/Release/FU_Hypervisor.cer -------------------------------------------------------------------------------- /x64/Release/FU_Hypervisor.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bb33bb/r3epthook/2ab806c04fbb6456eccae32d4374959f5116a05b/x64/Release/FU_Hypervisor.pdb -------------------------------------------------------------------------------- /x64/Release/FU_Hypervisor.sys: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bb33bb/r3epthook/2ab806c04fbb6456eccae32d4374959f5116a05b/x64/Release/FU_Hypervisor.sys -------------------------------------------------------------------------------- /x64/Release/FU_Hypervisor/FU_Hypervisor.sys: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bb33bb/r3epthook/2ab806c04fbb6456eccae32d4374959f5116a05b/x64/Release/FU_Hypervisor/FU_Hypervisor.sys -------------------------------------------------------------------------------- /x64/Release/FU_Hypervisor/WdfCoinstaller01009.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bb33bb/r3epthook/2ab806c04fbb6456eccae32d4374959f5116a05b/x64/Release/FU_Hypervisor/WdfCoinstaller01009.dll --------------------------------------------------------------------------------