HyperDbg Debugger
Loading...
Searching...
No Matches
IoHandler.c File Reference

The I/O Handler for vm-exit. More...

#include "pch.h"

Functions

VOID IoHandleIoVmExits (VIRTUAL_MACHINE_STATE *VCpu, VMX_EXIT_QUALIFICATION_IO_INSTRUCTION IoQualification, RFLAGS Flags)
 VM-Exit handler for I/O Instructions (in/out)
 
BOOLEAN IoHandleSetIoBitmap (VIRTUAL_MACHINE_STATE *VCpu, UINT32 Port)
 Set bits in I/O Bitmap.
 
VOID IoHandlePerformIoBitmapChange (VIRTUAL_MACHINE_STATE *VCpu, UINT32 Port)
 Change I/O Bitmap.
 
VOID IoHandlePerformIoBitmapReset (VIRTUAL_MACHINE_STATE *VCpu)
 Reset I/O Bitmap.
 

Detailed Description

The I/O Handler for vm-exit.

Author
Sina Karvandi (sina@.nosp@m.hype.nosp@m.rdbg..nosp@m.org)
Version
0.1
Date
2020-06-06

Function Documentation

◆ IoHandleIoVmExits()

VOID IoHandleIoVmExits ( VIRTUAL_MACHINE_STATE * VCpu,
VMX_EXIT_QUALIFICATION_IO_INSTRUCTION IoQualification,
RFLAGS Flags )

VM-Exit handler for I/O Instructions (in/out)

