import collections
import os
# IDAPython
import idaapi
import idautils
import idc
import struct
import ida_name
cfg_smart_mode_max_back_step = 10
def PrettyHex(v):
return '0x{0:08X}'.format(v)
# ------------------------------------------------------------------------------------- #
class KnowledgeDb():
def __init__(self):
self.ia32_vmcs_db = {
0x00000000 : 'VMCS_CTRL_VPID',
0x00000002 : 'VMCS_CTRL_POSTED_INTR_NOTIFY_VECTOR',
0x00000004 : 'VMCS_CTRL_EPTP_INDEX',
0x00000800 : 'VMCS_GUEST_ES_SEL',
0x00000802 : 'VMCS_GUEST_CS_SEL',
0x00000804 : 'VMCS_GUEST_SS_SEL',
0x00000806 : 'VMCS_GUEST_DS_SEL',
0x00000808 : 'VMCS_GUEST_FS_SEL',
0x0000080A : 'VMCS_GUEST_GS_SEL',
0x0000080C : 'VMCS_GUEST_LDTR_SEL',
0x0000080E : 'VMCS_GUEST_TR_SEL',
0x00000810 : 'VMCS_GUEST_INTR_STATUS',
0x00000812 : 'VMCS_GUEST_PML_INDEX',
0x00000C00 : 'VMCS_HOST_ES_SEL',
0x00000C02 : 'VMCS_HOST_CS_SEL',
0x00000C04 : 'VMCS_HOST_SS_SEL',
0x00000C06 : 'VMCS_HOST_DS_SEL',
0x00000C08 : 'VMCS_HOST_FS_SEL',
0x00000C0A : 'VMCS_HOST_GS_SEL',
0x00000C0C : 'VMCS_HOST_TR_SEL',
0x00002000 : 'VMCS_CTRL_IO_BITMAP_A',
0x00002002 : 'VMCS_CTRL_IO_BITMAP_B',
0x00002004 : 'VMCS_CTRL_MSR_BITMAP',
0x00002006 : 'VMCS_CTRL_VMEXIT_MSR_STORE',
0x00002008 : 'VMCS_CTRL_VMEXIT_MSR_LOAD',
0x0000200A : 'VMCS_CTRL_VMENTRY_MSR_LOAD',
0x0000200C : 'VMCS_CTRL_EXEC_VMCS_PTR',
0x0000200E : 'VMCS_CTRL_PML_ADDR',
0x00002010 : 'VMCS_CTRL_TSC_OFFSET',
0x00002012 : 'VMCS_CTRL_VAPIC_PAGEADDR',
0x00002014 : 'VMCS_CTRL_APIC_ACCESSADDR',
0x00002016 : 'VMCS_CTRL_POSTED_INTR_DESC',
0x00002018 : 'VMCS_CTRL_VMFUNC_CTRLS',
0x0000201A : 'VMCS_CTRL_EPTP',
0x0000201C : 'VMCS_CTRL_EOI_BITMAP_0',
0x0000201E : 'VMCS_CTRL_EOI_BITMAP_1',
0x00002020 : 'VMCS_CTRL_EOI_BITMAP_2',
0x00002022 : 'VMCS_CTRL_EOI_BITMAP_3',
0x00002024 : 'VMCS_CTRL_EPTP_LIST',
0x00002026 : 'VMCS_CTRL_VMREAD_BITMAP',
0x00002028 : 'VMCS_CTRL_VMWRITE_BITMAP',
0x0000202A : 'VMCS_CTRL_VIRTXCPT_INFO_ADDR',
0x0000202C : 'VMCS_CTRL_XSS_EXITING_BITMAP',
0x0000202E : 'VMCS_CTRL_ENCLS_EXITING_BITMAP',
0x00002032 : 'VMCS_CTRL_TSC_MULTIPLIER',
0x00002400 : 'VMCS_GUEST_PHYS_ADDR',
0x00002800 : 'VMCS_GUEST_VMCS_LINK_PTR',
0x00002802 : 'VMCS_GUEST_DEBUGCTL',
0x00002804 : 'VMCS_GUEST_PAT',
0x00002806 : 'VMCS_GUEST_EFER',
0x00002808 : 'VMCS_GUEST_PERF_GLOBAL_CTRL',
0x0000280A : 'VMCS_GUEST_PDPTE0',
0x0000280C : 'VMCS_GUEST_PDPTE1',
0x0000280E : 'VMCS_GUEST_PDPTE2',
0x00002810 : 'VMCS_GUEST_PDPTE3',
0x00002C00 : 'VMCS_HOST_PAT',
0x00002C02 : 'VMCS_HOST_EFER',
0x00002C04 : 'VMCS_HOST_PERF_GLOBAL_CTRL',
0x00004000 : 'VMCS_CTRL_PIN_EXEC',
0x00004002 : 'VMCS_CTRL_PROC_EXEC',
0x00004004 : 'VMCS_CTRL_EXCEPTION_BITMAP',
0x00004006 : 'VMCS_CTRL_PAGEFAULT_ERROR_MASK',
0x00004008 : 'VMCS_CTRL_PAGEFAULT_ERROR_MATCH',
0x0000400A : 'VMCS_CTRL_CR3_TARGET_COUNT',
0x0000400C : 'VMCS_CTRL_EXIT',
0x0000400E : 'VMCS_CTRL_EXIT_MSR_STORE_COUNT',
0x00004010 : 'VMCS_CTRL_EXIT_MSR_LOAD_COUNT',
0x00004012 : 'VMCS_CTRL_ENTRY',
0x00004014 : 'VMCS_CTRL_ENTRY_MSR_LOAD_COUNT',
0x00004016 : 'VMCS_CTRL_ENTRY_INTERRUPTION_INFO',
0x00004018 : 'VMCS_CTRL_ENTRY_EXCEPTION_ERRCODE',
0x0000401A : 'VMCS_CTRL_ENTRY_INSTR_LENGTH',
0x0000401C : 'VMCS_CTRL_TPR_THRESHOLD',
0x0000401E : 'VMCS_CTRL_PROC_EXEC2',
0x00004020 : 'VMCS_CTRL_PLE_GAP',
0x00004022 : 'VMCS_CTRL_PLE_WINDOW',
0x00004400 : 'VMCS_VM_INSTR_ERROR',
0x00004402 : 'VMCS_EXIT_REASON',
0x00004404 : 'VMCS_EXIT_INTERRUPTION_INFO',
0x00004406 : 'VMCS_EXIT_INTERRUPTION_ERROR_CODE',
0x00004408 : 'VMCS_IDT_VECTORING_INFO',
0x0000440A : 'VMCS_IDT_VECTORING_ERROR_CODE',
0x0000440C : 'VMCS_EXIT_INSTR_LENGTH',
0x0000440E : 'VMCS_EXIT_INSTR_INFO',
0x00004800 : 'VMCS_GUEST_ES_LIMIT',
0x00004802 : 'VMCS_GUEST_CS_LIMIT',
0x00004804 : 'VMCS_GUEST_SS_LIMIT',
0x00004806 : 'VMCS_GUEST_DS_LIMIT',
0x00004808 : 'VMCS_GUEST_FS_LIMIT',
0x0000480A : 'VMCS_GUEST_GS_LIMIT',
0x0000480C : 'VMCS_GUEST_LDTR_LIMIT',
0x0000480E : 'VMCS_GUEST_TR_LIMIT',
0x00004810 : 'VMCS_GUEST_GDTR_LIMIT',
0x00004812 : 'VMCS_GUEST_IDTR_LIMIT',
0x00004814 : 'VMCS_GUEST_ES_ACCESS_RIGHTS',
0x00004816 : 'VMCS_GUEST_CS_ACCESS_RIGHTS',
0x00004818 : 'VMCS_GUEST_SS_ACCESS_RIGHTS',
0x0000481A : 'VMCS_GUEST_DS_ACCESS_RIGHTS',
0x0000481C : 'VMCS_GUEST_FS_ACCESS_RIGHTS',
0x0000481E : 'VMCS_GUEST_GS_ACCESS_RIGHTS',
0x00004820 : 'VMCS_GUEST_LDTR_ACCESS_RIGHTS',
0x00004822 : 'VMCS_GUEST_TR_ACCESS_RIGHTS',
0x00004824 : 'VMCS_GUEST_INTERRUPTIBILITY_STATE',
0x00004826 : 'VMCS_GUEST_ACTIVITY_STATE',
0x00004828 : 'VMCS_GUEST_SMBASE',
0x0000482A : 'VMCS_GUEST_SYSENTER_CS',
0x0000482E : 'VMCS_GUEST_PREEMPT_TIMER_VALUE',
0x00004C00 : 'VMCS_SYSENTER_CS',
0x00006000 : 'VMCS_CTRL_CR0_MASK',
0x00006002 : 'VMCS_CTRL_CR4_MASK',
0x00006004 : 'VMCS_CTRL_CR0_READ_SHADOW',
0x00006006 : 'VMCS_CTRL_CR4_READ_SHADOW',
0x00006008 : 'VMCS_CTRL_CR3_TARGET_VAL0',
0x0000600A : 'VMCS_CTRL_CR3_TARGET_VAL1',
0x0000600C : 'VMCS_CTRL_CR3_TARGET_VAL2',
0x0000600E : 'VMCS_CTRL_CR3_TARGET_VAL3',
0x00006400 : 'VMCS_EXIT_QUALIFICATION',
0x00006402 : 'VMCS_IO_RCX',
0x00006404 : 'VMCS_IO_RSX',
0x00006406 : 'VMCS_IO_RDI',
0x00006408 : 'VMCS_IO_RIP',
0x0000640A : 'VMCS_EXIT_GUEST_LINEAR_ADDR',
0x00006800 : 'VMCS_GUEST_CR0',
0x00006802 : 'VMCS_GUEST_CR3',
0x00006804 : 'VMCS_GUEST_CR4',
0x00006806 : 'VMCS_GUEST_ES_BASE',
0x00006808 : 'VMCS_GUEST_CS_BASE',
0x0000680A : 'VMCS_GUEST_SS_BASE',
0x0000680C : 'VMCS_GUEST_DS_BASE',
0x0000680E : 'VMCS_GUEST_FS_BASE',
0x00006810 : 'VMCS_GUEST_GS_BASE',
0x00006812 : 'VMCS_GUEST_LDTR_BASE',
0x00006814 : 'VMCS_GUEST_TR_BASE',
0x00006816 : 'VMCS_GUEST_GDTR_BASE',
0x00006818 : 'VMCS_GUEST_IDTR_BASE',
0x0000681A : 'VMCS_GUEST_DR7',
0x0000681C : 'VMCS_GUEST_RSP',
0x0000681E : 'VMCS_GUEST_RIP',
0x00006820 : 'VMCS_GUEST_RFLAGS',
0x00006822 : 'VMCS_GUEST_PENDING_DEBUG_EXCEPTIONS',
0x00006824 : 'VMCS_GUEST_SYSENTER_ESP',
0x00006826 : 'VMCS_GUEST_SYSENTER_EIP',
0x00006C00 : 'VMCS_HOST_CR0',
0x00006C02 : 'VMCS_HOST_CR3',
0x00006C04 : 'VMCS_HOST_CR4',
0x00006C06 : 'VMCS_HOST_FS_BASE',
0x00006C08 : 'VMCS_HOST_GS_BASE',
0x00006C0A : 'VMCS_HOST_TR_BASE',
0x00006C0C : 'VMCS_HOST_GDTR_BASE',
0x00006C0E : 'VMCS_HOST_IDTR_BASE',
0x00006C10 : 'VMCS_HOST_SYSENTER_ESP',
0x00006C12 : 'VMCS_HOST_SYSENTER_EIP',
0x00006C14 : 'VMCS_HOST_RSP',
0x00006C16 : 'VMCS_HOST_RIP',
# new https://lore.kernel.org/patchwork/patch/1002950/.
0x00002811 : 'VMCS_GUEST_PDPTR3_HIGH',
0x00002812 : 'VMCS_GUEST_BNDCFGS',
0x00002813 : 'VMCS_GUEST_BNDCFGS_HIGH',
0x00002814 : 'VMCS_GUEST_RTIT_CTL',
0x00002815 : 'VMCS_GUEST_RTIT_CTL_HIGH'
}
def GetIa32VmcsDb(self):
return self.ia32_vmcs_db
# ------------------------------------------------------------------------------------- #
OPERAND_INDEX_0 = 0
OPERAND_INDEX_1 = 1
class Instruction_t(object):
def __init__(self,inst_ea):
self.inst_ea = inst_ea
self.mnemonic = idc.print_insn_mnem(self.inst_ea)
self.operand_0 = idc.print_operand(self.inst_ea, 0)
self.operand_1 = idc.print_operand(self.inst_ea, 1)
self.operand_value_0 = idc.get_operand_value(self.inst_ea,0)
self.operand_value_1 = idc.get_operand_value(self.inst_ea,1)
def get_operand_value_32bit(self,operand_index):
return idc.get_operand_value(self.inst_ea,operand_index) & 0xffffffff
def GetOperandType(self,operand_index):
return idc.get_operand_type(self.inst_ea,operand_index)
@property
def NextInstruction(self):
return Instruction_t(idc.next_head(self.inst_ea))
@property
def PrevInstruction(self):
return Instruction_t(idc.prev_head(self.inst_ea))
@property
def FunctionName(self):
return idc.get_func_name(self.inst_ea)
def IsCode(self):
return idaapi.is_code(idaapi.get_full_flags(self.inst_ea))
def IsCallInstruction(self):
return self.mnemonic == 'call'
def GetRvaFromBaseOfFunction(self):
func_ea = idc.get_name_ea_simple(self.FunctionName)
return int(self.inst_ea - func_ea)
def IsXoredThisReg(self,reg):
return self.mnemonic == 'xor' and self.operand_0 == self.operand_1 == reg;
def IsXoredWithItself(self):
return self.mnemonic == 'xor' and self.operand_0 == self.operand_1;
class MyIa32VmxHelper(idaapi.plugin_t):
def __init__(self):
print("MyIa32VmxHelper")
global g_knowledge_db
g_knowledge_db = KnowledgeDb()
self.vmcsdic={}
self.ia32_vmcs_db = g_knowledge_db.GetIa32VmcsDb()
def IsVmxInstruction(self,inst_ea):
mnemonic = idc.print_insn_mnem(inst_ea)
return mnemonic =='vmread' or mnemonic=='vmwrite'
def GetVmcsName(self,vmcs_code):
name = self.ia32_vmcs_db.get(vmcs_code)
if (name == None):
name = PrettyHex(vmcs_code)
return name
def GetValueRegister(self,inst_ea):
"""
vmread buffer, vmcs_code
vmwrite vmcs_code, buffer
"""
inst_t = Instruction_t(inst_ea)
if( inst_t.mnemonic == 'vmread' ):#and inst_t.GetOperandType(0) == idc.o_reg ):
return inst_t.operand_0
elif( inst_t.mnemonic == 'vmwrite'):# and inst_t.GetOperandType(1) == idc.o_reg ):
return inst_t.operand_1
else:
return None
def GetCodeRegister(self,inst_ea):
inst_t = Instruction_t(inst_ea)
if( inst_t.mnemonic == 'vmread' and inst_t.GetOperandType(1) == idc.o_reg ):
return inst_t.operand_1
elif( inst_t.mnemonic == 'vmwrite' and inst_t.GetOperandType(0) == idc.o_reg ):
return inst_t.operand_0
else:
return None
def GetVmcsCodeFromOperand(self,inst_ea):
curr_inst = Instruction_t(inst_ea)
code_reg = self.GetCodeRegister(inst_ea)
if( code_reg == None ):
return None
while True:
curr_inst = curr_inst.PrevInstruction
# mov ['cx', 'ecx', 'rcx'] [-2:] ==> 'cx' , ###
if( curr_inst.mnemonic == 'mov' and curr_inst.operand_0[-2:] == code_reg[-2:]):
if(curr_inst.GetOperandType(OPERAND_INDEX_1) == idc.o_imm):
self.vmcs_code_imm_ea = curr_inst.inst_ea
return curr_inst.get_operand_value_32bit(OPERAND_INDEX_1)
# if mov ecx, rcx keep looking for mov rax, imm
elif(curr_inst.GetOperandType(OPERAND_INDEX_1) == idc.o_reg):
reg_name = curr_inst.operand_1
rev_inst = Instruction_t(curr_inst.inst_ea)
if(reg_name[-2:] == 'ax' and rev_inst.PrevInstruction.IsCallInstruction()):
"""
register value came from a function call
"""
return None
# while True:
for i in range(cfg_smart_mode_max_back_step):
rev_inst = rev_inst.PrevInstruction
if rev_inst.mnemonic == 'mov' and rev_inst.operand_0 == reg_name and \
rev_inst.GetOperandType(OPERAND_INDEX_1) == idc.o_imm:
self.vmcs_code_imm_ea = rev_inst.inst_ea
return rev_inst.get_operand_value_32bit(OPERAND_INDEX_1)
# Not imm value :-(
elif (curr_inst.mnemonic == 'lea' and curr_inst.operand_0[-2:] == code_reg[-2:]):
return None
# xor ecx,ecx means vmcs code is 0x0 VMCS_CTRL_VPID
elif(curr_inst.operand_0[-2:] == code_reg[-2:] and curr_inst.IsXoredThisReg(code_reg)):
self.vmcs_code_imm_ea = curr_inst.inst_ea
return 0
def FnPass(self,func_ea):
self.func_ea=func_ea
self.vmcs_code_imm_reg=""
self.vmcsdicoffset=0
for self.inst_ea in idautils.FuncItems(self.func_ea):
inst_t = Instruction_t(self.inst_ea)
mnemonic=inst_t.mnemonic
if (self.IsVmxInstruction(self.inst_ea) == False):
continue
def RunPass(self,func_ea):
vmcsinstcount = 0
funcname=""
self.vmcs_code_imm_reg=""
self.vmcsdicoffset=0
self.func_ea=func_ea
self.vmcs_name=""
for self.inst_ea in idautils.FuncItems(self.func_ea):
mnemonic = idc.print_insn_mnem(self.inst_ea)
inst_t = Instruction_t(self.inst_ea)
if inst_t.operand_1[0:3]=="gs:":
print(mnemonic,",",inst_t.operand_0,",",inst_t.operand_1,",",inst_t.operand_value_0,",",inst_t.operand_value_1)
self.vmcs_code_imm_reg=inst_t.operand_0
if len(self.vmcs_code_imm_reg) and inst_t.mnemonic == 'mov' and inst_t.operand_0[1:1+len(self.vmcs_code_imm_reg)]==self.vmcs_code_imm_reg:
print(mnemonic,",",inst_t.operand_0,",",inst_t.operand_1,",",inst_t.operand_value_0,",",inst_t.operand_value_1)
print('vmcs filed offset:=>{:X}'.format(inst_t.operand_value_0))
self.vmcsdicoffset=inst_t.operand_value_0
if len(self.vmcs_code_imm_reg) and inst_t.mnemonic == 'mov' and inst_t.operand_1[1:1+len(self.vmcs_code_imm_reg)]==self.vmcs_code_imm_reg:
print(mnemonic,",",inst_t.operand_0,",",inst_t.operand_1,",",inst_t.operand_value_0,",",inst_t.operand_value_1)
print('vmcs filed offset:=>{:X}'.format(inst_t.operand_value_1))
self.vmcsdicoffset=inst_t.operand_value_1
if (self.IsVmxInstruction(self.inst_ea) == False):
continue
vmcs_name = None
vmcs_hex = None
vmcs_code = self.GetVmcsCodeFromOperand(self.inst_ea)
if(vmcs_code == None):
vmcs_name = 'Not imm value'
vmcs_hex = 'Not imm value'
else:
vmcs_name = self.GetVmcsName(vmcs_code)
vmcs_hex = PrettyHex(vmcs_code)
funcname = '{}_{}_{:X}'.format(mnemonic,vmcs_name,func_ea)
funcname=funcname.upper()
self.vmcs_name=vmcs_name
print(funcname)
vmcsinstcount+=1
print("vmcsinstcount %x \r\n" % vmcsinstcount)
if(vmcsinstcount==1 and self.vmcsdicoffset>0):
print(funcname)
self.vmcsdic[self.vmcsdicoffset]=self.vmcs_name
#ida_name.set_name(func_ea,funcname)
def dumpvmcs(self):
structnamestr="struct IDA_VMCS{";
startoffset=0;
prevmcsname="Start"
for offset in sorted(self.vmcsdic.keys()):
diffoffset=offset-startoffset
structnamestr+="_BYTE Field_"+ prevmcsname+'_{:X}[0x{:X}];'.format(startoffset,diffoffset)
vmcs_name=self.vmcsdic[offset]
prevmcsname=vmcs_name;
startoffset=offset;
print('dumpvmcs filed offset:=>{:X},name:=>{}'.format(offset,vmcs_name))
structnamestr+="};"
print(structnamestr)
def run(self,_=0):
for func_ea in idautils.Functions():
print("RunPass %x \r\n" % func_ea)
self.RunPass(func_ea)
# ------------------------------------------------------------------------------------- #
def PLUGIN_ENTRY():
return MyIa32VmxHelper()
def main():
f = PLUGIN_ENTRY()
#f.FnPass(0xFFFFF8000030B97C)
#f.FnPass(0xFFFFF8000031ED20)
f.run()
f.dumpvmcs()
if __name__ == '__main__':
main()