diff --git a/64-ia-32-architectures-software-developer-vol-3c-part-3-manual.pdf b/64-ia-32-architectures-software-developer-vol-3c-part-3-manual.pdf new file mode 100644 index 0000000..d09619e Binary files /dev/null and b/64-ia-32-architectures-software-developer-vol-3c-part-3-manual.pdf differ diff --git a/README.md b/README.md index 8a26072..2580868 100644 --- a/README.md +++ b/README.md @@ -5,10 +5,23 @@ # Bluepill -Bluepill is an Intel type-2 research hypervisor written with no access to github.com. This project is purely for educational purposes and is designed to run on Windows 10 systems. +Bluepill is an Intel type-2 research hypervisor. This project is purely for educational purposes and is designed to run on Windows 10 systems. This project uses WDK and thus Windows Kernel functions to facilitate vmxlaunch. ### VMCS -Dump of VMCS control fields can be found [here](https://githacks.org/_xeroxz/bluepill/-/blob/master/VMCS.md). This is not required, but for learning its nice to -see exactly what the MSR masks are, and what VMCS field's are enabled after you apply high/low bit masks. \ No newline at end of file +This section of the readme just contains notes and a list of things I stumbled on and took me a while to figure out and fix. + +##### VMCS Controls + +* One of the mistakes I made early on was setting bits high after applying high/low MSR values. For example my xeons dont support Intel Processor Trace (Intel PT) and I was setting `entry_ctls.conceal_vmx_from_pt = true` after applying the MSR high/low masks. This caused vmxerror #7 (invalid vmcs controls). Now i set the bit high before i apply the high/low bit mask so if my hypervisor runs on a cpu that has Intel PT support it will be concealed from Intel PT. +* My xeons also dont support xsave/xrstor and I was setting enable_xsave in secondary processor based vmexit controls after applying `IA32_VMX_PROCBASED_CTLS2` high/low bitmask. Which caused vmxerror #7 (invalid vmcs controls). + +Dump of VMCS control fields can be found [here](https://githacks.org/_xeroxz/bluepill/-/blob/master/VMCS-CONTROLS.md). This is not required, but for learning its nice to +see exactly what the MSR masks are, and what VMCS field's are enabled after you apply high/low bit masks. + +##### VMCS Guest State + +* After getting my first vmexit the exit reason was 0x80000021 (invalid guest state). I thought it was segmentation code since I've never done anything with segments before but after a few days of checking every single segment check in chapter 26 section 3, I continued reading the guest requirements in chapter 24 section 4, part 2 goes over non-register states and I was not setting any of these `VMCS_GUEST_ACTIVITY_STATE`, `VMCS_GUEST_INTERRUPTIBILITY_STATE`, or `VMCS_GUEST_PENDING_DEBUG_EXCEPTIONS`. + +Dump of VMCS guest fields can be found [here](https://githacks.org/_xeroxz/bluepill/-/blob/master/VMCS-GUEST.md). \ No newline at end of file diff --git a/VMCS.md b/VMCS-CONTROLS.md similarity index 100% rename from VMCS.md rename to VMCS-CONTROLS.md diff --git a/VMCS-GUEST.md b/VMCS-GUEST.md new file mode 100644 index 0000000..90eaafe --- /dev/null +++ b/VMCS-GUEST.md @@ -0,0 +1,260 @@ +# Intel Processor Info + +``` +Processors: (two xeon cpus) + Processor Intel(R) Xeon(R) CPU X5650 @ 2.67GHz, 2668 Mhz, 6 Core(s), 12 Logical Processor(s) + Processor Intel(R) Xeon(R) CPU X5650 @ 2.67GHz, 2668 Mhz, 6 Core(s), 12 Logical Processor(s) +``` + +# VMCS - Guest Fields + +#### 26.3.1.1 Checks on Guest Control Registers, Debug Registers, and MSRs + +##### Checks on Guest Control Registers + +* The CR0 field must not set any bit to a value not supported in VMX operation (see Section 23.8). The following +are exceptions: :white_check_mark: + + - Bit 0 (corresponding to CR0.PE) and bit 31 (PG) are not checked if the “unrestricted guest” VM-execution +control is 1. + + - Bit 29 (corresponding to CR0.NW) and bit 30 (CD) are never checked because the values of these bits are +not changed by VM entry; see Section 26.3.2.1. + +* The following checks are performed on processors that support Intel 64 architecture: + + - If the “IA-32e mode guest” VM-entry control is 1, bit 31 in the CR0 field (corresponding to CR0.PG) and +bit 5 in the CR4 field (corresponding to CR4.PAE) must each be 1. :white_check_mark: + + - If the “IA-32e mode guest” VM-entry control is 0, bit 17 in the CR4 field (corresponding to CR4.PCIDE) +must be 0. (this value is one in my entry controls) :white_check_mark: + + - The CR3 field must be such that bits 63:52 and bits in the range 51:32 beyond the processor’s physicaladdress +width are 0. :white_check_mark: + +* The CR4 field must not set any bit to a value not supported in VMX operation (see Section 23.8). :white_check_mark: + +``` +guest cr0: 0x0000000080050033 0b1000 0000 0000 0101 0000 0000 0011 0011 +guest cr3: 0x00000000001AD000 +guest cr4: 0x00000000000026F8 0b0010 0110 1111 1000 +``` + +##### Checks on Guest MSRs + +* If the “load debug controls” VM-entry control is 1, bits reserved in the IA32_DEBUGCTL MSR must be 0 in the +field for that register. (this is not set in vm entry control fields in my vmcs...) :white_check_mark: + +* The IA32_SYSENTER_ESP field and the IA32_SYSENTER_EIP field must each contain a canonical address. (this is MSR is zero) :white_check_mark: + +"In 64-bit mode, an address is considered to be in canonical form if address bits 63 through to the most-significant implemented bit by the microarchitecture are set to either all ones or all zeros..." + +``` +VMCS_GUEST_DEBUGCTL: 0x0000000000000000 +VMCS_GUEST_SYSENTER_CS: 0x0000000000000000 +VMCS_GUEST_SYSENTER_EIP: 0x0000000000000000 +VMCS_GUEST_SYSENTER_ESP: 0x0000000000000000 +``` + +#### 26.3.1.2 Checks on Guest Segment Registers + +This section specifies the checks on the fields for CS, SS, DS, ES, FS, GS, TR, and LDTR. + +* Selector fields. + + - TR. The TI flag (bit 2) must be 0. :white_check_mark: + - LDTR. If LDTR is usable, the TI flag (bit 2) must be 0. :white_check_mark: + - SS. If the guest will not be virtual-8086 and the “unrestricted guest” VM-execution control is 0, the RPL :white_check_mark: +(bits 1:0) must equal the RPL of the selector field for CS. :white_check_mark: + + +* Base-address fields. + + - TR, FS, GS. The address must be canonical. :white_check_mark: + - CS. Bits 63:32 of the address must be zero. :white_check_mark: + - SS, DS, ES. If the register is usable, bits 63:32 of the address must be zero. :white_check_mark: + +* Access-rights fields for CS, SS, DS, ES, FS, GS. + + - CS Bits 3:0 (Type): must be 9, 11, 13, or 15 (accessed code segment). :white_check_mark: + - SS. If SS is usable, the Type must be 3 or 7 (read/write, accessed data segment). :white_check_mark: + - DS, ES, FS, GS. The following checks apply if the register is usable :white_check_mark: + - Bit 0 of the Type must be 1 (accessed). :white_check_mark: + - If bit 3 of the Type is 1 (code segment), then bit 1 of the Type must be 1 (readable). :white_check_mark: + - Bit 4 (S). If the register is CS or if the register is usable, S must be 1 :white_check_mark: + +``` +es selector: 0x000000000000002B + - es.index: 5 + - es.request_privilege_level: 3 + - es.table: 0 +es base address: 0x0000000000000000 +es limit: 0x00000000FFFFFFFF +es rights: 0x000000000000C0F3 + - es_rights.available_bit: 0 + - es_rights.default_big: 1 + - es_rights.descriptor_privilege_level: 3 + - es_rights.descriptor_type: 1 + - es_rights.granularity: 1 + - es_rights.long_mode: 0 + - es_rights.present: 1 + - es_rights.type: 3 + - es_rights.unusable: 0 + + +fs selector: 0x0000000000000053 + - fs.index: 10 + - fs.request_privilege_level: 3 + - fs.table: 0 +fs base address: 0x0000000000000000 +fs base (from readmsr): 0x0000000000000000 +fs limit: 0x0000000000003C00 +fs rights: 0x00000000000040F3 + - fs_rights.available_bit: 0 + - fs_rights.default_big: 1 + - fs_rights.descriptor_privilege_level: 3 + - fs_rights.descriptor_type: 1 + - fs_rights.granularity: 0 + - fs_rights.long_mode: 0 + - fs_rights.present: 1 + - fs_rights.type: 3 + - fs_rights.unusable: 0 + + +gs selector: 0x000000000000002B + - gs.index: 5 + - gs.request_privilege_level: 3 + - gs.table: 0 +gs base address: 0x0000000000000000 +gs base (from readmsr): 0xFFFFF80365406000 +gs limit: 0x00000000FFFFFFFF +gs rights: 0x000000000000C0F3 + - gs_rights.available_bit: 0 + - gs_rights.default_big: 1 + - gs_rights.descriptor_privilege_level: 3 + - gs_rights.descriptor_type: 1 + - gs_rights.granularity: 1 + - gs_rights.long_mode: 0 + - gs_rights.present: 1 + - gs_rights.type: 3 + - gs_rights.unusable: 0 + + +ss selector: 0x0000000000000018 + - ss.index: 3 + - ss.request_privilege_level: 0 + - ss.table: 0 +ss base address: 0x0000000000000000 +ss limit: 0x0000000000000000 +ss rights: 0x0000000000004093 + - ss_rights.available_bit: 0 + - ss_rights.default_big: 1 + - ss_rights.descriptor_privilege_level: 0 + - ss_rights.descriptor_type: 1 + - ss_rights.granularity: 0 + - ss_rights.long_mode: 0 + - ss_rights.present: 1 + - ss_rights.type: 3 + - ss_rights.unusable: 0 + + +cs selector: 0x0000000000000010 + - cs.index: 2 + - cs.request_privilege_level: 0 + - cs.table: 0 +cs base address: 0x0000000000000000 +cs limit: 0x0000000000000000 +cs rights: 0x000000000000209B + - cs_rights.available_bit: 0 + - cs_rights.default_big: 0 + - cs_rights.descriptor_privilege_level: 0 + - cs_rights.descriptor_type: 1 + - cs_rights.granularity: 0 + - cs_rights.long_mode: 1 + - cs_rights.present: 1 + - cs_rights.type: 11 + - cs_rights.unusable: 0 + + +ds selector: 0x000000000000002B + - ds.index: 5 + - ds.request_privilege_level: 3 + - ds.table: 0 +ds base address: 0x0000000000000000 +ds limit: 0x00000000FFFFFFFF +ds rights: 0x000000000000C0F3 + - ds_rights.available_bit: 0 + - ds_rights.default_big: 1 + - ds_rights.descriptor_privilege_level: 3 + - ds_rights.descriptor_type: 1 + - ds_rights.granularity: 1 + - ds_rights.long_mode: 0 + - ds_rights.present: 1 + - ds_rights.type: 3 + - ds_rights.unusable: 0 +``` + +* TR Access Rights Checks. The different sub-fields are considered separately: + + - Bits 3:0 (Type). + - If the guest will not be IA-32e mode, the Type must be 3 (16-bit busy TSS) or 11 (32-bit busy +TSS). :white_check_mark: + - If the guest will be IA-32e mode, the Type must be 11 (64-bit busy TSS). :white_check_mark: + + - Bit 4 (S). S must be 0. :white_check_mark: + - Bit 7 (P). P must be 1. :white_check_mark: + - Bits 11:8 (reserved). These bits must all be 0. :white_check_mark: + - Bit 15 (G). + - If any bit in the limit field in the range 11:0 is 0, G must be 0. :white_check_mark: + - If any bit in the limit field in the range 31:20 is 1, G must be 1. :white_check_mark: + - Bit 16 (Unusable). The unusable bit must be 0. :white_check_mark: + - Bits 31:17 (reserved). These bits must all be 0. :white_check_mark: + +``` +tr selector: 0x0000000000000040 + - tr.index: 8 + - tr.request_privilege_level: 0 + - tr.table: 0 +tr base address: 0xFFFFF8036EA5F000 +tr limit: 0x0000000000000067 +tr rights: 0x000000000000008B + - tr_rights.available_bit: 0 + - tr_rights.default_big: 0 + - tr_rights.descriptor_privilege_level: 0 + - tr_rights.descriptor_type: 0 + - tr_rights.granularity: 0 + - tr_rights.long_mode: 0 + - tr_rights.present: 1 + - tr_rights.type: 11 + - tr_rights.unusable: 0 +``` + +* LDTR Access Rights Checks. The following checks on the different sub-fields apply only if LDTR is usable: + + - Bits 3:0 (Type). The Type must be 2 (LDT). :white_check_mark: + - Bit 4 (S). S must be 0. :white_check_mark: + - Bit 7 (P). P must be 1. :white_check_mark: + - Bits 11:8 (reserved). These bits must all be 0. :white_check_mark: + - Bit 15 (G). + - If any bit in the limit field in the range 11:0 is 0, G must be 0. :white_check_mark: + - If any bit in the limit field in the range 31:20 is 1, G must be 1. :white_check_mark: + - Bits 31:17 (reserved). These bits must all be 0. :white_check_mark: + +``` +ldt selector: 0x0000000000000000 + - ldt.index: 0 + - ldt.request_privilege_level: 0 + - ldt.table: 0 +ldt base address: 0xFFFFF8036EA5F000 +ldt limit: 0x0000000000000067 +ldt rights: 0x000000000000008B + - ldt_rights.available_bit: 0 + - ldt_rights.default_big: 0 + - ldt_rights.descriptor_privilege_level: 0 + - ldt_rights.descriptor_type: 0 + - ldt_rights.granularity: 0 + - ldt_rights.long_mode: 0 + - ldt_rights.present: 1 + - ldt_rights.type: 11 + - ldt_rights.unusable: 0 +``` \ No newline at end of file