#include "main.h"
#include "vmpaging.h"
#include "vmmhelper.h"
#include "vmeventhandler.h"
#include "osspecific.h"
#include "common.h"
#include "mm.h"
#include "vmcall.h"
#include "msrnames.h"
#include "ultimap.h"
#pragma GCC push_options
#pragma GCC optimize ("O0")
QWORD readMSRSafe(pcpuinfo currentcpuinfo, DWORD msr)
{
volatile QWORD result=0;
currentcpuinfo->LastInterrupt=0;
currentcpuinfo->OnInterrupt.RIP=(volatile void *)&&InterruptFired; currentcpuinfo->OnInterrupt.RSP=getRSP();
result=readMSR(msr);
InterruptFired:
currentcpuinfo->OnInterrupt.RIP=0;
return result;
}
#pragma GCC pop_options
int raisePagefault(pcpuinfo currentcpuinfo, UINT64 address)
{
PFerrorcode errorcode;
errorcode.errorcode=0;
if (isAMD)
{
if (((PSegment_Attribs)(¤tcpuinfo->vmcb->cs_attrib))->DPL==3)
errorcode.US=1;
else
errorcode.US=0;
}
else
{
Access_Rights ssaccessrights;
ssaccessrights.AccessRights=vmread(vm_guest_cs_access_rights);
if (ssaccessrights.DPL==3)
errorcode.US=1;
else
errorcode.US=0;
}
sendstring("Raising pagefault exception\n\r");
if (isAMD)
{
currentcpuinfo->vmcb->CR2=address;
currentcpuinfo->vmcb->inject_Type=3; currentcpuinfo->vmcb->inject_Vector=14; currentcpuinfo->vmcb->inject_Valid=1;
currentcpuinfo->vmcb->inject_ERRORCODE=errorcode.errorcode;
currentcpuinfo->vmcb->inject_EV=1;
currentcpuinfo->vmcb->VMCB_CLEAN_BITS&=~(1 << 9); }
else
{
VMEntry_interruption_information newintinfo;
sendstringf("errorcode.errorcode=%d\n\r",errorcode.errorcode);
newintinfo.interruption_information=0;
newintinfo.interruptvector=14;
newintinfo.type=3; newintinfo.haserrorcode=1;
newintinfo.valid=1;
vmwrite(0x4016, newintinfo.interruption_information); vmwrite(0x4018, errorcode.errorcode); vmwrite(0x401a, vmread(0x440c));
setCR2(address);
}
return 0;
}
int raiseInvalidOpcodeException(pcpuinfo currentcpuinfo)
{
sendstring("Raising Invalid opcode exception\n\r");
if (isAMD)
{
currentcpuinfo->vmcb->inject_Type=3; currentcpuinfo->vmcb->inject_Vector=6; currentcpuinfo->vmcb->inject_Valid=1;
currentcpuinfo->vmcb->inject_EV=0;
}
else
{
VMEntry_interruption_information newintinfo;
newintinfo.interruption_information=0;
newintinfo.interruptvector=6;
newintinfo.type=3; newintinfo.haserrorcode=0; newintinfo.valid=1;
vmwrite(0x4016, (ULONG)newintinfo.interruption_information); vmwrite(0x4018, 0); vmwrite(0x401a, vmread(0x440c)); }
return 0;
}
int raisePrivilege(pcpuinfo currentcpuinfo)
{
Access_Rights accessright;
UINT64 guestrflags=vmread(vm_guest_rflags);
PRFLAGS pguestrflags=(PRFLAGS)&guestrflags;
if (pguestrflags->IF==1) return 1;
pguestrflags->IOPL=0;
vmwrite(0x6820,(UINT64)guestrflags);
vmwrite(vm_guest_cs,vmread(vm_guest_cs) & 0xfffc); vmwrite(vm_guest_ss,vmread(vm_guest_ss) & 0xfffc);
accessright.AccessRights = vmread(vm_guest_cs_access_rights);
accessright.DPL = 0;
vmwrite(vm_guest_cs_access_rights, accessright.AccessRights);
accessright.AccessRights = vmread(vm_guest_ss_access_rights);
accessright.DPL = 0;
vmwrite(vm_guest_ss_access_rights, accessright.AccessRights);
if (currentcpuinfo==NULL)
return 1;
return 0;
}
int change_selectors(pcpuinfo currentcpuinfo, ULONG cs, ULONG ss, ULONG ds, ULONG es, ULONG fs, ULONG gs)
{
PGDT_ENTRY gdt=NULL,ldt=NULL;
UINT64 gdtbase=vmread(0x6816);
ULONG ldtselector=vmread(0x80c);
int notpaged=0;
sendstringf("Inside change_selectors\n\r");
gdt=(PGDT_ENTRY)(UINT64)MapPhysicalMemory(
getPhysicalAddressVM(currentcpuinfo, gdtbase, ¬paged)
,currentcpuinfo->AvailableVirtualAddress
);
if (ldtselector)
{
UINT64 ldtbase;
WORD ldtlimit;
sendstring("ldt is valid, so getting the information\n\r");
ldtbase=(gdt[(ldtselector >> 3)].Base24_31 << 24) + gdt[(ldtselector >> 3)].Base0_23;
ldtlimit=(gdt[(ldtselector >> 3)].Limit16_19 << 16) + gdt[(ldtselector >> 3)].Limit0_15;
ldt=(PGDT_ENTRY)(UINT64)MapPhysicalMemory(getPhysicalAddressVM(currentcpuinfo, ldtbase, ¬paged), currentcpuinfo->AvailableVirtualAddress+0x00200000);
}
vmwrite(0x800,es);
vmwrite(0x802,cs);
vmwrite(0x804,ss);
vmwrite(0x806,ds);
vmwrite(0x808,fs);
vmwrite(0x80a,gs);
vmwrite(0x4800,getSegmentLimit(gdt,ldt,es));
vmwrite(0x4802,getSegmentLimit(gdt,ldt,cs));
vmwrite(0x4804,getSegmentLimit(gdt,ldt,ss));
vmwrite(0x4806,getSegmentLimit(gdt,ldt,ds));
vmwrite(0x4808,getSegmentLimit(gdt,ldt,fs));
vmwrite(0x480a,getSegmentLimit(gdt,ldt,gs));
vmwrite(0x6806,getSegmentBase(gdt,ldt,es));
vmwrite(0x6808,getSegmentBase(gdt,ldt,cs));
vmwrite(0x680a,getSegmentBase(gdt,ldt,ss));
vmwrite(0x680c,getSegmentBase(gdt,ldt,ds));
vmwrite(0x680e,getSegmentBase(gdt,ldt,fs));
vmwrite(0x6810,getSegmentBase(gdt,ldt,gs));
setDescriptorAccessedFlag(gdt,ldt,es);
setDescriptorAccessedFlag(gdt,ldt,cs);
setDescriptorAccessedFlag(gdt,ldt,ss);
setDescriptorAccessedFlag(gdt,ldt,ds);
setDescriptorAccessedFlag(gdt,ldt,fs);
setDescriptorAccessedFlag(gdt,ldt,gs);
vmwrite(0x4814,getSegmentAccessRights(gdt,ldt,es));
vmwrite(0x4816,getSegmentAccessRights(gdt,ldt,cs));
vmwrite(0x4818,getSegmentAccessRights(gdt,ldt,ss));
vmwrite(0x481a,getSegmentAccessRights(gdt,ldt,ds));
vmwrite(0x481c,getSegmentAccessRights(gdt,ldt,fs));
vmwrite(0x481e,getSegmentAccessRights(gdt,ldt,gs));
return 0;
}
void returnFromCR3Callback(pcpuinfo currentcpuinfo, VMRegisters *vmregisters, unsigned long long newcr3)
{
vmregisters->rax=currentcpuinfo->cr3_callback.rax;
vmregisters->rbx=currentcpuinfo->cr3_callback.rbx;
vmregisters->rcx=currentcpuinfo->cr3_callback.rcx;
vmregisters->rdx=currentcpuinfo->cr3_callback.rdx;
vmregisters->rsi=currentcpuinfo->cr3_callback.rsi;
vmregisters->rdi=currentcpuinfo->cr3_callback.rdi;
vmregisters->rbp=currentcpuinfo->cr3_callback.rbp;
vmregisters->r8=currentcpuinfo->cr3_callback.r8;
vmregisters->r9=currentcpuinfo->cr3_callback.r9;
vmregisters->r10=currentcpuinfo->cr3_callback.r10;
vmregisters->r11=currentcpuinfo->cr3_callback.r11;
vmregisters->r12=currentcpuinfo->cr3_callback.r12;
vmregisters->r13=currentcpuinfo->cr3_callback.r13;
vmregisters->r14=currentcpuinfo->cr3_callback.r14;
vmregisters->r15=currentcpuinfo->cr3_callback.r15;
vmwrite(0x800,currentcpuinfo->cr3_callback.es_selector);
vmwrite(0x802,currentcpuinfo->cr3_callback.cs_selector);
vmwrite(0x804,currentcpuinfo->cr3_callback.ss_selector);
vmwrite(0x806,currentcpuinfo->cr3_callback.ds_selector);
vmwrite(0x808,currentcpuinfo->cr3_callback.fs_selector);
vmwrite(0x80a,currentcpuinfo->cr3_callback.gs_selector);
vmwrite(0x4800,currentcpuinfo->cr3_callback.es_limit);
vmwrite(0x4802,currentcpuinfo->cr3_callback.cs_limit);
vmwrite(0x4804,currentcpuinfo->cr3_callback.ss_limit);
vmwrite(0x4806,currentcpuinfo->cr3_callback.ds_limit);
vmwrite(0x4808,currentcpuinfo->cr3_callback.fs_limit);
vmwrite(0x480a,currentcpuinfo->cr3_callback.gs_limit);
vmwrite(0x6806,currentcpuinfo->cr3_callback.es_base);
vmwrite(0x6808,currentcpuinfo->cr3_callback.cs_base);
vmwrite(0x680a,currentcpuinfo->cr3_callback.ss_base);
vmwrite(0x680c,currentcpuinfo->cr3_callback.ds_base);
vmwrite(0x680e,currentcpuinfo->cr3_callback.fs_base);
vmwrite(0x6810,currentcpuinfo->cr3_callback.gs_base);
vmwrite(0x4814,currentcpuinfo->cr3_callback.es_accessrights);
vmwrite(0x4816,currentcpuinfo->cr3_callback.cs_accessrights);
vmwrite(0x4818,currentcpuinfo->cr3_callback.ss_accessrights);
vmwrite(0x481a,currentcpuinfo->cr3_callback.ds_accessrights);
vmwrite(0x481c,currentcpuinfo->cr3_callback.fs_accessrights);
vmwrite(0x481e,currentcpuinfo->cr3_callback.gs_accessrights);
vmwrite(0x681c,currentcpuinfo->cr3_callback.rsp);
vmwrite(0x681e,currentcpuinfo->cr3_callback.rip);
vmwrite(0x6820,currentcpuinfo->cr3_callback.rflags);
vmwrite(0x4824,currentcpuinfo->cr3_callback.interruptability_state);
vmwrite(0x6802, newcr3); currentcpuinfo->cr3_callback.newcr3=newcr3;
if (currentcpuinfo->cr3_callback.newcr3 != currentcpuinfo->guestCR3)
currentcpuinfo->cr3_callback.changedcr3=1;
else
currentcpuinfo->cr3_callback.changedcr3=0;
currentcpuinfo->cr3_callback.called_callback = 0;
}
int _handleVMCall(pcpuinfo currentcpuinfo, VMRegisters *vmregisters)
{
int i;
int error;
UINT64 pagefaultaddress;
ULONG *vmcall_instruction;
#ifdef DEBUG
#endif
nosendchar[getAPICID()]=0;
sendstringf("Handling vm(m)call on cpunr:%d \n\r", currentcpuinfo->cpunr);
if (isAMD)
vmregisters->rax=currentcpuinfo->vmcb->RAX;
if ((ULONG)vmregisters->rdx != Password1)
{
int x;
sendstringf("Invalid Password1. Given=%8 should be %8\n\r",(ULONG)vmregisters->rdx, Password1);
x = raiseInvalidOpcodeException(currentcpuinfo);
sendstringf("return = %d\n\r",x);
return x;
}
sendstringf("Password1 is valid\n\r");
if (currentcpuinfo->virtualTLB == NULL)
allocateVirtualTLB();
sendstringf("currentcpuinfo->AvailableVirtualAddress=%6\n", currentcpuinfo->AvailableVirtualAddress);
sendstringf("vmregisters->rax=%8\n\r", vmregisters->rax);
vmcall_instruction=(ULONG *)mapVMmemory(currentcpuinfo, vmregisters->rax, 12, currentcpuinfo->AvailableVirtualAddress, &error, &pagefaultaddress);
if (error)
{
sendstringf("1: Error. error=%d pagefaultaddress=%8\n\r",error,pagefaultaddress);
if (error==2) return raisePagefault(currentcpuinfo, pagefaultaddress);
return raiseInvalidOpcodeException(currentcpuinfo);
}
sendstringf("Mapped vmcall instruction structure (vmcall_instruction=%x)\n\r",(UINT64)vmcall_instruction);
sendstringf("vmcall_instruction[0]=%x\n\r",vmcall_instruction[0]);
sendstringf("vmcall_instruction[1]=%x\n\r",vmcall_instruction[1]);
sendstringf("vmcall_instruction[2]=%x\n\r",vmcall_instruction[2]);
if ((vmcall_instruction[0]<12) || (vmcall_instruction[1]!=Password2))
{
sendstringf("Invalid password2 or structuresize. Given=%8 should be %8\n\r",vmcall_instruction[1], Password2);
return raiseInvalidOpcodeException(currentcpuinfo);
}
if (vmcall_instruction[0]>12) {
vmcall_instruction=(ULONG *)mapVMmemory(currentcpuinfo, vmregisters->rax, vmcall_instruction[0], currentcpuinfo->AvailableVirtualAddress, &error, &pagefaultaddress);
}
#ifdef DEBUG
int totaldwords = vmcall_instruction[0] / 4;
for (i=3; i<totaldwords; i++)
{
sendstringf("vmcall_instruction[%d]=%x\n\r",i, vmcall_instruction[i]);
}
#endif
if (error)
{
sendstringf("2: Error. error=%d pagefaultaddress=%8\n\r",error,pagefaultaddress);
if (error==2) return raisePagefault(currentcpuinfo, pagefaultaddress);
return raiseInvalidOpcodeException(currentcpuinfo);
}
sendstringf("Handling vmcall command %d\n\r",vmcall_instruction[2]);
switch (vmcall_instruction[2])
{
case VMCALL_GETVERSION: sendstring("Version request\n\r");
vmregisters->rax=0xce000000 + dbvmversion;
break;
case VMCALL_CHANGEPASSWORD: sendstring("Password change\n\r");
Password1 = vmcall_instruction[3];
Password2 = vmcall_instruction[4];
sendstringf("Password1=%8\n\r",Password1);
sendstringf("Password2=%8\n\r",Password2);
vmregisters->rax=0;
break;
case 2: if(isAMD)
{
vmregisters->rax = 0xcedead;
}
else
{
if (memorycloak)
{
break; }
memorycloak = !memorycloak;
vmregisters->rax = memorycloak; }
break;
case VMCALL_READ_PHYSICAL_MEMORY: {
UINT64 PhysicalAddressToReadFrom=*(UINT64 *)&vmcall_instruction[3];
unsigned int size=vmcall_instruction[5];
UINT64 VirtualAddressToWriteTo=*(UINT64 *)&vmcall_instruction[6];
unsigned int noPageFault = vmcall_instruction[8];
unsigned char *Destination;
unsigned char *Source;
sendstringf("Reading physical address %6 and writing it to %6\n\r",PhysicalAddressToReadFrom, VirtualAddressToWriteTo);
sendstringf("noPageFault=%d\n\r",noPageFault);
Source=(unsigned char *)MapPhysicalMemory(PhysicalAddressToReadFrom, currentcpuinfo->AvailableVirtualAddress);
Destination=(unsigned char *)mapVMmemory(currentcpuinfo, VirtualAddressToWriteTo, size, currentcpuinfo->AvailableVirtualAddress+0x00400000, &error, &pagefaultaddress);
if (error)
{
sendstringf("An error occurred while mapping %6 and size %d\n\r",VirtualAddressToWriteTo, size);
if (error==2)
{
if (noPageFault)
size=pagefaultaddress-VirtualAddressToWriteTo;
else
return raisePagefault(currentcpuinfo, pagefaultaddress); }
else
size=0;
}
copymem(Destination, Source, size);
vmregisters->rax = size;
break;
}
case VMCALL_WRITE_PHYSICAL_MEMORY: {
UINT64 PhysicalAddressToWriteTo=*(UINT64 *)&vmcall_instruction[3];
unsigned int size=vmcall_instruction[5];
UINT64 VirtualAddressToReadFrom=*(UINT64 *)&vmcall_instruction[6];
unsigned int noPageFault = vmcall_instruction[8];
unsigned char *Destination;
unsigned char *Source;
Destination=(unsigned char *)MapPhysicalMemory(PhysicalAddressToWriteTo, currentcpuinfo->AvailableVirtualAddress);
Source=(unsigned char *)mapVMmemory(currentcpuinfo, VirtualAddressToReadFrom, size, currentcpuinfo->AvailableVirtualAddress+0x00400000, &error, &pagefaultaddress);
if (error)
{
if (error==2)
{
if (noPageFault)
size=pagefaultaddress-VirtualAddressToReadFrom;
else
return raisePagefault(currentcpuinfo, pagefaultaddress); }
else
size=0;
}
copymem(Destination, Source, size);
vmregisters->rax = size;
break;
}
case 5: {
if (isAMD)
{
vmregisters->rax = 0xcedead;
break;
}
if (currentcpuinfo->hidden_sysenter_modification==0) {
currentcpuinfo->actual_sysenter_CS=currentcpuinfo->sysenter_CS;
currentcpuinfo->actual_sysenter_ESP=currentcpuinfo->sysenter_ESP;
currentcpuinfo->actual_sysenter_EIP=currentcpuinfo->sysenter_EIP;
}
vmregisters->rax = 0;
break;
}
case 6: {
ULONG *sysenter_CS;
ULONG *sysenter_ESP;
ULONG *sysenter_EIP;
if (isAMD)
{
vmregisters->rax = 0xcedead;
break;
}
if (currentcpuinfo->hidden_sysenter_modification==0)
return raiseInvalidOpcodeException(currentcpuinfo);
sysenter_CS=(ULONG *)mapVMmemory(currentcpuinfo, vmcall_instruction[3], 4, currentcpuinfo->AvailableVirtualAddress+0x00400000, &error, &pagefaultaddress);
if (error==2)
return raisePagefault(currentcpuinfo, pagefaultaddress);
sysenter_EIP=(ULONG *)mapVMmemory(currentcpuinfo, vmcall_instruction[4], 4, currentcpuinfo->AvailableVirtualAddress+0x00600000, &error, &pagefaultaddress);
if (error==2)
return raisePagefault(currentcpuinfo, pagefaultaddress);
sysenter_ESP=(ULONG *)mapVMmemory(currentcpuinfo, vmcall_instruction[5], 4, currentcpuinfo->AvailableVirtualAddress+0x00800000, &error, &pagefaultaddress);
if (error==2)
return raisePagefault(currentcpuinfo, pagefaultaddress);
*sysenter_CS=currentcpuinfo->actual_sysenter_CS;
*sysenter_ESP=currentcpuinfo->actual_sysenter_ESP;
*sysenter_EIP=currentcpuinfo->actual_sysenter_EIP;
vmregisters->rax = 0;
break;
}
case 7: {
if (isAMD)
{
vmregisters->rax = 0xcedead;
break;
}
ULONG sysenter_CS=vmcall_instruction[3];
ULONG sysenter_ESP=vmcall_instruction[4];
ULONG sysenter_EIP=vmcall_instruction[5];
if (currentcpuinfo->hidden_sysenter_modification==0)
return raiseInvalidOpcodeException(currentcpuinfo);
currentcpuinfo->actual_sysenter_CS=sysenter_CS;
currentcpuinfo->actual_sysenter_ESP=sysenter_ESP;
currentcpuinfo->actual_sysenter_EIP=sysenter_EIP;
vmwrite(0x6826,currentcpuinfo->actual_sysenter_EIP);
vmwrite(0x6824,currentcpuinfo->actual_sysenter_ESP);
vmwrite(0x482a,currentcpuinfo->actual_sysenter_CS);
vmregisters->rax = 0;
break;
}
case 8: {
sendstring("Not yet implemented\n\r");
vmregisters->rax = 0xcedead;
break;
}
case VMCALL_REDIRECTINT1: {
sendstring("VMCALL_REDIRECTINT1\n\r");
if (vmcall_instruction[3] == 0)
{
int1redirection=vmcall_instruction[4];
int1redirection_idtbypass=0;
sendstringf("IDT1 redirection to int %d\n\r",int1redirection);
}
else
{
int1redirection_idtbypass_cs = vmcall_instruction[7]; int1redirection_idtbypass_rip = *(UINT64 *)&vmcall_instruction[5]; int1redirection_idtbypass=1;
sendstringf("IDT1 bypass to %x:%6\n\r",int1redirection_idtbypass_cs, int1redirection_idtbypass_rip);
}
if (isAMD)
{
if (vmcall_instruction[3] == 2) currentcpuinfo->vmcb->InterceptExceptions&=~(1<<1); else
currentcpuinfo->vmcb->InterceptExceptions|=(1<<1);
currentcpuinfo->vmcb->VMCB_CLEAN_BITS&=~(1 << 0); }
vmregisters->rax = 0;
break;
}
case VMCALL_CHANGESELECTORS: {
if (isAMD)
{
vmregisters->rax = 0xcedead;
break;
}
ULONG cs=vmcall_instruction[3];
ULONG ss=vmcall_instruction[4];
ULONG ds=vmcall_instruction[5];
ULONG es=vmcall_instruction[6];
ULONG fs=vmcall_instruction[7];
ULONG gs=vmcall_instruction[8];
sendstringf("VMCALL_CHANGESELECTORS: cs=%x, ss=%x, ds=%x, es=%x, fs=%x, gs=%x\n\r", cs,ss,ds,es,fs,gs);
sendstring("\n\rBefore:\n\r");
sendvmstate(currentcpuinfo, vmregisters);
vmregisters->rax = change_selectors(currentcpuinfo, cs,ss,ds,es,fs,gs);
sendstring("After:\n\r\n\r");
sendvmstate(currentcpuinfo, vmregisters);
break;
}
case VMCALL_BLOCK_INTERRUPTS:
{
if (isAMD)
{
vmregisters->rax = 0xcedead;
break;
}
sendstringf("VMCALL_BLOCK_INTERRUPTS\n");
currentcpuinfo->Previous_Interuptability_State=vmread(0x4824);
vmwrite(0x4824, (1<<3));
currentcpuinfo->Previous_CLI=(vmread(0x6820) >> 9) & 1;
vmwrite(0x6820,vmread(0x6820) & 0xFFFFFFFFFFFFFDFF);
vmregisters->rax = 0;
break;
}
case VMCALL_RESTORE_INTERRUPTS:
{
if (isAMD)
{
vmregisters->rax = 0xcedead;
break;
}
sendstringf("VMCALL_RESTORE_INTERRUPTS\n");
vmwrite(vm_guest_interruptability_state,currentcpuinfo->Previous_Interuptability_State);
vmwrite(vm_guest_rflags,(vmread(vm_guest_rflags) & 0xFFFFFFFFFFFFFDFF) | (currentcpuinfo->Previous_CLI << 9)); vmregisters->rax = 0;
break;
}
case 15: {
if (isAMD)
{
vmregisters->rax = 0xcedead;
break;
}
vmregisters->rax = getpid(currentcpuinfo);
break;
}
case VMCALL_INT1REDIRECTED:
{
vmregisters->rax = currentcpuinfo->int1happened;
currentcpuinfo->int1happened=0;
break;
}
case VMCALL_REGISTER_CR3_EDIT_CALLBACK:
{
if (isAMD)
{
vmregisters->rax = 0xcedead;
break;
}
sendstring("VMCALL_REGISTER_CR3_EDIT_CALLBACK\n\r");
currentcpuinfo->cr3_callback.calling_convention=vmcall_instruction[3];
currentcpuinfo->cr3_callback.callback_rip=*(UINT64*)&vmcall_instruction[4];
currentcpuinfo->cr3_callback.callback_cs=vmcall_instruction[6];
currentcpuinfo->cr3_callback.callback_rsp=*(UINT64*)&vmcall_instruction[7];
currentcpuinfo->cr3_callback.callback_ss=vmcall_instruction[9];
sendstringf("currentcpuinfo->cr3_callback.callback_rip=%x\n\r",currentcpuinfo->cr3_callback.callback_rip);
sendstringf("currentcpuinfo->cr3_callback.callback_cs=%x\n\r",currentcpuinfo->cr3_callback.callback_cs);
sendstringf("currentcpuinfo->cr3_callback.callback_rsp=%x\n\r",currentcpuinfo->cr3_callback.callback_rsp);
sendstringf("currentcpuinfo->cr3_callback.callback_ss=%x\n\r",currentcpuinfo->cr3_callback.callback_ss);
currentcpuinfo->cr3_callback.cr3_change_callback=1; break;
}
case VMCALL_RETURN_FROM_CR3_EDIT_CALLBACK:
{
UINT64 newcr3=*(UINT64 *)&vmcall_instruction[3];
if (isAMD)
{
vmregisters->rax = 0xcedead;
break;
}
returnFromCR3Callback(currentcpuinfo, vmregisters, newcr3);
return 0;
}
case VMCALL_GETCR0:
{
vmregisters->rax = isAMD?currentcpuinfo->vmcb->CR0:vmread(vm_guest_cr0);
break;
}
case VMCALL_GETCR3:
{
vmregisters->rax = isAMD?currentcpuinfo->vmcb->CR3:vmread(vm_guest_cr3);
break;
}
case VMCALL_GETCR4:
{
vmregisters->rax = isAMD?currentcpuinfo->vmcb->CR4:vmread(vm_guest_cr4);
break;
}
case VMCALL_RAISEPRIVILEGE:
{
if (isAMD)
{
vmregisters->rax = 0xcedead;
break;
}
vmregisters->rax = raisePrivilege(currentcpuinfo);
break;
}
case VMCALL_REDIRECTINT14: {
sendstring("VMCALL_REDIRECTINT14\n\r");
if (vmcall_instruction[3] == 0)
{
int14redirection=vmcall_instruction[4];
int14redirection_idtbypass=0;
sendstringf("IDT14 redirection to int %d\n\r",int14redirection);
}
else
{
int14redirection_idtbypass_cs = vmcall_instruction[7]; int14redirection_idtbypass_rip = *(UINT64 *)&vmcall_instruction[5]; int14redirection_idtbypass=1;
sendstringf("IDT14 bypass to %x:%6\n\r",int14redirection_idtbypass_cs, int14redirection_idtbypass_rip);
}
if (isAMD)
{
if (vmcall_instruction[3] == 2) currentcpuinfo->vmcb->InterceptExceptions&=~(1<<14); else
currentcpuinfo->vmcb->InterceptExceptions|=(1<<14);
currentcpuinfo->vmcb->VMCB_CLEAN_BITS&=~(1 << 0); }
vmregisters->rax = 0;
break;
}
case VMCALL_INT14REDIRECTED:
{
vmregisters->rax = currentcpuinfo->int14happened;
currentcpuinfo->int14happened=0;
break;
}
case VMCALL_REDIRECTINT3: {
sendstring("VMCALL_REDIRECTINT3\n\r");
if (vmcall_instruction[3] == 0)
{
int3redirection=vmcall_instruction[4];
int3redirection_idtbypass=0;
sendstringf("IDT3 redirection to int %d\n\r",int3redirection);
}
else
{
int3redirection_idtbypass_cs = vmcall_instruction[7]; int3redirection_idtbypass_rip = *(UINT64 *)&vmcall_instruction[5]; int3redirection_idtbypass=1;
sendstringf("IDT3 bypass to %x:%6\n\r",int3redirection_idtbypass_cs, int3redirection_idtbypass_rip);
}
if (isAMD)
{
if (vmcall_instruction[3] == 2) currentcpuinfo->vmcb->InterceptExceptions&=~(1<<3); else
currentcpuinfo->vmcb->InterceptExceptions|=(1<<3);
currentcpuinfo->vmcb->VMCB_CLEAN_BITS&=~(1 << 0); }
vmregisters->rax = 0;
break;
}
case VMCALL_INT3REDIRECTED:
{
vmregisters->rax = currentcpuinfo->int3happened;
currentcpuinfo->int3happened=0;
vmregisters->rax = 0;
break;
}
case VMCALL_READMSR:
{
DWORD msr=vmcall_instruction[3];
*(UINT64 *)&vmcall_instruction[4]=readMSRSafe(currentcpuinfo, msr);
vmregisters->rax = *(UINT64 *)&vmcall_instruction[4];
break;
}
case VMCALL_WRITEMSR:
{
DWORD msr=vmcall_instruction[3];
QWORD msrvalue=*(UINT64 *)&vmcall_instruction[4];
writeMSR(msr, msrvalue);
break;
}
case VMCALL_ULTIMAP:
{
if (isAMD)
{
vmregisters->rax = 0xcedead;
break;
}
QWORD CR3=*(QWORD *)&vmcall_instruction[3];
QWORD DEBUGCTL=*(QWORD *)&vmcall_instruction[5];
QWORD DS_AREA=*(QWORD *)&vmcall_instruction[7];
ultimap_setup(currentcpuinfo, CR3, DEBUGCTL, DS_AREA);
vmregisters->rax = 0;
break;
}
case VMCALL_ULTIMAP_DISABLE:
{
if (isAMD)
{
vmregisters->rax = 0xcedead;
break;
}
ultimap_disable(currentcpuinfo);
vmregisters->rax = 0;
break;
}
case VMCALL_ULTIMAP_PAUSE:
{
if (isAMD)
{
vmregisters->rax = 0xcedead;
break;
}
ultimap_pause(currentcpuinfo);
vmregisters->rax = 0;
break;
}
case VMCALL_ULTIMAP_RESUME:
{
if (isAMD)
{
vmregisters->rax = 0xcedead;
break;
}
ultimap_resume(currentcpuinfo);
vmregisters->rax = 0;
break;
}
case VMCALL_ULTIMAP_DEBUGINFO:
{
if (isAMD)
{
vmregisters->rax = 0xcedead;
break;
}
#ifdef ULTIMAPDEBUG
PULTIMAPDEBUGINFO Output=&vmcall_instruction[3];
ultimap_debugoutput(currentcpuinfo, Output);
#endif
vmregisters->rax = 0;
break;
}
case VMCALL_DISABLE_DATAPAGEFAULTS:
{
if (isAMD)
{
vmregisters->rax = 0xcedead;
break;
}
currentcpuinfo->IgnorePageFaults.Active=1;
currentcpuinfo->IgnorePageFaults.LastIgnoredPageFault=0;
vmregisters->rax = 0;
break;
}
case VMCALL_ENABLE_DATAPAGEFAULTS:
{
if (isAMD)
{
vmregisters->rax = 0xcedead;
break;
}
currentcpuinfo->IgnorePageFaults.Active=0;
vmregisters->rax = 0;
break;
}
case VMCALL_GETLASTSKIPPEDPAGEFAULT:
{
if (isAMD)
{
vmregisters->rax = 0xcedead;
break;
}
vmregisters->rax = currentcpuinfo->IgnorePageFaults.LastIgnoredPageFault;
currentcpuinfo->IgnorePageFaults.LastIgnoredPageFault=0;
break;
}
case VMCALL_SWITCH_TO_KERNELMODE:
{
if (isAMD)
{
vmregisters->rax = 0xcedead;
break;
}
DWORD cs=*(DWORD *)&vmcall_instruction[3];
QWORD rip=*(QWORD *)&vmcall_instruction[4];
QWORD parameters=*(QWORD *)&vmcall_instruction[6];
sendstringf("VMCALL_SWITCH_TO_KERNELMODE(%x:%6 (%6)\n", cs, rip, parameters);
vmwrite(0x681e,vmread(0x681e)+vmread(0x440c));
emulateExceptionInterrupt(currentcpuinfo, vmregisters, cs,rip,1, parameters, 1);
vmregisters->rax=0;
return 0; }
case VMCALL_PSODTEST:
{
if (isAMD)
{
vmregisters->rax = 0xcedead;
break;
}
break;
}
default:
vmregisters->rax = 0xcedead;
break;
}
if (isAMD)
{
currentcpuinfo->vmcb->RAX=vmregisters->rax;
currentcpuinfo->vmcb->RIP+=3; }
else
{
vmwrite(vm_guest_rip,vmread(vm_guest_rip)+vmread(vm_exit_instructionlength));
}
return 0;
}
criticalSection vmcallCS;
int handleVMCall(pcpuinfo currentcpuinfo, VMRegisters *vmregisters)
{
int result;
csEnter(&vmcallCS);
result=_handleVMCall(currentcpuinfo, vmregisters);
csLeave(&vmcallCS);
return result;
}