Parameters
VCpuThe virtual processor's state
IoQualificationThe I/O Qualification that indicates the instruction
FlagsGuest's RFLAGs
Returns
VOID
25{
26 UINT16 Port = 0;
27 UINT32 Count = 0;
28 UINT32 Size = 0;
29 PGUEST_REGS GuestRegs = VCpu->Regs;
30
31 //
32 // VMWare tools uses port (port 0x5658/0x5659) as I/O backdoor
33 // This function will not handle these cases so if you put bitmap
34 // to cause vm-exit on port 0x5658/0x5659 then VMWare tools will
35 // crash
36 //
37
38 union
39 {
40 unsigned char * AsBytePtr;
41 unsigned short * AsWordPtr;
42 unsigned long * AsDwordPtr;
43
44 void * AsPtr;
45 UINT64 AsUint64;
46
47 } PortValue;
48
49 //
50 // The I/O Implementation is derived from Petr Benes's hvpp
51 // Take a look at :
52 // https://github.com/wbenny/hvpp/blob/f1eece7d0def506f329b5770befd892497be2047/src/hvpp/hvpp/vmexit/vmexit_passthrough.cpp
53 //
54
55 //
56 // We don't check if CPL == 0 here, because the CPU would
57 // raise #GP instead of VM-exit.
58 //
59 // See Vol3C[25.1.1(Relative Priority of Faults and VM Exits)]
60 //
61
62 //
63 // Resolve address of the source or destination.
64 //
65 if (IoQualification.StringInstruction)
66 {
67 //
68 // String operations always operate either on RDI (in) or
69 // RSI (out) registers.
70 //
71 PortValue.AsPtr = (PVOID)(IoQualification.DirectionOfAccess == AccessIn ? GuestRegs->rdi : GuestRegs->rsi);
72 }
73 else
74 {
75 //
76 // Save pointer to the RAX register.
77 //
78 PortValue.AsPtr = &GuestRegs->rax;
79 }
80
81 //
82 // Resolve port as a nice 16-bit number.
83 //
84 Port = (UINT16)IoQualification.PortNumber;
85
86 //
87 // Resolve number of bytes to send/receive.
88 // REP prefixed instructions always take their count
89 // from *CX register.
90 //
91 Count = IoQualification.RepPrefixed ? (GuestRegs->rcx & 0xffffffff) : 1;
92
93 Size = (UINT32)(IoQualification.SizeOfAccess + 1);
94
95 switch (IoQualification.DirectionOfAccess)
96 {
97 case AccessIn:
98 if (IoQualification.StringInstruction)
99 {
100 switch (Size)
101 {
102 case 1:
103 IoInByteString(Port, (UINT8 *)PortValue.AsBytePtr, Count);
104 break;
105 case 2:
106 IoInWordString(Port, (UINT16 *)PortValue.AsWordPtr, Count);
107 break;
108 case 4:
109 IoInDwordString(Port, (UINT32 *)PortValue.AsDwordPtr, Count);
110 break;
111 }
112 }
113 else
114 {
115 //
116 // Note that port_value holds pointer to the
117 // vp.context().rax member, therefore we're
118 // directly overwriting the RAX value.
119 //
120 switch (Size)
121 {
122 case 1:
123 *PortValue.AsBytePtr = IoInByte(Port);
124 break;
125 case 2:
126 *PortValue.AsWordPtr = IoInWord(Port);
127 break;
128 case 4:
129 *PortValue.AsDwordPtr = IoInDword(Port);
130 break;
131 }
132 }
133 break;
134
135 case AccessOut:
136 if (IoQualification.StringInstruction)
137 {
138 switch (Size)
139 {
140 case 1:
141 IoOutByteString(Port, (UINT8 *)PortValue.AsBytePtr, Count);
142 break;
143 case 2:
144 IoOutWordString(Port, (UINT16 *)PortValue.AsWordPtr, Count);
145 break;
146 case 4:
147 IoOutDwordString(Port, (UINT32 *)PortValue.AsDwordPtr, Count);
148 break;
149 }
150 }
151 else
152 {
153 //
154 // Note that port_value holds pointer to the
155 // vp.context().rax member, therefore we're
156 // directly reading from the RAX value.
157 //
158 switch (Size)
159 {
160 case 1:
161 IoOutByte(Port, *PortValue.AsBytePtr);
162 break;
163 case 2:
164 IoOutWord(Port, *PortValue.AsWordPtr);
165 break;
166 case 4:
167 IoOutDword(Port, *PortValue.AsDwordPtr);
168 break;
169 }
170 }
171 break;
172 }
173
174 if (IoQualification.StringInstruction)
175 {
176 //
177 // Update register:
178 // If the DF (direction flag) is set, decrement,
179 // otherwise increment.
180 //
181 // For in the register is RDI, for out it's RSI.
182 //
183 UINT64 GpReg = IoQualification.DirectionOfAccess == AccessIn ? GuestRegs->rdi : GuestRegs->rsi;
184
185 if (Flags.DirectionFlag)
186 {
187 GpReg -= Count * Size;
188 }
189 else
190 {
191 GpReg += Count * Size;
192 }
193
194 //
195 // We've sent/received everything, reset counter register
196 // to 0.
197 //
198 if (IoQualification.RepPrefixed)
199 {
200 GuestRegs->rcx = 0;
201 }
202 }
203}
unsigned short UINT16
Definition BasicTypes.h:47
unsigned __int64 UINT64
Definition BasicTypes.h:21
unsigned char UINT8
Definition BasicTypes.h:46
unsigned int UINT32
Definition BasicTypes.h:48
UINT32 IoInDword(UINT16 port)
Definition IoHandler.h:67
void IoOutWord(UINT16 port, UINT16 value)
Definition IoHandler.h:117
void IoInDwordString(UINT16 port, UINT32 *data, UINT32 size)
Definition IoHandler.h:97
@ AccessOut
Definition IoHandler.h:24
@ AccessIn
Definition IoHandler.h:25
void IoOutByteString(UINT16 port, UINT8 *data, UINT32 count)
Definition IoHandler.h:137
UINT16 IoInWord(UINT16 port)
Definition IoHandler.h:57
void IoOutWordString(UINT16 port, UINT16 *data, UINT32 count)
Definition IoHandler.h:147
UINT8 IoInByte(UINT16 port)
Definition IoHandler.h:47
void IoOutByte(UINT16 port, UINT8 value)
Definition IoHandler.h:107
void IoOutDword(UINT16 port, UINT32 value)
Definition IoHandler.h:127
void IoInByteString(UINT16 port, UINT8 *data, UINT32 size)
Definition IoHandler.h:77
void IoInWordString(UINT16 port, UINT16 *data, UINT32 size)
Definition IoHandler.h:87
void IoOutDwordString(UINT16 port, UINT32 *data, UINT32 count)
Definition IoHandler.h:157
GUEST_REGS * Regs
Definition State.h:305
Definition BasicTypes.h:70
UINT64 rdi
Definition BasicTypes.h:82
UINT64 rax
Definition BasicTypes.h:75
UINT64 rcx
Definition BasicTypes.h:76
UINT64 rsi
Definition BasicTypes.h:81

