├── .gitattributes
├── .gitignore
├── LICENSE
├── README.md
├── airhv.sln
├── airhv
├── airhv.vcxproj
├── airhv.vcxproj.filters
├── airhv.vcxproj.user
├── allocators.h
├── asm
│ ├── vm_context.asm
│ ├── vm_context.h
│ ├── vm_intrin.asm
│ └── vm_intrin.h
├── common.h
├── ept.cpp
├── hypervisor_gateway.cpp
├── hypervisor_gateway.h
├── hypervisor_routines.cpp
├── hypervisor_routines.h
├── ia32
│ ├── cpuid.h
│ ├── cr.h
│ ├── dr.h
│ ├── ept.h
│ ├── exception.h
│ ├── msr.h
│ ├── mtrr.h
│ ├── rflags.h
│ ├── segment.h
│ ├── vmcs.h
│ └── vmcs_encodings.h
├── interrupt.h
├── invalidators.cpp
├── invalidators.h
├── lde
│ └── lde64.asm
├── log.cpp
├── log.h
├── main.cpp
├── ntapi.h
├── poolmanager.cpp
├── poolmanager.h
├── spinlock.cpp
├── spinlock.h
├── vmcall_handler.cpp
├── vmcall_handler.h
├── vmcall_reason.h
├── vmcs.cpp
├── vmexit_handler.cpp
├── vmexit_handler.h
├── vmm.cpp
├── vmm.h
└── xsave.h
└── airhvctrl
├── airhvctrl.vcxproj
├── airhvctrl.vcxproj.filters
├── hypervisor_gateway.cpp
├── hypervisor_gateway.h
├── log.cpp
├── log.h
├── main.cpp
├── nt.h
└── vmintrin.asm
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.h linguist-language=c++
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Mono auto generated files
17 | mono_crash.*
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | [Ww][Ii][Nn]32/
27 | [Aa][Rr][Mm]/
28 | [Aa][Rr][Mm]64/
29 | bld/
30 | [Bb]in/
31 | [Oo]bj/
32 | [Ll]og/
33 | [Ll]ogs/
34 |
35 | # Visual Studio 2015/2017 cache/options directory
36 | .vs/
37 | # Uncomment if you have tasks that create the project's static files in wwwroot
38 | #wwwroot/
39 |
40 | # Visual Studio 2017 auto generated files
41 | Generated\ Files/
42 |
43 | # MSTest test Results
44 | [Tt]est[Rr]esult*/
45 | [Bb]uild[Ll]og.*
46 |
47 | # NUnit
48 | *.VisualState.xml
49 | TestResult.xml
50 | nunit-*.xml
51 |
52 | # Build Results of an ATL Project
53 | [Dd]ebugPS/
54 | [Rr]eleasePS/
55 | dlldata.c
56 |
57 | # Benchmark Results
58 | BenchmarkDotNet.Artifacts/
59 |
60 | # .NET Core
61 | project.lock.json
62 | project.fragment.lock.json
63 | artifacts/
64 |
65 | # ASP.NET Scaffolding
66 | ScaffoldingReadMe.txt
67 |
68 | # StyleCop
69 | StyleCopReport.xml
70 |
71 | # Files built by Visual Studio
72 | *_i.c
73 | *_p.c
74 | *_h.h
75 | *.ilk
76 | *.meta
77 | *.obj
78 | *.iobj
79 | *.pch
80 | *.pdb
81 | *.ipdb
82 | *.pgc
83 | *.pgd
84 | *.rsp
85 | *.sbr
86 | *.tlb
87 | *.tli
88 | *.tlh
89 | *.tmp
90 | *.tmp_proj
91 | *_wpftmp.csproj
92 | *.log
93 | *.tlog
94 | *.vspscc
95 | *.vssscc
96 | .builds
97 | *.pidb
98 | *.svclog
99 | *.scc
100 |
101 | # Chutzpah Test files
102 | _Chutzpah*
103 |
104 | # Visual C++ cache files
105 | ipch/
106 | *.aps
107 | *.ncb
108 | *.opendb
109 | *.opensdf
110 | *.sdf
111 | *.cachefile
112 | *.VC.db
113 | *.VC.VC.opendb
114 |
115 | # Visual Studio profiler
116 | *.psess
117 | *.vsp
118 | *.vspx
119 | *.sap
120 |
121 | # Visual Studio Trace Files
122 | *.e2e
123 |
124 | # TFS 2012 Local Workspace
125 | $tf/
126 |
127 | # Guidance Automation Toolkit
128 | *.gpState
129 |
130 | # ReSharper is a .NET coding add-in
131 | _ReSharper*/
132 | *.[Rr]e[Ss]harper
133 | *.DotSettings.user
134 |
135 | # TeamCity is a build add-in
136 | _TeamCity*
137 |
138 | # DotCover is a Code Coverage Tool
139 | *.dotCover
140 |
141 | # AxoCover is a Code Coverage Tool
142 | .axoCover/*
143 | !.axoCover/settings.json
144 |
145 | # Coverlet is a free, cross platform Code Coverage Tool
146 | coverage*.json
147 | coverage*.xml
148 | coverage*.info
149 |
150 | # Visual Studio code coverage results
151 | *.coverage
152 | *.coveragexml
153 |
154 | # NCrunch
155 | _NCrunch_*
156 | .*crunch*.local.xml
157 | nCrunchTemp_*
158 |
159 | # MightyMoose
160 | *.mm.*
161 | AutoTest.Net/
162 |
163 | # Web workbench (sass)
164 | .sass-cache/
165 |
166 | # Installshield output folder
167 | [Ee]xpress/
168 |
169 | # DocProject is a documentation generator add-in
170 | DocProject/buildhelp/
171 | DocProject/Help/*.HxT
172 | DocProject/Help/*.HxC
173 | DocProject/Help/*.hhc
174 | DocProject/Help/*.hhk
175 | DocProject/Help/*.hhp
176 | DocProject/Help/Html2
177 | DocProject/Help/html
178 |
179 | # Click-Once directory
180 | publish/
181 |
182 | # Publish Web Output
183 | *.[Pp]ublish.xml
184 | *.azurePubxml
185 | # Note: Comment the next line if you want to checkin your web deploy settings,
186 | # but database connection strings (with potential passwords) will be unencrypted
187 | *.pubxml
188 | *.publishproj
189 |
190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
191 | # checkin your Azure Web App publish settings, but sensitive information contained
192 | # in these scripts will be unencrypted
193 | PublishScripts/
194 |
195 | # NuGet Packages
196 | *.nupkg
197 | # NuGet Symbol Packages
198 | *.snupkg
199 | # The packages folder can be ignored because of Package Restore
200 | **/[Pp]ackages/*
201 | # except build/, which is used as an MSBuild target.
202 | !**/[Pp]ackages/build/
203 | # Uncomment if necessary however generally it will be regenerated when needed
204 | #!**/[Pp]ackages/repositories.config
205 | # NuGet v3's project.json files produces more ignorable files
206 | *.nuget.props
207 | *.nuget.targets
208 |
209 | # Microsoft Azure Build Output
210 | csx/
211 | *.build.csdef
212 |
213 | # Microsoft Azure Emulator
214 | ecf/
215 | rcf/
216 |
217 | # Windows Store app package directories and files
218 | AppPackages/
219 | BundleArtifacts/
220 | Package.StoreAssociation.xml
221 | _pkginfo.txt
222 | *.appx
223 | *.appxbundle
224 | *.appxupload
225 |
226 | # Visual Studio cache files
227 | # files ending in .cache can be ignored
228 | *.[Cc]ache
229 | # but keep track of directories ending in .cache
230 | !?*.[Cc]ache/
231 |
232 | # Others
233 | ClientBin/
234 | ~$*
235 | *~
236 | *.dbmdl
237 | *.dbproj.schemaview
238 | *.jfm
239 | *.pfx
240 | *.publishsettings
241 | orleans.codegen.cs
242 |
243 | # Including strong name files can present a security risk
244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
245 | #*.snk
246 |
247 | # Since there are multiple workflows, uncomment next line to ignore bower_components
248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
249 | #bower_components/
250 |
251 | # RIA/Silverlight projects
252 | Generated_Code/
253 |
254 | # Backup & report files from converting an old project file
255 | # to a newer Visual Studio version. Backup files are not needed,
256 | # because we have git ;-)
257 | _UpgradeReport_Files/
258 | Backup*/
259 | UpgradeLog*.XML
260 | UpgradeLog*.htm
261 | ServiceFabricBackup/
262 | *.rptproj.bak
263 |
264 | # SQL Server files
265 | *.mdf
266 | *.ldf
267 | *.ndf
268 |
269 | # Business Intelligence projects
270 | *.rdl.data
271 | *.bim.layout
272 | *.bim_*.settings
273 | *.rptproj.rsuser
274 | *- [Bb]ackup.rdl
275 | *- [Bb]ackup ([0-9]).rdl
276 | *- [Bb]ackup ([0-9][0-9]).rdl
277 |
278 | # Microsoft Fakes
279 | FakesAssemblies/
280 |
281 | # GhostDoc plugin setting file
282 | *.GhostDoc.xml
283 |
284 | # Node.js Tools for Visual Studio
285 | .ntvs_analysis.dat
286 | node_modules/
287 |
288 | # Visual Studio 6 build log
289 | *.plg
290 |
291 | # Visual Studio 6 workspace options file
292 | *.opt
293 |
294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
295 | *.vbw
296 |
297 | # Visual Studio 6 auto-generated project file (contains which files were open etc.)
298 | *.vbp
299 |
300 | # Visual Studio 6 workspace and project file (working project files containing files to include in project)
301 | *.dsw
302 | *.dsp
303 |
304 | # Visual Studio 6 technical files
305 | *.ncb
306 | *.aps
307 |
308 | # Visual Studio LightSwitch build output
309 | **/*.HTMLClient/GeneratedArtifacts
310 | **/*.DesktopClient/GeneratedArtifacts
311 | **/*.DesktopClient/ModelManifest.xml
312 | **/*.Server/GeneratedArtifacts
313 | **/*.Server/ModelManifest.xml
314 | _Pvt_Extensions
315 |
316 | # Paket dependency manager
317 | .paket/paket.exe
318 | paket-files/
319 |
320 | # FAKE - F# Make
321 | .fake/
322 |
323 | # CodeRush personal settings
324 | .cr/personal
325 |
326 | # Python Tools for Visual Studio (PTVS)
327 | __pycache__/
328 | *.pyc
329 |
330 | # Cake - Uncomment if you are using it
331 | # tools/**
332 | # !tools/packages.config
333 |
334 | # Tabs Studio
335 | *.tss
336 |
337 | # Telerik's JustMock configuration file
338 | *.jmconfig
339 |
340 | # BizTalk build output
341 | *.btp.cs
342 | *.btm.cs
343 | *.odx.cs
344 | *.xsd.cs
345 |
346 | # OpenCover UI analysis results
347 | OpenCover/
348 |
349 | # Azure Stream Analytics local run output
350 | ASALocalRun/
351 |
352 | # MSBuild Binary and Structured Log
353 | *.binlog
354 |
355 | # NVidia Nsight GPU debugger configuration file
356 | *.nvuser
357 |
358 | # MFractors (Xamarin productivity tool) working folder
359 | .mfractor/
360 |
361 | # Local History for Visual Studio
362 | .localhistory/
363 |
364 | # Visual Studio History (VSHistory) files
365 | .vshistory/
366 |
367 | # BeatPulse healthcheck temp database
368 | healthchecksdb
369 |
370 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
371 | MigrationBackup/
372 |
373 | # Ionide (cross platform F# VS Code tools) working folder
374 | .ionide/
375 |
376 | # Fody - auto-generated XML schema
377 | FodyWeavers.xsd
378 |
379 | # VS Code files for those working on multiple tools
380 | .vscode/*
381 | !.vscode/settings.json
382 | !.vscode/tasks.json
383 | !.vscode/launch.json
384 | !.vscode/extensions.json
385 | *.code-workspace
386 |
387 | # Local History for Visual Studio Code
388 | .history/
389 |
390 | # Windows Installer files from build outputs
391 | *.cab
392 | *.msi
393 | *.msix
394 | *.msm
395 | *.msp
396 |
397 | # JetBrains Rider
398 | *.sln.iml
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Air14
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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # airhv
2 |
3 | airhv is a simple hypervisor based on Intel VT-x mainly focused on ept hooking
4 | ## Features
5 | * Ept support with mapping of 2MB pages (splitted dynamicly to 4KB pages if needed)
6 | * Ability to run in VMWare which is using few IO ports for communication between vmtools and VMWare hypervisor
7 | * Ability to handle various VM-exit cases: `CPUID` `RDTSC` `RDTSCP` `RDRAND` `RDSEED` `WBINVD/INVD` `IN/OUT` `XSETBV` `RDMSR` `WRMSR` `INVPCID` `MOV DR` `CR ACCESS` `EXCEPTIONS/NMI` `VMCALL` `INVLPG` `GDTR/IDTR ACCESS` `LDTR/TR ACCESS`
8 | * Ability to perform inline hooking via ept
9 | * Included simple driver (airhvctrl) which is communicating with hypervisor via `VMCALL` to hook syscall (via ept).
10 | It hooks NtCreateFile and every time user when tries to create a file named test.txt it prevents user from doing that.
11 |
12 | ## Future possible features
13 | * Ability to run under AMD-SVM
14 | * Ability to handle more VM-exit cases
15 | * Ability to make hypervisor not detectable via counters (rdtsc,rdtscp)
16 | * Ability to run nested VMs
17 | * MSR_LSTAR hooking
18 |
19 | ## Compilation
20 |
21 | Compile with Visual Studio 2019 (Requires [WDK](https://docs.microsoft.com/en-us/windows-hardware/drivers/download-the-wdk))
22 |
23 | ## Supported hardware
24 | Intel processors with VT-x and EPT support
25 |
26 | ## Supported platforms
27 | Windows 7 - Windows 10, x64 only
28 |
29 | ## License
30 | airhv is under MIT license.
31 | Dependencies are licensed by their own licenses.
32 |
--------------------------------------------------------------------------------
/airhv.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.30907.101
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "airhv", "airhv\airhv.vcxproj", "{CC497BEE-6B9E-4732-8B60-35DFE6526C28}"
7 | EndProject
8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "airhvctrl", "airhvctrl\airhvctrl.vcxproj", "{98E8F109-6A08-4461-A245-42B7CE32A703}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug_Minimal|x64 = Debug_Minimal|x64
13 | Debug|x64 = Debug|x64
14 | Release_Minimal|x64 = Release_Minimal|x64
15 | Release|x64 = Release|x64
16 | EndGlobalSection
17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
18 | {CC497BEE-6B9E-4732-8B60-35DFE6526C28}.Debug_Minimal|x64.ActiveCfg = Debug_Minimal|x64
19 | {CC497BEE-6B9E-4732-8B60-35DFE6526C28}.Debug_Minimal|x64.Build.0 = Debug_Minimal|x64
20 | {CC497BEE-6B9E-4732-8B60-35DFE6526C28}.Debug_Minimal|x64.Deploy.0 = Debug_Minimal|x64
21 | {CC497BEE-6B9E-4732-8B60-35DFE6526C28}.Debug|x64.ActiveCfg = Debug|x64
22 | {CC497BEE-6B9E-4732-8B60-35DFE6526C28}.Debug|x64.Build.0 = Debug|x64
23 | {CC497BEE-6B9E-4732-8B60-35DFE6526C28}.Debug|x64.Deploy.0 = Debug|x64
24 | {CC497BEE-6B9E-4732-8B60-35DFE6526C28}.Release_Minimal|x64.ActiveCfg = Release_Minimal|x64
25 | {CC497BEE-6B9E-4732-8B60-35DFE6526C28}.Release_Minimal|x64.Build.0 = Release_Minimal|x64
26 | {CC497BEE-6B9E-4732-8B60-35DFE6526C28}.Release_Minimal|x64.Deploy.0 = Release_Minimal|x64
27 | {CC497BEE-6B9E-4732-8B60-35DFE6526C28}.Release|x64.ActiveCfg = Release|x64
28 | {CC497BEE-6B9E-4732-8B60-35DFE6526C28}.Release|x64.Build.0 = Release|x64
29 | {CC497BEE-6B9E-4732-8B60-35DFE6526C28}.Release|x64.Deploy.0 = Release|x64
30 | {98E8F109-6A08-4461-A245-42B7CE32A703}.Debug_Minimal|x64.ActiveCfg = Debug|x64
31 | {98E8F109-6A08-4461-A245-42B7CE32A703}.Debug_Minimal|x64.Build.0 = Debug|x64
32 | {98E8F109-6A08-4461-A245-42B7CE32A703}.Debug_Minimal|x64.Deploy.0 = Debug|x64
33 | {98E8F109-6A08-4461-A245-42B7CE32A703}.Debug|x64.ActiveCfg = Debug|x64
34 | {98E8F109-6A08-4461-A245-42B7CE32A703}.Debug|x64.Build.0 = Debug|x64
35 | {98E8F109-6A08-4461-A245-42B7CE32A703}.Debug|x64.Deploy.0 = Debug|x64
36 | {98E8F109-6A08-4461-A245-42B7CE32A703}.Release_Minimal|x64.ActiveCfg = Release_Minimal|x64
37 | {98E8F109-6A08-4461-A245-42B7CE32A703}.Release_Minimal|x64.Build.0 = Release_Minimal|x64
38 | {98E8F109-6A08-4461-A245-42B7CE32A703}.Release_Minimal|x64.Deploy.0 = Release_Minimal|x64
39 | {98E8F109-6A08-4461-A245-42B7CE32A703}.Release|x64.ActiveCfg = Release|x64
40 | {98E8F109-6A08-4461-A245-42B7CE32A703}.Release|x64.Build.0 = Release|x64
41 | {98E8F109-6A08-4461-A245-42B7CE32A703}.Release|x64.Deploy.0 = Release|x64
42 | EndGlobalSection
43 | GlobalSection(SolutionProperties) = preSolution
44 | HideSolutionNode = FALSE
45 | EndGlobalSection
46 | GlobalSection(ExtensibilityGlobals) = postSolution
47 | SolutionGuid = {A387B9A7-546D-4699-8524-1E3CC92C3650}
48 | EndGlobalSection
49 | EndGlobal
50 |
--------------------------------------------------------------------------------
/airhv/airhv.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug_Minimal
6 | x64
7 |
8 |
9 | Debug
10 | x64
11 |
12 |
13 | Release_Minimal
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | {CC497BEE-6B9E-4732-8B60-35DFE6526C28}
23 | {1bc93793-694f-48fe-9372-81e2b05556fd}
24 | v4.5
25 | 12.0
26 | Debug
27 | Win32
28 | airhv
29 | 10.0.19041.0
30 | airhv
31 |
32 |
33 |
34 | Windows7
35 | true
36 | WindowsKernelModeDriver10.0
37 | Driver
38 | KMDF
39 | Desktop
40 | Spectre
41 |
42 |
43 | Windows7
44 | true
45 | WindowsKernelModeDriver10.0
46 | Driver
47 | KMDF
48 | Desktop
49 | Spectre
50 |
51 |
52 | Windows7
53 | false
54 | WindowsKernelModeDriver10.0
55 | Driver
56 | KMDF
57 | Desktop
58 | Spectre
59 |
60 |
61 | Windows7
62 | false
63 | WindowsKernelModeDriver10.0
64 | Driver
65 | KMDF
66 | Desktop
67 | Spectre
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 | DbgengKernelDebugger
80 |
81 |
82 | DbgengKernelDebugger
83 |
84 |
85 | DbgengKernelDebugger
86 |
87 |
88 | DbgengKernelDebugger
89 |
90 |
91 |
92 | stdcpp17
93 | false
94 | TurnOffAllWarnings
95 | true
96 | MaxSpeed
97 | Speed
98 | true
99 | false
100 | _WIN64;_AMD64_;AMD64;%(PreprocessorDefinitions)
101 |
102 |
103 |
104 |
105 | stdcpp17
106 | false
107 | TurnOffAllWarnings
108 | true
109 | MaxSpeed
110 | Speed
111 | true
112 | false
113 | _MINIMAL;_WIN64;_AMD64_;AMD64;%(PreprocessorDefinitions)
114 |
115 |
116 |
117 |
118 | true
119 | false
120 | _WIN64;_AMD64_;AMD64;%(PreprocessorDefinitions)
121 |
122 |
123 | %(AdditionalDependencies);$(KernelBufferOverflowLib);$(DDK_LIB_PATH)ntoskrnl.lib;$(DDK_LIB_PATH)hal.lib;$(DDK_LIB_PATH)wmilib.lib;$(KMDF_LIB_PATH)$(KMDF_VER_PATH)\WdfLdr.lib;$(KMDF_LIB_PATH)$(KMDF_VER_PATH)\WdfDriverEntry.lib
124 |
125 |
126 |
127 |
128 | true
129 | false
130 | _MINIMAL;_WIN64;_AMD64_;AMD64;%(PreprocessorDefinitions)
131 |
132 |
133 | %(AdditionalDependencies);$(KernelBufferOverflowLib);$(DDK_LIB_PATH)ntoskrnl.lib;$(DDK_LIB_PATH)hal.lib;$(DDK_LIB_PATH)wmilib.lib;$(KMDF_LIB_PATH)$(KMDF_VER_PATH)\WdfLdr.lib;$(KMDF_LIB_PATH)$(KMDF_VER_PATH)\WdfDriverEntry.lib
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
--------------------------------------------------------------------------------
/airhv/airhv.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 | {73422af8-864e-442f-a192-be64adb0a0fc}
22 |
23 |
24 | {136f69bf-5e7e-4a02-ab6a-1aef8e5a1207}
25 |
26 |
27 | {797b5b3d-b662-46aa-91a2-ba6aa5ce53d3}
28 |
29 |
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 | Source Files
63 |
64 |
65 | Source Files
66 |
67 |
68 |
69 |
70 | Header Files
71 |
72 |
73 | Header Files
74 |
75 |
76 | Header Files
77 |
78 |
79 | Header Files
80 |
81 |
82 | ia32
83 |
84 |
85 | ia32
86 |
87 |
88 | ia32
89 |
90 |
91 | ia32
92 |
93 |
94 | ia32
95 |
96 |
97 | ia32
98 |
99 |
100 | ia32
101 |
102 |
103 | ia32
104 |
105 |
106 | ia32
107 |
108 |
109 | Header Files
110 |
111 |
112 | Header Files
113 |
114 |
115 | ia32
116 |
117 |
118 | asm
119 |
120 |
121 | asm
122 |
123 |
124 | Header Files
125 |
126 |
127 | Header Files
128 |
129 |
130 | Header Files
131 |
132 |
133 | Header Files
134 |
135 |
136 | Header Files
137 |
138 |
139 | Header Files
140 |
141 |
142 | Header Files
143 |
144 |
145 | Header Files
146 |
147 |
148 | Header Files
149 |
150 |
151 |
152 |
153 | lde
154 |
155 |
156 | asm
157 |
158 |
159 | asm
160 |
161 |
162 |
--------------------------------------------------------------------------------
/airhv/airhv.vcxproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | WindowsRemoteDebugger
5 |
6 |
7 | WindowsRemoteDebugger
8 |
9 |
--------------------------------------------------------------------------------
/airhv/allocators.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include "common.h"
4 |
5 | ///
6 | /// Allocate NonPagedPool with hypervisor tag, custom size
7 | ///
8 | /// Return type
9 | /// Size of allocation, base value is sizeof(T)
10 | ///
11 | template
12 | inline T allocate_pool(unsigned __int64 size)
13 | {
14 | return (T)ExAllocatePoolWithTag(NonPagedPool, size, VMM_TAG);
15 | }
16 |
17 | ///
18 | /// Allocate NonPagedPool size of T with hypervisor tag,
19 | ///
20 | /// Return type
21 | /// Size of allocation, base value is sizeof(T)
22 | ///
23 | template
24 | inline T* allocate_pool()
25 | {
26 | return (T*)ExAllocatePoolWithTag(NonPagedPool, sizeof(T), VMM_TAG);
27 | }
28 |
29 | ///
30 | /// Allocate Contignous memory size of T
31 | ///
32 | /// Return type
33 | ///
34 | template
35 | inline T* allocate_contignous_memory()
36 | {
37 | PHYSICAL_ADDRESS a;
38 | a.QuadPart = 0ULL - 1;
39 | return (T*)MmAllocateContiguousMemory(sizeof(T), a);
40 | }
41 |
42 | ///
43 | /// Allocate Contignous memory custom size
44 | ///
45 | /// Return type
46 | ///
47 | template
48 | inline T allocate_contignous_memory(unsigned __int64 size)
49 | {
50 | PHYSICAL_ADDRESS a;
51 | a.QuadPart = 0ULL - 1;
52 | return (T)MmAllocateContiguousMemory(size, a);
53 | }
54 |
55 | ///
56 | /// Free pool with tahg
57 | ///
58 | /// Base address of pool
59 | inline void free_pool(void* pool_address)
60 | {
61 | ExFreePoolWithTag(pool_address, VMM_TAG);
62 | }
63 |
64 | ///
65 | /// Free contignous memory
66 | ///
67 | /// Contignous memory base address
68 | inline void free_contignous_memory(void* memory_address)
69 | {
70 | MmFreeContiguousMemory(memory_address);
71 | }
--------------------------------------------------------------------------------
/airhv/asm/vm_context.asm:
--------------------------------------------------------------------------------
1 | .CODE
2 | extern ?vmexit_handler@@YA_NPEAU__vmexit_guest_registers@@@Z : proc
3 | extern ?init_logical_processor@@YAXPEAX@Z : proc
4 | extern ?return_rsp_for_vmxoff@@YA_KXZ : proc
5 | extern ?return_rip_for_vmxoff@@YA_KXZ : proc
6 |
7 | PUBLIC ?vmm_entrypoint@@YAXXZ
8 | PUBLIC ?vmx_restore_state@@YAXXZ
9 | PUBLIC ?vmx_save_state@@YAXXZ
10 |
11 | SAVE_GP macro
12 | push rax
13 | push rcx
14 | push rdx
15 | push rbx
16 | push -01h ; placeholder for rsp
17 | push rbp
18 | push rsi
19 | push rdi
20 | push r8
21 | push r9
22 | push r10
23 | push r11
24 | push r12
25 | push r13
26 | push r14
27 | push r15
28 | endm
29 | RESTORE_GP macro
30 | pop r15
31 | pop r14
32 | pop r13
33 | pop r12
34 | pop r11
35 | pop r10
36 | pop r9
37 | pop r8
38 | pop rdi
39 | pop rsi
40 | pop rbp
41 | pop rbx ; placeholder for rsp
42 | pop rbx
43 | pop rdx
44 | pop rcx
45 | pop rax
46 | endm
47 |
48 | ?vmm_entrypoint@@YAXXZ proc
49 | SAVE_GP
50 | sub rsp ,60h
51 | movdqa xmmword ptr [rsp], xmm0
52 | movdqa xmmword ptr [rsp+10h], xmm1
53 | movdqa xmmword ptr [rsp+20h], xmm2
54 | movdqa xmmword ptr [rsp+30h], xmm3
55 | movdqa xmmword ptr [rsp+40h], xmm4
56 | movdqa xmmword ptr [rsp+50h], xmm5
57 | mov rcx, rsp
58 | sub rsp, 20h
59 | call ?vmexit_handler@@YA_NPEAU__vmexit_guest_registers@@@Z
60 | add rsp, 20h
61 | movdqa xmm0, xmmword ptr [rsp]
62 | movdqa xmm1, xmmword ptr [rsp+10h]
63 | movdqa xmm2, xmmword ptr [rsp+20h]
64 | movdqa xmm3, xmmword ptr [rsp+30h]
65 | movdqa xmm4, xmmword ptr [rsp+40h]
66 | movdqa xmm5, xmmword ptr [rsp+50h]
67 | add rsp, 60h
68 | cmp al, 1
69 | jnz exit
70 | RESTORE_GP
71 | vmresume
72 | exit:
73 | sub rsp, 20h
74 | call ?return_rsp_for_vmxoff@@YA_KXZ
75 | add rsp, 20h
76 |
77 | push rax
78 |
79 | sub rsp, 20h
80 | call ?return_rip_for_vmxoff@@YA_KXZ
81 | add rsp, 20h
82 |
83 | push rax
84 |
85 | mov rcx,rsp
86 | mov rsp,[rcx+8h]
87 | mov rax,[rcx]
88 | push rax
89 |
90 | mov r15,[rcx+10h]
91 | mov r14,[rcx+18h]
92 | mov r13,[rcx+20h]
93 | mov r12,[rcx+28h]
94 | mov r11,[rcx+30h]
95 | mov r10,[rcx+38h]
96 | mov r9,[rcx+40h]
97 | mov r8,[rcx+48h]
98 | mov rdi,[rcx+50h]
99 | mov rsi,[rcx+58h]
100 | mov rbp,[rcx+60h]
101 | mov rbx,[rcx+70h]
102 | mov rdx,[rcx+78h]
103 | mov rax,[rcx+88h]
104 | mov rcx,[rcx+80h]
105 |
106 | ret
107 | ?vmm_entrypoint@@YAXXZ endp
108 |
109 | ?vmx_save_state@@YAXXZ PROC
110 | pushfq
111 | SAVE_GP
112 | sub rsp, 020h
113 | mov rcx, rsp
114 | call ?init_logical_processor@@YAXPEAX@Z
115 | int 3 ; we should never be here
116 |
117 | ?vmx_save_state@@YAXXZ ENDP
118 |
119 | ?vmx_restore_state@@YAXXZ PROC
120 | add rsp, 020h
121 | RESTORE_GP
122 | popfq
123 | ret
124 | ?vmx_restore_state@@YAXXZ ENDP
125 |
126 | END
--------------------------------------------------------------------------------
/airhv/asm/vm_context.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "vmexit_handler.h"
3 |
4 | void vmm_entrypoint();
5 | void vmx_restore_state();
6 | void vmx_save_state();
--------------------------------------------------------------------------------
/airhv/asm/vm_intrin.asm:
--------------------------------------------------------------------------------
1 | .CODE
2 |
3 | __writecr2 proc
4 | mov cr2,rcx
5 | ret
6 | __writecr2 endp
7 |
8 | __read_ldtr proc
9 | sldt ax
10 | ret
11 | __read_ldtr endp
12 |
13 | __read_tr proc
14 | str ax
15 | ret
16 | __read_tr endp
17 |
18 | __read_cs proc
19 | mov ax, cs
20 | ret
21 | __read_cs endp
22 |
23 | __read_ss proc
24 | mov ax, ss
25 | ret
26 | __read_ss endp
27 |
28 | __read_ds proc
29 | mov ax, ds
30 | ret
31 | __read_ds endp
32 |
33 | __read_es proc
34 | mov ax, es
35 | ret
36 | __read_es endp
37 |
38 | __read_fs proc
39 | mov ax, fs
40 | ret
41 | __read_fs endp
42 |
43 | __read_gs proc
44 | mov ax, gs
45 | ret
46 | __read_gs endp
47 |
48 | __sgdt proc
49 | sgdt qword ptr [rcx]
50 | ret
51 | __sgdt endp
52 |
53 | __sidt proc
54 | sidt qword ptr [rcx]
55 | ret
56 | __sidt endp
57 |
58 | __load_ar proc
59 | lar rax, rcx
60 | jz no_error
61 | xor rax, rax
62 | no_error:
63 | ret
64 | __load_ar endp
65 |
66 | __vm_call proc
67 | mov rax,0CDAEFAEDBBAEBEEFh
68 | vmcall
69 | ret
70 | __vm_call endp
71 |
72 | __vm_call_ex proc
73 | mov rax,0CDAEFAEDBBAEBEEFh ; Our vmcall indentitifer
74 |
75 | sub rsp, 30h
76 | mov qword ptr [rsp], r10
77 | mov qword ptr [rsp + 8h], r11
78 | mov qword ptr [rsp + 10h], r12
79 | mov qword ptr [rsp + 18h], r13
80 | mov qword ptr [rsp + 20h], r14
81 | mov qword ptr [rsp + 28h], r15
82 |
83 | mov r10, qword ptr [rsp + 58h]
84 | mov r11, qword ptr [rsp + 60h]
85 | mov r12, qword ptr [rsp + 68h]
86 | mov r13, qword ptr [rsp + 70h]
87 | mov r14, qword ptr [rsp + 78h]
88 | mov r15, qword ptr [rsp + 80h]
89 |
90 | vmcall
91 | mov r10, qword ptr [rsp]
92 | mov r11, qword ptr [rsp + 8h]
93 | mov r12, qword ptr [rsp + 10h]
94 | mov r13, qword ptr [rsp + 18h]
95 | mov r14, qword ptr [rsp + 20h]
96 | mov r15, qword ptr [rsp + 28h]
97 | add rsp, 30h
98 |
99 | ret
100 | __vm_call_ex endp
101 |
102 | __hyperv_vm_call proc
103 | vmcall
104 | ret
105 | __hyperv_vm_call endp
106 |
107 | __reload_gdtr PROC
108 | push rcx
109 | shl rdx, 48
110 | push rdx
111 | lgdt fword ptr [rsp+6]
112 | pop rax
113 | pop rax
114 | ret
115 | __reload_gdtr ENDP
116 |
117 |
118 | __reload_idtr PROC
119 | push rcx
120 | shl rdx, 48
121 | push rdx
122 | lidt fword ptr [rsp+6]
123 | pop rax
124 | pop rax
125 | ret
126 | __reload_idtr ENDP
127 |
128 | __invept PROC
129 | invept rcx,oword ptr[rdx]
130 | ret
131 | __invept ENDP
132 |
133 | __invvpid PROC
134 | invvpid rcx,oword ptr[rdx]
135 | ret
136 | __invvpid ENDP
137 |
138 | END
--------------------------------------------------------------------------------
/airhv/asm/vm_intrin.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | extern "C"
3 | {
4 | unsigned short __read_ldtr(void);
5 | unsigned short __read_tr(void);
6 | unsigned short __read_cs(void);
7 | unsigned short __read_ss(void);
8 | unsigned short __read_ds(void);
9 | unsigned short __read_es(void);
10 | unsigned short __read_fs(void);
11 | unsigned short __read_gs(void);
12 | void __sgdt(void*);
13 | void __sidt(void*);
14 | unsigned __int32 __load_ar(unsigned __int16);
15 | bool __vm_call(unsigned __int64 vmcall_reason, unsigned __int64 rdx, unsigned __int64 r8, unsigned __int64 r9);
16 | bool __vm_call_ex(unsigned __int64 vmcall_reason, unsigned __int64 rdx, unsigned __int64 r8, unsigned __int64 r9, unsigned __int64 r10, unsigned __int64 r11, unsigned __int64 r12, unsigned __int64 r13, unsigned __int64 r14, unsigned __int64 r15);
17 | unsigned __int64 __hyperv_vm_call(unsigned __int64 param1, unsigned __int64 param2, unsigned __int64 param3);
18 | void __reload_gdtr(unsigned __int64 base, unsigned long limit);
19 | void __reload_idtr(unsigned __int64 base, unsigned long limit);
20 | void __invept(unsigned __int32 type, void* descriptors);
21 | void __invvpid(unsigned __int32 type, void* descriptors);
22 | void __writecr2(unsigned __int64 cr2);
23 | int __cdecl _rdseed16_step(unsigned __int16* return_value);
24 | int __cdecl _rdseed32_step(unsigned __int32* return_value);
25 | int __cdecl _rdseed64_step(unsigned __int64* return_value);
26 | }
--------------------------------------------------------------------------------
/airhv/common.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include "ia32\ept.h"
4 | #include "poolmanager.h"
5 | #include "ia32\exception.h"
6 | #include "ia32\mtrr.h"
7 | #include "ia32\rflags.h"
8 |
9 | extern "C" size_t __fastcall LDE(const void* lpData, unsigned int size);
10 |
11 | #define VMCALL_IDENTIFIER 0xCDAEFAEDBBAEBEEF
12 | #define VMM_TAG 'vhra'
13 | #define VMM_STACK_SIZE 0x6000
14 |
15 | #define LARGE_PAGE_SIZE 0x200000
16 | #define GET_PFN(_VAR_) (_VAR_ >> PAGE_SHIFT)
17 |
18 | #define MASK_GET_HIGHER_32BITS(_ARG_)(_ARG_ & 0xffffffff00000000)
19 | #define MASK_GET_LOWER_32BITS(_ARG_)(_ARG_ & 0xffffffff)
20 | #define MASK_GET_LOWER_16BITS(_ARG_)(_ARG_ & 0xffff)
21 | #define MASK_GET_LOWER_8BITS(_ARG_)(_ARG_ & 0xff)
22 | #define MASK_32BITS 0xffffffff
23 |
24 | struct __vmexit_guest_registers
25 | {
26 | __m128 xmm[6];
27 | unsigned __int64 r15;
28 | unsigned __int64 r14;
29 | unsigned __int64 r13;
30 | unsigned __int64 r12;
31 | unsigned __int64 r11;
32 | unsigned __int64 r10;
33 | unsigned __int64 r9;
34 | unsigned __int64 r8;
35 | unsigned __int64 rdi;
36 | unsigned __int64 rsi;
37 | unsigned __int64 rbp;
38 | unsigned __int64 rsp;
39 | unsigned __int64 rbx;
40 | unsigned __int64 rdx;
41 | unsigned __int64 rcx;
42 | unsigned __int64 rax;
43 | };
44 |
45 | struct __vmcs
46 | {
47 | union
48 | {
49 | unsigned int all;
50 | struct
51 | {
52 | unsigned int revision_identifier : 31;
53 | unsigned int shadow_vmcs_indicator : 1;
54 | };
55 | } header;
56 | unsigned int abort_indicator;
57 | char data[0x1000 - 2 * sizeof(unsigned)];
58 | };
59 |
60 | struct __vcpu
61 | {
62 | void* vmm_stack;
63 |
64 | __vmcs* vmcs;
65 | unsigned __int64 vmcs_physical;
66 |
67 | __vmcs* vmxon;
68 | unsigned __int64 vmxon_physical;
69 |
70 | struct __vmexit_info
71 | {
72 | __vmexit_guest_registers* guest_registers;
73 |
74 | unsigned __int64 guest_rip;
75 |
76 | __rflags guest_rflags;
77 |
78 | unsigned __int64 instruction_length;
79 |
80 | unsigned __int64 reason;
81 |
82 | unsigned __int64 qualification;
83 |
84 | unsigned __int64 instruction_information;
85 |
86 | }vmexit_info;
87 |
88 | struct __vcpu_status
89 | {
90 | unsigned __int64 vmx_on;
91 | unsigned __int64 vmm_launched;
92 | }vcpu_status;
93 |
94 | struct __vmx_off_state
95 | {
96 | unsigned __int64 vmx_off_executed;
97 | unsigned __int64 guest_rip;
98 | unsigned __int64 guest_rsp;
99 | }vmx_off_state;
100 |
101 | struct __vcpu_bitmaps
102 | {
103 | unsigned __int8* msr_bitmap;
104 | unsigned __int64 msr_bitmap_physical;
105 |
106 | unsigned __int8* io_bitmap_a;
107 | unsigned __int64 io_bitmap_a_physical;
108 |
109 | unsigned __int8* io_bitmap_b;
110 | unsigned __int64 io_bitmap_b_physical;
111 | }vcpu_bitmaps;
112 |
113 | __ept_state* ept_state;
114 | };
115 |
116 | struct __mtrr_info
117 | {
118 | __mtrr_range_descriptor memory_range[100];
119 | unsigned __int32 enabled_memory_ranges;
120 | unsigned __int8 default_memory_type;
121 | };
122 |
123 | struct __vmm_context
124 | {
125 | __vcpu** vcpu_table;
126 | pool_manager::__pool_manager* pool_manager;
127 | __mtrr_info mtrr_info;
128 | unsigned __int32 processor_count;
129 | unsigned __int32 highest_basic_leaf;
130 | bool hv_presence;
131 | };
132 |
133 | extern __vmm_context* g_vmm_context;
--------------------------------------------------------------------------------
/airhv/ept.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Air14/airhv/d2b4a6cdc8c8efb56637c6992dd36b8fdce68202/airhv/ept.cpp
--------------------------------------------------------------------------------
/airhv/hypervisor_gateway.cpp:
--------------------------------------------------------------------------------
1 | #pragma warning( disable : 4201)
2 |
3 | #include
4 | #include
5 | #include "ntapi.h"
6 | #include "asm\vm_intrin.h"
7 | #include "vmcall_reason.h"
8 | #include "log.h"
9 |
10 | #define IOCTL_POOL_MANAGER_ALLOCATE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x900, METHOD_BUFFERED, FILE_SPECIAL_ACCESS)
11 |
12 | namespace hvgt
13 | {
14 | void broadcast_vmoff(KDPC*, PVOID, PVOID SystemArgument1, PVOID SystemArgument2)
15 | {
16 | __vm_call(VMCALL_VMXOFF, 0, 0, 0);
17 | KeSignalCallDpcSynchronize(SystemArgument2);
18 | KeSignalCallDpcDone(SystemArgument1);
19 | }
20 |
21 | struct HookFunctionArgs
22 | {
23 | void* target_address;
24 | void* hook_function;
25 | void** origin_function;
26 | unsigned __int64 current_cr3;
27 | volatile SHORT statuses;
28 | };
29 | void broadcast_hook_function(KDPC*, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2)
30 | {
31 | const auto args = reinterpret_cast(DeferredContext);
32 |
33 | if (__vm_call_ex(VMCALL_EPT_HOOK_FUNCTION, (unsigned __int64)args->target_address,
34 | (unsigned __int64)args->hook_function, (unsigned __int64)args->origin_function, args->current_cr3, 0, 0, 0, 0, 0))
35 | {
36 | InterlockedIncrement16(&args->statuses);
37 | }
38 |
39 | KeSignalCallDpcSynchronize(SystemArgument2);
40 | KeSignalCallDpcDone(SystemArgument1);
41 | }
42 |
43 | struct UnHookFunctionArgs
44 | {
45 | bool unhook_all_functions;
46 | void* function_to_unhook;
47 | unsigned __int64 current_cr3;
48 | volatile SHORT statuses;
49 | };
50 | void broadcast_unhook_function(KDPC*, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2)
51 | {
52 | const auto args = reinterpret_cast(DeferredContext);
53 |
54 | if (__vm_call(VMCALL_EPT_UNHOOK_FUNCTION, args->unhook_all_functions,
55 | (unsigned __int64)args->function_to_unhook, args->current_cr3))
56 | {
57 | InterlockedIncrement16(&args->statuses);
58 | }
59 |
60 | KeSignalCallDpcSynchronize(SystemArgument2);
61 | KeSignalCallDpcDone(SystemArgument1);
62 | }
63 |
64 | void broadcast_test_vmcall(KDPC*, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2)
65 | {
66 | const auto statuses = reinterpret_cast(DeferredContext);
67 |
68 | if (__vm_call(VMCALL_TEST, 0, 0, 0))
69 | {
70 | InterlockedIncrement16(statuses);
71 | }
72 |
73 | KeSignalCallDpcSynchronize(SystemArgument2);
74 | KeSignalCallDpcDone(SystemArgument1);
75 | }
76 |
77 | ///
78 | /// Turn off virtual machine
79 | ///
80 | void vmoff()
81 | {
82 | KeGenericCallDpc(broadcast_vmoff, NULL);
83 | }
84 |
85 | ///
86 | /// Set/Unset presence of hypervisor
87 | ///
88 | /// If false, hypervisor is not visible via cpuid interface, If true, it become visible
89 | void hypervisor_visible(bool value)
90 | {
91 | if (value == true)
92 | __vm_call(VMCALL_UNHIDE_HV_PRESENCE, 0, 0, 0);
93 | else
94 | __vm_call(VMCALL_HIDE_HV_PRESENCE, 0, 0, 0);
95 | }
96 |
97 | ///
98 | /// Unhook all functions and invalidate tlb
99 | ///
100 | /// status
101 | bool unhook_all_functions()
102 | {
103 | UnHookFunctionArgs args{ true, nullptr, __readcr3(), 0 };
104 | KeGenericCallDpc(broadcast_unhook_function, &args);
105 |
106 | return static_cast(args.statuses) == KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
107 | }
108 |
109 | ///
110 | /// Unhook single function and invalidate tlb
111 | ///
112 | ///
113 | /// status
114 | bool unhook_function(void* function_address)
115 | {
116 | UnHookFunctionArgs args{ false, function_address, __readcr3(), 0 };
117 | KeGenericCallDpc(broadcast_unhook_function, &args);
118 |
119 | return static_cast(args.statuses) == KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
120 | }
121 |
122 | ///
123 | /// Hook function via ept and invalidates mappings
124 | ///
125 | /// Address of function which we want to hook
126 | /// Address of function which is used to call original function
127 | /// Address of function which is used to call original function
128 | /// status
129 | bool hook_function(void* target_address, void* hook_function, void** origin_function)
130 | {
131 | HookFunctionArgs args{ target_address, hook_function, origin_function, __readcr3(), 0 };
132 | KeGenericCallDpc(broadcast_hook_function, &args);
133 |
134 | return static_cast(args.statuses) == KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
135 | }
136 |
137 | ///
138 | /// Dump info about allocated pools (Use Dbgview to see information)
139 | ///
140 | void dump_pool_manager()
141 | {
142 | __vm_call(VMCALL_DUMP_POOL_MANAGER, 0, 0, 0);
143 | }
144 |
145 | ///
146 | /// Check if we can communicate with hypervisor
147 | ///
148 | /// status
149 | bool test_vmcall()
150 | {
151 | volatile SHORT statuses{};
152 | KeGenericCallDpc(broadcast_test_vmcall, (PVOID)&statuses);
153 |
154 | return static_cast(statuses) == KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
155 | }
156 |
157 | ///
158 | /// Send irp with information to allocate memory
159 | ///
160 | /// status
161 | bool send_irp_perform_allocation()
162 | {
163 | PDEVICE_OBJECT airhv_device_object;
164 | KEVENT event;
165 | PIRP irp;
166 | IO_STATUS_BLOCK io_status = { 0 };
167 | UNICODE_STRING airhv_name;
168 | PFILE_OBJECT file_object;
169 |
170 | RtlInitUnicodeString(&airhv_name, L"\\Device\\airhv");
171 |
172 | NTSTATUS status = IoGetDeviceObjectPointer(&airhv_name, 0, &file_object, &airhv_device_object);
173 |
174 | ObReferenceObjectByPointer(airhv_device_object, FILE_ALL_ACCESS, NULL, KernelMode);
175 |
176 | // We don't need this so we instantly dereference file object
177 | ObDereferenceObject(file_object);
178 |
179 | if (NT_SUCCESS(status) == false)
180 | {
181 | LogError("Couldn't get hypervisor device object pointer");
182 | return false;
183 | }
184 |
185 | KeInitializeEvent(&event, NotificationEvent, 0);
186 | irp = IoBuildDeviceIoControlRequest(IOCTL_POOL_MANAGER_ALLOCATE, airhv_device_object, 0, 0, 0, 0, 0, &event, &io_status);
187 |
188 | if (irp == NULL)
189 | {
190 | LogError("Couldn't create Irp");
191 | ObDereferenceObject(airhv_device_object);
192 | return false;
193 | }
194 |
195 | else
196 | {
197 | status = IofCallDriver(airhv_device_object, irp);
198 |
199 | if (status == STATUS_PENDING)
200 | KeWaitForSingleObject(&event, Executive, KernelMode, 0, 0);
201 |
202 | ObDereferenceObject(airhv_device_object);
203 | return true;
204 | }
205 | }
206 | }
--------------------------------------------------------------------------------
/airhv/hypervisor_gateway.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | namespace hvgt
3 | {
4 | ///
5 | /// Turn off virtual machine
6 | ///
7 | void vmoff();
8 |
9 | ///
10 | /// Set/Unset presence of hypervisor
11 | ///
12 | /// If false, hypervisor is not visible via cpuid interface, If true, it become visible
13 | void hypervisor_visible(bool value);
14 |
15 | ///
16 | /// Unhook all pages and invalidate tlb
17 | ///
18 | /// status
19 | bool unhook_all_functions();
20 |
21 | ///
22 | /// Unhook single page and invalidate tlb
23 | ///
24 | ///
25 | /// status
26 | bool unhook_function(void* function_address);
27 |
28 | ///
29 | /// Hook function via ept and invalidates mappings
30 | ///
31 | /// Address of function which we want to hook
32 | /// Address of function which is used to call original function
33 | /// Address of function which is used to call original function
34 | /// status
35 | bool hook_function(void* target_address, void* hook_function, void** origin_function);
36 |
37 | ///
38 | /// Check if we can communicate with hypervisor
39 | ///
40 | /// status
41 | bool test_vmcall();
42 |
43 | ///
44 | /// Send irp with information to allocate memory
45 | ///
46 | /// status
47 | bool send_irp_perform_allocation();
48 |
49 | ///
50 | /// Dump info about allocated pools (Use Dbgview to see information)
51 | ///
52 | void dump_pool_manager();
53 | }
54 |
--------------------------------------------------------------------------------
/airhv/hypervisor_routines.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include "common.h"
4 |
5 | enum __syscall_type
6 | {
7 | SYSCALL_NT,
8 | SYSCALL_WIN32K
9 | };
10 |
11 | namespace hv
12 | {
13 | ///
14 | /// Check if cpu support virtualization
15 | ///
16 | ///
17 | bool virtualization_support();
18 |
19 | ///
20 | /// Disable vmx operation
21 | ///
22 | ///
23 | void disable_vmx_operation();
24 |
25 | ///
26 | /// Read vmcs field
27 | ///
28 | ///
29 | ///
30 | unsigned __int64 vmread(unsigned __int64 vmcs_field);
31 |
32 | ///
33 | /// Dump whole vmcs structure
34 | ///
35 | void dump_vmcs();
36 |
37 | ///
38 | /// Set 1 msr in msr bitmap
39 | ///
40 | /// Msr number
41 | /// Pointer to current vcpu
42 | /// If set vmexit occur on reading this msr
43 | /// If set vmexit occur on writing to this msr
44 | /// If true set msr bit else clear
45 | void set_msr_bitmap(unsigned __int32 msr, __vcpu* vcpu, bool read, bool write, bool value);
46 |
47 | ///
48 | /// Set or unset bit in io port bitmap
49 | ///
50 | /// IO port which you want to set
51 | /// Pointer to current vcpu
52 | /// If true then set bit else unset bit
53 | void set_io_bitmap(unsigned __int16 io_port, __vcpu* vcpu, bool value);
54 |
55 | ///
56 | ///
57 | ///
58 | /// Return current guest privilage level
59 | unsigned __int8 get_guest_cpl();
60 |
61 | ///
62 | /// Swap cr3 with current process dtb
63 | ///
64 | /// old cr3
65 | unsigned __int64 swap_context();
66 |
67 | ///
68 | /// Swap cr3 with current process dtb
69 | ///
70 | ///
71 | /// old cr3
72 | unsigned __int64 swap_context(unsigned __int64 new_cr3);
73 |
74 | ///
75 | /// Restore cr3
76 | ///
77 | ///
78 | void restore_context(unsigned __int64 old_cr3);
79 |
80 | ///
81 | /// Check if address is canonicial (level 4 paging)
82 | ///
83 | ///
84 | ///
85 | bool is_address_canonical(unsigned __int64 address);
86 |
87 | ///
88 | /// Get system directory table base
89 | ///
90 | ///
91 | unsigned __int64 get_system_directory_table_base();
92 |
93 | ///
94 | /// Inject interrupt/exception to guest system
95 | ///
96 | ///
97 | ///
98 | ///
99 | ///
100 | void inject_interruption(unsigned __int32 vector, unsigned __int32 type, unsigned __int32 error_code, bool deliver_error_code);
101 |
102 | ///
103 | /// Write to reset io port to perform hard reset
104 | ///
105 | void hard_reset();
106 |
107 | ///
108 | /// Used to get address passed by user in inpvcid
109 | ///
110 | ///
111 | ///
112 | unsigned __int64 get_guest_address(__vcpu* vcpu);
113 |
114 | ///
115 | /// Set or unset monitor trap flag
116 | ///
117 | ///
118 | void set_mtf(bool set);
119 |
120 | ///
121 | /// Write to vmcs field
122 | ///
123 | ///
124 | /// Field number
125 | /// Value
126 | template
127 | void vmwrite(unsigned __int64 vmcs_field, T value)
128 | {
129 | __vmx_vmwrite(vmcs_field, (unsigned __int64)value);
130 | }
131 | }
--------------------------------------------------------------------------------
/airhv/ia32/cpuid.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #define QUERY_CPUID_BIT(x, b) ((x) & (1 << b))
4 | #define SET_CPUID_BIT(x, b) (x = (x) | (1 << b))
5 | #define CLR_CPUID_BIT(x, b) ((x) & ~(1 << b))
6 |
7 | #define CPUID_EXTENDED_FEATURES 0x00000007
8 | #define CPUID_HV_VENDOR_AND_MAX_FUNCTIONS 0x40000000
9 | #define CPUID_HV_INTERFACE 0x40000001
10 | #define CPUID_PROCESSOR_FEATURES 0x00000001
11 |
12 | union __cpuid_info
13 | {
14 | struct
15 | {
16 | int cpu_info[4];
17 | };
18 |
19 | struct
20 | {
21 | unsigned __int32 eax;
22 | unsigned __int32 ebx;
23 | unsigned __int32 ecx;
24 | unsigned __int32 edx;
25 | };
26 |
27 | struct
28 | {
29 | union
30 | {
31 | unsigned __int32 flags;
32 |
33 | struct
34 | {
35 | unsigned __int32 stepping_id : 4;
36 | unsigned __int32 model : 4;
37 | unsigned __int32 family_id : 4;
38 | unsigned __int32 processor_type : 2;
39 | unsigned __int32 reserved1 : 2;
40 | unsigned __int32 extended_model_id : 4;
41 | unsigned __int32 extended_family_id : 8;
42 | unsigned __int32 reserved2 : 4;
43 | };
44 | } version_information;
45 |
46 | union
47 | {
48 | unsigned __int32 flags;
49 |
50 | struct
51 | {
52 | unsigned __int32 brand_index : 8;
53 | unsigned __int32 clflush_line_size : 8;
54 | unsigned __int32 max_addressable_ids : 8;
55 | unsigned __int32 initial_apic_id : 8;
56 | };
57 | } additional_information;
58 |
59 | union
60 | {
61 | unsigned __int32 flags;
62 |
63 | struct
64 | {
65 | unsigned __int32 streaming_simd_extensions_3 : 1;
66 | unsigned __int32 pclmulqdq_instruction : 1;
67 | unsigned __int32 ds_area_64bit_layout : 1;
68 | unsigned __int32 monitor_mwait_instruction : 1;
69 | unsigned __int32 cpl_qualified_debug_store : 1;
70 | unsigned __int32 virtual_machine_extensions : 1;
71 | unsigned __int32 safer_mode_extensions : 1;
72 | unsigned __int32 enhanced_intel_speedstep_technology : 1;
73 | unsigned __int32 thermal_monitor_2 : 1;
74 | unsigned __int32 supplemental_streaming_simd_extensions_3 : 1;
75 | unsigned __int32 l1_context_id : 1;
76 | unsigned __int32 silicon_debug : 1;
77 | unsigned __int32 fma_extensions : 1;
78 | unsigned __int32 cmpxchg16b_instruction : 1;
79 | unsigned __int32 xtpr_update_control : 1;
80 | unsigned __int32 perfmon_and_debug_capability : 1;
81 | unsigned __int32 reserved1 : 1;
82 | unsigned __int32 process_context_identifiers : 1;
83 | unsigned __int32 direct_cache_access : 1;
84 | unsigned __int32 sse41_support : 1;
85 | unsigned __int32 sse42_support : 1;
86 | unsigned __int32 x2apic_support : 1;
87 | unsigned __int32 movbe_instruction : 1;
88 | unsigned __int32 popcnt_instruction : 1;
89 | unsigned __int32 tsc_deadline : 1;
90 | unsigned __int32 aesni_instruction_extensions : 1;
91 | unsigned __int32 xsave_xrstor_instruction : 1;
92 | unsigned __int32 osx_save : 1;
93 | unsigned __int32 avx_support : 1;
94 | unsigned __int32 half_precision_conversion_instructions : 1;
95 | unsigned __int32 rdrand_instruction : 1;
96 | unsigned __int32 hypervisor_present : 1;
97 | };
98 | } feature_information_ecx;
99 |
100 | union
101 | {
102 | unsigned __int32 flags;
103 |
104 | struct
105 | {
106 | unsigned __int32 floating_point_unit_on_chip : 1;
107 | unsigned __int32 virtual_8086_mode_enhancements : 1;
108 | unsigned __int32 debugging_extensions : 1;
109 | unsigned __int32 page_size_extension : 1;
110 | unsigned __int32 timestamp_counter : 1;
111 | unsigned __int32 rdmsr_wrmsr_instructions : 1;
112 | unsigned __int32 physical_address_extension : 1;
113 | unsigned __int32 machine_check_exception : 1;
114 | unsigned __int32 cmpxchg8b : 1;
115 | unsigned __int32 apic_on_chip : 1;
116 | unsigned __int32 reserved1 : 1;
117 | unsigned __int32 sysenter_sysexit_instructions : 1;
118 | unsigned __int32 memory_type_range_registers : 1;
119 | unsigned __int32 page_global_bit : 1;
120 | unsigned __int32 machine_check_architecture : 1;
121 | unsigned __int32 conditional_move_instructions : 1;
122 | unsigned __int32 page_attribute_table : 1;
123 | unsigned __int32 page_size_extension_36bit : 1;
124 | unsigned __int32 processor_serial_number : 1;
125 | unsigned __int32 clflush : 1;
126 | unsigned __int32 reserved2 : 1;
127 | unsigned __int32 debug_store : 1;
128 | unsigned __int32 thermal_control_msrs_for_acpi : 1;
129 | unsigned __int32 mmx_support : 1;
130 | unsigned __int32 fxsave_fxrstor_instructions : 1;
131 | unsigned __int32 sse_support : 1;
132 | unsigned __int32 sse2_support : 1;
133 | unsigned __int32 self_snoop : 1;
134 | unsigned __int32 hyper_threading_technology : 1;
135 | unsigned __int32 thermal_monitor : 1;
136 | unsigned __int32 reserved3 : 1;
137 | unsigned __int32 pending_break_enable : 1;
138 | };
139 | } feature_information_edx;
140 | }cpuid_eax_01;
141 |
142 | struct
143 | {
144 | union
145 | {
146 | unsigned __int32 flags;
147 |
148 | struct
149 | {
150 | unsigned __int32 perf_mon_arch_ver_id : 8;
151 | unsigned __int32 gp_perf_mon_counter_number : 8;
152 | unsigned __int32 gp_perf_mon_counter_bit_width : 8;
153 | unsigned __int32 ebx_bit_vector_length : 8;
154 | };
155 | } feature_information_eax;
156 |
157 | union
158 | {
159 | unsigned __int32 flags;
160 |
161 | struct
162 | {
163 | unsigned __int32 core_cycles : 1;
164 | unsigned __int32 instructions_retired : 1;
165 | unsigned __int32 reference_cycles : 1;
166 | unsigned __int32 last_level_cache_references : 1;
167 | unsigned __int32 last_level_cache_misses : 1;
168 | unsigned __int32 branch_instructions_retired : 1;
169 | unsigned __int32 branch_misprediction_retired : 1;
170 | unsigned __int32 reserved : 25;
171 | };
172 | } feature_information_ebx;
173 |
174 | union
175 | {
176 | unsigned __int32 flags;
177 |
178 | struct
179 | {
180 | unsigned __int32 reserved : 32;
181 | };
182 | } feature_information_ecx;
183 |
184 | union
185 | {
186 | unsigned __int32 flags;
187 |
188 | struct
189 | {
190 | unsigned __int32 fixed_counters_number : 5;
191 | unsigned __int32 fixed_counters_number_bits : 8;
192 | unsigned __int32 reserved : 19;
193 | };
194 | } feature_information_edx;
195 | }cpuid_eax_0a;
196 | };
--------------------------------------------------------------------------------
/airhv/ia32/cr.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | enum __cr_access_type
4 | {
5 | CR_ACCESS_MOV_TO_CR,
6 | CR_ACCESS_MOV_FROM_CR,
7 | CR_ACCESS_CLTS,
8 | CR_ACCESS_LMSW
9 | };
10 |
11 | union __cr_access_qualification
12 | {
13 | unsigned __int64 all;
14 | struct
15 | {
16 | unsigned __int64 cr_number : 4;
17 | unsigned __int64 access_type : 2;
18 | unsigned __int64 operand_type : 1;
19 | unsigned __int64 reserved1 : 1;
20 | unsigned __int64 register_type : 4;
21 | unsigned __int64 reserved2 : 4;
22 | unsigned __int64 source_data : 16;
23 | unsigned __int64 reserved3 : 32;
24 | };
25 | };
26 |
27 | union __cr_fixed
28 | {
29 | unsigned __int64 all;
30 | struct
31 | {
32 | unsigned long low;
33 | long high;
34 | } split;
35 | struct
36 | {
37 | unsigned long low;
38 | long high;
39 | } u;
40 | };
41 |
42 | union __cr8
43 | {
44 | unsigned __int64 all;
45 | struct
46 | {
47 | unsigned __int64 task_priority_level : 4;
48 | unsigned __int64 reserved : 59;
49 | };
50 | };
51 |
52 | union __cr0
53 |
54 | {
55 | unsigned __int64 all;
56 | struct
57 | {
58 | unsigned __int64 protection_enable : 1;
59 | unsigned __int64 monitor_coprocessor : 1;
60 | unsigned __int64 emulate_fpu : 1;
61 | unsigned __int64 task_switched : 1;
62 | unsigned __int64 extension_type : 1;
63 | unsigned __int64 numeric_error : 1;
64 | unsigned __int64 reserved_1 : 10;
65 | unsigned __int64 write_protect : 1;
66 | unsigned __int64 reserved_2 : 1;
67 | unsigned __int64 alignment_mask : 1;
68 | unsigned __int64 reserved_3 : 10;
69 | unsigned __int64 not_write_through : 1;
70 | unsigned __int64 cache_disable : 1;
71 | unsigned __int64 paging_enable : 1;
72 | unsigned __int64 reserved_4 : 32;
73 | };
74 | };
75 |
76 | union __cr2
77 | {
78 | unsigned __int64 linear_address;
79 | };
80 |
81 | union __cr3
82 | {
83 | unsigned __int64 all;
84 | struct
85 | {
86 | unsigned __int64 pcid : 12;
87 | unsigned __int64 page_frame_number : 36;
88 | unsigned __int64 reserved_1 : 12;
89 | unsigned __int64 reserved_2 : 3;
90 | unsigned __int64 pcid_invalidate : 1;
91 | };
92 | };
93 |
94 | union __cr4
95 | {
96 | unsigned __int64 all;
97 | struct
98 | {
99 | unsigned __int64 virtual_mode_extensions : 1;
100 | unsigned __int64 protected_mode_virtual_interrupts : 1;
101 | unsigned __int64 timestamp_disable : 1;
102 | unsigned __int64 debugging_extensions : 1;
103 | unsigned __int64 page_size_extensions : 1;
104 | unsigned __int64 physical_address_extension : 1;
105 | unsigned __int64 machine_check_enable : 1;
106 | unsigned __int64 page_global_enable : 1;
107 | unsigned __int64 performance_monitoring_counter_enable : 1;
108 | unsigned __int64 os_fxsave_fxrstor_support : 1;
109 | unsigned __int64 os_xmm_exception_support : 1;
110 | unsigned __int64 usermode_instruction_prevention : 1;
111 | unsigned __int64 reserved_1 : 1;
112 | unsigned __int64 vmx_enable : 1;
113 | unsigned __int64 smx_enable : 1;
114 | unsigned __int64 reserved_2 : 1;
115 | unsigned __int64 fsgsbase_enable : 1;
116 | unsigned __int64 pcid_enable : 1;
117 | unsigned __int64 os_xsave : 1;
118 | unsigned __int64 reserved_3 : 1;
119 | unsigned __int64 smep_enable : 1;
120 | unsigned __int64 smap_enable : 1;
121 | unsigned __int64 protection_key_enable : 1;
122 | };
123 | };
124 |
125 | union __xcr0
126 | {
127 | unsigned __int64 all;
128 | struct
129 | {
130 | unsigned __int64 x87 : 1;
131 | unsigned __int64 sse : 1;
132 | unsigned __int64 avx : 1;
133 | unsigned __int64 bndreg : 1;
134 | unsigned __int64 bndcsr : 1;
135 | unsigned __int64 opmask : 1;
136 | unsigned __int64 zmm_hi256 : 1;
137 | unsigned __int64 hi16_zmm : 1;
138 | unsigned __int64 reserved1 : 1;
139 | unsigned __int64 pkru : 1;
140 | unsigned __int64 reserved2 : 1;
141 | unsigned __int64 cet_user_state : 1;
142 | unsigned __int64 cet_supervisor_state : 1;
143 | unsigned __int64 xaad : 1;
144 | unsigned __int64 reserved3 : 50;
145 | };
146 | };
--------------------------------------------------------------------------------
/airhv/ia32/dr.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | union __dr6
3 | {
4 | unsigned __int64 all;
5 | struct
6 | {
7 | unsigned __int64 breakpoint_condition : 4;
8 | unsigned __int64 reserved_1 : 8; // always 1
9 | unsigned __int64 reserved_2 : 1; // always 0
10 | unsigned __int64 debug_register_access_detected : 1;
11 | unsigned __int64 single_instruction : 1;
12 | unsigned __int64 task_switch : 1;
13 | unsigned __int64 restricted_transactional_memory : 1;
14 | unsigned __int64 reserved_3 : 15; // always 1
15 | };
16 | };
17 |
18 | union __dr7
19 | {
20 | unsigned __int64 all;
21 | struct
22 | {
23 | unsigned __int64 local_breakpoint_0 : 1;
24 | unsigned __int64 global_breakpoint_0 : 1;
25 | unsigned __int64 local_breakpoint_1 : 1;
26 | unsigned __int64 global_breakpoint_1 : 1;
27 | unsigned __int64 local_breakpoint_2 : 1;
28 | unsigned __int64 global_breakpoint_2 : 1;
29 | unsigned __int64 local_breakpoint_3 : 1;
30 | unsigned __int64 global_breakpoint_3 : 1;
31 | unsigned __int64 local_exact_breakpoint : 1;
32 | unsigned __int64 global_exact_breakpoint : 1;
33 | unsigned __int64 reserved_1 : 1; // always 1
34 | unsigned __int64 restricted_transactional_memory : 1;
35 | unsigned __int64 reserved_2 : 1; // always 0
36 | unsigned __int64 general_detect : 1;
37 | unsigned __int64 reserved_3 : 2; // always 0
38 | unsigned __int64 read_write_0 : 2;
39 | unsigned __int64 length_0 : 2;
40 | unsigned __int64 read_write_1 : 2;
41 | unsigned __int64 length_1 : 2;
42 | unsigned __int64 read_write_2 : 2;
43 | unsigned __int64 length_2 : 2;
44 | unsigned __int64 read_write_3 : 2;
45 | unsigned __int64 length_3 : 2;
46 | };
47 | };
48 |
--------------------------------------------------------------------------------
/airhv/ia32/ept.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "invalidators.h"
3 |
4 | #define MASK_EPT_PML1_OFFSET(_VAR_) ((unsigned __int64)_VAR_ & 0xFFFULL)
5 | #define MASK_EPT_PML1_INDEX(_VAR_) ((_VAR_ & 0x1FF000ULL) >> 12)
6 | #define MASK_EPT_PML2_INDEX(_VAR_) ((_VAR_ & 0x3FE00000ULL) >> 21)
7 | #define MASK_EPT_PML3_INDEX(_VAR_) ((_VAR_ & 0x7FC0000000ULL) >> 30)
8 | #define MASK_EPT_PML4_INDEX(_VAR_) ((_VAR_ & 0xFF8000000000ULL) >> 39)
9 | #define CPU_BASED_MONITOR_TRAP_FLAG 0x08000000
10 |
11 | union __eptp
12 | {
13 | unsigned __int64 all;
14 | struct
15 | {
16 | unsigned __int64 memory_type : 3;
17 | unsigned __int64 page_walk_length : 3;
18 | unsigned __int64 dirty_and_aceess_enabled : 1;
19 | unsigned __int64 reserved1 : 5;
20 | unsigned __int64 pml4_address : 36;
21 | unsigned __int64 reserved2 : 16;
22 | };
23 | };
24 |
25 |
26 | // See Table 28-1.
27 | union __ept_pml4e
28 | {
29 | unsigned __int64 all;
30 | struct
31 | {
32 | unsigned __int64 read : 1; // bit 0
33 | unsigned __int64 write : 1; // bit 1
34 | unsigned __int64 execute : 1; // bit 2
35 | unsigned __int64 reserved1 : 5; // bit 7:3 (Must be Zero)
36 | unsigned __int64 accessed : 1; // bit 8
37 | unsigned __int64 ignored1 : 1; // bit 9
38 | unsigned __int64 execute_for_usermode : 1; // bit 10
39 | unsigned __int64 ignored2 : 1; // bit 11
40 | unsigned __int64 physical_address : 36; // bit (N-1):12 or Page-Frame-Number
41 | unsigned __int64 reserved2 : 4; // bit 51:N
42 | unsigned __int64 ignored3 : 12; // bit 63:52
43 | };
44 | };
45 |
46 | // See Table 28-3
47 | union __ept_pdpte
48 | {
49 | unsigned __int64 all;
50 | struct
51 | {
52 | unsigned __int64 read : 1; // bit 0
53 | unsigned __int64 write : 1; // bit 1
54 | unsigned __int64 execute : 1; // bit 2
55 | unsigned __int64 reserved1 : 5; // bit 7:3 (Must be Zero)
56 | unsigned __int64 accessed : 1; // bit 8
57 | unsigned __int64 ignored1 : 1; // bit 9
58 | unsigned __int64 execute_for_usermode : 1; // bit 10
59 | unsigned __int64 ignored2 : 1; // bit 11
60 | unsigned __int64 physical_address : 36; // bit (N-1):12 or Page-Frame-Number
61 | unsigned __int64 reserved2 : 4; // bit 51:N
62 | unsigned __int64 ignored3 : 12; // bit 63:52
63 | };
64 | };
65 |
66 | // See Table 28-5
67 | union __ept_pde {
68 | unsigned __int64 all;
69 | struct
70 | {
71 | unsigned __int64 read : 1; // bit 0
72 | unsigned __int64 write : 1; // bit 1
73 | unsigned __int64 execute : 1; // bit 2
74 | unsigned __int64 reserved1 : 5; // bit 7:3 (Must be Zero)
75 | unsigned __int64 accessed : 1; // bit 8
76 | unsigned __int64 ignored1 : 1; // bit 9
77 | unsigned __int64 execute_for_usermode : 1; // bit 10
78 | unsigned __int64 ignored2 : 1; // bit 11
79 | unsigned __int64 physical_address : 36; // bit (N-1):12 or Page-Frame-Number
80 | unsigned __int64 reserved2 : 4; // bit 51:N
81 | unsigned __int64 ignored3 : 12; // bit 63:52
82 | }large_page;
83 | struct
84 | {
85 | unsigned __int64 read : 1;
86 | unsigned __int64 write : 1;
87 | unsigned __int64 execute : 1;
88 | unsigned __int64 memory_type : 3;
89 | unsigned __int64 ignore_pat : 1;
90 | unsigned __int64 large_page : 1;
91 | unsigned __int64 accessed : 1;
92 | unsigned __int64 dirty : 1;
93 | unsigned __int64 execute_for_usermode : 1;
94 | unsigned __int64 reserved1 : 10;
95 | unsigned __int64 physical_address : 27;
96 | unsigned __int64 reserved2 : 15;
97 | unsigned __int64 suppressve : 1;
98 | }page_directory_entry;
99 | };
100 |
101 | // See Table 28-6
102 | union __ept_pte {
103 | unsigned __int64 all;
104 | struct
105 | {
106 | unsigned __int64 read : 1; // bit 0
107 | unsigned __int64 write : 1; // bit 1
108 | unsigned __int64 execute : 1; // bit 2
109 | unsigned __int64 ept_memory_type : 3; // bit 5:3 (EPT Memory type)
110 | unsigned __int64 ignore_pat : 1; // bit 6
111 | unsigned __int64 ignored1 : 1; // bit 7
112 | unsigned __int64 accessed_flag : 1; // bit 8
113 | unsigned __int64 dirty_flag : 1; // bit 9
114 | unsigned __int64 execute_for_usermode : 1; // bit 10
115 | unsigned __int64 ignored2 : 1; // bit 11
116 | unsigned __int64 physical_address : 36; // bit (N-1):12 or Page-Frame-Number
117 | unsigned __int64 reserved : 4; // bit 51:N
118 | unsigned __int64 ignored3 : 11; // bit 62:52
119 | unsigned __int64 suppress_ve : 1; // bit 63
120 | };
121 | };
122 |
123 | struct __ept_dynamic_split
124 | {
125 | DECLSPEC_ALIGN(PAGE_SIZE) __ept_pte pml1[512];
126 |
127 | __ept_pde* entry;
128 |
129 | LIST_ENTRY dynamic_split_list;
130 | };
131 |
132 | struct __vmm_ept_page_table
133 | {
134 | DECLSPEC_ALIGN(PAGE_SIZE) __ept_pml4e pml4[512];
135 |
136 | DECLSPEC_ALIGN(PAGE_SIZE) __ept_pdpte pml3[512];
137 |
138 | DECLSPEC_ALIGN(PAGE_SIZE) __ept_pde pml2[512][512];
139 | };
140 |
141 | struct __ept_hooked_function_info
142 | {
143 | //
144 | // Linked list entires for each function hook.
145 | //
146 | LIST_ENTRY hooked_function_list;
147 |
148 | //
149 | // Pointer to page with our hooked functions
150 | //
151 | unsigned __int8* fake_page_contents;
152 |
153 | //
154 | // Size of hook
155 | //
156 | unsigned __int64 hook_size;
157 |
158 | //
159 | // Virtual address of hooked function
160 | //
161 | void* hooked_function_va;
162 |
163 | //
164 | // Virtual address of original function
165 | //
166 | void* original_function_va;
167 |
168 | //
169 | // Address of trampoline used to call original function
170 | //
171 | unsigned __int8* trampoline_address;
172 | };
173 |
174 | struct __ept_hooked_page_info
175 | {
176 | //
177 | // Page with our hooked functions
178 | //
179 | unsigned __int8* fake_page_contents;
180 |
181 | //
182 | // Linked list entires for each page hook.
183 | //
184 | LIST_ENTRY hooked_page_list;
185 |
186 | //
187 | // Linked list entries for each function hook
188 | //
189 | LIST_ENTRY hooked_functions_list;
190 |
191 | //
192 | // Page frame number of the hooked page. Used to find this structure in the list of page hooks
193 | //
194 | unsigned __int64 pfn_of_hooked_page;
195 |
196 | //
197 | // Page frame number of the page with fake contents. Used to swap page with fake contents
198 | //
199 | unsigned __int64 pfn_of_fake_page_contents;
200 |
201 | //
202 | // The page entry in the page tables that this page is targetting.
203 | //
204 | __ept_pte* entry_address;
205 |
206 | //
207 | // The original page entry
208 | //
209 | __ept_pte original_entry;
210 |
211 | //
212 | // The changed page entry
213 | //
214 | __ept_pte changed_entry;
215 | };
216 |
217 | union __ept_violation
218 | {
219 | unsigned __int64 all;
220 | struct
221 | {
222 | /**
223 | * [Bit 0] Set if the access causing the EPT violation was a data read.
224 | */
225 | unsigned __int64 read_access : 1;
226 |
227 | /**
228 | * [Bit 1] Set if the access causing the EPT violation was a data write.
229 | */
230 | unsigned __int64 write_access : 1;
231 |
232 | /**
233 | * [Bit 2] Set if the access causing the EPT violation was an instruction fetch.
234 | */
235 | unsigned __int64 execute_access : 1;
236 |
237 | /**
238 | * [Bit 3] The logical-AND of bit 0 in the EPT paging-structure entries used to translate the guest-physical address of the
239 | * access causing the EPT violation (indicates whether the guest-physical address was readable).
240 | */
241 | unsigned __int64 ept_readable : 1;
242 |
243 | /**
244 | * [Bit 4] The logical-AND of bit 1 in the EPT paging-structure entries used to translate the guest-physical address of the
245 | * access causing the EPT violation (indicates whether the guest-physical address was writeable).
246 | */
247 | unsigned __int64 ept_writeable : 1;
248 |
249 | /**
250 | * [Bit 5] The logical-AND of bit 2 in the EPT paging-structure entries used to translate the guest-physical address of the
251 | * access causing the EPT violation.
252 | * If the "mode-based execute control for EPT" VM-execution control is 0, this indicates whether the guest-physical address
253 | * was executable. If that control is 1, this indicates whether the guest-physical address was executable for
254 | * supervisor-mode linear addresses.
255 | */
256 | unsigned __int64 ept_executable : 1;
257 |
258 | /**
259 | * [Bit 6] If the "mode-based execute control" VM-execution control is 0, the value of this bit is undefined. If that
260 | * control is 1, this bit is the logical-AND of bit 10 in the EPT paging-structures entries used to translate the
261 | * guest-physical address of the access causing the EPT violation. In this case, it indicates whether the guest-physical
262 | * address was executable for user-mode linear addresses.
263 | */
264 | unsigned __int64 ept_executable_for_usermode : 1;
265 |
266 | /**
267 | * [Bit 7] Set if the guest linear-address field is valid. The guest linear-address field is valid for all EPT violations
268 | * except those resulting from an attempt to load the guest PDPTEs as part of the execution of the MOV CR instruction.
269 | */
270 | unsigned __int64 valid_guest_linear_address : 1;
271 |
272 | /**
273 | * [Bit 8] If bit 7 is 1:
274 | * - Set if the access causing the EPT violation is to a guest-physical address that is the translation of a linear
275 | * address.
276 | * - Clear if the access causing the EPT violation is to a paging-structure entry as part of a page walk or the update of
277 | * an accessed or dirty bit.
278 | * Reserved if bit 7 is 0 (cleared to 0).
279 | */
280 | unsigned __int64 caused_by_translation : 1;
281 |
282 | /**
283 | * [Bit 9] This bit is 0 if the linear address is a supervisor-mode linear address and 1 if it is a user-mode linear
284 | * address. Otherwise, this bit is undefined.
285 | *
286 | * @remarks If bit 7 is 1, bit 8 is 1, and the processor supports advanced VM-exit information for EPT violations. (If
287 | * CR0.PG = 0, the translation of every linear address is a user-mode linear address and thus this bit will be 1.)
288 | */
289 | unsigned __int64 usermode_linear_address : 1;
290 |
291 | /**
292 | * [Bit 10] This bit is 0 if paging translates the linear address to a read-only page and 1 if it translates to a
293 | * read/write page. Otherwise, this bit is undefined
294 | *
295 | * @remarks If bit 7 is 1, bit 8 is 1, and the processor supports advanced VM-exit information for EPT violations. (If
296 | * CR0.PG = 0, every linear address is read/write and thus this bit will be 1.)
297 | */
298 | unsigned __int64 readable_writable_page : 1;
299 |
300 | /**
301 | * [Bit 11] This bit is 0 if paging translates the linear address to an executable page and 1 if it translates to an
302 | * execute-disable page. Otherwise, this bit is undefined.
303 | *
304 | * @remarks If bit 7 is 1, bit 8 is 1, and the processor supports advanced VM-exit information for EPT violations. (If
305 | * CR0.PG = 0, CR4.PAE = 0, or MSR_IA32_EFER.NXE = 0, every linear address is executable and thus this bit will be 0.)
306 | */
307 | unsigned __int64 execute_disable_page : 1;
308 |
309 | /**
310 | * [Bit 12] NMI unblocking due to IRET.
311 | */
312 | unsigned __int64 nmi_unblocking : 1;
313 | unsigned __int64 reserved1 : 51;
314 | };
315 | };
316 |
317 | struct __ept_state
318 | {
319 | LIST_ENTRY hooked_page_list;
320 | __eptp* ept_pointer;
321 | __vmm_ept_page_table* ept_page_table;
322 | __ept_hooked_page_info* page_to_change;
323 | };
324 |
325 | namespace ept
326 | {
327 | ///
328 | /// Build mtrr map to track physical memory type
329 | ///
330 | void build_mtrr_map();
331 |
332 | ///
333 | /// Initialize ept structure
334 | ///
335 | ///
336 | bool initialize(__ept_state& ept_state);
337 |
338 | ///
339 | /// Change page physcial frame number and invalidate tlb
340 | ///
341 | /// Pointer to page table entry which we want to change
342 | /// Pointer to page table entry which we want use to change
343 | /// If true invalidates tlb after changning pte value
344 | /// Specifiy if we want to invalidate single context or all contexts
345 | void swap_pml1_and_invalidate_tlb(__ept_state& ept_state, __ept_pte* entry_address, __ept_pte entry_value, invept_type invalidation_type);
346 |
347 | ///
348 | /// Unhook all functions and invalidate tlb
349 | ///
350 | void unhook_all_functions(__ept_state& ept_state);
351 |
352 | ///
353 | /// Perfrom a hook
354 | ///
355 | /// Address of function which we want to hook
356 | /// Address of hooked version of function which we are hooking
357 | /// Address of codecave which is located in 2gb range of target function (Use only if you need smaller trampoline)
358 | /// Address used to call original function
359 | ///
360 | bool hook_function(__ept_state& ept_state, void* target_address, void* hook_function, void** origin_function);
361 |
362 | ///
363 | /// Unhook single function
364 | ///
365 | ///
366 | ///
367 | bool unhook_function(__ept_state& ept_state, unsigned __int64 virtual_address);
368 |
369 | ///
370 | /// Split pml2 into 512 pml1 entries (From one 2MB page to 512 4KB pages)
371 | ///
372 | /// Pre allocated buffer for split
373 | ///
374 | /// status
375 | bool split_pml2(__ept_state& ept_state, void* pre_allocated_buffer, unsigned __int64 physical_address);
376 | }
--------------------------------------------------------------------------------
/airhv/ia32/exception.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | union __exception_bitmap
3 | {
4 | unsigned __int32 all;
5 | struct
6 | {
7 | unsigned __int32 divide_error : 1;
8 | unsigned __int32 debug : 1;
9 | unsigned __int32 nmi_interrupt : 1;
10 | unsigned __int32 breakpoint : 1;
11 | unsigned __int32 overflow : 1;
12 | unsigned __int32 bound : 1;
13 | unsigned __int32 invalid_opcode : 1;
14 | unsigned __int32 device_not_available : 1;
15 | unsigned __int32 double_fault : 1;
16 | unsigned __int32 coprocessor_segment_overrun : 1;
17 | unsigned __int32 invalid_tss : 1;
18 | unsigned __int32 segment_not_present : 1;
19 | unsigned __int32 stack_segment_fault : 1;
20 | unsigned __int32 general_protection : 1;
21 | unsigned __int32 page_fault : 1;
22 | unsigned __int32 x87_floating_point_error : 1;
23 | unsigned __int32 alignment_check : 1;
24 | unsigned __int32 machine_check : 1;
25 | unsigned __int32 simd_floating_point_error : 1;
26 | unsigned __int32 virtualization_exception : 1;
27 | };
28 | };
--------------------------------------------------------------------------------
/airhv/ia32/msr.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "common.h"
3 |
4 | #define IA32_FEATURE_CONTROL 0x3A
5 | #define IA32_VMX_BASIC 0x480
6 | #define IA32_VMX_ENTRY_CTLS 0x484
7 | #define IA32_VMX_CR0_FIXED0 0x486
8 | #define IA32_VMX_CR0_FIXED1 0x487
9 | #define IA32_VMX_CR4_FIXED0 0x488
10 | #define IA32_VMX_CR4_FIXED1 0x489
11 | #define IA32_VMX_TRUE_ENTRY_CTLS 0x490
12 | #define IA32_VMX_TRUE_EXIT_CTLS 0x48F
13 | #define IA32_VMX_EXIT_CTLS 0x483
14 | #define IA32_VMX_TRUE_PINBASED_CTLS 0x48D
15 | #define IA32_VMX_PINBASED_CTLS 0x481
16 | #define IA32_VMX_TRUE_PROCBASED_CTLS 0x48E
17 | #define IA32_VMX_PROCBASED_CTLS 0x482
18 | #define IA32_VMX_PROCBASED_CTLS2 0x48B
19 | #define IA32_DEBUGCTL 0x1D9
20 | #define IA32_SYSENTER_CS 0x174
21 | #define IA32_SYSENTER_ESP 0x175
22 | #define IA32_SYSENTER_EIP 0x176
23 | #define IA32_PERF_GLOBAL_CTRL 0x38F
24 | #define IA32_PAT 0x277
25 | #define IA32_EFER 0xC0000080
26 | #define IA32_BNDCFGS 0xD90
27 | #define IA32_RTIT_CTL 0x570
28 | #define IA32_S_CET 0x6A2
29 | #define IA32_INTERRUPT_SSP_TABLE_ADDR 0x6A8
30 | #define IA32_XSS 0xDA0
31 | #define IA32_PKRS 0x6E1
32 | #define IA32_FS_BASE 0xC0000100
33 | #define IA32_GS_BASE 0xC0000101
34 | #define IA32_TSC_AUX 0xC0000103
35 | #define IA32_MTRRCAP 0xFE
36 | #define IA32_MTRR_DEF_TYPE 0x2FF
37 | #define IA32_MTRR_PHYSBASE0 0x200
38 | #define IA32_MTRR_PHYSMASK0 0x201
39 | #define IA32_SMRR_PHYSBASE 0x1F2
40 | #define IA32_SMRR_PHYSMASK 0x1F3
41 | #define IA32_MTRR_FIX64K_00000 0x250
42 | #define IA32_MTRR_FIX16K_80000 0x258
43 | #define IA32_MTRR_FIX4K_C0000 0x268
44 | #define IA32_LSTAR 0xC0000082
45 | #define SYNTHETHIC_MSR_LOW 0x40000000
46 | #define SYNTHETHIC_MSR_HI 0x400000F0
47 | #define MSR_MASK_LOW ((unsigned __int64)(unsigned __int32) - 1)
48 |
49 | union __msr
50 | {
51 | unsigned __int64 all;
52 | struct
53 | {
54 | unsigned __int32 low;
55 | unsigned __int32 high;
56 | };
57 | };
58 |
59 | union __ia32_efer_t
60 | {
61 | unsigned __int64 all;
62 | struct
63 | {
64 | unsigned __int64 syscall_enable : 1;
65 | unsigned __int64 reserved_0 : 7;
66 | unsigned __int64 long_mode_enable : 1;
67 | unsigned __int64 reserved_1 : 1;
68 | unsigned __int64 long_mode_active : 1;
69 | unsigned __int64 execute_disable : 1;
70 | unsigned __int64 reserved_2 : 52;
71 | };
72 | };
73 |
74 | union __ia32_feature_control_msr
75 | {
76 | unsigned __int64 all;
77 | struct
78 | {
79 | unsigned __int64 lock : 1;
80 | unsigned __int64 vmxon_inside_smx : 1;
81 | unsigned __int64 vmxon_outside_smx : 1;
82 | unsigned __int64 reserved_0 : 5;
83 | unsigned __int64 senter_local : 6;
84 | unsigned __int64 senter_global : 1;
85 | unsigned __int64 reserved_1 : 1;
86 | unsigned __int64 sgx_launch_control_enable : 1;
87 | unsigned __int64 sgx_global_enable : 1;
88 | unsigned __int64 reserved_2 : 1;
89 | unsigned __int64 lmce : 1;
90 | unsigned __int64 system_reserved : 42;
91 | };
92 | };
93 |
94 | union __vmx_misc_msr_t
95 | {
96 | unsigned __int64 all;
97 | struct
98 | {
99 | unsigned __int64 vmx_preemption_tsc_rate : 5;
100 | unsigned __int64 store_lma_in_vmentry_control : 1;
101 | unsigned __int64 activate_state_bitmap : 3;
102 | unsigned __int64 reserved_0 : 5;
103 | unsigned __int64 pt_in_vmx : 1;
104 | unsigned __int64 rdmsr_in_smm : 1;
105 | unsigned __int64 cr3_target_value_count : 9;
106 | unsigned __int64 max_msr_vmexit : 3;
107 | unsigned __int64 allow_smi_blocking : 1;
108 | unsigned __int64 vmwrite_to_any : 1;
109 | unsigned __int64 interrupt_mod : 1;
110 | unsigned __int64 reserved_1 : 1;
111 | unsigned __int64 mseg_revision_identifier : 32;
112 | };
113 | };
114 |
115 | union __vmx_basic_msr
116 | {
117 | unsigned __int64 all;
118 | struct
119 | {
120 | unsigned __int64 vmcs_revision_identifier : 31;
121 | unsigned __int64 always_0 : 1;
122 | unsigned __int64 vmxon_region_size : 13;
123 | unsigned __int64 reserved_1 : 3;
124 | unsigned __int64 vmxon_physical_address_width : 1;
125 | unsigned __int64 dual_monitor_smi : 1;
126 | unsigned __int64 memory_type : 4;
127 | unsigned __int64 io_instruction_reporting : 1;
128 | unsigned __int64 true_controls : 1;
129 | };
130 | };
--------------------------------------------------------------------------------
/airhv/ia32/mtrr.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | enum __mtrr_memory_types
3 | {
4 | MEMORY_TYPE_UNCACHEABLE,
5 | MEMORY_TYPE_WRITE_COMBINING,
6 | MEMORY_TYPE_WRITE_THROUGH = 4,
7 | MEMORY_TYPE_WRITE_PROTECTED,
8 | MEMORY_TYPE_WRITE_BACK,
9 | MEMORY_TYPE_INVALID = 255,
10 | };
11 |
12 | struct __mtrr_range_descriptor
13 | {
14 | unsigned __int64 physcial_base_address;
15 | unsigned __int64 physcial_end_address;
16 | unsigned __int8 memory_type;
17 | bool fixed_range;
18 | };
19 |
20 | union __mtrr_physmask_reg
21 | {
22 | unsigned __int64 all;
23 | struct
24 | {
25 | unsigned __int64 reserved : 11;
26 | unsigned __int64 valid : 1;
27 | unsigned __int64 physmask : 36;
28 | unsigned __int64 reserved2 : 16;
29 | };
30 | };
31 |
32 | union __mtrr_physbase_reg
33 | {
34 | unsigned __int64 all;
35 | struct
36 | {
37 | unsigned __int64 type : 8;
38 | unsigned __int64 reserved : 4;
39 | unsigned __int64 physbase : 36;
40 | unsigned __int64 reserved2 : 16;
41 | };
42 | };
43 |
44 | union __mtrr_cap_reg
45 | {
46 | unsigned __int64 all;
47 | struct
48 | {
49 | unsigned __int64 range_register_number : 8;
50 | unsigned __int64 fixed_range_support : 1;
51 | unsigned __int64 reserved : 1;
52 | unsigned __int64 write_combining_support : 1;
53 | unsigned __int64 smrr_support : 1;
54 | unsigned __int64 reserved2 : 52;
55 | };
56 | };
57 |
58 | union __mtrr_def_type
59 | {
60 | unsigned __int64 all;
61 | struct
62 | {
63 | unsigned __int64 memory_type : 8;
64 | unsigned __int64 reserved1 : 2;
65 | unsigned __int64 fixed_range_mtrr_enabled : 1;
66 | unsigned __int64 mtrr_enabled : 1;
67 | unsigned __int64 reserved2 : 52;
68 | };
69 | };
70 |
71 | union __mtrr_fixed_range_type
72 | {
73 | unsigned __int64 all;
74 | struct
75 | {
76 | unsigned __int8 types[8];
77 | };
78 | };
--------------------------------------------------------------------------------
/airhv/ia32/rflags.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | union __rflags
4 | {
5 | unsigned __int64 all;
6 | struct
7 | {
8 | unsigned __int64 carry_flag : 1;
9 | unsigned __int64 read_as_1 : 1;
10 | unsigned __int64 parity_flag : 1;
11 | unsigned __int64 reserved_1 : 1;
12 | unsigned __int64 auxiliary_carry_flag : 1;
13 | unsigned __int64 reserved_2 : 1;
14 | unsigned __int64 zero_flag : 1;
15 | unsigned __int64 sign_flag : 1;
16 | unsigned __int64 trap_flag : 1;
17 | unsigned __int64 interrupt_enable_flag : 1;
18 | unsigned __int64 direction_flag : 1;
19 | unsigned __int64 overflow_flag : 1;
20 | unsigned __int64 io_privilege_level : 2;
21 | unsigned __int64 nested_task_flag : 1;
22 | unsigned __int64 reserved_3 : 1;
23 | unsigned __int64 resume_flag : 1;
24 | unsigned __int64 virtual_8086_mode_flag : 1;
25 | unsigned __int64 alignment_check_flag : 1;
26 | unsigned __int64 virtual_interrupt_flag : 1;
27 | unsigned __int64 virtual_interrupt_pending_flag : 1;
28 | unsigned __int64 identification_flag : 1;
29 | };
30 | };
--------------------------------------------------------------------------------
/airhv/ia32/segment.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | enum __segment_registers
3 | {
4 | ES = 0,
5 | CS,
6 | SS,
7 | DS,
8 | FS,
9 | GS,
10 | LDTR,
11 | TR
12 | };
13 |
14 | union __segment_access_rights
15 | {
16 | struct
17 | {
18 | unsigned __int32 type : 4;
19 | unsigned __int32 descriptor_type : 1;
20 | unsigned __int32 dpl : 2;
21 | unsigned __int32 present : 1;
22 | unsigned __int32 reserved0 : 4;
23 | unsigned __int32 available : 1;
24 | unsigned __int32 long_mode : 1;
25 | unsigned __int32 default_big : 1;
26 | unsigned __int32 granularity : 1;
27 | unsigned __int32 unusable : 1;
28 | unsigned __int32 reserved1 : 15;
29 | };
30 |
31 | unsigned __int32 all;
32 | };
33 |
34 | struct __segment_descriptor
35 | {
36 | unsigned __int16 limit_low;
37 | unsigned __int16 base_low;
38 | union
39 | {
40 | struct
41 | {
42 | unsigned __int32 base_middle : 8;
43 | unsigned __int32 type : 4;
44 | unsigned __int32 descriptor_type : 1;
45 | unsigned __int32 dpl : 2;
46 | unsigned __int32 present : 1;
47 | unsigned __int32 segment_limit_high : 4;
48 | unsigned __int32 system : 1;
49 | unsigned __int32 long_mode : 1;
50 | unsigned __int32 default_big : 1;
51 | unsigned __int32 granularity : 1;
52 | unsigned __int32 base_high : 8;
53 | };
54 | };
55 |
56 | unsigned __int32 base_upper;
57 | unsigned __int32 reserved;
58 | };
59 |
60 | union __segment_selector
61 | {
62 | unsigned short all;
63 | struct
64 | {
65 | unsigned short rpl : 2;
66 | unsigned short ti : 1;
67 | unsigned short index : 13;
68 | };
69 | };
70 |
71 | #pragma pack(push, 1)
72 | struct __pseudo_descriptor64
73 | {
74 | unsigned __int16 limit;
75 | unsigned __int64 base_address;
76 | };
77 | #pragma pack(pop)
78 |
79 | #pragma pack(push, 1)
80 | struct __pseudo_descriptor32
81 | {
82 | unsigned __int16 limit;
83 | unsigned __int32 base_address;
84 | };
85 | #pragma pack(pop)
--------------------------------------------------------------------------------
/airhv/ia32/vmcs.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | union __vmx_secondary_processor_based_control
4 | {
5 | unsigned __int64 all;
6 | struct
7 | {
8 | unsigned __int64 virtualize_apic_accesses : 1;
9 | unsigned __int64 enable_ept : 1;
10 | unsigned __int64 descriptor_table_exiting : 1;
11 | unsigned __int64 enable_rdtscp : 1;
12 | unsigned __int64 virtualize_x2apic : 1;
13 | unsigned __int64 enable_vpid : 1;
14 | unsigned __int64 wbinvd_exiting : 1;
15 | unsigned __int64 unrestricted_guest : 1;
16 | unsigned __int64 apic_register_virtualization : 1;
17 | unsigned __int64 virtual_interrupt_delivery : 1;
18 | unsigned __int64 pause_loop_exiting : 1;
19 | unsigned __int64 rdrand_exiting : 1;
20 | unsigned __int64 enable_invpcid : 1;
21 | unsigned __int64 enable_vmfunc : 1;
22 | unsigned __int64 vmcs_shadowing : 1;
23 | unsigned __int64 enable_encls_exiting : 1;
24 | unsigned __int64 rdseed_exiting : 1;
25 | unsigned __int64 enable_pml : 1;
26 | unsigned __int64 use_virtualization_exception : 1;
27 | unsigned __int64 conceal_vmx_from_pt : 1;
28 | unsigned __int64 enable_xsave_xrstor : 1;
29 | unsigned __int64 reserved_0 : 1;
30 | unsigned __int64 mode_based_execute_control_ept : 1;
31 | unsigned __int64 sub_page_write_permission_for_ept : 1;
32 | unsigned __int64 intel_pt_uses_guest_physical_address : 1;
33 | unsigned __int64 use_tsc_scaling : 1;
34 | unsigned __int64 enable_user_wait_and_pause : 1;
35 | unsigned __int64 enable_enclv_exiting : 1;
36 | };
37 | };
38 |
39 | union __vmx_primary_processor_based_control
40 | {
41 | unsigned __int64 all;
42 | struct
43 | {
44 | unsigned __int64 reserved_0 : 2;
45 | unsigned __int64 interrupt_window_exiting : 1;
46 | unsigned __int64 use_tsc_offsetting : 1;
47 | unsigned __int64 reserved_1 : 3;
48 | unsigned __int64 hlt_exiting : 1;
49 | unsigned __int64 reserved_2 : 1;
50 | unsigned __int64 invldpg_exiting : 1;
51 | unsigned __int64 mwait_exiting : 1;
52 | unsigned __int64 rdpmc_exiting : 1;
53 | unsigned __int64 rdtsc_exiting : 1;
54 | unsigned __int64 reserved_3 : 2;
55 | unsigned __int64 cr3_load_exiting : 1;
56 | unsigned __int64 cr3_store_exiting : 1;
57 | unsigned __int64 reserved_4 : 2;
58 | unsigned __int64 cr8_load_exiting : 1;
59 | unsigned __int64 cr8_store_exiting : 1;
60 | unsigned __int64 use_tpr_shadow : 1;
61 | unsigned __int64 nmi_window_exiting : 1;
62 | unsigned __int64 mov_dr_exiting : 1;
63 | unsigned __int64 unconditional_io_exiting : 1;
64 | unsigned __int64 use_io_bitmaps : 1;
65 | unsigned __int64 reserved_5 : 1;
66 | unsigned __int64 monitor_trap_flag : 1;
67 | unsigned __int64 use_msr_bitmaps : 1;
68 | unsigned __int64 monitor_exiting : 1;
69 | unsigned __int64 pause_exiting : 1;
70 | unsigned __int64 active_secondary_controls : 1;
71 | };
72 | };
73 |
74 | union __vmx_pinbased_control_msr
75 | {
76 | unsigned __int64 all;
77 | struct
78 | {
79 | unsigned __int64 external_interrupt_exiting : 1;
80 | unsigned __int64 reserved_0 : 2;
81 | unsigned __int64 nmi_exiting : 1;
82 | unsigned __int64 reserved_1 : 1;
83 | unsigned __int64 virtual_nmis : 1;
84 | unsigned __int64 vmx_preemption_timer : 1;
85 | unsigned __int64 process_posted_interrupts : 1;
86 | };
87 | };
88 |
89 | union __vmx_true_control_settings
90 | {
91 | unsigned __int64 all;
92 | struct
93 | {
94 | unsigned __int32 allowed_0_settings;
95 | unsigned __int32 allowed_1_settings;
96 | };
97 | };
98 |
99 | union __vmx_entry_control
100 | {
101 | unsigned __int64 all;
102 | struct
103 | {
104 | unsigned __int64 reserved_0 : 2;
105 | unsigned __int64 load_dbg_controls : 1;
106 | unsigned __int64 reserved_1 : 6;
107 | unsigned __int64 ia32e_mode_guest : 1;
108 | unsigned __int64 entry_to_smm : 1;
109 | unsigned __int64 deactivate_dual_monitor_treament : 1;
110 | unsigned __int64 reserved_3 : 1;
111 | unsigned __int64 load_ia32_perf_global_control : 1;
112 | unsigned __int64 load_ia32_pat : 1;
113 | unsigned __int64 load_ia32_efer : 1;
114 | unsigned __int64 load_ia32_bndcfgs : 1;
115 | unsigned __int64 conceal_vmx_from_pt : 1;
116 | unsigned __int64 load_ia32_rtit_ctl : 1;
117 | unsigned __int64 load_cet_state : 1;
118 | unsigned __int64 load_pkrs : 1;
119 | };
120 | };
121 |
122 | union __interrupt_command_register
123 | {
124 | unsigned __int64 all;
125 | struct
126 | {
127 | unsigned __int64 vector : 8;
128 | unsigned __int64 delivery_mode : 3;
129 | unsigned __int64 destination_mode : 1;
130 | unsigned __int64 delivery_status : 1;
131 | unsigned __int64 reserved_0 : 1;
132 | unsigned __int64 level : 1;
133 | unsigned __int64 trigger_mode : 1;
134 | unsigned __int64 reserved_1 : 2;
135 | unsigned __int64 destination_short : 2;
136 | unsigned __int64 reserved_3 : 35;
137 | unsigned __int64 destination : 8;
138 | };
139 | };
140 |
141 | union __vmx_exit_control
142 | {
143 | unsigned __int64 all;
144 | struct
145 | {
146 | unsigned __int64 reserved_0 : 2;
147 | unsigned __int64 save_dbg_controls : 1;
148 | unsigned __int64 reserved_1 : 6;
149 | unsigned __int64 host_address_space_size : 1;
150 | unsigned __int64 reserved_2 : 2;
151 | unsigned __int64 load_ia32_perf_global_control : 1;
152 | unsigned __int64 reserved_3 : 2;
153 | unsigned __int64 ack_interrupt_on_exit : 1;
154 | unsigned __int64 reserved_4 : 2;
155 | unsigned __int64 save_ia32_pat : 1;
156 | unsigned __int64 load_ia32_pat : 1;
157 | unsigned __int64 save_ia32_efer : 1;
158 | unsigned __int64 load_ia32_efer : 1;
159 | unsigned __int64 save_vmx_preemption_timer_value : 1;
160 | unsigned __int64 clear_ia32_bndcfgs : 1;
161 | unsigned __int64 conceal_vmx_from_pt : 1;
162 | unsigned __int64 load_ia32_rtit_ctl : 1;
163 | unsigned __int64 load_cet_state : 1;
164 | unsigned __int64 load_pkrs : 1;
165 | };
166 | };
167 |
168 | union __vmx_pending_debug_exceptions
169 | {
170 | unsigned __int64 all;
171 | struct
172 | {
173 | unsigned __int64 b0 : 1;
174 | unsigned __int64 b1 : 1;
175 | unsigned __int64 b2 : 1;
176 | unsigned __int64 b3 : 1;
177 | unsigned __int64 reserved1 : 8;
178 | unsigned __int64 enabled_bp : 1;
179 | unsigned __int64 reserved2 : 1;
180 | unsigned __int64 bs : 1;
181 | unsigned __int64 reserved3 : 1;
182 | unsigned __int64 rtm : 1;
183 | unsigned __int64 reserved4 : 47;
184 | };
185 |
186 | };
187 |
188 | union __vmx_interruptibility_state
189 | {
190 | unsigned __int64 all;
191 | struct
192 | {
193 | unsigned __int64 blocking_by_sti : 1;
194 | unsigned __int64 blocking_by_mov_ss : 1;
195 | unsigned __int64 blocking_by_smi : 1;
196 | unsigned __int64 blocking_by_nmi : 1;
197 | unsigned __int64 enclave_interruption : 1;
198 | unsigned __int64 reserved : 27;
199 | };
200 | };
201 |
202 | void fill_vmcs(__vcpu* vcpu, void* guest_rsp);
--------------------------------------------------------------------------------
/airhv/ia32/vmcs_encodings.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #define VMCS_ENCODE_COMPONENT( access, type, width, index ) ( unsigned )( ( unsigned short )( access ) | \
4 | ( ( unsigned short )( index ) << 1 ) | \
5 | ( ( unsigned short )( type ) << 10 ) | \
6 | ( ( unsigned short )( width ) << 13 ) )
7 |
8 |
9 | #define VMCS_ENCODE_COMPONENT_FULL( type, width, index ) VMCS_ENCODE_COMPONENT( full, type, width, index )
10 | #define VMCS_ENCODE_COMPONENT_FULL_16( type, index ) VMCS_ENCODE_COMPONENT_FULL( type, word, index )
11 | #define VMCS_ENCODE_COMPONENT_FULL_32( type, index ) VMCS_ENCODE_COMPONENT_FULL( type, doubleword, index )
12 | #define VMCS_ENCODE_COMPONENT_FULL_64( type, index ) VMCS_ENCODE_COMPONENT_FULL( type, quadword, index )
13 |
14 | enum __vmcs_access
15 | {
16 | full = 0,
17 | high = 1
18 | };
19 |
20 | enum __vmcs_type
21 | {
22 | control = 0,
23 | readonly,
24 | guest,
25 | host
26 | };
27 |
28 | enum __vmcs_width
29 | {
30 | word = 0,
31 | quadword,
32 | doubleword,
33 | natural
34 | };
35 |
36 | enum __vmcs_fields
37 | {
38 | // Natural Guest Register State Fields
39 | GUEST_CR0 = VMCS_ENCODE_COMPONENT_FULL(guest, natural, 0),
40 | GUEST_CR3 = VMCS_ENCODE_COMPONENT_FULL(guest, natural, 1),
41 | GUEST_CR4 = VMCS_ENCODE_COMPONENT_FULL(guest, natural, 2),
42 | GUEST_ES_BASE = VMCS_ENCODE_COMPONENT_FULL(guest, natural, 3),
43 | GUEST_CS_BASE = VMCS_ENCODE_COMPONENT_FULL(guest, natural, 4),
44 | GUEST_SS_BASE = VMCS_ENCODE_COMPONENT_FULL(guest, natural, 5),
45 | GUEST_DS_BASE = VMCS_ENCODE_COMPONENT_FULL(guest, natural, 6),
46 | GUEST_FS_BASE = VMCS_ENCODE_COMPONENT_FULL(guest, natural, 7),
47 | GUEST_GS_BASE = VMCS_ENCODE_COMPONENT_FULL(guest, natural, 8),
48 | GUEST_LDTR_BASE = VMCS_ENCODE_COMPONENT_FULL(guest, natural, 9),
49 | GUEST_TR_BASE = VMCS_ENCODE_COMPONENT_FULL(guest, natural, 10),
50 | GUEST_GDTR_BASE = VMCS_ENCODE_COMPONENT_FULL(guest, natural, 11),
51 | GUEST_IDTR_BASE = VMCS_ENCODE_COMPONENT_FULL(guest, natural, 12),
52 | GUEST_DR7 = VMCS_ENCODE_COMPONENT_FULL(guest, natural, 13),
53 | GUEST_RSP = VMCS_ENCODE_COMPONENT_FULL(guest, natural, 14),
54 | GUEST_RIP = VMCS_ENCODE_COMPONENT_FULL(guest, natural, 15),
55 | GUEST_RFLAGS = VMCS_ENCODE_COMPONENT_FULL(guest, natural, 16),
56 | GUEST_PENDING_DEBUG_EXCEPTION = VMCS_ENCODE_COMPONENT_FULL(guest, natural, 17),
57 | GUEST_SYSENTER_ESP = VMCS_ENCODE_COMPONENT_FULL(guest, natural, 18),
58 | GUEST_SYSENTER_EIP = VMCS_ENCODE_COMPONENT_FULL(guest, natural, 19),
59 | GUEST_S_CET = VMCS_ENCODE_COMPONENT_FULL(guest, natural, 20),
60 | GUEST_SSP = VMCS_ENCODE_COMPONENT_FULL(guest, natural, 21),
61 | GUEST_INTERRUPT_SSP_TABLE_ADDR = VMCS_ENCODE_COMPONENT_FULL(guest, natural, 22),
62 |
63 | // 64-bit Guest Register State Fields
64 | GUEST_VMCS_LINK_POINTER = VMCS_ENCODE_COMPONENT_FULL_64(guest, 0),
65 | GUEST_DEBUG_CONTROL = VMCS_ENCODE_COMPONENT_FULL_64(guest, 1),
66 | GUEST_PAT = VMCS_ENCODE_COMPONENT_FULL_64(guest, 2),
67 | GUEST_EFER = VMCS_ENCODE_COMPONENT_FULL_64(guest, 3),
68 | GUEST_PERF_GLOBAL_CONTROL = VMCS_ENCODE_COMPONENT_FULL_64(guest, 4),
69 | GUEST_PDPTE0 = VMCS_ENCODE_COMPONENT_FULL_64(guest, 5),
70 | GUEST_PDPTE1 = VMCS_ENCODE_COMPONENT_FULL_64(guest, 6),
71 | GUEST_PDPTE2 = VMCS_ENCODE_COMPONENT_FULL_64(guest, 7),
72 | GUEST_PDPTE3 = VMCS_ENCODE_COMPONENT_FULL_64(guest, 8),
73 | GUEST_BNDCFGS = VMCS_ENCODE_COMPONENT_FULL_64(guest, 9),
74 | GUEST_RTIT_CTL = VMCS_ENCODE_COMPONENT_FULL_64(guest, 10),
75 | GUEST_PKRS = VMCS_ENCODE_COMPONENT_FULL_64(guest, 11),
76 |
77 | // 32-Bit Guest Register State Fields
78 | GUEST_ES_LIMIT = VMCS_ENCODE_COMPONENT_FULL_32(guest, 0),
79 | GUEST_CS_LIMIT = VMCS_ENCODE_COMPONENT_FULL_32(guest, 1),
80 | GUEST_SS_LIMIT = VMCS_ENCODE_COMPONENT_FULL_32(guest, 2),
81 | GUEST_DS_LIMIT = VMCS_ENCODE_COMPONENT_FULL_32(guest, 3),
82 | GUEST_FS_LIMIT = VMCS_ENCODE_COMPONENT_FULL_32(guest, 4),
83 | GUEST_GS_LIMIT = VMCS_ENCODE_COMPONENT_FULL_32(guest, 5),
84 | GUEST_LDTR_LIMIT = VMCS_ENCODE_COMPONENT_FULL_32(guest, 6),
85 | GUEST_TR_LIMIT = VMCS_ENCODE_COMPONENT_FULL_32(guest, 7),
86 | GUEST_GDTR_LIMIT = VMCS_ENCODE_COMPONENT_FULL_32(guest, 8),
87 | GUEST_IDTR_LIMIT = VMCS_ENCODE_COMPONENT_FULL_32(guest, 9),
88 | GUEST_ES_ACCESS_RIGHTS = VMCS_ENCODE_COMPONENT_FULL_32(guest, 10),
89 | GUEST_CS_ACCESS_RIGHTS = VMCS_ENCODE_COMPONENT_FULL_32(guest, 11),
90 | GUEST_SS_ACCESS_RIGHTS = VMCS_ENCODE_COMPONENT_FULL_32(guest, 12),
91 | GUEST_DS_ACCESS_RIGHTS = VMCS_ENCODE_COMPONENT_FULL_32(guest, 13),
92 | GUEST_FS_ACCESS_RIGHTS = VMCS_ENCODE_COMPONENT_FULL_32(guest, 14),
93 | GUEST_GS_ACCESS_RIGHTS = VMCS_ENCODE_COMPONENT_FULL_32(guest, 15),
94 | GUEST_LDTR_ACCESS_RIGHTS = VMCS_ENCODE_COMPONENT_FULL_32(guest, 16),
95 | GUEST_TR_ACCESS_RIGHTS = VMCS_ENCODE_COMPONENT_FULL_32(guest, 17),
96 | GUEST_INTERRUPTIBILITY_STATE = VMCS_ENCODE_COMPONENT_FULL_32(guest, 18),
97 | GUEST_ACTIVITY_STATE = VMCS_ENCODE_COMPONENT_FULL_32(guest, 19),
98 | GUEST_SMBASE = VMCS_ENCODE_COMPONENT_FULL_32(guest, 20),
99 | GUEST_SYSENTER_CS = VMCS_ENCODE_COMPONENT_FULL_32(guest, 21),
100 | GUEST_VMX_PREEMPTION_TIMER_VALUE = VMCS_ENCODE_COMPONENT_FULL_32(guest, 23),
101 |
102 | // 16-Bit Guest Register State Fields
103 | GUEST_ES_SELECTOR = VMCS_ENCODE_COMPONENT_FULL_16(guest, 0),
104 | GUEST_CS_SELECTOR = VMCS_ENCODE_COMPONENT_FULL_16(guest, 1),
105 | GUEST_SS_SELECTOR = VMCS_ENCODE_COMPONENT_FULL_16(guest, 2),
106 | GUEST_DS_SELECTOR = VMCS_ENCODE_COMPONENT_FULL_16(guest, 3),
107 | GUEST_FS_SELECTOR = VMCS_ENCODE_COMPONENT_FULL_16(guest, 4),
108 | GUEST_GS_SELECTOR = VMCS_ENCODE_COMPONENT_FULL_16(guest, 5),
109 | GUEST_LDTR_SELECTOR = VMCS_ENCODE_COMPONENT_FULL_16(guest, 6),
110 | GUEST_TR_SELECTOR = VMCS_ENCODE_COMPONENT_FULL_16(guest, 7),
111 | GUEST_GUEST_INTERRUPT_STATUS = VMCS_ENCODE_COMPONENT_FULL_16(guest, 8),
112 | GUEST_PML_INDEX = VMCS_ENCODE_COMPONENT_FULL_16(guest, 9),
113 |
114 | // Natural Host Register State Fields
115 | HOST_CR0 = VMCS_ENCODE_COMPONENT_FULL(host, natural, 0),
116 | HOST_CR3 = VMCS_ENCODE_COMPONENT_FULL(host, natural, 1),
117 | HOST_CR4 = VMCS_ENCODE_COMPONENT_FULL(host, natural, 2),
118 | HOST_FS_BASE = VMCS_ENCODE_COMPONENT_FULL(host, natural, 3),
119 | HOST_GS_BASE = VMCS_ENCODE_COMPONENT_FULL(host, natural, 4),
120 | HOST_TR_BASE = VMCS_ENCODE_COMPONENT_FULL(host, natural, 5),
121 | HOST_GDTR_BASE = VMCS_ENCODE_COMPONENT_FULL(host, natural, 6),
122 | HOST_IDTR_BASE = VMCS_ENCODE_COMPONENT_FULL(host, natural, 7),
123 | HOST_SYSENTER_ESP = VMCS_ENCODE_COMPONENT_FULL(host, natural, 8),
124 | HOST_SYSENTER_EIP = VMCS_ENCODE_COMPONENT_FULL(host, natural, 9),
125 | HOST_RSP = VMCS_ENCODE_COMPONENT_FULL(host, natural, 10),
126 | HOST_RIP = VMCS_ENCODE_COMPONENT_FULL(host, natural, 11),
127 | HOST_S_CET = VMCS_ENCODE_COMPONENT_FULL(host, natural, 12),
128 | HOST_SSP = VMCS_ENCODE_COMPONENT_FULL(host, natural, 13),
129 | HOST_INTERRUPT_SSP_TABLE_ADDR = VMCS_ENCODE_COMPONENT_FULL(host, natural, 14),
130 |
131 | // 64-bit Host Register State Fields
132 | HOST_PAT = VMCS_ENCODE_COMPONENT_FULL_64(host, 0),
133 | HOST_EFER = VMCS_ENCODE_COMPONENT_FULL_64(host, 1),
134 | HOST_PERF_GLOBAL_CTRL = VMCS_ENCODE_COMPONENT_FULL_64(host, 2),
135 | HOST_PKRS = VMCS_ENCODE_COMPONENT_FULL_64(host, 3),
136 |
137 | // 32-bit Host Register State Fields
138 | HOST_SYSENTER_CS = VMCS_ENCODE_COMPONENT_FULL_32(host, 0),
139 |
140 | // 16-bit Host Register State Fields
141 | HOST_ES_SELECTOR = VMCS_ENCODE_COMPONENT_FULL_16(host, 0),
142 | HOST_CS_SELECTOR = VMCS_ENCODE_COMPONENT_FULL_16(host, 1),
143 | HOST_SS_SELECTOR = VMCS_ENCODE_COMPONENT_FULL_16(host, 2),
144 | HOST_DS_SELECTOR = VMCS_ENCODE_COMPONENT_FULL_16(host, 3),
145 | HOST_FS_SELECTOR = VMCS_ENCODE_COMPONENT_FULL_16(host, 4),
146 | HOST_GS_SELECTOR = VMCS_ENCODE_COMPONENT_FULL_16(host, 5),
147 | HOST_TR_SELECTOR = VMCS_ENCODE_COMPONENT_FULL_16(host, 6),
148 |
149 | // Natural Control Register State Fields
150 | CONTROL_CR0_GUEST_HOST_MASK = VMCS_ENCODE_COMPONENT_FULL(control, natural, 0),
151 | CONTROL_CR4_GUEST_HOST_MASK = VMCS_ENCODE_COMPONENT_FULL(control, natural, 1),
152 | CONTROL_CR0_READ_SHADOW = VMCS_ENCODE_COMPONENT_FULL(control, natural, 2),
153 | CONTROL_CR4_READ_SHADOW = VMCS_ENCODE_COMPONENT_FULL(control, natural, 3),
154 | CONTROL_CR3_TARGET_VALUE_0 = VMCS_ENCODE_COMPONENT_FULL(control, natural, 4),
155 | CONTROL_CR3_TARGET_VALUE_1 = VMCS_ENCODE_COMPONENT_FULL(control, natural, 5),
156 | CONTROL_CR3_TARGET_VALUE_2 = VMCS_ENCODE_COMPONENT_FULL(control, natural, 6),
157 | CONTROL_CR3_TARGET_VALUE_3 = VMCS_ENCODE_COMPONENT_FULL(control, natural, 7),
158 |
159 | // 64-bit Control Register State Fields
160 | CONTROL_BITMAP_IO_A_ADDRESS = VMCS_ENCODE_COMPONENT_FULL_64(control, 0),
161 | CONTROL_BITMAP_IO_B_ADDRESS = VMCS_ENCODE_COMPONENT_FULL_64(control, 1),
162 | CONTROL_MSR_BITMAPS_ADDRESS = VMCS_ENCODE_COMPONENT_FULL_64(control, 2),
163 | CONTROL_VMEXIT_MSR_STORE_ADDRESS = VMCS_ENCODE_COMPONENT_FULL_64(control, 3),
164 | CONTROL_VMEXIT_MSR_LOAD_ADDRESS = VMCS_ENCODE_COMPONENT_FULL_64(control, 4),
165 | CONTROL_VMENTER_MSR_LOAD_ADDRESS = VMCS_ENCODE_COMPONENT_FULL_64(control, 5),
166 | CONTROL_VMCS_EXECUTIVE_POINTER = VMCS_ENCODE_COMPONENT_FULL_64(control, 6),
167 | CONTROL_PML_ADDRESS = VMCS_ENCODE_COMPONENT_FULL_64(control, 7),
168 | CONTROL_TSC_OFFSET = VMCS_ENCODE_COMPONENT_FULL_64(control, 8),
169 | CONTROL_VIRTUAL_APIC_ADDRESS = VMCS_ENCODE_COMPONENT_FULL_64(control, 9),
170 | CONTROL_APIC_ACCESS_ADDRESS = VMCS_ENCODE_COMPONENT_FULL_64(control, 10),
171 | CONTROL_POSTED_INTERRUPT_DESCRIPTOR_ADDRESS = VMCS_ENCODE_COMPONENT_FULL_64(control, 11),
172 | CONTROL_VM_FUNCTION_CONTROLS = VMCS_ENCODE_COMPONENT_FULL_64(control, 12),
173 | CONTROL_EPT_POINTER = VMCS_ENCODE_COMPONENT_FULL_64(control, 13),
174 | CONTROL_EOI_EXIT_BITMAP_0 = VMCS_ENCODE_COMPONENT_FULL_64(control, 14),
175 | CONTROL_EOI_EXIT_BITMAP_1 = VMCS_ENCODE_COMPONENT_FULL_64(control, 15),
176 | CONTROL_EOI_EXIT_BITMAP_2 = VMCS_ENCODE_COMPONENT_FULL_64(control, 16),
177 | CONTROL_EOI_EXIT_BITMAP_3 = VMCS_ENCODE_COMPONENT_FULL_64(control, 17),
178 | CONTROL_EPTP_LIST_ADDRESS = VMCS_ENCODE_COMPONENT_FULL_64(control, 18),
179 | CONTROL_VMREAD_BITMAP_ADDRESS = VMCS_ENCODE_COMPONENT_FULL_64(control, 19),
180 | CONTROL_VMWRITE_BITMAP_ADDRESS = VMCS_ENCODE_COMPONENT_FULL_64(control, 20),
181 | CONTROL_VIRTUALIZATION_EXCEPTION_INFORMATION_ADDRESS = VMCS_ENCODE_COMPONENT_FULL_64(control, 21),
182 | CONTROL_XSS_EXITING_BITMAP = VMCS_ENCODE_COMPONENT_FULL_64(control, 22),
183 | CONTROL_ENCLS_EXITING_BITMAP = VMCS_ENCODE_COMPONENT_FULL_64(control, 23),
184 | CONTROL_SUB_PAGE_PERMISSION_TABLE_POINTER = VMCS_ENCODE_COMPONENT_FULL_64(control, 24),
185 | CONTROL_TSC_MULTIPLIER = VMCS_ENCODE_COMPONENT_FULL_64(control, 25),
186 | CONTROL_ENCLV_EXITING_BITMAP = VMCS_ENCODE_COMPONENT_FULL_64(control, 27),
187 |
188 | // 32-bit Control Register State Fields
189 | CONTROL_PIN_BASED_VM_EXECUTION_CONTROLS = VMCS_ENCODE_COMPONENT_FULL_32(control, 0),
190 | CONTROL_PRIMARY_PROCESSOR_BASED_VM_EXECUTION_CONTROLS = VMCS_ENCODE_COMPONENT_FULL_32(control, 1),
191 | CONTROL_EXCEPTION_BITMAP = VMCS_ENCODE_COMPONENT_FULL_32(control, 2),
192 | CONTROL_PAGE_FAULT_ERROR_CODE_MASK = VMCS_ENCODE_COMPONENT_FULL_32(control, 3),
193 | CONTROL_PAGE_FAULT_ERROR_CODE_MATCH = VMCS_ENCODE_COMPONENT_FULL_32(control, 4),
194 | CONTROL_CR3_TARGET_COUNT = VMCS_ENCODE_COMPONENT_FULL_32(control, 5),
195 | CONTROL_VM_EXIT_CONTROLS = VMCS_ENCODE_COMPONENT_FULL_32(control, 6),
196 | CONTROL_VM_EXIT_MSR_STORE_COUNT = VMCS_ENCODE_COMPONENT_FULL_32(control, 7),
197 | CONTROL_VM_EXIT_MSR_LOAD_COUNT = VMCS_ENCODE_COMPONENT_FULL_32(control, 8),
198 | CONTROL_VM_ENTRY_CONTROLS = VMCS_ENCODE_COMPONENT_FULL_32(control, 9),
199 | CONTROL_VM_ENTRY_MSR_LOAD_COUNT = VMCS_ENCODE_COMPONENT_FULL_32(control, 10),
200 | CONTROL_VM_ENTRY_INTERRUPTION_INFORMATION_FIELD = VMCS_ENCODE_COMPONENT_FULL_32(control, 11),
201 | CONTROL_VM_ENTRY_EXCEPTION_ERROR_CODE = VMCS_ENCODE_COMPONENT_FULL_32(control, 12),
202 | CONTROL_VM_ENTRY_INSTRUCTION_LENGTH = VMCS_ENCODE_COMPONENT_FULL_32(control, 13),
203 | CONTROL_TPR_THRESHOLD = VMCS_ENCODE_COMPONENT_FULL_32(control, 14),
204 | CONTROL_SECONDARY_PROCESSOR_BASED_VM_EXECUTION_CONTROLS = VMCS_ENCODE_COMPONENT_FULL_32(control, 15),
205 | CONTROL_PLE_GAP = VMCS_ENCODE_COMPONENT_FULL_32(control, 16),
206 | CONTROL_PLE_WINDOW = VMCS_ENCODE_COMPONENT_FULL_32(control, 17),
207 |
208 | // 16-bit Control Register State Fields
209 | CONTROL_VIRTUAL_PROCESSOR_IDENTIFIER = VMCS_ENCODE_COMPONENT_FULL_16(control, 0),
210 | CONTROL_POSTED_INTERRUPT_NOTIFICATION_VECTOR = VMCS_ENCODE_COMPONENT_FULL_16(control, 1),
211 | CONTROL_EPTP_INDEX = VMCS_ENCODE_COMPONENT_FULL_16(control, 2),
212 |
213 | // Natural Read only Register State Fields
214 | EXIT_QUALIFICATION = VMCS_ENCODE_COMPONENT_FULL(readonly, natural, 0),
215 | IO_RCX = VMCS_ENCODE_COMPONENT_FULL(readonly, natural, 1),
216 | IO_RSI = VMCS_ENCODE_COMPONENT_FULL(readonly, natural, 2),
217 | IO_RDI = VMCS_ENCODE_COMPONENT_FULL(readonly, natural, 3),
218 | IO_RIP = VMCS_ENCODE_COMPONENT_FULL(readonly, natural, 4),
219 | GUEST_LINEAR_ADDRESS = VMCS_ENCODE_COMPONENT_FULL(readonly, natural, 5),
220 |
221 | // 64-bit Read only Register State Fields
222 | GUEST_PHYSICAL_ADDRESS = VMCS_ENCODE_COMPONENT_FULL_64(readonly,0),
223 |
224 | // 32-bit Read only Register State Fields
225 | VM_INSTRUCTION_ERROR = VMCS_ENCODE_COMPONENT_FULL_32(readonly, 0),
226 | EXIT_REASON = VMCS_ENCODE_COMPONENT_FULL_32(readonly, 1),
227 | VM_EXIT_INTERRUPTION_INFORMATION = VMCS_ENCODE_COMPONENT_FULL_32(readonly, 2),
228 | VM_EXIT_INTERRUPTION_ERROR_CODE = VMCS_ENCODE_COMPONENT_FULL_32(readonly, 3),
229 | IDT_VECTORING_INFORMATION_FIELD = VMCS_ENCODE_COMPONENT_FULL_32(readonly, 4),
230 | IDT_VECTORING_ERROR_CODE = VMCS_ENCODE_COMPONENT_FULL_32(readonly, 5),
231 | VM_EXIT_INSTRUCTION_LENGTH = VMCS_ENCODE_COMPONENT_FULL_32(readonly, 6),
232 | VM_EXIT_INSTRUCTION_INFORMATION = VMCS_ENCODE_COMPONENT_FULL_32(readonly, 7),
233 | };
234 |
235 |
--------------------------------------------------------------------------------
/airhv/interrupt.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #define RESET_IO_PORT 0xCF9
3 |
4 | enum __exception_vectors
5 | {
6 | EXCEPTION_VECTOR_DIVIDE_ERROR,
7 | EXCEPTION_VECTOR_SINGLE_STEP,
8 | EXCEPTION_VECTOR_NMII,
9 | EXCEPTION_VECTOR_BREAKPOINT,
10 | EXCEPTION_VECTOR_OVERFLOW,
11 | EXCEPTION_VECTOR_BOUND_RANGE_EXCEEDED,
12 | EXCEPTION_VECTOR_UNDEFINED_OPCODE,
13 | EXCEPTION_VECTOR_NO_MATH_COPROCESSOR,
14 | EXCEPTION_VECTOR_DOUBLE_FAULTT,
15 | EXCEPTION_VECTOR_RESERVED0,
16 | EXCEPTION_VECTOR_INVALID_TASK_SEGMENT_SELECTOR,
17 | EXCEPTION_VECTOR_SEGMENT_NOT_PRESENTT,
18 | EXCEPTION_VECTOR_STACK_SEGMENT_FAULT,
19 | EXCEPTION_VECTOR_GENERAL_PROTECTION_FAULT,
20 | EXCEPTION_VECTOR_PAGE_FAULT,
21 | EXCEPTION_VECTOR_RESERVED1,
22 | EXCEPTION_VECTOR_MATH_FAULT,
23 | EXCEPTION_VECTOR_ALIGNMENT_CHECK,
24 | EXCEPTION_VECTOR_MACHINE_CHECK,
25 | EXCEPTION_VECTOR_SIMD_FLOATING_POINT_NUMERIC_ERROR,
26 | EXCEPTION_VECTOR_VIRTUAL_EXCEPTION,
27 | EXCEPTION_VECTOR_RESERVED2,
28 | EXCEPTION_VECTOR_RESERVED3,
29 | EXCEPTION_VECTOR_RESERVED4,
30 | EXCEPTION_VECTOR_RESERVED5,
31 | EXCEPTION_VECTOR_RESERVED6,
32 | EXCEPTION_VECTOR_RESERVED7,
33 | EXCEPTION_VECTOR_RESERVED8,
34 | EXCEPTION_VECTOR_RESERVED9,
35 | EXCEPTION_VECTOR_RESERVED10,
36 | EXCEPTION_VECTOR_RESERVED11,
37 | EXCEPTION_VECTOR_RESERVED12
38 | };
39 |
40 | enum interrupt_type
41 | {
42 | INTERRUPT_TYPE_EXTERNAL_INTERRUPT = 0,
43 | INTERRUPT_TYPE_RESERVED = 1,
44 | INTERRUPT_TYPE_NMI = 2,
45 | INTERRUPT_TYPE_HARDWARE_EXCEPTION = 3,
46 | INTERRUPT_TYPE_SOFTWARE_INTERRUPT = 4,
47 | INTERRUPT_TYPE_PRIVILEGED_SOFTWARE_INTERRUPT = 5,
48 | INTERRUPT_TYPE_SOFTWARE_EXCEPTION = 6,
49 | INTERRUPT_TYPE_OTHER_EVENT = 7
50 | };
51 |
52 | union __vmentry_interrupt_info
53 | {
54 | unsigned __int32 all;
55 | struct
56 | {
57 | unsigned __int32 interrupt_vector : 8;
58 | unsigned __int32 interruption_type : 3;
59 | unsigned __int32 deliver_error_code : 1;
60 | unsigned __int32 reserved : 19;
61 | unsigned __int32 valid : 1;
62 |
63 | };
64 | };
65 |
66 | struct __vmentry_event_information
67 | {
68 | __vmentry_interrupt_info interrupt_info;
69 | unsigned __int32 instruction_length;
70 | unsigned __int64 error_code;
71 | };
72 |
73 | union __vmexit_interrupt_info
74 | {
75 | struct
76 | {
77 | unsigned __int32 vector : 8;
78 | unsigned __int32 interruption_type : 3;
79 | unsigned __int32 error_code_valid : 1;
80 | unsigned __int32 nmi_unblocking : 1;
81 | unsigned __int32 reserved : 18;
82 | unsigned __int32 valid : 1;
83 | };
84 | unsigned __int32 all;
85 | };
86 |
87 | union __reset_control_register
88 | {
89 | unsigned __int8 all;
90 | struct
91 | {
92 | unsigned __int8 reserved0 : 1;
93 | unsigned __int8 system_reset : 1;
94 | unsigned __int8 reset_cpu : 1;
95 | unsigned __int8 full_reset : 1;
96 | unsigned __int8 reserved1 : 4;
97 | };
98 | };
99 |
--------------------------------------------------------------------------------
/airhv/invalidators.cpp:
--------------------------------------------------------------------------------
1 | #pragma warning( disable : 4201)
2 | #include "invalidators.h"
3 | #include "asm\vm_intrin.h"
4 |
5 | ///
6 | /// Invept single context
7 | ///
8 | ///
9 | void invept_single_context(unsigned __int64 ept_pointer)
10 | {
11 | __invept_descriptor descriptor = { 0 };
12 | descriptor.ept_pointer = ept_pointer;
13 | descriptor.reserved = 0;
14 | __invept(INVEPT_SINGLE_CONTEXT, &descriptor);
15 | }
16 |
17 | ///
18 | /// Invept all contexts
19 | ///
20 | void invept_all_contexts()
21 | {
22 | __invept_descriptor descriptor = { 0 };
23 | __invept(INVEPT_ALL_CONTEXTS, &descriptor);
24 | }
25 |
26 | ///
27 | /// Invvpid invidual address
28 | ///
29 | /// Logical processor invalidates mappings for the linear address
30 | /// Invalidates entries in the TLBs and paging-structure caches based on this vpid
31 | void invvpid_invidual_address(unsigned __int64 linear_address,unsigned __int8 vpid)
32 | {
33 | __invvpid_descriptor descriptor = { 0 };
34 | descriptor.linear_address = linear_address;
35 | descriptor.vpid = vpid;
36 |
37 | __invvpid(INVVPID_INVIDUAL_ADDRESS,&descriptor);
38 | }
39 |
40 | ///
41 | /// Invvpid single context
42 | ///
43 | /// Invalidates entries in the TLBs and paging-structure caches based on this vpid
44 | void invvpid_single_context(unsigned __int8 vpid)
45 | {
46 | __invvpid_descriptor descriptor = { 0 };
47 | descriptor.vpid = vpid;
48 |
49 | __invvpid(INVVPID_SINGLE_CONTEXT, &descriptor);
50 | }
51 |
52 | ///
53 | /// Invvpid all contexts
54 | ///
55 | void invvpid_all_contexts()
56 | {
57 | __invvpid_descriptor descriptor = { 0 };
58 | __invvpid(INVVPID_ALL_CONTEXTS, &descriptor);
59 | }
60 |
61 | ///
62 | /// Invvpid single context except global translations
63 | ///
64 | /// Invalidates entries in the TLBs and paging-structure caches based on this vpid
65 | void invvpid_single_context_except_global_translations(unsigned __int8 vpid)
66 | {
67 | __invvpid_descriptor descriptor = { 0 };
68 | descriptor.vpid = vpid;
69 | return __invvpid(INVVPID_SINGLE_EXCEPT_GLOBAL_TRANSLATIONS, &descriptor);
70 | }
71 |
--------------------------------------------------------------------------------
/airhv/invalidators.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 |
4 | struct __invept_descriptor
5 | {
6 | unsigned __int64 ept_pointer;
7 | unsigned __int64 reserved;
8 | };
9 |
10 | struct __invpcid_descriptor
11 | {
12 | unsigned __int64 pcid : 12;
13 | unsigned __int64 reserved : 52;
14 | unsigned __int64 linear_address;
15 | };
16 |
17 | struct __invvpid_descriptor
18 | {
19 | union
20 | {
21 | unsigned __int64 vpid : 16;
22 | unsigned __int64 reserved : 48;
23 | };
24 |
25 | unsigned __int64 linear_address;
26 | };
27 |
28 | enum invept_type
29 | {
30 | INVEPT_SINGLE_CONTEXT = 0x00000001,
31 | INVEPT_ALL_CONTEXTS = 0x00000002
32 | };
33 |
34 | enum invvpid_type
35 | {
36 | INVVPID_INVIDUAL_ADDRESS,
37 | INVVPID_SINGLE_CONTEXT,
38 | INVVPID_ALL_CONTEXTS,
39 | INVVPID_SINGLE_EXCEPT_GLOBAL_TRANSLATIONS
40 | };
41 |
42 | enum invpcid_type
43 | {
44 | INVPCID_INVIDUAL_ADDRESS,
45 | INVPCID_SINGLE_CONTEXT,
46 | INVPCID_ALL_CONTEXTS,
47 | INVPCID_ALL_CONTEXTS_EXCEPT_GLOBAL_TRANSLATIONS
48 | };
49 |
50 | ///
51 | /// Invept single context
52 | ///
53 | ///
54 | void invept_single_context(unsigned __int64 ept_pointer);
55 |
56 | ///
57 | /// Invept all contexts
58 | ///
59 | void invept_all_contexts();
60 |
61 | ///
62 | /// Invvpid invidual address
63 | ///
64 | /// Logical processor invalidates mappings for the linear address
65 | /// Invalidates entries in the TLBs and paging-structure caches based on this vpid
66 | void invvpid_invidual_address(unsigned __int64 linear_address, unsigned __int8 vpid);
67 |
68 | ///
69 | /// Invvpid single context
70 | ///
71 | /// Invalidates entries in the TLBs and paging-structure caches based on this vpid
72 | void invvpid_single_context(unsigned __int8 vpid);
73 |
74 | ///
75 | /// Invvpid all contexts
76 | ///
77 | void invvpid_all_contexts();
78 |
79 | ///
80 | /// Invvpid single context except global translations
81 | ///
82 | /// Invalidates entries in the TLBs and paging-structure caches based on this vpid
83 | void invvpid_single_context_except_global_translations(unsigned __int8 vpid);
84 |
--------------------------------------------------------------------------------
/airhv/log.cpp:
--------------------------------------------------------------------------------
1 | #define _NO_CRT_STDIO_INLINE
2 | #include
3 | #include
4 | #include
5 | #include "log.h"
6 |
7 | void LogPrint(__log_type type, const char* fmt, ...)
8 | {
9 | char* LogType = NULL;
10 | LARGE_INTEGER SystemTime = {};
11 | LARGE_INTEGER LocalTime = {};
12 | TIME_FIELDS TimeFields = {};
13 | char TimeBuffer[20] = {};
14 | char MessageBuffer[412] = {};
15 | char* OutputFormat = NULL;
16 | char OutputBuffer[512] = {};
17 | va_list Args = {};
18 |
19 | switch (type)
20 | {
21 | case LOG_TYPE_DEBUG:
22 | {
23 | LogType = "[DEBUG]";
24 | break;
25 | }
26 | case LOG_TYPE_DUMP:
27 | {
28 | LogType = "[DUMP]";
29 | break;
30 | }
31 | case LOG_TYPE_ERROR:
32 | {
33 | LogType = "[ERROR]";
34 | ; break;
35 | }
36 | case LOG_TYPE_INFO:
37 | {
38 | LogType = "[INFORMATION]";
39 | break;
40 | }
41 | default:
42 | {
43 | break;
44 | }
45 |
46 | }
47 |
48 | KeQuerySystemTime(&SystemTime);
49 | ExSystemTimeToLocalTime(&SystemTime, &LocalTime);
50 | RtlTimeToTimeFields(&LocalTime, &TimeFields);
51 |
52 | RtlStringCchPrintfA(
53 | TimeBuffer,
54 | sizeof(TimeBuffer),
55 | "[%02hd:%02hd:%02hd.%03hd]",
56 | TimeFields.Hour,
57 | TimeFields.Minute,
58 | TimeFields.Second,
59 | TimeFields.Milliseconds);
60 |
61 | va_start(Args, fmt);
62 | RtlStringCchVPrintfA(MessageBuffer, sizeof(MessageBuffer), fmt, Args);
63 | va_end(Args);
64 |
65 | OutputFormat = "%s %s %s\r\n";
66 |
67 | RtlStringCchPrintfA(
68 | OutputBuffer,
69 | sizeof(OutputBuffer),
70 | OutputFormat,
71 | TimeBuffer,
72 | LogType,
73 | MessageBuffer);
74 |
75 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "%s", OutputBuffer);
76 | }
--------------------------------------------------------------------------------
/airhv/log.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #define LogError(format, ...) \
3 | LogPrint(LOG_TYPE_ERROR," [%s:%d] " format , __func__, __LINE__, __VA_ARGS__)
4 | #define LogDebug(format, ...) \
5 | LogPrint(LOG_TYPE_DEBUG," [%s:%d] " format , __func__, __LINE__, __VA_ARGS__)
6 | #define LogDump(format, ...) \
7 | LogPrint(LOG_TYPE_DUMP," [%s:%d] " format , __func__, __LINE__, __VA_ARGS__)
8 | #define LogInfo(format, ...) \
9 | LogPrint(LOG_TYPE_INFO," [%s:%d] " format , __func__, __LINE__, __VA_ARGS__)
10 |
11 | enum __log_type
12 | {
13 | LOG_TYPE_DEBUG,
14 | LOG_TYPE_ERROR,
15 | LOG_TYPE_DUMP,
16 | LOG_TYPE_INFO
17 | };
18 |
19 | void LogPrint(__log_type type, const char* fmt, ...);
--------------------------------------------------------------------------------
/airhv/main.cpp:
--------------------------------------------------------------------------------
1 | #pragma warning( disable : 4201 4805)
2 | #include
3 | #include
4 | #include "log.h"
5 | #include "ntapi.h"
6 | #include "hypervisor_routines.h"
7 | #include "hypervisor_gateway.h"
8 | #include "vmm.h"
9 |
10 | #define IOCTL_POOL_MANAGER_ALLOCATE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x900, METHOD_BUFFERED, FILE_SPECIAL_ACCESS)
11 |
12 | __vmm_context* g_vmm_context = 0;
13 |
14 | VOID driver_unload(PDRIVER_OBJECT driver_object)
15 | {
16 | UNICODE_STRING dos_device_name;
17 | if(g_vmm_context != NULL)
18 | {
19 | if (g_vmm_context->vcpu_table[0]->vcpu_status.vmm_launched == true)
20 | {
21 | hvgt::unhook_all_functions();
22 | hvgt::vmoff();
23 | }
24 | }
25 |
26 | hv::disable_vmx_operation();
27 | free_vmm_context();
28 |
29 | RtlInitUnicodeString(&dos_device_name, L"\\DosDevices\\airhv");
30 | IoDeleteSymbolicLink(&dos_device_name);
31 | IoDeleteDevice(driver_object->DeviceObject);
32 | }
33 |
34 | NTSTATUS driver_create_close(_In_ PDEVICE_OBJECT device_object, _In_ PIRP irp)
35 | {
36 | UNREFERENCED_PARAMETER(device_object);
37 |
38 | irp->IoStatus.Status = STATUS_SUCCESS;
39 | irp->IoStatus.Information = 0;
40 |
41 | IoCompleteRequest(irp, IO_NO_INCREMENT);
42 |
43 | return STATUS_SUCCESS;
44 | }
45 |
46 | NTSTATUS driver_ioctl_dispatcher(_In_ PDEVICE_OBJECT device_object, _In_ PIRP irp)
47 | {
48 | UNREFERENCED_PARAMETER(device_object);
49 | unsigned __int32 bytes_io = 0;
50 | PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(irp);
51 | NTSTATUS status = STATUS_SUCCESS;
52 |
53 | switch (stack->Parameters.DeviceIoControl.IoControlCode)
54 | {
55 | //
56 | // Used by hypervisor control driver to perform allocations
57 | //
58 | case IOCTL_POOL_MANAGER_ALLOCATE:
59 | {
60 | status = pool_manager::perform_allocation();
61 | break;
62 | }
63 | }
64 |
65 | irp->IoStatus.Status = status;
66 | irp->IoStatus.Information = bytes_io;
67 |
68 | IoCompleteRequest(irp, IO_NO_INCREMENT);
69 | return status;
70 | }
71 |
72 | extern "C"
73 | NTSTATUS DriverEntry(PDRIVER_OBJECT driver_object, PCUNICODE_STRING reg)
74 | {
75 | UNREFERENCED_PARAMETER(reg);
76 |
77 | NTSTATUS status = STATUS_SUCCESS;
78 | PDEVICE_OBJECT device_object = NULL;
79 | UNICODE_STRING driver_name, dos_device_name;
80 |
81 | RtlInitUnicodeString(&driver_name, L"\\Device\\airhv");
82 | RtlInitUnicodeString(&dos_device_name, L"\\DosDevices\\airhv");
83 |
84 | status = IoCreateDevice(driver_object, 0, &driver_name, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &device_object);
85 |
86 | if (status == STATUS_SUCCESS)
87 | {
88 | driver_object->MajorFunction[IRP_MJ_CLOSE] = driver_create_close;
89 | driver_object->MajorFunction[IRP_MJ_CREATE] = driver_create_close;
90 | driver_object->MajorFunction[IRP_MJ_DEVICE_CONTROL] = driver_ioctl_dispatcher;
91 |
92 | driver_object->DriverUnload = driver_unload;
93 | driver_object->Flags |= DO_BUFFERED_IO;
94 | IoCreateSymbolicLink(&dos_device_name, &driver_name);
95 | }
96 |
97 | //
98 | // Check if our cpu support virtualization
99 | //
100 | if (!hv::virtualization_support()) {
101 | LogError("VMX operation is not supported on this processor.\n");
102 | return STATUS_FAILED_DRIVER_ENTRY;
103 | }
104 |
105 | //
106 | // Initialize and start virtual machine
107 | // If it fails turn off vmx and deallocate all structures
108 | //
109 | if(vmm_init() == false)
110 | {
111 | hv::disable_vmx_operation();
112 | free_vmm_context();
113 | LogError("Vmm initialization failed");
114 | return STATUS_FAILED_DRIVER_ENTRY;
115 | }
116 |
117 | return status;
118 | }
--------------------------------------------------------------------------------
/airhv/ntapi.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 |
4 | struct __nt_kprocess
5 | {
6 | DISPATCHER_HEADER Header; //0x0
7 | LIST_ENTRY ProfileListHead; //0x18
8 | ULONGLONG DirectoryTableBase;
9 | };
10 |
11 | extern "C"
12 | {
13 | void NTAPI KeGenericCallDpc(_In_ PKDEFERRED_ROUTINE Routine, PVOID Context);
14 | void NTAPI KeSignalCallDpcDone(_In_ PVOID SystemArgument1);
15 | BOOLEAN NTAPI KeSignalCallDpcSynchronize(_In_ PVOID SystemArgument2);
16 | }
--------------------------------------------------------------------------------
/airhv/poolmanager.cpp:
--------------------------------------------------------------------------------
1 | #pragma warning( disable : 4201)
2 | #include
3 | #include "poolmanager.h"
4 | #include "common.h"
5 | #include "log.h"
6 | #include "allocators.h"
7 | #include "spinlock.h"
8 |
9 | namespace pool_manager
10 | {
11 | ///
12 | /// Allocate pools and add them to pool table
13 | ///
14 | /// Size of pool
15 | /// Number of pools to allocate
16 | ///
17 | ///
18 | bool allocate_pool(unsigned __int64 size, unsigned __int32 count, allocation_intention intention)
19 | {
20 | for (unsigned int i = 0; i < count; i++)
21 | {
22 | __pool_table* single_pool = ::allocate_pool<__pool_table>();
23 | if (single_pool == nullptr)
24 | {
25 | LogError("Memory allocation failed");
26 | return false;
27 | }
28 | RtlSecureZeroMemory(single_pool, sizeof(__pool_table));
29 |
30 | if (size % PAGE_SIZE == 0)
31 | {
32 | single_pool->address = ::allocate_contignous_memory(size);
33 | }
34 | else
35 | {
36 | single_pool->address = ::allocate_pool(size);
37 | }
38 |
39 | if (single_pool->address == nullptr)
40 | {
41 | LogError("Memory allocation failed");
42 | return false;
43 | }
44 | RtlSecureZeroMemory((void*)single_pool->address, size);
45 |
46 | single_pool->intention = intention;
47 | single_pool->is_busy = false;
48 | single_pool->size = size;
49 |
50 | InsertTailList(g_vmm_context->pool_manager->list_of_allocated_pools, &(single_pool->pool_list));
51 | }
52 |
53 | return true;
54 | }
55 |
56 | ///
57 | /// Request allocation
58 | ///
59 | /// Size of pool
60 | /// Number of pools to allocate
61 | ///
62 | ///
63 | bool request_allocation(unsigned __int64 size, unsigned __int32 count, allocation_intention intention)
64 | {
65 | spinlock allocation_lock(&g_vmm_context->pool_manager->lock_for_request_allocation);
66 |
67 | for (unsigned __int64 i = 0; i < 10; i++)
68 | {
69 | if (g_vmm_context->pool_manager->allocation_requests->size[i] == 0)
70 | {
71 | g_vmm_context->pool_manager->allocation_requests->count[i] = count;
72 | g_vmm_context->pool_manager->allocation_requests->size[i] = size;
73 | g_vmm_context->pool_manager->allocation_requests->intention[i] = intention;
74 | g_vmm_context->pool_manager->is_request_for_allocation_recived = true;
75 | break;
76 | }
77 | }
78 |
79 | return g_vmm_context->pool_manager->is_request_for_allocation_recived;
80 | }
81 |
82 | ///
83 | /// Allocate all requested pools
84 | ///
85 | ///
86 | bool perform_allocation()
87 | {
88 | bool status = true;
89 |
90 | if (g_vmm_context->pool_manager->is_request_for_allocation_recived == false)
91 | {
92 | LogInfo("No pending allocations");
93 | return status;
94 | }
95 |
96 | for (unsigned __int64 i = 0; i < 10; i++)
97 | {
98 | if (g_vmm_context->pool_manager->allocation_requests->size[i] != 0)
99 | {
100 | status = allocate_pool
101 | (
102 | g_vmm_context->pool_manager->allocation_requests->size[i],
103 | g_vmm_context->pool_manager->allocation_requests->count[i],
104 | g_vmm_context->pool_manager->allocation_requests->intention[i]
105 | );
106 |
107 | if (status == false)
108 | {
109 | LogError("Pool manager allocate and add to pool table failed");
110 | break;
111 | }
112 |
113 | g_vmm_context->pool_manager->allocation_requests->size[i] = 0;
114 | g_vmm_context->pool_manager->allocation_requests->count[i] = 0;
115 | g_vmm_context->pool_manager->allocation_requests->intention[i] = INTENTION_NONE;
116 |
117 | LogInfo("Allocation successful");
118 | }
119 | }
120 |
121 | g_vmm_context->pool_manager->is_request_for_allocation_recived = false;
122 |
123 | return status;
124 | }
125 |
126 | ///
127 | /// Initalize pool manager struct and preallocate pools
128 | ///
129 | /// status
130 | bool initialize()
131 | {
132 | g_vmm_context->pool_manager = ::allocate_pool<__pool_manager>();
133 | if (g_vmm_context->pool_manager == nullptr)
134 | {
135 | LogError("Pool manager allocation failed");
136 | return false;
137 | }
138 | RtlSecureZeroMemory(g_vmm_context->pool_manager, sizeof(__pool_manager));
139 |
140 | g_vmm_context->pool_manager->allocation_requests = ::allocate_pool<__request_new_allocation>();
141 | if (g_vmm_context->pool_manager->allocation_requests == nullptr)
142 | {
143 | LogError("Allacation requests allocation failed");
144 | return false;
145 | }
146 | RtlSecureZeroMemory(g_vmm_context->pool_manager->allocation_requests, sizeof(__request_new_allocation));
147 |
148 | g_vmm_context->pool_manager->list_of_allocated_pools = ::allocate_pool();
149 | if (g_vmm_context->pool_manager->list_of_allocated_pools == nullptr)
150 | {
151 | LogError("List of allocated pools allocation failed");
152 | return false;
153 | }
154 | RtlSecureZeroMemory(g_vmm_context->pool_manager->list_of_allocated_pools, sizeof(LIST_ENTRY));
155 |
156 | InitializeListHead(g_vmm_context->pool_manager->list_of_allocated_pools);
157 |
158 | if (request_allocation(sizeof(__ept_dynamic_split), g_vmm_context->processor_count * 50, INTENTION_SPLIT_PML2) == false)
159 | {
160 | LogError("Pool mangaer request allocation Failed");
161 | return false;
162 | }
163 |
164 | if (request_allocation(sizeof(__ept_hooked_page_info), g_vmm_context->processor_count * 50, INTENTION_TRACK_HOOKED_PAGES) == false)
165 | {
166 | LogError("Pool mangaer request allocation Failed");
167 | return false;
168 | }
169 |
170 | if (request_allocation(100, g_vmm_context->processor_count * 50, INTENTION_EXEC_TRAMPOLINE) == false)
171 | {
172 | LogError("Pool mangaer request allocation Failed");
173 | return false;
174 | }
175 |
176 | if (request_allocation(sizeof(__ept_hooked_function_info), g_vmm_context->processor_count * 50, INTENTION_TRACK_HOOKED_FUNCTIONS) == false)
177 | {
178 | LogError("Pool mangaer request allocation Failed");
179 | return false;
180 | }
181 |
182 | if (request_allocation(PAGE_SIZE, g_vmm_context->processor_count * 50, INTENTION_FAKE_PAGE_CONTENTS) == false)
183 | {
184 | LogError("Pool mangaer request allocation Failed");
185 | return false;
186 | }
187 |
188 | return perform_allocation();
189 | }
190 | ///
191 | /// Free all allocted pools
192 | ///
193 | void uninitialize()
194 | {
195 | PLIST_ENTRY current = 0;
196 | if (g_vmm_context->pool_manager->list_of_allocated_pools != nullptr)
197 | {
198 | current = g_vmm_context->pool_manager->list_of_allocated_pools->Flink;
199 | while (g_vmm_context->pool_manager->list_of_allocated_pools != current)
200 | {
201 | // Get the head of the record
202 | __pool_table* pool_table = (__pool_table*)CONTAINING_RECORD(current, __pool_table, pool_list);
203 |
204 | current = current->Flink;
205 |
206 | // Free the alloocated buffer
207 | if (pool_table->size % PAGE_SIZE == 0)
208 | {
209 | free_contignous_memory(pool_table->address);
210 | }
211 | else
212 | {
213 | free_pool(pool_table->address);
214 | }
215 |
216 | // Free the record itself
217 | free_pool(pool_table);
218 | }
219 |
220 | free_pool(g_vmm_context->pool_manager->list_of_allocated_pools);
221 | }
222 |
223 | if (g_vmm_context->pool_manager->allocation_requests != nullptr)
224 | {
225 | free_pool(g_vmm_context->pool_manager->allocation_requests);
226 | }
227 | }
228 |
229 | ///
230 | /// Set information that pool is no longer used anymore
231 | ///
232 | ///
233 | void release_pool(void* address)
234 | {
235 | PLIST_ENTRY current = 0;
236 | current = g_vmm_context->pool_manager->list_of_allocated_pools;
237 |
238 | spinlock pool_lock(&g_vmm_context->pool_manager->lock_for_reading_pool);
239 | while (g_vmm_context->pool_manager->list_of_allocated_pools != current->Flink)
240 | {
241 | current = current->Flink;
242 |
243 | // Get the head of the record
244 | __pool_table* pool_table = (__pool_table*)CONTAINING_RECORD(current, __pool_table, pool_list);
245 |
246 | if (address == pool_table->address)
247 | {
248 | RtlSecureZeroMemory(address, pool_table->size);
249 | pool_table->is_busy = false;
250 | pool_table->recycled = true;
251 | break;
252 | }
253 | }
254 | }
255 |
256 | inline const char* intention_to_string(allocation_intention intention)
257 | {
258 | switch (intention)
259 | {
260 | case INTENTION_NONE: return "None";
261 | case INTENTION_TRACK_HOOKED_PAGES: return "Track Hooked Pages";
262 | case INTENTION_EXEC_TRAMPOLINE: return "Trampoline";
263 | case INTENTION_SPLIT_PML2: return "Split Pml2";
264 | case INTENTION_TRACK_HOOKED_FUNCTIONS: return "Trace Hooked Functions";
265 | default: return "Unknown";
266 | }
267 | }
268 |
269 | ///
270 | /// Writes all information about allocated pools
271 | ///
272 | void dump_pools_info()
273 | {
274 | PLIST_ENTRY current = g_vmm_context->pool_manager->list_of_allocated_pools;
275 |
276 | spinlock pool_lock(&g_vmm_context->pool_manager->lock_for_reading_pool);
277 |
278 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "-----------------------------------POOL MANAGER DUMP-----------------------------------\r\n");
279 |
280 | while (g_vmm_context->pool_manager->list_of_allocated_pools != current->Flink)
281 | {
282 | current = current->Flink;
283 |
284 | // Get the head of the record
285 | __pool_table* pool_table = (__pool_table*)CONTAINING_RECORD(current, __pool_table, pool_list);
286 |
287 | LogDump("Address: 0x%X Size: %llu Intention: %s Is Busy: %s Recycled: %s",
288 | pool_table->address, pool_table->size, intention_to_string(pool_table->intention), pool_table->is_busy ? "Yes" : "No",
289 | pool_table->recycled ? "Yes" : "No");
290 | }
291 |
292 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "-----------------------------------POOL MANAGER DUMP-----------------------------------\r\n");
293 | }
294 | }
--------------------------------------------------------------------------------
/airhv/poolmanager.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 |
4 | namespace pool_manager
5 | {
6 | enum allocation_intention
7 | {
8 | INTENTION_NONE,
9 | INTENTION_TRACK_HOOKED_PAGES,
10 | INTENTION_EXEC_TRAMPOLINE,
11 | INTENTION_SPLIT_PML2,
12 | INTENTION_TRACK_HOOKED_FUNCTIONS,
13 | INTENTION_FAKE_PAGE_CONTENTS,
14 | };
15 |
16 | struct __request_new_allocation
17 | {
18 | unsigned __int64 size[10];
19 | unsigned __int32 count[10];
20 | allocation_intention intention[10];
21 | };
22 |
23 | struct __pool_manager
24 | {
25 | __request_new_allocation* allocation_requests;
26 | PLIST_ENTRY list_of_allocated_pools;
27 | volatile long lock_for_request_allocation;
28 | volatile long lock_for_reading_pool;
29 | bool is_request_for_allocation_recived;
30 | };
31 |
32 | struct __pool_table
33 | {
34 | void* address;
35 | unsigned __int64 size;
36 | allocation_intention intention;
37 | LIST_ENTRY pool_list;
38 | bool is_busy;
39 | bool recycled;
40 | };
41 |
42 | ///
43 | /// Writes all information about allocated pools
44 | ///
45 | void dump_pools_info();
46 |
47 | ///
48 | /// Request allocation
49 | ///
50 | /// Size of pool
51 | /// Number of pools to allocate
52 | ///
53 | ///
54 | bool request_allocation(unsigned __int64 size, unsigned __int32 count, allocation_intention intention);
55 |
56 | ///
57 | /// Initalize pool manager struct and preallocate pools
58 | ///
59 | /// status
60 | bool initialize();
61 |
62 | ///
63 | /// Free all allocted pools
64 | ///
65 | void uninitialize();
66 |
67 | ///
68 | /// Set information that pool is no longer used by anyone and mark as recycled
69 | ///
70 | ///
71 | void release_pool(void* address);
72 |
73 | ///
74 | /// Allocate all requested pools
75 | ///
76 | ///
77 | bool perform_allocation();
78 |
79 | ///
80 | /// Returns pre allocated pool and request new one for allocation
81 | ///
82 | /// Indicates what will be pool used for
83 | /// If set new pool will (with same properties) be requested to allocate
84 | /// Only if new_pool is true. Size of new pool
85 | ///
86 | template
87 | T request_pool(allocation_intention intention, bool new_pool, unsigned __int64 size)
88 | {
89 | PLIST_ENTRY current = 0;
90 | void* address = 0;
91 | bool is_recycled = false;
92 | __pool_table* pool_table;
93 | current = g_vmm_context->pool_manager->list_of_allocated_pools;
94 |
95 | spinlock pool_lock(&g_vmm_context->pool_manager->lock_for_reading_pool);
96 |
97 | while (g_vmm_context->pool_manager->list_of_allocated_pools != current->Flink)
98 | {
99 | current = current->Flink;
100 |
101 | // Get the head of the record
102 | pool_table = (__pool_table*)CONTAINING_RECORD(current, __pool_table, pool_list);
103 |
104 | if (pool_table->intention == intention && pool_table->is_busy == false)
105 | {
106 | pool_table->is_busy = true;
107 | is_recycled = pool_table->recycled;
108 | address = pool_table->address;
109 | break;
110 | }
111 | }
112 |
113 | //
114 | // If pool which we got is recycled then we don't allocate
115 | // a new one because we don't want to overload memory, If there wasn't any preallocated pool
116 | // this function will send a request
117 | //
118 | if (new_pool == true && is_recycled == false)
119 | request_allocation(size, 1, intention);
120 |
121 | return (T)address;
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/airhv/spinlock.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include "spinlock.h"
3 |
4 | // This implementation is derived from Hvpp by Petr Benes
5 | // - https://github.com/wbenny/hvpp
6 | // Based on my benchmarks, this simple implementation beats other (often
7 | // more complex) spinlock implementations - such as queue spinlocks, ticket
8 | // spinlocks, MCS locks. The only difference between this implementation
9 | // and completely naive spinlock is the "backoff".
10 | //
11 | // Also, benefit of this implementation is that we can use it with
12 | // STL lock guards, e.g.: std::lock_guard.
13 | //
14 | // Look here for more information:
15 | // - https://locklessinc.com/articles/locks/
16 | // - https://github.com/cyfdecyf/spinlock
17 |
18 | static unsigned max_wait = 65536;
19 |
20 | spinlock::spinlock(volatile long* _lock) : m_lock(_lock)
21 | {
22 | lock();
23 | }
24 |
25 | spinlock::~spinlock()
26 | {
27 | unlock();
28 | }
29 |
30 | bool spinlock::try_lock()
31 | {
32 | return (!(*m_lock) && !_interlockedbittestandset(m_lock, 0));
33 | }
34 |
35 | void spinlock::lock()
36 | {
37 | unsigned __int32 wait = 1;
38 |
39 | while (!try_lock())
40 | {
41 | for (unsigned __int32 i = 0; i < wait; ++i)
42 | {
43 | _mm_pause();
44 | }
45 |
46 | // Don't call "pause" too many times. If the wait becomes too big,
47 | // clamp it to the max_wait.
48 |
49 | if (wait * 2 > max_wait)
50 | {
51 | wait = max_wait;
52 | }
53 | else
54 | {
55 | wait = wait * 2;
56 | }
57 | }
58 | }
59 |
60 | void spinlock::unlock()
61 | {
62 | *m_lock = 0;
63 | }
--------------------------------------------------------------------------------
/airhv/spinlock.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | class spinlock
4 | {
5 | public:
6 | spinlock(volatile long* _lock);
7 | ~spinlock();
8 | private:
9 | bool try_lock();
10 | void lock();
11 | void unlock();
12 |
13 | volatile long* m_lock;
14 | };
--------------------------------------------------------------------------------
/airhv/vmcall_handler.cpp:
--------------------------------------------------------------------------------
1 | #pragma warning( disable : 4201 4244 4805 4189)
2 |
3 | #include
4 | #include "common.h"
5 | #include "vmcall_handler.h"
6 | #include "asm\vm_intrin.h"
7 | #include "vmcall_reason.h"
8 | #include "ia32\vmcs_encodings.h"
9 | #include "ia32\msr.h"
10 | #include "ia32\cr.h"
11 | #include "ia32\cpuid.h"
12 | #include "vmexit_handler.h"
13 | #include "hypervisor_routines.h"
14 | #include "interrupt.h"
15 |
16 | void restore_segment_registers()
17 | {
18 | __writemsr(IA32_FS_BASE, hv::vmread(GUEST_FS_BASE));
19 | __writemsr(IA32_GS_BASE, hv::vmread(GUEST_GS_BASE));
20 | __reload_gdtr(hv::vmread(GUEST_GDTR_BASE), hv::vmread(GUEST_GDTR_LIMIT));
21 | __reload_idtr(hv::vmread(GUEST_IDTR_BASE), hv::vmread(GUEST_IDTR_LIMIT));
22 | }
23 |
24 | void call_vmxoff(__vcpu* vcpu)
25 | {
26 | __writecr3(hv::vmread(GUEST_CR3));
27 |
28 | vcpu->vmx_off_state.guest_rip = vcpu->vmexit_info.guest_rip + vcpu->vmexit_info.instruction_length;
29 | vcpu->vmx_off_state.guest_rsp = vcpu->vmexit_info.guest_registers->rsp;
30 | vcpu->vmx_off_state.vmx_off_executed = true;
31 |
32 | restore_segment_registers();
33 |
34 | __vmx_off();
35 |
36 | __writecr4(__readcr4() & (~0x2000));
37 | }
38 |
39 | void vmexit_vmcall_handler(__vcpu* vcpu)
40 | {
41 | bool status = true;
42 | unsigned __int64 vmcall_reason = vcpu->vmexit_info.guest_registers->rcx;
43 | unsigned __int64 vmcall_parameter1 = vcpu->vmexit_info.guest_registers->rdx;
44 | unsigned __int64 vmcall_parameter2 = vcpu->vmexit_info.guest_registers->r8;
45 | unsigned __int64 vmcall_parameter3 = vcpu->vmexit_info.guest_registers->r9;
46 |
47 | //
48 | // These only if __vmcall_ex was called
49 | //
50 | unsigned __int64 vmcall_parameter4 = vcpu->vmexit_info.guest_registers->r10;
51 | unsigned __int64 vmcall_parameter5 = vcpu->vmexit_info.guest_registers->r11;
52 | unsigned __int64 vmcall_parameter6 = vcpu->vmexit_info.guest_registers->r12;
53 | unsigned __int64 vmcall_parameter7 = vcpu->vmexit_info.guest_registers->r13;
54 | unsigned __int64 vmcall_parameter8 = vcpu->vmexit_info.guest_registers->r14;
55 | unsigned __int64 vmcall_parameter9 = vcpu->vmexit_info.guest_registers->r15;
56 |
57 | //
58 | // Check if this vmcall belongs to us
59 | //
60 | __cpuid_info cpuid_reg{};
61 | __cpuid(reinterpret_cast(&cpuid_reg), 0x40000001);
62 | if (cpuid_reg.eax == 'Hv#1' && vcpu->vmexit_info.guest_registers->rax != VMCALL_IDENTIFIER)
63 | {
64 | vcpu->vmexit_info.guest_registers->rax = __hyperv_vm_call(vcpu->vmexit_info.guest_registers->rcx,
65 | vcpu->vmexit_info.guest_registers->rdx, vcpu->vmexit_info.guest_registers->r8);
66 |
67 | adjust_rip(vcpu);
68 | return;
69 | }
70 |
71 | if (vcpu->vmexit_info.guest_registers->rax != VMCALL_IDENTIFIER)
72 | {
73 | adjust_rip(vcpu);
74 | return;
75 | }
76 |
77 | if (hv::get_guest_cpl() != 0)
78 | {
79 | hv::inject_interruption(EXCEPTION_VECTOR_GENERAL_PROTECTION_FAULT, INTERRUPT_TYPE_HARDWARE_EXCEPTION, 0, 1);
80 | return;
81 | }
82 |
83 | switch (vmcall_reason)
84 | {
85 | case VMCALL_TEST:
86 | {
87 | adjust_rip(vcpu);
88 | break;
89 | }
90 |
91 | case VMCALL_VMXOFF:
92 | {
93 | call_vmxoff(vcpu);
94 | break;
95 | }
96 |
97 | case VMCALL_EPT_HOOK_FUNCTION:
98 | {
99 | unsigned __int64 old_cr3 = hv::swap_context(vmcall_parameter4);
100 |
101 | status = ept::hook_function(*vcpu->ept_state, (void*)vmcall_parameter1, (void*)vmcall_parameter2, (void**)vmcall_parameter3);
102 |
103 | hv::restore_context(old_cr3);
104 |
105 | adjust_rip(vcpu);
106 | break;
107 | }
108 |
109 | case VMCALL_EPT_UNHOOK_FUNCTION:
110 | {
111 | unsigned __int64 old_cr3 = hv::swap_context(vmcall_parameter3);
112 |
113 | // If set unhook all pages
114 | if (vmcall_parameter1 == true)
115 | {
116 | ept::unhook_all_functions(*vcpu->ept_state);
117 | }
118 |
119 | else
120 | {
121 | // Page physciall address
122 | status = ept::unhook_function(*vcpu->ept_state, vmcall_parameter2);
123 | }
124 |
125 | hv::restore_context(old_cr3);
126 |
127 | adjust_rip(vcpu);
128 | break;
129 | }
130 |
131 | case VMCALL_DUMP_POOL_MANAGER:
132 | {
133 | pool_manager::dump_pools_info();
134 | adjust_rip(vcpu);
135 | break;
136 | }
137 |
138 | case VMCALL_DUMP_VMCS_STATE:
139 | {
140 | hv::dump_vmcs();
141 | adjust_rip(vcpu);
142 | break;
143 | }
144 |
145 | case VMCALL_HIDE_HV_PRESENCE:
146 | {
147 | g_vmm_context->hv_presence = false;
148 | adjust_rip(vcpu);
149 | break;
150 | }
151 |
152 | case VMCALL_UNHIDE_HV_PRESENCE:
153 | {
154 | g_vmm_context->hv_presence = true;
155 | adjust_rip(vcpu);
156 | break;
157 | }
158 |
159 | default:
160 | {
161 | adjust_rip(vcpu);
162 | break;
163 | }
164 | }
165 |
166 | vcpu->vmexit_info.guest_registers->rax = status;
167 | }
--------------------------------------------------------------------------------
/airhv/vmcall_handler.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | struct __vmcall_hook_page
4 | {
5 | void* target_adress;
6 | void* hook_function;
7 | void** origin_adress;
8 | void* code_cave;
9 | unsigned __int8 protection_mask;
10 | bool swap_context;
11 | };
12 |
13 | struct __vmcall_unhook_page
14 | {
15 | unsigned __int64 physical_adress;
16 | bool unhook_all;
17 | };
18 |
19 | struct __vmcall_hook_msr_lstar
20 | {
21 | unsigned __int64 new_lstar_value;
22 | };
23 |
24 | struct __vmcall_invept
25 | {
26 | bool invept_all_context;
27 | };
28 |
29 | void restore_segment_registers();
30 | void call_vmxoff(__vcpu* vcpu);
31 | //void vmcall_operations(__vmexit_guest_registers_t* guest_regs);
32 | void vmexit_vmcall_handler(__vcpu* vcpu);
--------------------------------------------------------------------------------
/airhv/vmcall_reason.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | enum vm_call_reasons
3 | {
4 | VMCALL_TEST,
5 | VMCALL_VMXOFF,
6 | VMCALL_EPT_HOOK_FUNCTION,
7 | VMCALL_EPT_UNHOOK_FUNCTION,
8 | VMCALL_DUMP_POOL_MANAGER,
9 | VMCALL_DUMP_VMCS_STATE,
10 | VMCALL_HIDE_HV_PRESENCE,
11 | VMCALL_UNHIDE_HV_PRESENCE
12 | };
--------------------------------------------------------------------------------
/airhv/vmcs.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Air14/airhv/d2b4a6cdc8c8efb56637c6992dd36b8fdce68202/airhv/vmcs.cpp
--------------------------------------------------------------------------------
/airhv/vmexit_handler.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Air14/airhv/d2b4a6cdc8c8efb56637c6992dd36b8fdce68202/airhv/vmexit_handler.cpp
--------------------------------------------------------------------------------
/airhv/vmexit_handler.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | enum __vm_exit_reason
4 | {
5 | EXIT_REASON_EXCEPTION_NMI,
6 | EXIT_REASON_EXTERNAL_INTERRUPT,
7 | EXIT_REASON_TRIPLE_FAULT,
8 | EXIT_REASON_INIT_SIGNAL,
9 | EXIT_REASON_SIPI,
10 | EXIT_REASON_SMI,
11 | EXIT_REASON_OTHER_SMI,
12 | EXIT_REASON_INTERRUPT_WINDOW,
13 | EXIT_REASON_NMI_WINDOW,
14 | EXIT_REASON_TASK_SWITCH,
15 | EXIT_REASON_CPUID,
16 | EXIT_REASON_GETSEC,
17 | EXIT_REASON_HLT,
18 | EXIT_REASON_INVD,
19 | EXIT_REASON_INVLPG,
20 | EXIT_REASON_RDPMC,
21 | EXIT_REASON_RDTSC,
22 | EXIT_REASON_RSM,
23 | EXIT_REASON_VMCALL,
24 | EXIT_REASON_VMCLEAR,
25 | EXIT_REASON_VMLAUNCH,
26 | EXIT_REASON_VMPTRLD,
27 | EXIT_REASON_VMPTRST,
28 | EXIT_REASON_VMREAD,
29 | EXIT_REASON_VMRESUME,
30 | EXIT_REASON_VMWRITE,
31 | EXIT_REASON_VMXOFF,
32 | EXIT_REASON_VMXON,
33 | EXIT_REASON_CR_ACCESSES,
34 | EXIT_REASON_MOV_DR,
35 | EXIT_REASON_IO_INSTRUCTION,
36 | EXIT_REASON_RDMSR,
37 | EXIT_REASON_WRMSR,
38 | EXIT_REASON_VM_ENTRY_FAILURE_INVALID_GUEST_STATE,
39 | EXIT_REASON_VM_ENTRY_FAILURE_MSR_LODAING,
40 | EXIT_REASON_RESERVED1,
41 | EXIT_REASON_MWAIT,
42 | EXIT_REASON_MONITOR_TRAP_FLAG,
43 | EXIT_REASON_RESERVED2,
44 | EXIT_REASON_MONITOR,
45 | EXIT_REASON_PAUSE,
46 | EXIT_REASON_VM_ENTRY_FAILURE_MACHINE_CHECK_EVENT,
47 | EXIT_REASON_RESERVED3,
48 | EXIT_REASON_TPR_BELOW_THRESHOLD,
49 | EXIT_REASON_APIC_ACCESS,
50 | EXIT_REASON_VIRTUALIZED_EOI,
51 | EXIT_REASON_ACCESS_TO_GDTR_OR_IDTR,
52 | EXIT_REASON_ACCESS_TO_LDTR_OR_TR,
53 | EXIT_REASON_EPT_VIOLATION,
54 | EXIT_REASON_EPT_MISCONFIGURATION,
55 | EXIT_REASON_INVEPT,
56 | EXIT_REASON_RDTSCP,
57 | EXIT_REASON_VMX_PREEMPTION_TIMER_EXPIRED,
58 | EXIT_REASON_INVVPID,
59 | EXIT_REASON_WBINVD,
60 | EXIT_REASON_XSETBV,
61 | EXIT_REASON_APIC_WRITE,
62 | EXIT_REASON_RDRAND,
63 | EXIT_REASON_INVPCID,
64 | EXIT_REASON_VMFUNC,
65 | EXIT_REASON_ENCLS,
66 | EXIT_REASON_RDSEED,
67 | EXIT_REASON_PAGE_MODIFICATION_LOG_FULL,
68 | EXIT_REASON_XSAVES,
69 | EXIT_REASON_XRSTORS,
70 | EXIT_REASON_RESERVED4,
71 | EXIT_REASON_SPP_RELATED_EVENT,
72 | EXIT_REASON_UMWAIT,
73 | EXIT_REASON_TPAUSE,
74 | EXIT_REASON_LAST
75 | };
76 |
77 | // Table 27-8. Format of the VM-Exit Instruction-Information Field as Used for INS and OUTS
78 | union __vmexit_instruction_information1
79 | {
80 | unsigned __int64 all;
81 | struct
82 | {
83 | unsigned __int64 reserved1 : 7;
84 | unsigned __int64 address_size : 3;
85 | unsigned __int64 reserved2 : 5;
86 | unsigned __int64 segment_register : 3;
87 | unsigned __int64 reserved3 : 14;
88 | };
89 | };
90 |
91 | // Table 27-9. Format of the VM-Exit Instruction-Information Field as Used for INVEPT, INVPCID, and INVVPID
92 | union __vmexit_instruction_information2
93 | {
94 | unsigned __int64 all;
95 | struct
96 | {
97 | unsigned __int64 scaling : 2;
98 | unsigned __int64 reserved1 : 5;
99 | unsigned __int64 address_size : 3;
100 | unsigned __int64 reserved2 : 1;
101 | unsigned __int64 reserved3 : 4;
102 | unsigned __int64 segment_register : 3;
103 | unsigned __int64 index_reg : 4;
104 | unsigned __int64 index_reg_invalid : 1;
105 | unsigned __int64 base_reg : 4;
106 | unsigned __int64 base_reg_invalid : 1;
107 | unsigned __int64 reg2 : 4;
108 | };
109 | };
110 |
111 | // Table 27-10. Format of the VM-Exit Instruction-Information Field as Used for LIDT, LGDT, SIDT, or SGDT
112 | union __vmexit_instruction_information3
113 | {
114 | unsigned __int64 all;
115 | struct
116 | {
117 | unsigned __int64 scaling : 2;
118 | unsigned __int64 reserved1 : 5;
119 | unsigned __int64 address_size : 3;
120 | unsigned __int64 reserved2 : 1;
121 | unsigned __int64 operand_size : 1;
122 | unsigned __int64 reserved3 : 3;
123 | unsigned __int64 segment_register : 3;
124 | unsigned __int64 index_reg : 4;
125 | unsigned __int64 index_reg_invalid : 1;
126 | unsigned __int64 base_reg : 4;
127 | unsigned __int64 base_reg_invalid : 1;
128 | unsigned __int64 instruction_identity : 2;
129 | unsigned __int64 reserved4 : 2;
130 | };
131 | };
132 |
133 | // Table 27-11. Format of the VM-Exit Instruction-Information Field as Used for LLDT, LTR, SLDT, and STR
134 | union __vmexit_instruction_information4
135 | {
136 | unsigned __int64 all;
137 | struct
138 | {
139 | unsigned __int64 scaling : 2;
140 | unsigned __int64 reserved1 : 1;
141 | unsigned __int64 reg1 : 4;
142 | unsigned __int64 address_size : 3;
143 | unsigned __int64 mem_reg : 1;
144 | unsigned __int64 reserved2 : 4;
145 | unsigned __int64 segment_register : 3;
146 | unsigned __int64 index_reg : 4;
147 | unsigned __int64 index_reg_invalid : 1;
148 | unsigned __int64 base_reg : 4;
149 | unsigned __int64 base_reg_invalid : 1;
150 | unsigned __int64 instruction_identity : 2;
151 | unsigned __int64 reserved4 : 2;
152 | };
153 | };
154 |
155 | // Table 27-12. Format of the VM-Exit Instruction-Information Field as Used for RDRAND, RDSEED, TPAUSE, and UMWAIT
156 | union __vmexit_instruction_information5
157 | {
158 | unsigned __int64 all;
159 | struct
160 | {
161 | unsigned __int64 reserved1 : 3;
162 | unsigned __int64 operand_register : 4;
163 | unsigned __int64 reserved2 : 4;
164 | unsigned __int64 operand_size : 2;
165 | unsigned __int64 reserved3 : 19;
166 | };
167 | };
168 |
169 | // Table 27 - 13. Format of the VM - Exit Instruction - Information Field as Used for VMCLEAR, VMPTRLD, VMPTRST, VMXON, XRSTORS, and XSAVES
170 | union __vmexit_instruction_information6
171 | {
172 | unsigned __int64 all;
173 | struct
174 | {
175 | unsigned __int64 scaling : 2;
176 | unsigned __int64 reserved1 : 5;
177 | unsigned __int64 address_size : 3;
178 | unsigned __int64 reserved2 : 1;
179 | unsigned __int64 reserved3 : 4;
180 | unsigned __int64 segment_register : 3;
181 | unsigned __int64 index_reg : 4;
182 | unsigned __int64 index_reg_invalid : 1;
183 | unsigned __int64 base_reg : 4;
184 | unsigned __int64 base_reg_invalid : 1;
185 | unsigned __int64 instruction_identity : 2;
186 | unsigned __int64 reserved4 : 2;
187 | };
188 | };
189 |
190 | // Table 27-14. Format of the VM-Exit Instruction-Information Field as Used for VMREAD and VMWRITE
191 | union __vmexit_instruction_information7
192 | {
193 | unsigned __int64 all;
194 | struct
195 | {
196 | unsigned __int64 scaling : 2;
197 | unsigned __int64 reserved1 : 1;
198 | unsigned __int64 reg1 : 4;
199 | unsigned __int64 address_size : 3;
200 | unsigned __int64 mem_reg : 1;
201 | unsigned __int64 reserved2 : 4;
202 | unsigned __int64 segment_register : 3;
203 | unsigned __int64 index_reg : 4;
204 | unsigned __int64 index_reg_invalid : 1;
205 | unsigned __int64 base_reg : 4;
206 | unsigned __int64 base_reg_invalid : 1;
207 | unsigned __int64 reg2 : 4;
208 | };
209 | };
210 |
211 | // Table 27-5. Exit Qualification for I/O Instructions
212 | union __exit_qualification_io
213 | {
214 | unsigned __int64 all;
215 | struct
216 | {
217 | //
218 | // 0 = 1 - byte
219 | // 1 = 2 - byte
220 | // 3 = 4 - byte
221 | //
222 | unsigned __int64 access_size : 3;
223 |
224 | //
225 | // 0 = OUT
226 | // 1 = IN
227 | //
228 | unsigned __int64 direction : 1;
229 |
230 | //
231 | // 0 = not string
232 | // 1 = string
233 | //
234 | unsigned __int64 string_instruction : 1;
235 |
236 | //
237 | // 0 = not REP
238 | // 1 = REP
239 | //
240 | unsigned __int64 rep : 1;
241 |
242 | //
243 | // 0 = DX
244 | // 1 = immediate
245 | //
246 | unsigned __int64 operand_encoding : 1;
247 |
248 | //
249 | // Not currently defined
250 | //
251 | unsigned __int64 reserved1 : 9;
252 |
253 | //
254 | // as specified in DX or in an immediate operand
255 | //
256 | unsigned __int64 port_number : 16;
257 |
258 | //
259 | // Not currently defined. These bits exist only on processors that support Intel 64 architecture.
260 | //
261 | unsigned __int64 reserved2 : 32;
262 | };
263 | };
264 |
265 | union __exit_qualification_dr
266 | {
267 | unsigned __int64 all;
268 | struct
269 | {
270 | unsigned __int64 debug_register_number : 3;
271 |
272 | unsigned __int64 reserved1 : 1;
273 |
274 | //
275 | // 0 = MOV to DR
276 | // 1 = MOV from DR
277 | //
278 | unsigned __int64 access_direction : 1;
279 |
280 | unsigned __int64 reserved2 : 3;
281 |
282 | unsigned __int64 gp_register : 4;
283 |
284 | unsigned __int64 reserved3 : 52;
285 | };
286 | };
287 |
288 | unsigned __int64 return_rsp_for_vmxoff();
289 |
290 | unsigned __int64 return_rip_for_vmxoff();
291 |
292 | bool vmexit_handler(__vmexit_guest_registers * guest_registers);
293 |
294 | void adjust_rip(__vcpu* vcpu);
--------------------------------------------------------------------------------
/airhv/vmm.cpp:
--------------------------------------------------------------------------------
1 | #pragma warning( disable : 4201)
2 |
3 | #include
4 | #include
5 | #include "common.h"
6 | #include "ia32\cpuid.h"
7 | #include "asm\vm_context.h"
8 | #include "ia32\cr.h"
9 | #include "ia32\msr.h"
10 | #include "ia32\vmcs.h"
11 | #include "log.h"
12 | #include "ntapi.h"
13 | #include "ia32\vmcs_encodings.h"
14 | #include "allocators.h"
15 |
16 | void dpc_broadcast_initialize_guest(KDPC* Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2)
17 | {
18 | UNREFERENCED_PARAMETER(DeferredContext);
19 | UNREFERENCED_PARAMETER(Dpc);
20 | vmx_save_state();
21 |
22 | // Wait for all DPCs to synchronize at this point
23 | KeSignalCallDpcSynchronize(SystemArgument2);
24 |
25 | // Mark the DPC as being complete
26 | KeSignalCallDpcDone(SystemArgument1);
27 | }
28 |
29 |
30 | ///
31 | /// Deallocate all structures
32 | ///
33 | void free_vmm_context()
34 | {
35 | if (g_vmm_context != nullptr)
36 | {
37 | // POOL MANAGER
38 | if (g_vmm_context->pool_manager != nullptr)
39 | {
40 | pool_manager::uninitialize();
41 | free_pool(g_vmm_context->pool_manager);
42 | }
43 |
44 | // VCPU TABLE
45 | if (g_vmm_context->vcpu_table != nullptr)
46 | {
47 | for (unsigned int i = 0; i < g_vmm_context->processor_count; i++)
48 | {
49 | // VCPU
50 | if (g_vmm_context->vcpu_table[i] != nullptr)
51 | {
52 | // VCPU VMXON REGION
53 | if (g_vmm_context->vcpu_table[i]->vmxon != nullptr)
54 | {
55 | free_contignous_memory(g_vmm_context->vcpu_table[i]->vmxon);
56 | }
57 |
58 | // VCPU VMCS REGION
59 | if (g_vmm_context->vcpu_table[i]->vmcs != nullptr)
60 | {
61 | free_contignous_memory(g_vmm_context->vcpu_table[i]->vmcs);
62 | }
63 |
64 | // VCPU VMM STACK
65 | if (g_vmm_context->vcpu_table[i]->vmm_stack != nullptr)
66 | {
67 | free_pool(g_vmm_context->vcpu_table[i]->vmm_stack);
68 | }
69 |
70 | // MSR BITMAP
71 | if (g_vmm_context->vcpu_table[i]->vcpu_bitmaps.msr_bitmap != nullptr)
72 | {
73 | free_pool(g_vmm_context->vcpu_table[i]->vcpu_bitmaps.msr_bitmap);
74 | }
75 |
76 | // IO BITMAP A
77 | if (g_vmm_context->vcpu_table[i]->vcpu_bitmaps.io_bitmap_a != nullptr)
78 | {
79 | free_pool(g_vmm_context->vcpu_table[i]->vcpu_bitmaps.io_bitmap_a);
80 | }
81 |
82 | // IO BITMAP B
83 | if (g_vmm_context->vcpu_table[i]->vcpu_bitmaps.io_bitmap_b != nullptr)
84 | {
85 | free_pool(g_vmm_context->vcpu_table[i]->vcpu_bitmaps.io_bitmap_b);
86 | }
87 |
88 | // EPT_STATE
89 | if (g_vmm_context->vcpu_table[i]->ept_state != nullptr)
90 | {
91 | // EPT POINTER
92 | if (g_vmm_context->vcpu_table[i]->ept_state->ept_pointer != nullptr)
93 | {
94 | free_pool(g_vmm_context->vcpu_table[i]->ept_state->ept_pointer);
95 | }
96 | // EPT PAGE TABLE
97 | if (g_vmm_context->vcpu_table[i]->ept_state->ept_page_table != nullptr)
98 | {
99 | free_contignous_memory(g_vmm_context->vcpu_table[i]->ept_state->ept_page_table);
100 | }
101 |
102 | free_pool(g_vmm_context->vcpu_table[i]->ept_state);
103 | }
104 |
105 | free_pool(g_vmm_context->vcpu_table[i]);
106 | }
107 | }
108 | free_pool(g_vmm_context->vcpu_table);
109 | }
110 |
111 | free_pool(g_vmm_context);
112 | }
113 |
114 | g_vmm_context = 0;
115 | }
116 |
117 |
118 | ///
119 | /// Allocates contiguous memory for vmcs
120 | ///
121 | /// Pointer to vcpu
122 | /// status
123 | bool init_vmcs(__vcpu* vcpu)
124 | {
125 | __vmx_basic_msr vmx_basic = { 0 };
126 | PHYSICAL_ADDRESS physical_max;
127 |
128 | vmx_basic.all = __readmsr(IA32_VMX_BASIC);
129 |
130 | physical_max.QuadPart = ~0ULL;
131 | vcpu->vmcs = allocate_contignous_memory<__vmcs*>(PAGE_SIZE);
132 | if (vcpu->vmcs == NULL)
133 | {
134 | LogError("Vmcs structure could not be allocated");
135 | return false;
136 | }
137 |
138 | vcpu->vmcs_physical = MmGetPhysicalAddress(vcpu->vmcs).QuadPart;
139 | if (vcpu->vmcs_physical == NULL)
140 | {
141 | LogError("Could not get physical address of vmcs");
142 | return false;
143 | }
144 |
145 | RtlSecureZeroMemory(vcpu->vmcs, PAGE_SIZE);
146 | vcpu->vmcs->header.revision_identifier = vmx_basic.vmcs_revision_identifier;
147 |
148 | // Indicates if it's shadow vmcs or not
149 | vcpu->vmcs->header.shadow_vmcs_indicator = 0;
150 |
151 | return true;
152 | }
153 |
154 | ///
155 | /// Allocate whole vmm context, build mtrr map, initalize pool manager and initialize ept structure
156 | ///
157 | /// status
158 | bool allocate_vmm_context()
159 | {
160 | __cpuid_info cpuid_reg = { 0 };
161 |
162 | //
163 | // Allocate Nonpaged memory for vm global context structure
164 | //
165 | g_vmm_context = allocate_pool<__vmm_context>();
166 | if (g_vmm_context == nullptr) {
167 | LogError("g_vmm_context could not be allocated");
168 | return false;
169 | }
170 | RtlSecureZeroMemory(g_vmm_context, sizeof(__vmm_context));
171 |
172 | //
173 | // Allocate virtual cpu context for every logical core
174 | //
175 | g_vmm_context->processor_count = KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
176 | g_vmm_context->vcpu_table = allocate_pool<__vcpu**>(sizeof(__vcpu*) * (g_vmm_context->processor_count));
177 | if (g_vmm_context->vcpu_table == nullptr)
178 | {
179 | LogError("vcpu_table could not be allocated");
180 | return false;
181 | }
182 | RtlSecureZeroMemory(g_vmm_context->vcpu_table, sizeof(__vcpu*) * (g_vmm_context->processor_count));
183 |
184 | //
185 | // Build mtrr map for physcial memory caching informations
186 | //
187 | ept::build_mtrr_map();
188 |
189 | if (pool_manager::initialize() == false)
190 | {
191 | return false;
192 | }
193 |
194 | g_vmm_context->hv_presence = true;
195 |
196 | __cpuid((int*)&cpuid_reg.eax, 0);
197 | g_vmm_context->highest_basic_leaf = cpuid_reg.eax;
198 |
199 | return true;
200 | }
201 |
202 | ///
203 | /// Allocate whole vcpu context and bitmaps
204 | ///
205 | /// Pointer to vcpu
206 | bool init_vcpu(__vcpu*& vcpu)
207 | {
208 | vcpu = allocate_pool<__vcpu>();
209 | if (vcpu == nullptr)
210 | {
211 | LogError("vcpu structure could not be allocated");
212 | return false;
213 | }
214 | RtlSecureZeroMemory(vcpu, sizeof(__vcpu));
215 |
216 | vcpu->vmm_stack = allocate_pool(VMM_STACK_SIZE);
217 | if (vcpu->vmm_stack == nullptr)
218 | {
219 | LogError("vmm stack could not be allocated");
220 | return false;
221 | }
222 | RtlSecureZeroMemory(vcpu->vmm_stack, VMM_STACK_SIZE);
223 |
224 | vcpu->vcpu_bitmaps.msr_bitmap = allocate_pool(PAGE_SIZE);
225 | if (vcpu->vcpu_bitmaps.msr_bitmap == nullptr)
226 | {
227 | LogError("msr bitmap could not be allocated");
228 | return false;
229 | }
230 | RtlSecureZeroMemory(vcpu->vcpu_bitmaps.msr_bitmap, PAGE_SIZE);
231 | vcpu->vcpu_bitmaps.msr_bitmap_physical = MmGetPhysicalAddress(vcpu->vcpu_bitmaps.msr_bitmap).QuadPart;
232 |
233 | vcpu->vcpu_bitmaps.io_bitmap_a = allocate_pool(PAGE_SIZE);
234 | if (vcpu->vcpu_bitmaps.io_bitmap_a == nullptr)
235 | {
236 | LogError("io bitmap a could not be allocated");
237 | return false;
238 | }
239 | RtlSecureZeroMemory(vcpu->vcpu_bitmaps.io_bitmap_a, PAGE_SIZE);
240 | vcpu->vcpu_bitmaps.io_bitmap_a_physical = MmGetPhysicalAddress(vcpu->vcpu_bitmaps.io_bitmap_a).QuadPart;
241 |
242 | vcpu->vcpu_bitmaps.io_bitmap_b = allocate_pool(PAGE_SIZE);
243 | if (vcpu->vcpu_bitmaps.io_bitmap_b == nullptr)
244 | {
245 | LogError("io bitmap b could not be allocated");
246 | return false;
247 | }
248 | RtlSecureZeroMemory(vcpu->vcpu_bitmaps.io_bitmap_b, PAGE_SIZE);
249 | vcpu->vcpu_bitmaps.io_bitmap_b_physical = MmGetPhysicalAddress(vcpu->vcpu_bitmaps.io_bitmap_b).QuadPart;
250 |
251 | //
252 | // Allocate ept state structure
253 | //
254 | vcpu->ept_state = allocate_pool<__ept_state>();
255 | if (vcpu->ept_state == nullptr)
256 | {
257 | LogError("ept state could not be allocated");
258 | return false;
259 | }
260 | RtlSecureZeroMemory(vcpu->ept_state, sizeof(__ept_state));
261 | InitializeListHead(&vcpu->ept_state->hooked_page_list);
262 |
263 | //
264 | // Initialize ept structure
265 | //
266 | if (ept::initialize(*vcpu->ept_state) == false)
267 | {
268 | return false;
269 | }
270 |
271 | LogInfo("vcpu entry allocated successfully at %llX", vcpu);
272 |
273 | return true;
274 | }
275 |
276 | ///
277 | /// Initialize vmxon structure
278 | ///
279 | /// Pointer to vcpu
280 | /// status
281 | bool init_vmxon(__vcpu* vcpu)
282 | {
283 | __vmx_basic_msr vmx_basic = { 0 };
284 |
285 | vmx_basic.all = __readmsr(IA32_VMX_BASIC);
286 |
287 | if (vmx_basic.vmxon_region_size > PAGE_SIZE)
288 | vcpu->vmxon = allocate_contignous_memory<__vmcs*>(PAGE_SIZE);
289 |
290 | else
291 | vcpu->vmxon = allocate_contignous_memory<__vmcs*>(vmx_basic.vmxon_region_size);
292 |
293 | if (vcpu->vmxon == nullptr)
294 | {
295 | LogError("vmxon could not be allocated");
296 | return false;
297 | }
298 |
299 | vcpu->vmxon_physical = MmGetPhysicalAddress(vcpu->vmxon).QuadPart;
300 | if (vcpu->vmxon_physical == 0)
301 | {
302 | LogError("Could not get vmxon physical address");
303 | return false;
304 | }
305 |
306 | RtlSecureZeroMemory(vcpu->vmxon, PAGE_SIZE);
307 | vcpu->vmxon->header.all = vmx_basic.vmcs_revision_identifier;
308 | vcpu->vmxon->header.shadow_vmcs_indicator = 0;
309 |
310 | return true;
311 | }
312 |
313 | ///
314 | /// Adjust cr4 and cr0 for turning on vmx
315 | ///
316 | void adjust_control_registers()
317 | {
318 | __cr4 cr4;
319 | __cr0 cr0;
320 | __cr_fixed cr_fixed;
321 |
322 | cr_fixed.all = __readmsr(IA32_VMX_CR0_FIXED0);
323 | cr0.all = __readcr0();
324 | cr0.all |= cr_fixed.split.low;
325 | cr_fixed.all = __readmsr(IA32_VMX_CR0_FIXED1);
326 | cr0.all &= cr_fixed.split.low;
327 | __writecr0(cr0.all);
328 | cr_fixed.all = __readmsr(IA32_VMX_CR4_FIXED0);
329 | cr4.all = __readcr4();
330 | cr4.all |= cr_fixed.split.low;
331 | cr_fixed.all = __readmsr(IA32_VMX_CR4_FIXED1);
332 | cr4.all &= cr_fixed.split.low;
333 | __writecr4(cr4.all);
334 |
335 | __ia32_feature_control_msr feature_msr = { 0 };
336 | feature_msr.all = __readmsr(IA32_FEATURE_CONTROL);
337 |
338 | if (feature_msr.lock == 0)
339 | {
340 | feature_msr.vmxon_outside_smx = 1;
341 | feature_msr.lock = 1;
342 |
343 | __writemsr(IA32_FEATURE_CONTROL, feature_msr.all);
344 | }
345 | }
346 |
347 |
348 | ///
349 | /// Initialize logical core and launch virtual machine managed by current vmcs
350 | ///
351 | ///
352 | void init_logical_processor(void* guest_rsp)
353 | {
354 | unsigned __int64 processor_number = KeGetCurrentProcessorNumberEx(NULL);
355 |
356 | __vcpu* vcpu = g_vmm_context->vcpu_table[processor_number];
357 |
358 | adjust_control_registers();
359 |
360 | if (__vmx_on(&vcpu->vmxon_physical))
361 | {
362 | LogError("Failed to put vcpu %d into VMX operation.\n", processor_number);
363 | return;
364 | }
365 |
366 | vcpu->vcpu_status.vmx_on = true;
367 | LogInfo("vcpu %d is now in VMX operation.\n", processor_number);
368 |
369 | fill_vmcs(vcpu, guest_rsp);
370 | vcpu->vcpu_status.vmm_launched = true;
371 |
372 | __vmx_vmlaunch();
373 |
374 | // We should never get here
375 |
376 | LogError("Vmlaunch failed");
377 | ASSERT(FALSE);
378 | vcpu->vcpu_status.vmm_launched = false;
379 | vcpu->vcpu_status.vmx_on = false;
380 | __vmx_off();
381 | }
382 |
383 | ///
384 | /// Initialize and launch vmm
385 | ///
386 | /// status
387 | bool vmm_init()
388 | {
389 | if (allocate_vmm_context() == false)
390 | return false;
391 |
392 | //
393 | // Initalize vcpu for each logical core
394 | for (unsigned int iter = 0; iter < g_vmm_context->processor_count; iter++)
395 | {
396 | if (init_vcpu(g_vmm_context->vcpu_table[iter]) == false)
397 | return false;
398 |
399 | if (init_vmxon(g_vmm_context->vcpu_table[iter]) == false)
400 | return false;
401 |
402 | if (init_vmcs(g_vmm_context->vcpu_table[iter]) == false)
403 | return false;
404 | }
405 |
406 | //
407 | // Call derefered procedure call (DPC) to fill vmcs and launch vmm for every logical core
408 | KeGenericCallDpc(dpc_broadcast_initialize_guest, 0);
409 | return true;
410 | }
--------------------------------------------------------------------------------
/airhv/vmm.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | ///
3 | /// Initialize and launch vmm
4 | ///
5 | /// status
6 | bool vmm_init();
7 |
8 | ///
9 | /// Deallocate all structures
10 | ///
11 | void free_vmm_context();
--------------------------------------------------------------------------------
/airhv/xsave.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | union __xcomp_bv
3 | {
4 | unsigned __int64 all;
5 | struct
6 | {
7 | unsigned __int64 reserved1 : 63;
8 | unsigned __int64 fromat : 1;
9 | };
10 | };
11 |
12 | union __xstate_bv
13 | {
14 | unsigned __int64 all;
15 | struct
16 | {
17 | unsigned __int64 x87state : 1;
18 | unsigned __int64 sse_state : 1;
19 | unsigned __int64 avx_state : 1;
20 | unsigned __int64 bndregs_state : 1;
21 | unsigned __int64 bndcsr_state : 1;
22 | unsigned __int64 opmask_state : 1;
23 | unsigned __int64 zmm_hi256_state : 1;
24 | unsigned __int64 hi16_zmm_state : 1;
25 | unsigned __int64 pt_state : 1;
26 | unsigned __int64 pkru_state : 1;
27 | unsigned __int64 reserved1 : 1;
28 | unsigned __int64 cet_u_state : 1;
29 | unsigned __int64 cet_s_state : 1;
30 | unsigned __int64 hdc_state : 1;
31 | unsigned __int64 reserved2 : 2;
32 | unsigned __int64 hwp_state : 1;
33 | unsigned __int64 reserved3 : 46;
34 | unsigned __int64 special : 1;
35 | };
36 | };
37 |
38 | struct __xsave_header
39 | {
40 | __xstate_bv xstate_bv;
41 | __xcomp_bv xcomp_bv;
42 | unsigned __int64 reserved[6];
43 | };
--------------------------------------------------------------------------------
/airhvctrl/airhvctrl.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | x64
7 |
8 |
9 | Release_Minimal
10 | x64
11 |
12 |
13 | Release
14 | x64
15 |
16 |
17 |
18 | {98E8F109-6A08-4461-A245-42B7CE32A703}
19 | {1bc93793-694f-48fe-9372-81e2b05556fd}
20 | v4.5
21 | 12.0
22 | Debug
23 | Win32
24 | airhvctrl
25 | 10.0.19041.0
26 |
27 |
28 |
29 | Windows7
30 | true
31 | WindowsKernelModeDriver10.0
32 | Driver
33 | KMDF
34 | Desktop
35 | Spectre
36 |
37 |
38 | Windows7
39 | false
40 | WindowsKernelModeDriver10.0
41 | Driver
42 | KMDF
43 | Desktop
44 | Spectre
45 |
46 |
47 | Windows7
48 | false
49 | WindowsKernelModeDriver10.0
50 | Driver
51 | KMDF
52 | Desktop
53 | Spectre
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 | DbgengKernelDebugger
66 |
67 |
68 | DbgengKernelDebugger
69 | false
70 |
71 |
72 | DbgengKernelDebugger
73 | false
74 |
75 |
76 |
77 | true
78 |
79 |
80 |
81 |
82 | true
83 |
84 |
85 |
86 |
87 | Speed
88 | false
89 | MaxSpeed
90 |
91 |
92 |
93 |
94 | Speed
95 | false
96 | MaxSpeed
97 |
98 |
99 |
100 |
101 | false
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
--------------------------------------------------------------------------------
/airhvctrl/airhvctrl.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 |
33 |
34 | Source Files
35 |
36 |
37 |
38 |
39 | Header Files
40 |
41 |
42 | Header Files
43 |
44 |
45 | Header Files
46 |
47 |
48 |
--------------------------------------------------------------------------------
/airhvctrl/hypervisor_gateway.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include "log.h"
4 |
5 | #define IOCTL_POOL_MANAGER_ALLOCATE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x900, METHOD_BUFFERED, FILE_SPECIAL_ACCESS)
6 |
7 | extern "C"
8 | {
9 | void NTAPI KeGenericCallDpc(_In_ PKDEFERRED_ROUTINE Routine, PVOID Context);
10 | void NTAPI KeSignalCallDpcDone(_In_ PVOID SystemArgument1);
11 | BOOLEAN NTAPI KeSignalCallDpcSynchronize(_In_ PVOID SystemArgument2);
12 | bool __vm_call(unsigned __int64 vmcall_reason, unsigned __int64 rdx, unsigned __int64 r8, unsigned __int64 r9);
13 | bool __vm_call_ex(unsigned __int64 vmcall_reason, unsigned __int64 rdx, unsigned __int64 r8, unsigned __int64 r9, unsigned __int64 r10, unsigned __int64 r11, unsigned __int64 r12, unsigned __int64 r13, unsigned __int64 r14, unsigned __int64 r15);
14 | }
15 |
16 | enum vm_call_reasons
17 | {
18 | VMCALL_TEST,
19 | VMCALL_VMXOFF,
20 | VMCALL_EPT_HOOK_FUNCTION,
21 | VMCALL_EPT_UNHOOK_FUNCTION,
22 | VMCALL_DUMP_POOL_MANAGER,
23 | VMCALL_DUMP_VMCS_STATE,
24 | VMCALL_HIDE_HV_PRESENCE,
25 | VMCALL_UNHIDE_HV_PRESENCE
26 | };
27 |
28 | namespace hvgt
29 | {
30 | void broadcast_vmoff(KDPC*, PVOID, PVOID SystemArgument1, PVOID SystemArgument2)
31 | {
32 | __vm_call(VMCALL_VMXOFF, 0, 0, 0);
33 | KeSignalCallDpcSynchronize(SystemArgument2);
34 | KeSignalCallDpcDone(SystemArgument1);
35 | }
36 |
37 | struct HookFunctionArgs
38 | {
39 | void* target_address;
40 | void* hook_function;
41 | void** origin_function;
42 | unsigned __int64 current_cr3;
43 | volatile SHORT statuses;
44 | };
45 | void broadcast_hook_function(KDPC*, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2)
46 | {
47 | const auto args = reinterpret_cast(DeferredContext);
48 |
49 | if (__vm_call_ex(VMCALL_EPT_HOOK_FUNCTION, (unsigned __int64)args->target_address,
50 | (unsigned __int64)args->hook_function, (unsigned __int64)args->origin_function, args->current_cr3, 0, 0, 0, 0, 0))
51 | {
52 | InterlockedIncrement16(&args->statuses);
53 | }
54 |
55 | KeSignalCallDpcSynchronize(SystemArgument2);
56 | KeSignalCallDpcDone(SystemArgument1);
57 | }
58 |
59 | struct UnHookFunctionArgs
60 | {
61 | bool unhook_all_functions;
62 | void* function_to_unhook;
63 | unsigned __int64 current_cr3;
64 | volatile SHORT statuses;
65 | };
66 | void broadcast_unhook_function(KDPC*, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2)
67 | {
68 | const auto args = reinterpret_cast(DeferredContext);
69 |
70 | if (__vm_call(VMCALL_EPT_UNHOOK_FUNCTION, args->unhook_all_functions,
71 | (unsigned __int64)args->function_to_unhook, args->current_cr3))
72 | {
73 | InterlockedIncrement16(&args->statuses);
74 | }
75 |
76 | KeSignalCallDpcSynchronize(SystemArgument2);
77 | KeSignalCallDpcDone(SystemArgument1);
78 | }
79 |
80 | void broadcast_test_vmcall(KDPC*, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2)
81 | {
82 | const auto statuses = reinterpret_cast(DeferredContext);
83 |
84 | if (__vm_call(VMCALL_TEST, 0, 0, 0))
85 | {
86 | InterlockedIncrement16(statuses);
87 | }
88 |
89 | KeSignalCallDpcSynchronize(SystemArgument2);
90 | KeSignalCallDpcDone(SystemArgument1);
91 | }
92 |
93 | ///
94 | /// Turn off virtual machine
95 | ///
96 | void vmoff()
97 | {
98 | KeGenericCallDpc(broadcast_vmoff, NULL);
99 | }
100 |
101 | ///
102 | /// Set/Unset presence of hypervisor
103 | ///
104 | /// If false, hypervisor is not visible via cpuid interface, If true, it become visible
105 | void hypervisor_visible(bool value)
106 | {
107 | if (value == true)
108 | __vm_call(VMCALL_UNHIDE_HV_PRESENCE, 0, 0, 0);
109 | else
110 | __vm_call(VMCALL_HIDE_HV_PRESENCE, 0, 0, 0);
111 | }
112 |
113 | ///
114 | /// Unhook all functions and invalidate tlb
115 | ///
116 | /// status
117 | bool unhook_all_functions()
118 | {
119 | UnHookFunctionArgs args{ true, nullptr, __readcr3(), 0 };
120 | KeGenericCallDpc(broadcast_unhook_function, &args);
121 |
122 | return static_cast(args.statuses) == KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
123 | }
124 |
125 | ///
126 | /// Unhook single function and invalidate tlb
127 | ///
128 | ///
129 | /// status
130 | bool unhook_function(void* function_address)
131 | {
132 | UnHookFunctionArgs args{ false, function_address, __readcr3(), 0 };
133 | KeGenericCallDpc(broadcast_unhook_function, &args);
134 |
135 | return static_cast(args.statuses) == KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
136 | }
137 |
138 | ///
139 | /// Hook function via ept and invalidates mappings
140 | ///
141 | /// Address of function which we want to hook
142 | /// Address of function which is used to call original function
143 | /// Address of function which is used to call original function
144 | /// status
145 | bool hook_function(void* target_address, void* hook_function, void** origin_function)
146 | {
147 | HookFunctionArgs args{ target_address, hook_function, origin_function, __readcr3(), 0 };
148 | KeGenericCallDpc(broadcast_hook_function, &args);
149 |
150 | return static_cast(args.statuses) == KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
151 | }
152 |
153 | ///
154 | /// Dump info about allocated pools (Use Dbgview to see information)
155 | ///
156 | void dump_pool_manager()
157 | {
158 | __vm_call(VMCALL_DUMP_POOL_MANAGER, 0, 0, 0);
159 | }
160 |
161 | ///
162 | /// Check if we can communicate with hypervisor
163 | ///
164 | /// status
165 | bool test_vmcall()
166 | {
167 | volatile SHORT statuses{};
168 | KeGenericCallDpc(broadcast_test_vmcall, (PVOID)&statuses);
169 |
170 | return static_cast(statuses) == KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
171 | }
172 |
173 | ///
174 | /// Send irp with information to allocate memory
175 | ///
176 | /// status
177 | bool send_irp_perform_allocation()
178 | {
179 | PDEVICE_OBJECT airhv_device_object;
180 | KEVENT event;
181 | PIRP irp;
182 | IO_STATUS_BLOCK io_status = { 0 };
183 | UNICODE_STRING airhv_name;
184 | PFILE_OBJECT file_object;
185 |
186 | RtlInitUnicodeString(&airhv_name, L"\\Device\\airhv");
187 |
188 | NTSTATUS status = IoGetDeviceObjectPointer(&airhv_name, 0, &file_object, &airhv_device_object);
189 |
190 | ObReferenceObjectByPointer(airhv_device_object, FILE_ALL_ACCESS, NULL, KernelMode);
191 |
192 | // We don't need this so we instantly dereference file object
193 | ObDereferenceObject(file_object);
194 |
195 | if (NT_SUCCESS(status) == false)
196 | {
197 | LogError("Couldn't get hypervisor device object pointer");
198 | return false;
199 | }
200 |
201 | KeInitializeEvent(&event, NotificationEvent, 0);
202 | irp = IoBuildDeviceIoControlRequest(IOCTL_POOL_MANAGER_ALLOCATE, airhv_device_object, 0, 0, 0, 0, 0, &event, &io_status);
203 |
204 | if (irp == NULL)
205 | {
206 | LogError("Couldn't create Irp");
207 | ObDereferenceObject(airhv_device_object);
208 | return false;
209 | }
210 |
211 | else
212 | {
213 | status = IofCallDriver(airhv_device_object, irp);
214 |
215 | if (status == STATUS_PENDING)
216 | KeWaitForSingleObject(&event, Executive, KernelMode, 0, 0);
217 |
218 | ObDereferenceObject(airhv_device_object);
219 | return true;
220 | }
221 | }
222 | }
--------------------------------------------------------------------------------
/airhvctrl/hypervisor_gateway.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | namespace hvgt
4 | {
5 | ///
6 | /// Turn off virtual machine
7 | ///
8 | void vmoff();
9 |
10 | ///
11 | /// Set/Unset presence of hypervisor
12 | ///
13 | /// If false, hypervisor is not visible via cpuid interface, If true, it become visible
14 | void hypervisor_visible(bool value);
15 |
16 | ///
17 | /// Unhook all pages and invalidate tlb
18 | ///
19 | /// status
20 | bool unhook_all_functions();
21 |
22 | ///
23 | /// Unhook single page and invalidate tlb
24 | ///
25 | ///
26 | /// status
27 | bool unhook_function(void* function_address);
28 |
29 | ///
30 | /// Hook function via ept and invalidates mappings
31 | ///
32 | /// Address of function which we want to hook
33 | /// Address of function which is used to call original function
34 | /// Address of function which is used to call original function
35 | /// status
36 | bool hook_function(void* target_address, void* hook_function, void** origin_function);
37 |
38 | ///
39 | /// Check if we can communicate with hypervisor
40 | ///
41 | /// status
42 | bool test_vmcall();
43 |
44 | ///
45 | /// Send irp with information to allocate memory
46 | ///
47 | /// status
48 | bool send_irp_perform_allocation();
49 |
50 | ///
51 | /// Dump info about allocated pools (Use Dbgview to see information)
52 | ///
53 | void dump_pool_manager();
54 | }
--------------------------------------------------------------------------------
/airhvctrl/log.cpp:
--------------------------------------------------------------------------------
1 | #define _NO_CRT_STDIO_INLINE
2 | #include
3 | #include
4 | #include
5 | #include "log.h"
6 |
7 | void LogPrint(__log_type type, const char* fmt, ...)
8 | {
9 | char* LogType = NULL;
10 | LARGE_INTEGER SystemTime = {};
11 | LARGE_INTEGER LocalTime = {};
12 | TIME_FIELDS TimeFields = {};
13 | char TimeBuffer[20] = {};
14 | char MessageBuffer[412] = {};
15 | char* OutputFormat = NULL;
16 | char OutputBuffer[512] = {};
17 | va_list Args = {};
18 |
19 | switch (type)
20 | {
21 | case LOG_TYPE_DEBUG:
22 | {
23 | LogType = "[DEBUG]";
24 | break;
25 | }
26 | case LOG_TYPE_DUMP:
27 | {
28 | LogType = "[DUMP]";
29 | break;
30 | }
31 | case LOG_TYPE_ERROR:
32 | {
33 | LogType = "[ERROR]";
34 | ; break;
35 | }
36 | case LOG_TYPE_INFO:
37 | {
38 | LogType = "[INFORMATION]";
39 | break;
40 | }
41 | default:
42 | {
43 | break;
44 | }
45 |
46 | }
47 |
48 | KeQuerySystemTime(&SystemTime);
49 | ExSystemTimeToLocalTime(&SystemTime, &LocalTime);
50 | RtlTimeToTimeFields(&LocalTime, &TimeFields);
51 |
52 | RtlStringCchPrintfA(
53 | TimeBuffer,
54 | sizeof(TimeBuffer),
55 | "[%02hd:%02hd:%02hd.%03hd]",
56 | TimeFields.Hour,
57 | TimeFields.Minute,
58 | TimeFields.Second,
59 | TimeFields.Milliseconds);
60 |
61 | va_start(Args, fmt);
62 | RtlStringCchVPrintfA(MessageBuffer, sizeof(MessageBuffer), fmt, Args);
63 | va_end(Args);
64 |
65 | OutputFormat = "%s %s %s\r\n";
66 |
67 | RtlStringCchPrintfA(
68 | OutputBuffer,
69 | sizeof(OutputBuffer),
70 | OutputFormat,
71 | TimeBuffer,
72 | LogType,
73 | MessageBuffer);
74 |
75 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "%s", OutputBuffer);
76 | }
--------------------------------------------------------------------------------
/airhvctrl/log.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #define LogError(format, ...) \
3 | LogPrint(LOG_TYPE_ERROR," [%s:%d] " format , __func__, __LINE__, __VA_ARGS__)
4 | #define LogDebug(format, ...) \
5 | LogPrint(LOG_TYPE_DEBUG," [%s:%d] " format , __func__, __LINE__, __VA_ARGS__)
6 | #define LogDump(format, ...) \
7 | LogPrint(LOG_TYPE_DUMP," [%s:%d] " format , __func__, __LINE__, __VA_ARGS__)
8 | #define LogInfo(format, ...) \
9 | LogPrint(LOG_TYPE_INFO," [%s:%d] " format , __func__, __LINE__, __VA_ARGS__)
10 |
11 | enum __log_type
12 | {
13 | LOG_TYPE_DEBUG,
14 | LOG_TYPE_ERROR,
15 | LOG_TYPE_DUMP,
16 | LOG_TYPE_INFO
17 | };
18 |
19 | void LogPrint(__log_type type, const char* fmt, ...);
--------------------------------------------------------------------------------
/airhvctrl/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include "hypervisor_gateway.h"
3 | #include "log.h"
4 |
5 | extern void* kernel_code_caves[200];
6 |
7 | void* nt_create_file_address;
8 |
9 | NTSTATUS(*original_nt_create_file)(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes,
10 | PIO_STATUS_BLOCK IoStatusBlock, PLARGE_INTEGER AllocationSize, ULONG FileAttributes,
11 | ULONG ShareAccess, ULONG CreateDisposition, ULONG CreateOptions, PVOID EaBuffer, ULONG EaLength
12 | );
13 |
14 |
15 | NTSTATUS NTAPI hooked_nt_create_file(
16 | PHANDLE FileHandle,
17 | ACCESS_MASK DesiredAccess,
18 | POBJECT_ATTRIBUTES ObjectAttributes,
19 | PIO_STATUS_BLOCK IoStatusBlock,
20 | PLARGE_INTEGER AllocationSize,
21 | ULONG FileAttributes,
22 | ULONG ShareAccess,
23 | ULONG CreateDisposition,
24 | ULONG CreateOptions,
25 | PVOID EaBuffer,
26 | ULONG EaLength
27 | )
28 | {
29 | __try
30 | {
31 | ProbeForRead(FileHandle, sizeof(HANDLE), 1);
32 | ProbeForRead(ObjectAttributes, sizeof(OBJECT_ATTRIBUTES), 1);
33 | ProbeForRead(ObjectAttributes->ObjectName, sizeof(UNICODE_STRING), 1);
34 | ProbeForRead(ObjectAttributes->ObjectName->Buffer, ObjectAttributes->ObjectName->Length, 1);
35 | if (wcsstr(ObjectAttributes->ObjectName->Buffer, L"test.txt") != NULL)
36 | {
37 | return STATUS_INVALID_BUFFER_SIZE;
38 | }
39 | }
40 | __except (EXCEPTION_EXECUTE_HANDLER)
41 | {
42 |
43 | }
44 | return original_nt_create_file(FileHandle, DesiredAccess, ObjectAttributes, IoStatusBlock, AllocationSize, FileAttributes, ShareAccess, CreateDisposition, CreateOptions, EaBuffer, EaLength);
45 | }
46 |
47 | VOID driver_unload(PDRIVER_OBJECT driver_object)
48 | {
49 | UNICODE_STRING dos_device_name;
50 |
51 | hvgt::unhook_function(nt_create_file_address);
52 |
53 | RtlInitUnicodeString(&dos_device_name, L"\\DosDevices\\airhvctrl");
54 | IoDeleteSymbolicLink(&dos_device_name);
55 | IoDeleteDevice(driver_object->DeviceObject);
56 | }
57 |
58 | NTSTATUS driver_create_close(_In_ PDEVICE_OBJECT device_object, _In_ PIRP irp)
59 | {
60 | UNREFERENCED_PARAMETER(device_object);
61 |
62 | irp->IoStatus.Status = STATUS_SUCCESS;
63 | irp->IoStatus.Information = 0;
64 |
65 | IoCompleteRequest(irp, IO_NO_INCREMENT);
66 |
67 | return STATUS_SUCCESS;
68 | }
69 |
70 | NTSTATUS driver_ioctl_dispatcher(_In_ PDEVICE_OBJECT device_object, _In_ PIRP irp)
71 | {
72 | UNREFERENCED_PARAMETER(device_object);
73 | unsigned __int32 bytes_io = 0;
74 |
75 | NTSTATUS status = STATUS_SUCCESS;
76 |
77 | irp->IoStatus.Status = status;
78 | irp->IoStatus.Information = bytes_io;
79 |
80 | IoCompleteRequest(irp, IO_NO_INCREMENT);
81 | return status;
82 | }
83 |
84 | extern "C"
85 | NTSTATUS DriverEntry(PDRIVER_OBJECT driver_object, PCUNICODE_STRING reg)
86 | {
87 | UNREFERENCED_PARAMETER(reg);
88 |
89 | NTSTATUS status = STATUS_SUCCESS;
90 | PDEVICE_OBJECT device_oject = 0;
91 | UNICODE_STRING driver_name, dos_device_name;
92 |
93 | RtlInitUnicodeString(&driver_name, L"\\Device\\airhvctrl");
94 | RtlInitUnicodeString(&dos_device_name, L"\\DosDevices\\airhvctrl");
95 |
96 | status = IoCreateDevice(driver_object, 0, &driver_name, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &device_oject);
97 |
98 | if (status == STATUS_SUCCESS)
99 | {
100 | driver_object->MajorFunction[IRP_MJ_CLOSE] = driver_create_close;
101 | driver_object->MajorFunction[IRP_MJ_CREATE] = driver_create_close;
102 | driver_object->MajorFunction[IRP_MJ_DEVICE_CONTROL] = driver_ioctl_dispatcher;
103 |
104 | driver_object->DriverUnload = driver_unload;
105 | driver_object->Flags |= DO_BUFFERED_IO;
106 | IoCreateSymbolicLink(&dos_device_name, &driver_name);
107 | }
108 |
109 | UNICODE_STRING routine_name;
110 | RtlInitUnicodeString(&routine_name,L"NtCreateFile");
111 |
112 | // Get address of NtCreateFile syscall
113 | nt_create_file_address = MmGetSystemRoutineAddress(&routine_name);
114 | if (!nt_create_file_address)
115 | {
116 | LogError("Couldn't find NtCreateFile address");
117 | return STATUS_UNSUCCESSFUL;
118 | }
119 |
120 | // 1 byte hook by using icebp instruction
121 | if (!hvgt::hook_function(nt_create_file_address, hooked_nt_create_file, (void**)&original_nt_create_file))
122 | {
123 | LogError("Couldn't hook NtCreateFile");
124 | return STATUS_UNSUCCESSFUL;
125 | }
126 |
127 | // Send information to hypervisor to allocate new pools
128 | hvgt::send_irp_perform_allocation();
129 |
130 | return status;
131 | }
--------------------------------------------------------------------------------
/airhvctrl/nt.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 |
4 | typedef enum _SYSTEM_INFORMATION_CLASS
5 | {
6 | SystemBasicInformation = 0,
7 | SystemPerformanceInformation = 2,
8 | SystemTimeOfDayInformation = 3,
9 | SystemProcessInformation = 5,
10 | SystemExtendedProcessInformation = 6,
11 | SystemProcessorPerformanceInformation = 8,
12 | SystemModuleInformation = 11,
13 | SystemInterruptInformation = 23,
14 | SystemExceptionInformation = 33,
15 | SystemKernelDebuggerInformation = 35,
16 | SystemRegistryQuotaInformation = 37,
17 | SystemLookasideInformation = 45,
18 | SystemFullProcessInformation = 148
19 | } SYSTEM_INFORMATION_CLASS;
20 |
21 | extern "C"
22 | {
23 | NTKERNELAPI NTSTATUS NTAPI ZwQuerySystemInformation
24 | (
25 | IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
26 | OUT PVOID SystemInformation,
27 | IN ULONG SystemInformationLength,
28 | OUT PULONG ReturnLength OPTIONAL
29 | );
30 | }
31 |
32 | typedef struct _SYSTEM_MODULE_ENTRY {
33 | HANDLE Section;
34 | PVOID MappedBase;
35 | PVOID ImageBase;
36 | ULONG ImageSize;
37 | ULONG Flags;
38 | USHORT LoadOrderIndex;
39 | USHORT InitOrderIndex;
40 | USHORT LoadCount;
41 | USHORT OffsetToFileName;
42 | UCHAR FullPathName[256];
43 | } SYSTEM_MODULE_ENTRY, * PSYSTEM_MODULE_ENTRY;
44 |
45 | typedef struct _SYSTEM_MODULE {
46 | PVOID Reserved1;
47 | PVOID Reserved2;
48 | PVOID ImageBaseAddress;
49 | ULONG ImageSize;
50 | ULONG Flags;
51 | unsigned short Id;
52 | unsigned short Rank;
53 | unsigned short Unknown;
54 | unsigned short NameOffset;
55 | unsigned char Name[MAXIMUM_FILENAME_LENGTH];
56 | } SYSTEM_MODULE, * PSYSTEM_MODULE;
57 |
58 | typedef struct _SYSTEM_MODULE_INFORMATION {
59 | ULONG ModulesCount;
60 | SYSTEM_MODULE_ENTRY Modules[1];
61 | ULONG Count;
62 | SYSTEM_MODULE Sys_Modules[1];
63 | } SYSTEM_MODULE_INFORMATION, * PSYSTEM_MODULE_INFORMATION;
--------------------------------------------------------------------------------
/airhvctrl/vmintrin.asm:
--------------------------------------------------------------------------------
1 | .CODE
2 |
3 | __vm_call proc
4 | mov rax,0CDAEFAEDBBAEBEEFh
5 | vmcall
6 | ret
7 | __vm_call endp
8 |
9 | __vm_call_ex proc
10 | mov rax,0CDAEFAEDBBAEBEEFh ; Our vmcall indentitifer
11 |
12 | sub rsp, 30h
13 | mov qword ptr [rsp], r10
14 | mov qword ptr [rsp + 8h], r11
15 | mov qword ptr [rsp + 10h], r12
16 | mov qword ptr [rsp + 18h], r13
17 | mov qword ptr [rsp + 20h], r14
18 | mov qword ptr [rsp + 28h], r15
19 |
20 | mov r10, qword ptr [rsp + 58h]
21 | mov r11, qword ptr [rsp + 60h]
22 | mov r12, qword ptr [rsp + 68h]
23 | mov r13, qword ptr [rsp + 70h]
24 | mov r14, qword ptr [rsp + 78h]
25 | mov r15, qword ptr [rsp + 80h]
26 |
27 | vmcall
28 | mov r10, qword ptr [rsp]
29 | mov r11, qword ptr [rsp + 8h]
30 | mov r12, qword ptr [rsp + 10h]
31 | mov r13, qword ptr [rsp + 18h]
32 | mov r14, qword ptr [rsp + 20h]
33 | mov r15, qword ptr [rsp + 28h]
34 | add rsp, 30h
35 |
36 | ret
37 | __vm_call_ex endp
38 |
39 | END
--------------------------------------------------------------------------------