You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

212 lines
7.6 KiB

#include "Virtualizer.h"
#include "VirtualMachine.h"
#define VmIRegLoadMemHandlerId(IReg, MemOpType) (VM_ICLASS_LD_IREG_MEM_START + VM_MEMOP_TYPE_COUNT * (IReg) + (MemOpType))
#define VmIRegStoreMemHandlerId(IReg, MemOpType) (VM_ICLASS_ST_IREG_MEM_START + VM_MEMOP_TYPE_COUNT * (IReg) + (MemOpType))
#define VmIRegLoadRegHandlerId(IReg) (VM_ICLASS_LD_IREG_REG_START + (IReg))
#define VmIRegStoreRegHandlerId(IReg) (VM_ICLASS_ST_IREG_REG_START + (IReg))
#define VmIRegLoadImmHandlerId(IReg) (VM_ICLASS_LD_IREG_IMM_START + (IReg))
PVM_HANDLER ViGetVmHandler(PVIRTUALIZER Virt, UINT Id)
{
if (Virt->HandlerMap[Id] == 0)
{
Virt->Handlers.push_back(new VM_HANDLER());
Virt->HandlerMap[Id] = (USHORT)(Virt->Handlers.size() - 1);
}
return Virt->Handlers[Virt->HandlerMap[Id]];
}
CONST CHAR* ViIClassToString(UINT IClass)
{
if (IClass >= VM_ICLASS_ENTER)
return VmIClassToString((VM_ICLASS_ENUM)IClass);
return XedIClassEnumToString((XED_ICLASS_ENUM)IClass);
}
BOOL ViCanHandleInst(PNATIVE_CODE_LINK Link)
{
switch (XedDecodedInstGetIClass(&Link->XedInstruction))
{
case XED_ICLASS_MOV:
return TRUE;
}
return FALSE;
}
BOOL ViValidateNativeCodeBlock(PVIRTUALIZER Virt, PNATIVE_CODE_BLOCK Block)
{
for (PNATIVE_CODE_LINK T = Block->Start; T && T != Block->End->Next; T = T->Next)
{
if (!ViCanHandleInst(T))
return FALSE;
//Cant handle RIP relative instructions.
CONST XED_INST* Inst = XedDecodedInstInst(&T->XedInstruction);
UINT OperandCount = XedDecodedInstNumOperands(&T->XedInstruction);
for (UINT i = 0; i < OperandCount; i++)
{
XED_OPERAND_ENUM OperandName = XedOperandName(XedInstOperand(Inst, i));
if ((OperandName == XED_OPERAND_MEM0 || OperandName == XED_OPERAND_MEM1)
&& XedDecodedInstGetBaseReg(&T->XedInstruction, OperandName - XED_OPERAND_MEM0) == XED_REG_RIP)
return FALSE;
}
}
return TRUE;
}
BOOL ViVirtualizeInst(PVIRTUALIZER Virt, XED_DECODED_INST* DecodedInst, PVM_CODE_BLOCK Block)
{
VM_CODE_BLOCK Prologue = { };
VM_CODE_BLOCK Epilogue = { };
CONST XED_INST* Inst = XedDecodedInstInst(DecodedInst);
UINT OperandCount = XedDecodedInstNumOperands(DecodedInst);
XED_ICLASS_ENUM IClass = XedDecodedInstGetIClass(DecodedInst);
STDVECTOR<CONST XED_OPERAND*> Operands = {};
VM_OPERAND_SIZE_ENUM OpSize[3] = { VM_OPSIZE_8 };
for (UINT i = 0; i < OperandCount; i++)
{
CONST XED_OPERAND* Operand = XedInstOperand(Inst, i);
XED_OPERAND_ENUM OperandName = XedOperandName(Operand);
if (XedOperandIsRegister(OperandName) && XED_REG_RFLAGS == XedDecodedInstGetReg(DecodedInst, OperandName))
continue;
Operands.push_back(Operand);
OpSize[Operands.size() - 1] = (VM_OPERAND_SIZE_ENUM)(log2(XedDecodedInstOperandLength(DecodedInst, i)));
}
for (UINT i = 0; i < Operands.size(); i++)
{
CONST XED_OPERAND* Operand = Operands[i];
XED_OPERAND_ENUM OperandName = XedOperandName(Operand);
VM_IREG_ENUM IReg = (VM_IREG_ENUM)(VM_IREG_1 + i);
if (XedOperandIsRegister(OperandName))
{
if (XedOperandRead(Operand))
{
USHORT HandlerId = VmIRegLoadRegHandlerId(IReg);
PVM_HANDLER_DESCRIPTOR Desc = ViGetVmHandler(Virt, HandlerId)->GetDesc(OpSize);
if (!Desc->Data) Desc->Data = VmHandlerIRegReg(IReg, OpSize[i], TRUE, &Desc->DataSize);
PVM_CODE_LINK Link = new VM_CODE_LINK();
Link->HandlerId = HandlerId;
Link->Flags |= CODE_FLAG_IREG_OPERATION;
Link->Reg.Register = VmXRegToVRegId(XedDecodedInstGetReg(DecodedInst, OperandName));
VcAppendToBlock(&Prologue, Link);
}
if (XedOperandWritten(Operand))
{
USHORT HandlerId = VmIRegStoreRegHandlerId(IReg);
PVM_HANDLER_DESCRIPTOR Desc = ViGetVmHandler(Virt, HandlerId)->GetDesc(OpSize);
if (!Desc->Data) Desc->Data = VmHandlerIRegReg(IReg, OpSize[i], FALSE, &Desc->DataSize);
PVM_CODE_LINK Link = new VM_CODE_LINK();
Link->HandlerId = HandlerId;
Link->Flags |= CODE_FLAG_IREG_OPERATION;
Link->Reg.Register = VmXRegToVRegId(XedDecodedInstGetReg(DecodedInst, OperandName));
VcAppendToBlock(&Epilogue, Link);
}
}
else if (OperandName == XED_OPERAND_MEM0/* || OperandName == XED_OPERAND_MEM1*/)
{
UINT MemOpIndex = OperandName - XED_OPERAND_MEM0;
XED_REG_ENUM Base = XedDecodedInstGetBaseReg(DecodedInst, MemOpIndex);
XED_REG_ENUM Index = XedDecodedInstGetIndexReg(DecodedInst, MemOpIndex);
UINT Scale = XedDecodedInstGetScale(DecodedInst, MemOpIndex);
LONGLONG Displacement = XedDecodedInstGetMemoryDisplacement(DecodedInst, MemOpIndex);
UINT MemOpType = VM_MEMOP_TYPE_COUNT;
if (Base != XED_REG_INVALID) MemOpType = VM_MEMOP_B;
if (Index != XED_REG_INVALID) MemOpType = VM_MEMOP_BIS;
if (Displacement != 0) MemOpType += 1;
if (XedOperandRead(Operand))
{
USHORT HandlerId = VmIRegLoadMemHandlerId(IReg, MemOpType);
PVM_HANDLER_DESCRIPTOR Desc = ViGetVmHandler(Virt, HandlerId)->GetDesc(OpSize);
if (!Desc->Data) Desc->Data = VmHandlerIRegMem((VM_MEMOP_TYPE_ENUM)MemOpType, IReg, OpSize[i], TRUE, &Desc->DataSize);
PVM_CODE_LINK Link = new VM_CODE_LINK();
Link->HandlerId = HandlerId;
Link->Flags |= CODE_FLAG_IREG_OPERATION;
Link->Mem.Base = VmXRegToVRegId(Base);
Link->Mem.Index = VmXRegToVRegId(Index);
Link->Mem.Scale = Scale;
Link->Mem.Displacement = Displacement;
VcAppendToBlock(&Prologue, Link);
}
if (XedOperandWritten(Operand))
{
USHORT HandlerId = VmIRegStoreMemHandlerId(IReg, MemOpType);
PVM_HANDLER_DESCRIPTOR Desc = ViGetVmHandler(Virt, HandlerId)->GetDesc(OpSize);
if (!Desc->Data) Desc->Data = VmHandlerIRegMem((VM_MEMOP_TYPE_ENUM)MemOpType, IReg, OpSize[i], FALSE, &Desc->DataSize);
PVM_CODE_LINK Link = new VM_CODE_LINK();
Link->HandlerId = HandlerId;
Link->Flags |= CODE_FLAG_IREG_OPERATION;
Link->Mem.Base = VmXRegToVRegId(Base);
Link->Mem.Index = VmXRegToVRegId(Index);
Link->Mem.Scale = Scale;
Link->Mem.Displacement = Displacement;
VcAppendToBlock(&Epilogue, Link);
}
}
else if (OperandName == XED_OPERAND_IMM0)
{
USHORT HandlerId = VmIRegLoadImmHandlerId(IReg);
if (Operands.size() > 1)
OpSize[i] = OpSize[i - 1];
else
OpSize[i] = VM_OPSIZE_64; //assume 16 for 1 operand imm instructions
PVM_HANDLER_DESCRIPTOR Desc = ViGetVmHandler(Virt, HandlerId)->GetDesc(OpSize);
if (!Desc->Data) Desc->Data = VmHandlerIRegImm(IReg, OpSize[i], &Desc->DataSize);
PVM_CODE_LINK Link = new VM_CODE_LINK();
Link->HandlerId = HandlerId;
Link->Flags |= CODE_FLAG_IREG_OPERATION;
if (XedDecodedInstGetImmediateIsSigned(DecodedInst))
Link->Imm.Immediate.i64 = (INT64)XedDecodedInstGetSignedImmediate(DecodedInst);
else
Link->Imm.Immediate.u64 = XedDecodedInstGetUnsignedImmediate(DecodedInst);
/*else
{
ULONG64 ImmRaw = xed_decoded_inst_get_unsigned_immediate(DecodedInst);
memcpy(&Link->Imm.Immediate.Raw, &ImmRaw, VmOpSizeToBytes(OpSize[i]));
}*/
VcAppendToBlock(&Prologue, Link);
}
}
switch (IClass)
{
default:
PVM_CODE_LINK Link = new VM_CODE_LINK();
Link->HandlerId = IClass;
Link->Flags |= CODE_FLAG_NATIVE_OPERATION;
PVM_HANDLER_DESCRIPTOR Desc = ViGetVmHandler(Virt, IClass)->GetDesc(OpSize);
if (!Desc->Data)
{
switch (Operands.size())
{
case 1: Desc->Data = VmHandlerEncode1(IClass, OpSize[0], &Desc->DataSize); break;
case 2: Desc->Data = VmHandlerEncode2(IClass, OpSize[0], OpSize[1], &Desc->DataSize); break;
case 3: Desc->Data = VmHandlerEncode3(IClass, OpSize[0], OpSize[1], OpSize[2], &Desc->DataSize); break;
}
}
VcAppendToBlock(&Prologue, Link);
}
if (Epilogue.Start)
{
Prologue.End->Next = Epilogue.Start;
Epilogue.Start = Prologue.End;
Prologue.End = Epilogue.End;
}
Block->Start = Prologue.Start;
Block->End = Prologue.End;
return TRUE;
}