ida脚本自动分析vmcs

2023-12-20 16:47:44

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()

在这里插入图片描述
在这里插入图片描述

文章来源:https://blog.csdn.net/oShuangYue12/article/details/135109314
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。