◆ IoHandlePerformIoBitmapChange()

VOID IoHandlePerformIoBitmapChange ( VIRTUAL_MACHINE_STATE * VCpu,
UINT32 Port )

Change I/O Bitmap.

should be called in vmx-root mode

Parameters
VCpuThe virtual processor's state
IoPortPort
Returns
VOID
242{
243 if (Port == DEBUGGER_EVENT_ALL_IO_PORTS)
244 {
245 //
246 // Means all the bitmaps should be put to 1
247 //
248 memset((void *)VCpu->IoBitmapVirtualAddressA, 0xFF, PAGE_SIZE);
249 memset((void *)VCpu->IoBitmapVirtualAddressB, 0xFF, PAGE_SIZE);
250 }
251 else
252 {
253 //
254 // Means only one i/o bitmap is target
255 //
256 IoHandleSetIoBitmap(VCpu, Port);
257 }
258}
#define DEBUGGER_EVENT_ALL_IO_PORTS
Apply to all I/O ports.
Definition Constants.h:641
BOOLEAN IoHandleSetIoBitmap(VIRTUAL_MACHINE_STATE *VCpu, UINT32 Port)
Set bits in I/O Bitmap.
Definition IoHandler.c:214
#define PAGE_SIZE
Size of each page (4096 bytes)
Definition common.h:69
UINT64 IoBitmapVirtualAddressB
Definition State.h:319
UINT64 IoBitmapVirtualAddressA
Definition State.h:317

◆ IoHandlePerformIoBitmapReset()

VOID IoHandlePerformIoBitmapReset ( VIRTUAL_MACHINE_STATE * VCpu)

Reset I/O Bitmap.

should be called in vmx-root mode

Parameters
VCpuThe virtual processor's state
Returns
VOID
269{
270 //
271 // Means all the bitmaps should be put to 0
272 //
273 memset((void *)VCpu->IoBitmapVirtualAddressA, 0x0, PAGE_SIZE);
274 memset((void *)VCpu->IoBitmapVirtualAddressB, 0x0, PAGE_SIZE);
275}

◆ IoHandleSetIoBitmap()

BOOLEAN IoHandleSetIoBitmap ( VIRTUAL_MACHINE_STATE * VCpu,
UINT32 Port )

Set bits in I/O Bitmap.

Parameters
VCpuThe virtual processor's state
PortPort
Returns
BOOLEAN Returns true if the I/O Bitmap is successfully applied or false if not applied
215{
216 if (Port <= 0x7FFF)
217 {
218 SetBit(Port, (unsigned long *)VCpu->IoBitmapVirtualAddressA);
219 }
220 else if ((0x8000 <= Port) && (Port <= 0xFFFF))
221 {
222 SetBit(Port - 0x8000, (unsigned long *)VCpu->IoBitmapVirtualAddressB);
223 }
224 else
225 {
226 return FALSE;
227 }
228
229 return TRUE;
230}
#define TRUE
Definition BasicTypes.h:55
#define FALSE
Definition BasicTypes.h:54
void SetBit(int BitNumber, unsigned long *addr)
set the bit
Definition Bitwise.c:46