Geoff Chappell - Software Analyst
The public symbol file NTKRPAMP.PDB for the original release of Windows 10 tells that the kernel is built with the HVGDK_MINI.H header at
d:\th.public.fre\internal\minwin\priv_sdk\inc
and draws from it the following type definitions:
Line Number | Type |
---|---|
449 | union _HV_PARTITION_PRIVILEGE_MASK |
717 | struct _HV_X64_HYPERVISOR_FEATURES |
The header HVGDK_MINI.H is not known in any Device Driver Kit (DDK) or Windows Driver Kit (WDK). There was, however, an HVGDK.H in the WDK for Windows 7. It defines the HV_PARTITION_PRIVILEGE_MASK at line 2653. That’s no small difference. It may mean that the reduction suggested by the MINI suffix was of thousands of lines. More likely, though, is that separating material to another header brought with it a substantial rearrangement.
For the record, Microsoft’s possibly accidental inclusion of private symbol files for URLMON.DLL in downloadable packages of public symbols shows that many more types were accessible to the source code for URLMON.DLL from including HVGDK_MINI.H when building for the original release of 32-bit Windows 10:
Line Number | Type |
---|---|
431 | struct _HV_HYPERVISOR_VERSION_INFO |
449 | union _HV_PARTITION_PRIVILEGE_MASK |
565 | union _HV_X64_PLATFORM_CAPABILITIES |
650 | enum _HV_CPUID_FUNCTION |
689 | struct _HV_VENDOR_AND_MAX_FUNCTION |
700 | struct _HV_HYPERVISOR_INTERFACE_INFO |
717 | struct _HV_X64_HYPERVISOR_FEATURES |
811 | struct _HV_X64_ENLIGHTENMENT_INFORMATION |
885 | struct _HV_IMPLEMENTATION_LIMITS |
917 | struct _HV_X64_HYPERVISOR_HARDWARE_FEATURES |
960 | struct _HV_X64_HYPERVISOR_CPU_MANAGEMENT_FEATURES |
1062 | struct _HV_HYPERVISOR_SVM_FEATURES |
1089 | union _HV_CPUID_RESULT |
1101 | unnamed struct for VersionAndFeatures in
union _HV_CPUID_RESULT |
None of these types are known from headers that Microsoft publishes for either kernel-mode or user-mode programming for Windows 10 by programmers outside Microsoft. Most were not yet defined for Windows 7 and therefore were not published even in the short-lived HVGDK.H. Indeed, most are not disclosed even as type information in other symbol files except for the Windows 8.1 kernel. Aside from the curiosity of their appearance for just one version, there is also that the symbol files for the Windows 8.1 kernel have type information for one enumeration that the symbol files for the Windows 8.1 URLMON do not. This is the HV_HYPERVISOR_INTERFACE. How this happened is not known: more research is required.
The point to singling out URLMON.DLL is of course that it is part of Internet Explorer. It was first distributed with Internet Explorer. Even for Windows 10 its version numbering still follows that of Internet Explorer. Microsoft defended an anti-trust suit that was largely motivated by complaints that Microsoft’s development and distribution of Internet Explorer in competition with other web browsers benefited from Microsoft’s monopoly control of the operating system that these web browsers run on. Among the complaints is that Microsoft’s programmers of Internet Explorer had access to programming resources for Windows that were not available to the programmers of competing web browsers. Plainly they did!
Whether such access got Internet Exlorer any direct benefit is another question. Whether it got an indirect benefit, as with faster or easier development just from knowing more than was explicitly used, is also another question. The evidence here is just that they did have the alleged access and still had it many years after the supposed enforcement of a settlement that ought to have seen the access removed. Either that or the access has been arranged since, which some would say is worse for its surely deliberate contempt of the settlement.
The published symbol files for URLMON.DLL also suggest a little of how HVGDK_MINI.H comes to exist. As noted above, Microsoft published an HVGDK.H for Windows 7 but never for any later version. Also described above from symbol files for Windows 8 and higher, some types that are defined in the Windows 7 HVGDK.H are later defined in HVGDK_MINI.H. The natural supposition is that HVGDK_MINI.H was extracted from HVGDK.H, but does the latter still exist and is the former the only extract? The answers look to be yes and no, respectively.
Symbol files for URLMON.DLL in Windows 8 and higher confirm the continued existence of a header named HVGDK.H and the existence of an otherwise unknown HVGDK_EXT.H. These are not in the same directory as HVGDK_MINI.H. For the original Windows 10, they are instead at
d:\th.public.fre\internal\vm\inc
as if to suggest they are specialised to a “vm” project, separate from the “minkernel” and not as any sort of SDK, private or otherwise. No type definitions are reported from these headers and it may indeed be that URLMON.DLL would be no different if built without access to these headers. What is reported is that the two paths that have the various HVGDK headers are named in -I switches that are given to the compiler only when building source files while the current directory is
d:\th\inetcore\lib\common\iel1_sp
The source files are all in this directory’s parent: strcmpii.cpp, ieisos_sp.cpp, easyclassfactory.cpp, brproc.cpp, handlehelpers.cpp, dxhardwaredenylist.cpp, dxgiadapterwrapper.cpp, gcount.cpp, lrieutil.cpp, privacieutil.cpp, ieprocesshelper.cpp, strutil.cpp, hashtable.cpp, iecrypt.cpp, ieverdetect.cpp, ieisos_phonentimpl.cpp, cmptime.cpp, useraccess.cpp, idllib.cpp, ishost_sp.cpp and arrayimpl.cpp.
The point to the tedium of listing them, aside from noticing that several are plainly named for Internet Explorer, is that this—meaning their names and their inclusion of system-level headers that aren’t generally available to the programmers of web browsers—is what can be learnt from forensic analysis of an Internet Explorer DLL at the distance of having only the symbol files. For supervising Microsoft’s compliance with the anti-trust settlement, the Technical Committee had source code. Whatever this supervision achieved, however it was conducted, it evidently did not establish at Microsoft any persistent caution that Microsoft’s web browser in competition with others must not have the anti-competitive advantage of being programmed with access to definitions for Microsoft’s monopoly product that are withheld from the competitors. It might not be too cynical to suspect that what was established at Microsoft is an attitude that inevitably inadequate supervision lets Microsoft get away with pretty much whatever it wants.
There is here an enduring lesson for governments: advanced technology might still be influenced through business, legal and political mechanisms but it is too advanced for enforcement. Probably everyone knows, but it’s as well to have a record.
The most complete catalogue that I know of types defined in HVGDK_MINI.H is from type information not in any symbol files but in a statically linked library. That object files and libraries (which are essentially archives of object files) can have type information is often overlooked, even by experts at reverse engineering. Type information is retained in only very few libraries that Microsoft publishes for programmers to link their code to. It seems fair to suspect that almost all cases, especially in any WDK or Software Development Kit (SDK), are oversights. Still, they are as openly published as are any symbol files that Microsoft publishes as debugging support. In some ways type information in libraries is better than in symbol files, and in some ways worse. Their forensic value is less because the libraries are typically developed separately from the operating system. Type information in a library is immaterial to the library’s role as supplier of code for a linker’s resolution of external references. Even in a library that is clearly targeted to one version of the operating system, its type information can be a long way out of date, and often is. Against this is that type information in a library or object file is sometimes—rarely, but sometimes—much more extensive than in symbol files because there hasn’t yet been any selection according to use.
Two statically linked libraries in open distribution are known to have type information from compiling HVGDK_MINI.H. One is relatively recent, only for Windows 10 but continuing at least to the 2004 release, and has obvious relevance to the Hypervisor. It is named KDHV.LIB. Microsoft distributes it among the programming samples in the package of Debugging Tools for Windows. If only for the version that targets the original Windows 10, its type information from HVGDK_MINI.H comes from compiling two source files. Their names, kdhvintel.c and kdhvhc.c, likely don’t matter. What does is that the type information is already selected according to what the compiler used for each object. What used means in this context can be surprising, but the essential point is that although the private symbols in this library cover many more hypervisor types than do the public symbols for the kernel, the library is not much of a gold mine.
The other library is. It is named CLFSMGMT.LIB. That it has no obvious relevance to any hypervisor may be why it seems to have escaped the attention of most researchers (including me in 2016 when I first wrote about Hyper-V support). Yet this library knows of HVGDK_MINI.H as far back as Windows Vista—curiously without knowing of HVGDK.H even in the library’s versions for Windows 7. This is a very odd library. Microsoft distributes it only with the SDK, not the WDK. The Windows 10 SDK even puts it in a subdirectory named “um” as if to make explicit that it’s for user-mode programming. Yet the library has kernel-mode code to support the CLFS.SYS file system driver. This mixture of modes may explain the curious way it got built. Still, take its publication as a gift.
What makes CLFSMGMT.LIB a gold mine for hypervisor studies is that its type information from HVGDK_MINI.H comes from precompilation. This type information is therefore not of types that have got used but of types that might get used. Speaking again of the version for the original Windows 10, just for concreteness, the library archives five objects. Four are compiled from C++ source files that are particular to the library’s contribution to its project. Again the names likely don’t matter: public_interface.cpp, managed_log.cpp, managed_client.cpp and log_collection.cpp. Each is compiled using a pre-compiled header. The fifth object in the library, stdpch.obj, is what was precompiled from a (pre-processed) C++ source file named pch_hdr.src to use for the other source files where they would #include stdpch.h.
The lesson here goes several ways. For programmers, even at Microsoft, understand that if you throw everything but the kitchen sink into a precompiled header that you create by compiling a source file into an object file, then the object file contains pretty much everything but the kitchen sink! If the project was to build a library of archived object files, then be sure to exempt this object file from the archive—well, unless you really do mean that reverse engineers should have everything but the kitchen sink. For commentators on reverse engineering, especially if taking the line that information supposedly found by reverse engineering couldn’t possibly have been found without source code, please think a little more about what some techniques of building from source code may let slip into the finished product. For reverse engineers, remember that symbol files aren’t everything. Even a software manufacturer as careful as Microsoft sometimes builds the software in ways that reveal far more than intended.
The table that follows is of user-defined types (classes, enumerations, structures and unions) for which the CLFSMGMT.LIB from the SDK for the original release of Windows 10 shows the type as defined in HVGDK_MINI.H:
Line Number | Type |
---|---|
82 | union _HV_UINT128 |
84 | anonymous struct in union _HV_UINT128 |
97 | struct _HV_UINT256 |
108 | struct _HV_UINT512 |
326 | enum _HV_HYPERVISOR_INTERFACE |
341 | enum _HV_SERVICE_BRANCH |
369 | enum _HV_GUEST_OS_VENDOR |
375 | enum _HV_GUEST_OS_MICROSOFT_IDS |
386 | enum _HV_GUEST_OS_OPENSOURCE_IDS |
401 | union _HV_GUEST_OS_ID_CONTENTS |
404 | anonymous struct in union _HV_GUEST_OS_ID_CONTENTS |
417 | unnamed struct for OpenSource in union _HV_GUEST_OS_ID_CONTENTS |
431 | struct _HV_HYPERVISOR_VERSION_INFO |
449 | union _HV_PARTITION_PRIVILEGE_MASK |
452 | anonymous struct in union _HV_PARTITION_PRIVILEGE_MASK |
565 | union _HV_X64_PLATFORM_CAPABILITIES |
567 | anonymous struct in union _HV_X64_PLATFORM_CAPABILITIES |
650 | enum _HV_CPUID_FUNCTION |
689 | struct _HV_VENDOR_AND_MAX_FUNCTION |
700 | struct _HV_HYPERVISOR_INTERFACE_INFO |
717 | struct _HV_X64_HYPERVISOR_FEATURES |
811 | struct _HV_X64_ENLIGHTENMENT_INFORMATION |
885 | struct _HV_IMPLEMENTATION_LIMITS |
917 | struct _HV_X64_HYPERVISOR_HARDWARE_FEATURES |
960 | struct _HV_X64_HYPERVISOR_CPU_MANAGEMENT_FEATURES |
1062 | struct _HV_HYPERVISOR_SVM_FEATURES |
1089 | union _HV_CPUID_RESULT |
1091 | anonymous struct in union _HV_CPUID_RESULT |
1101 | unnamed struct for VersionAndFeatures in
union _HV_CPUID_RESULT |
1157 | union _HV_X64_MSR_HYPERCALL_CONTENTS |
1160 | anonymous struct in union _HV_X64_MSR_HYPERCALL_CONTENTS |
1183 | union _HV_REGISTER_VP_ASSIST_PAGE |
1186 | anonymous struct in union _HV_REGISTER_VP_ASSIST_PAGE |
1316 | union _HV_X64_MSR_RESET_CONTENTS |
1319 | anonymous struct in union _HV_X64_MSR_RESET_CONTENTS |
1358 | struct _HV_VIRTUAL_APIC_ASSIST |
1360 | anonymous union in struct _HV_VIRTUAL_APIC_ASSIST |
1363 | anonymous struct in anonymous union in struct _HV_VIRTUAL_APIC_ASSIST |
1373 | enum _HV_CALL_CODE |
1979 | union _HV_HYPERCALL_INPUT |
1984 | anonymous struct in union _HV_HYPERCALL_INPUT |
1999 | union _HV_HYPERCALL_OUTPUT |
2004 | anonymous struct in union _HV_HYPERCALL_OUTPUT |
2031 | union _HV_GVA_RANGE_SIMPLE |
2035 | anonymous struct in union _HV_GVA_RANGE_SIMPLE |
2052 | union _HV_GVA_RANGE_EXTENDED |
2056 | anonymous struct in union _HV_GVA_RANGE_EXTENDED |
2078 | anonymous struct in union _HV_GVA_RANGE_EXTENDED |
2108 | union _HV_GVA_RANGE |
2146 | struct _HV_INPUT_FLUSH_VIRTUAL_ADDRESS_SPACE_HEADER |
2160 | struct _HV_INPUT_FLUSH_VIRTUAL_ADDRESS_SPACE |
2171 | struct _HV_INPUT_FLUSH_VIRTUAL_ADDRESS_LIST |
2181 | struct _HV_OUTPUT_GET_PARTITION_ID |
2192 | struct _HV_INPUT_SEND_SYNTHETIC_CLUSTER_IPI |
2244 | union _HV_X64_MSR_REFERENCE_TSC_CONTENTS |
2247 | anonymous struct in union _HV_X64_MSR_REFERENCE_TSC_CONTENTS |
2266 | struct _HV_REFERENCE_TSC_PAGE |
2302 | enum _HV_INTERRUPT_TYPE |
2339 | union _HV_SYNIC_SINT |
2342 | anonymous struct in union _HV_SYNIC_SINT |
2407 | enum _HV_ARCHITECTURE |
2415 | struct _HV_X64_SEGMENT_REGISTER |
2420 | anonymous union in struct _HV_X64_SEGMENT_REGISTER |
2422 | anonymous struct in anonymous union in struct _HV_X64_SEGMENT_REGISTER |
2439 | struct _HV_X64_TABLE_REGISTER |
2453 | union _HV_X64_XSAVE_XFEM_REGISTER |
2457 | anonymous struct in union _HV_X64_XSAVE_XFEM_REGISTER |
2463 | anonymous struct in union _HV_X64_XSAVE_XFEM_REGISTER |
2477 | struct _HV_X64_XSAVE_HEADER |
2503 | union _HV_X64_FP_CONTROL_STATUS_REGISTER |
2506 | anonymous struct in union _HV_X64_FP_CONTROL_STATUS_REGISTER |
2514 | anonymous union in anonymous struct in union _HV_X64_FP_CONTROL_STATUS_REGISTER |
2519 | anonymous struct in anonymous union in anonymous struct in union _HV_X64_FP_CONTROL_STATUS_REGISTER |
2528 | union _HV_X64_XMM_CONTROL_STATUS_REGISTER |
2531 | anonymous struct in union _HV_X64_XMM_CONTROL_STATUS_REGISTER |
2533 | anonymous union in anonymous struct in union _HV_X64_XMM_CONTROL_STATUS_REGISTER |
2538 | anonymous struct in anonymous union in anonymous struct in union _HV_X64_XMM_CONTROL_STATUS_REGISTER |
2549 | union _HV_X64_FP_REGISTER |
2552 | anonymous struct in union _HV_X64_FP_REGISTER |
2561 | union _HV_X64_FP_MMX_REGISTER |
2573 | union _HV_X64_FX_REGISTERS |
2575 | anonymous struct in union _HV_X64_FX_REGISTERS |
2604 | union _HV_X64_X_REGISTERS |
2606 | anonymous struct in union _HV_X64_X_REGISTERS |
2612 | anonymous union in anonymous struct in union _HV_X64_X_REGISTERS |
2645 | union _HV_X64_XSAVE_AREA |
2651 | struct _HV_X64_CONTEXT |
2779 | anonymous union in struct _HV_X64_CONTEXT |
2800 | struct _HV_ARM64_CONTEXT |
2924 | struct _HV_VP_CONTEXT |
2938 | anonymous union in struct _HV_VP_CONTEXT |
2950 | struct _HV_X64_MSR_STIMER_CONFIG_CONTENTS |
2952 | anonymous union in struct _HV_X64_MSR_STIMER_CONFIG_CONTENTS |
2955 | anonymous struct in anonymous union in struct _HV_X64_MSR_STIMER_CONFIG_CONTENTS |
2979 | union _HV_PORT_ID |
2983 | anonymous struct in union _HV_PORT_ID |
3002 | enum _HV_MESSAGE_TYPE |
3061 | union _HV_SYNIC_SIMP |
3064 | anonymous struct in union _HV_SYNIC_SIMP |
3082 | enum HV_EVENTLOG_TYPE |
3094 | struct _HV_EVENTLOG_MESSAGE_PAYLOAD |
3106 | union _HV_MESSAGE_FLAGS |
3109 | anonymous struct in union _HV_MESSAGE_FLAGS |
3120 | struct _HV_MESSAGE_HEADER |
3126 | anonymous union in struct _HV_MESSAGE_HEADER |
3138 | struct _HV_TIMER_MESSAGE_PAYLOAD |
3150 | struct _HV_MESSAGE |
3153 | anonymous union in struct _HV_MESSAGE |
3165 | struct _HV_MESSAGE_PAGE |
3176 | union _HV_X64_MSR_NPIEP_CONFIG_CONTENTS |
3179 | anonymous struct in union _HV_X64_MSR_NPIEP_CONFIG_CONTENTS |
3227 | struct _HV_INPUT_POST_DEBUG_DATA |
3234 | struct _HV_OUTPUT_POST_DEBUG_DATA |
3239 | struct _HV_INPUT_RETRIEVE_DEBUG_DATA |
3246 | struct _HV_OUTPUT_RETRIEVE_DEBUG_DATA |
3253 | struct _HV_DEBUG_NET_DATA |
3271 | struct _HV_INPUT_RESET_DEBUG_SESSION |
3276 | struct _HV_OUTPUT_RESET_DEBUG_SESSION |
3300 | union _HV_CRASH_CTL_REG_CONTENTS |
3303 | anonymous struct in union _HV_CRASH_CTL_REG_CONTENTS |
3336 | union _HV_INPUT_VTL |
3339 | anonymous struct in union _HV_INPUT_VTL |
3351 | struct _HV_INITIAL_VP_CONTEXT |
3425 | union _HV_ENABLE_PARTITION_VTL_FLAGS |
3428 | anonymous struct in union _HV_ENABLE_PARTITION_VTL_FLAGS |
3435 | struct _HV_INPUT_ENABLE_PARTITION_VTL |
3450 | struct _HV_INPUT_DISABLE_PARTITION_VTL |
3465 | struct _HV_INPUT_ENABLE_VP_VTL |
3480 | struct _HV_INPUT_DISABLE_VP_VTL |
3493 | union _HV_VTL_RETURN_INPUT |
3497 | anonymous struct in union _HV_VTL_RETURN_INPUT |
3513 | enum _HV_VTL_MBEC_MODE |
3527 | union _HV_REGISTER_VSM_VP_VTL_CONTROL |
3530 | anonymous struct in union _HV_REGISTER_VSM_VP_VTL_CONTROL |
3546 | union _HV_REGISTER_VSM_CODE_PAGE_OFFSETS |
3549 | anonymous struct in union _HV_REGISTER_VSM_CODE_PAGE_OFFSETS |
3564 | union _HV_REGISTER_VSM_PARTITION_STATUS |
3567 | anonymous struct in union _HV_REGISTER_VSM_PARTITION_STATUS |
3582 | union _HV_REGISTER_VSM_VP_STATUS |
3585 | anonymous struct in union _HV_REGISTER_VSM_VP_STATUS |
3594 | enum _HV_REGISTER_NAME |
3601 | union _HV_REGISTER_VSM_VINA |
3604 | anonymous struct in union _HV_REGISTER_VSM_VINA |
3640 | union _HV_REGISTER_VSM_CAPABILITIES |
3643 | anonymous struct in union _HV_REGISTER_VSM_CAPABILITIES |
3663 | union _HV_REGISTER_VSM_VP_SECURE_VTL_CONFIG |
3666 | anonymous struct in union _HV_REGISTER_VSM_VP_SECURE_VTL_CONFIG |
3681 | union _HV_REGISTER_VSM_PARTITION_CONFIG |
3684 | anonymous struct in union _HV_REGISTER_VSM_PARTITION_CONFIG |
3696 | enum _HV_VTL_ENTRY_REASON |
3717 | struct _HV_VP_VTL_CONTROL |
3730 | unnamed union for VinaStatus in struct _HV_VP_VTL_CONTROL |
3733 | anonymous struct in unnamed union for VinaStatus in struct _HV_VP_VTL_CONTROL |
3749 | anonymous union in struct _HV_VP_VTL_CONTROL |
3751 | anonymous struct in anonymous union in struct _HV_VP_VTL_CONTROL |
3757 | anonymous struct in anonymous union in struct _HV_VP_VTL_CONTROL |
3775 | struct _HV_VP_ASSIST_PAGE |
4363 | union _HV_EXPLICIT_SUSPEND_REGISTER |
4366 | anonymous struct in union _HV_EXPLICIT_SUSPEND_REGISTER |
4369 | anonymous struct in union _HV_EXPLICIT_SUSPEND_REGISTER |
4373 | union _HV_INTERCEPT_SUSPEND_REGISTER |
4383 | union _HV_X64_INTERRUPT_STATE_REGISTER |
4386 | anonymous struct in union _HV_X64_INTERRUPT_STATE_REGISTER |
4396 | enum _HV_X64_PENDING_INTERRUPTION_TYPE |
4403 | union _HV_X64_PENDING_INTERRUPTION_REGISTER |
4406 | anonymous struct in union _HV_X64_PENDING_INTERRUPTION_REGISTER |
4453 | union _HV_REGISTER_VALUE |
4494 | struct _HV_REGISTER_ASSOC |
4501 | struct _HV_INPUT_SET_VP_REGISTERS |
4517 | struct _HV_INPUT_GET_VP_REGISTERS |
4528 | union _HV_REGISTER_CR_INTERCEPT_CONTROL |
4531 | anonymous struct in union _HV_REGISTER_CR_INTERCEPT_CONTROL |
4559 | struct _HV_INPUT_START_VIRTUAL_PROCESSOR |
4569 | struct _HV_INPUT_GET_VP_INDEX_FROM_APIC_ID |
4591 | struct _HV_INPUT_MODIFY_VTL_PROTECTION_MASK |
Not listed above are the types that HVGDK_MINI.H apparently defines in conditional blocks for the 32-bit and 64-bit ARM platforms. These can be found by inspecting the ARM-specific CLFSMGMT.LIB. They fill some of the gaps between the Intel-specific definitions.
For instance, that _HV_X64_HYPERVISOR_FEATURES is defined at line 717 survives into the x86 and x64 builds of the library. These show nothing of a _HV_ARM64_HYPERVISOR_FEATURES, presumably because its definition was eliminated by the preprocessor’s interpretation of some sort of #if directive. The ARM builds similarly miss the X64 structure but show that _HV_ARM64_HYPERVISOR_FEATURES is defined at line 775, i.e., between _HV_X64_HYPERVISOR_FEATURES and _HV_X64_ENLIGHTENMENT_INFORMATION.
It would be a sound guess, but is not knowable from the libraries, that such paired definitions as those of _HV_X64_HYPERVISOR_FEATURES and _HV_AMD64_HYPERVISOR_FEATURES are followed by definitions of macros, in this case HV_HYPERVISOR_FEATURES, that equate to the appropriate type for whichever platform the source code is built for.
That the types have platform-specific names means that conditional compilation to eliminate the “wrong” one causes no error. Conditional compilation does indeed look to have been skipped for _HV_X64_CONTEXT and _HV_AMD64_CONTEXT. Each library for the original Windows 10 has both. This is deliberate, so that both are nested within the multi-platform HV_VP_CONTEXT.