Python idc.GetMnem() Examples

The following are 20 code examples of idc.GetMnem(). You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may also want to check out all available functions/classes of the module idc , or try the search function .
Example #1
Source File: win_driver_plugin.py    From win_driver_plugin with BSD 3-Clause "New" or "Revised" License 13 votes vote down vote up
def find_dispatch_by_struct_index():
    """Attempts to locate the dispatch function based off it being loaded in a structure
    at offset 70h, based off of https://github.com/kbandla/ImmunityDebugger/blob/master/1.73/Libs/driverlib.py """
    
    out = set()
    for function_ea in idautils.Functions():
        flags = idc.get_func_flags(function_ea)
        # skip library functions
        if flags & idc.FUNC_LIB:
            continue
        func = idaapi.get_func(function_ea)
        addr = func.startEA
        while addr < func.endEA:
            if idc.GetMnem(addr) == 'mov':
                if '+70h' in idc.GetOpnd(addr, 0) and idc.GetOpType(addr, 1) == 5:
                    out.add(idc.GetOpnd(addr, 1))
            addr = idc.NextHead(addr)
    return out 
Example #2
Source File: win_driver_plugin.py    From win_driver_plugin with BSD 3-Clause "New" or "Revised" License 7 votes vote down vote up
def find_all_ioctls():
    """
    From the currently selected address attempts to traverse all blocks inside the current function to find all immediate values which
    are used for a comparison/sub immediately before a jz. Returns a list of address, second operand pairs.
    """
    
    ioctls = []
    # Find the currently selected function and get a list of all of it's basic blocks
    addr = idc.ScreenEA()
    f = idaapi.get_func(addr)
    fc = idaapi.FlowChart(f, flags=idaapi.FC_PREDS)
    for block in fc:
        # grab the last two instructions in the block 
        last_inst = idc.PrevHead(block.endEA)
        penultimate_inst = idc.PrevHead(last_inst)
        # If the penultimate instruction is cmp or sub against an immediate value immediately preceding a 'jz' 
        # then it's a decent guess that it's an IOCTL code (if this is a dispatch function)
        if idc.GetMnem(penultimate_inst) in ['cmp', 'sub'] and idc.GetOpType(penultimate_inst, 1) == 5:
            if idc.GetMnem(last_inst) == 'jz':
                value = get_operand_value(penultimate_inst)
                ioctls.append((penultimate_inst, value))
                ioctl_tracker.add_ioctl(penultimate_inst, value)
    return ioctls 
Example #3
Source File: configuration_file.py    From idasec with GNU Lesser General Public License v2.1 6 votes vote down vote up
def create_call_map(self, ftype):
        assert_ida_available()
        import idc
        import idautils
        seg_mapping = {idc.SegName(x): (idc.SegStart(x), idc.SegEnd(x)) for x in idautils.Segments()}
        imports = seg_mapping[".idata"] if ftype == PE else seg_mapping['.plt']
        start, stop = seg_mapping[".text"]
        current = start
        while current <= stop:
            inst = current
            if idc.GetMnem(inst) in ["call", "jmp"]:
                value = idc.GetOperandValue(inst, 0)
                name = idc.GetOpnd(inst, 0)
                if imports[0] <= value <= imports[1]:
                    entry = self.config.call_map.add()
                    entry.address = inst
                    entry.name = name
            current = idc.NextHead(current, stop) 
Example #4
Source File: AnalysisWidget.py    From idasec with GNU Lesser General Public License v2.1 6 votes vote down vote up
def detect_start_and_stop(self):  # FIXME:Duplicate code with core (or something similar)
        start, stop = 0, 0
        if self.core.ftype == "PE":
            start, stop = self.core.fun_mapping["start"]
        else:
            if "main" in self.core.fun_mapping:
                start, stop = self.core.fun_mapping["main"]
            elif "start" in self.core.fun_mapping:
                if "__libc_start_main" in self.core.fun_mapping:
                    instrs = list(idautils.FuncItems(self.core.fun_mapping["start"][0]))
                    instrs.reverse()
                    for inst in instrs:
                        arg1 = idc.GetOperandValue(inst, 0)
                        if idc.GetMnem(inst) == "push":
                            start, stop = arg1, self.core.fun_mapping["start"][1]
                            break
                else:
                    start, stop = self.core.fun_mapping["start"]
            else:
                start, stop = idc.BeginEA(), 0
        self.start, self.stop = start, stop 
Example #5
Source File: IDAMetrics_static.py    From IDAmetrics with BSD 2-Clause "Simplified" License 6 votes vote down vote up
def get_oviedo_df(self, local_vars):
        '''
        The function calculates Oviedo's DF value
        @local_vars - a dictionary of local variables for function
        @return - Oviedo's DF value
        '''
        oviedo_df = 0
        # get local variables usage count, except initialization, such as:
        # mov [ebp+var_0], some_value
        for local_var in local_vars:
            usage_list = local_vars.get(local_var, None)
            if usage_list == None:
                print "WARNING: empty usage list for ", local_var
                continue
            for instr_addr in usage_list:
                instr_mnem = idc.GetMnem(int(instr_addr, 16))
                if instr_mnem.startswith('mov'):
                    # get local var position
                    operands = self.get_instr_operands(int(instr_addr, 16))
                    for idx, (operand, type) in enumerate(operands):
                        if local_var in operand and idx == 0:
                            oviedo_df -= 1
                            break
            oviedo_df += len(usage_list)
        return oviedo_df 
Example #6
Source File: interesting_xor.py    From idataco with GNU General Public License v3.0 6 votes vote down vote up
def find_interesting_xors(self):
        next_xor = idc.FindText(idc.MinEA(), idc.SEARCH_DOWN|idc.SEARCH_NEXT, 0, 0, "xor")
        while next_xor != idc.BADADDR:
            if idc.GetOpnd(next_xor, 0) != idc.GetOpnd(next_xor, 1):
                entry = {"func":"", "addr": next_xor, "loop":False, "disasm": idc.GetDisasm(next_xor)}
                func = idaapi.get_func(next_xor)
                if func:
                    entry["func"] = idaapi.get_name(idc.BADADDR, func.startEA)
                    heads = idautils.Heads(next_xor, func.endEA)
                    lxors = []
                    for head in heads:
                        if idc.GetMnem(head).startswith('j'):
                            jmp_addr = idc.GetOperandValue(head,0)
                            if jmp_addr < next_xor and jmp_addr > func.startEA:
                                entry["loop"] = True
                                break
                self._interesting_xors.append(entry)
            next_xor = idc.FindText(idc.NextHead(next_xor), idc.SEARCH_DOWN|idc.SEARCH_NEXT, 0, 0, "xor") 
Example #7
Source File: IDAMetrics_static.py    From IDAmetrics with BSD 2-Clause "Simplified" License 6 votes vote down vote up
def GetInstructionType(instr_addr):
    instr_mnem = idc.GetMnem(instr_addr)
    if instr_mnem.startswith('call'):
        return CALL_INSTRUCTION
    elif instr_mnem.startswith('j'):
        # It seems that there is no other type of instructions
        # starting with j in x86/x86_64
        return BRANCH_INSTRUCTION
    for assign_instr_mnem in assign_instructions_general:
        if instr_mnem.startswith(assign_instr_mnem):
            return ASSIGNMENT_INSTRUCTION
    for assign_instr_mnem in assign_instructions_fp:
        if instr_mnem.startswith(assign_instr_mnem):
            return ASSIGNMENT_INSTRUCTION
    for compare_instruction in compare_instructions:
        if instr_mnem.startswith(compare_instruction):
            return COMPARE_INSTRUCTION
    for stack_push_instruction in stack_push_instructions:
        if instr_mnem.startswith(stack_push_instruction):
            return STACK_PUSH_INSTRUCTION
    for stack_pop_instruction in stack_pop_instructions:
        if instr_mnem.startswith(stack_pop_instruction):
            return STACK_POP_INSTRUCTION
    return OTHER_INSTRUCTION 
Example #8
Source File: mnemonic_hist.py    From rematch with GNU General Public License v3.0 5 votes vote down vote up
def data(self):
    instruction_hist = defaultdict(int)

    for ea in idautils.FuncItems(self.offset):
      mnem_line = idc.GetMnem(ea)
      mnem_line = mnem_line.lower()
      instruction_hist[mnem_line] += 1

    if sum(instruction_hist.values()) < 5:
      return None

    return instruction_hist 
Example #9
Source File: objc2_xrefs_helper.py    From flare-ida with Apache License 2.0 5 votes vote down vote up
def walk_selector_refs(self):
        #sel_ref_va is the address of the selref, which itself is a pointer to the selector string
        #we're looking for cross references *to* the the address of the selref
        #If we find ones we like and replace them with a cross reference to the actual method implementation, rather than the selector
        for xref in XrefsTo(self.sel_ref_va):
            if GetMnem(xref.frm) == self.CALL_MNEMONIC:
                continue
            #We found a xref *from* somewhere *to* our selref. We need to replace that with a reference
            #To the actual method implementation
            method_xref=self.add_method_xref(xref)
            self.patched_xrefs.append(method_xref) 
Example #10
Source File: IDAMetrics_static.py    From IDAmetrics with BSD 2-Clause "Simplified" License 5 votes vote down vote up
def get_chepin(self, local_vars, function_ea, function_metrics):
        '''
        The function calculates Chepin metric
        @local_vars - a dictionary of local variables
        @function_ea - function entry address
        @function_metrics - function metrics structure
        @return - Chepin value
        '''
        chepin = 0
        p = 0
        m = 0
        c = 0
        tmp_dict = dict()
        var_args_tmp = dict()
        (p, var_args_tmp) = self.get_function_args_count(function_ea, local_vars)
        for local_var in local_vars:
            usage_list = local_vars.get(local_var, None)
            if usage_list == None:
                print "WARNING: empty usage list for ", local_var
                continue
            for instr_addr in usage_list:
                instr_mnem = idc.GetMnem(int(instr_addr, 16))
                if instr_mnem.startswith('cmp') or instr_mnem.startswith('test'):
                    tmp_dict.setdefault(local_var, []).append(instr_addr)

        for var_arg in var_args_tmp:
            if var_arg in local_vars:
                del local_vars[var_arg]
        for cmp_var in tmp_dict:
            if cmp_var in local_vars:
                del local_vars[cmp_var]

        c = len(tmp_dict)
        m = len(local_vars)
        chepin = p + 2*m + 3*c
        return chepin 
Example #11
Source File: yara_fn.py    From python-idb with Apache License 2.0 5 votes vote down vote up
def is_jump(va):
    """
    return True if the instruction at the given address appears to be a jump.
    """
    return idc.GetMnem(va).startswith("j") 
Example #12
Source File: configuration_file.py    From idasec with GNU Lesser General Public License v2.1 5 votes vote down vote up
def set_start_stop(self, ftype):
        assert_ida_available()
        import idc
        import idaapi
        import idautils
        fun_mapping = {idc.GetFunctionName(x): (idaapi.get_func(x).startEA, idaapi.get_func(x).endEA-1)
                       for x in idautils.Functions()}
        start = idc.BeginEA()
        stop = 0
        if ftype == PE:
            start, stop = fun_mapping["start"]
        else:
            if not idc.isCode(idc.GetFlags(start)):
                if idc.MakeCode(start) == 0:
                    print "Fail to decode instr !"
                idaapi.autoWait()
            if idc.GetFunctionName(start) == "":
                if idc.MakeFunction(start) == 0:
                    print "Fail to create function !"
                idaapi.autoWait()
                fun_mapping = {idc.GetFunctionName(x): (idaapi.get_func(x).startEA, idaapi.get_func(x).endEA-1)
                               for x in idautils.Functions()}

            if "main" in fun_mapping:
                start, stop = fun_mapping["main"]
            elif "start" in fun_mapping:
                if "__libc_start_main" in fun_mapping:
                    instrs = list(idautils.FuncItems(fun_mapping["start"][0]))
                    instrs.reverse()
                    for inst in instrs:
                        arg1 = idc.GetOperandValue(inst, 0)
                        if idc.GetMnem(inst) == "push":
                            start, stop = arg1, fun_mapping["start"][1]
                            break
                else:
                    start, stop = fun_mapping["start"]
        self.config.start, self.config.stop = start, stop 
Example #13
Source File: mnemonic_hash.py    From rematch with GNU General Public License v3.0 5 votes vote down vote up
def data(self):
    md5 = hashlib.md5()
    for ea in idautils.FuncItems(self.offset):
      mnem_line = idc.GetMnem(ea)
      mnem_line = mnem_line.strip()
      mnem_line = mnem_line.lower()
      md5.update(mnem_line)
    return md5.hexdigest() 
Example #14
Source File: switch_jumps.py    From idataco with GNU General Public License v3.0 5 votes vote down vote up
def find_all_switch_jumps(self):
        self._switch_dict = defaultdict(list)
        next_switch = idc.FindBinary(idc.MinEA(), idc.SEARCH_DOWN|idc.SEARCH_NEXT, "ff 24")
        while next_switch != idc.BADADDR:
            sw = idaapi.get_switch_info_ex(next_switch)
            if idc.GetMnem(next_switch).startswith("jmp") and sw:
                ic = self.get_jlocs(sw)
                self._switch_dict[idaapi.get_func_name(next_switch)].append((next_switch, sw.ncases, ic))
            next_switch = idc.FindBinary(idc.NextHead(next_switch), idc.SEARCH_DOWN|idc.SEARCH_NEXT, "ff 24") 
Example #15
Source File: static_opaque_analysis.py    From idasec with GNU Lesser General Public License v2.1 5 votes vote down vote up
def process_routine(self, rtn_addr, pred_addr=None, rtn_i=1, total_rtn=1):
        if rtn_addr not in self.functions_cfg:
            self.functions_cfg[rtn_addr] = MyFlowGraph(rtn_addr)
        cfg = self.functions_cfg[rtn_addr]
        path_to = self.config_to_path_function(cfg)
        if pred_addr is None:
            candidates = {x for x in idautils.FuncItems(rtn_addr) if idc.GetMnem(x) in cond_jump}
        else:
            candidates = {pred_addr}
        nb_candidates = len(candidates)
        self.functions_candidates[rtn_addr] = set()
        self.functions_spurious_instrs[rtn_addr] = set()

        self.progressbar_loading.reset()
        self.progressbar_loading.setMaximum(len(candidates))

        name = idc.GetFunctionName(rtn_addr)
        self.result_widget.webview.append("\n=> Function:%s\n" % name)

        self.log("[result]", "Start processing function: 0x%x" % rtn_addr)
        for i, addr in zip(xrange(len(candidates)), candidates):
            path = path_to(addr)
            res = self.process_addr(rtn_addr, addr, path)
            if self.STOP:
                return
            elif res is None:
                continue
            dead_br = "/" if res.dead_branch is None else "%x" % res.dead_branch
            self.result_widget.webview.append("%x:\t%s\t\tK:%d\tDead:%s" % (addr, to_status_name(res.status), res.k, dead_br))

            self.result_widget.webview.verticalScrollBar().setValue(self.result_widget.webview.verticalScrollBar().maximum())
            self.loading_stat.setText("Fun: %d/%d  Addr: %d/%d" % (rtn_i, total_rtn, i+1, nb_candidates))

            self.progressbar_loading.setValue(self.progressbar_loading.value()+1)
            self.functions_candidates[rtn_addr].add(addr) 
Example #16
Source File: IDAMetrics_static.py    From IDAmetrics with BSD 2-Clause "Simplified" License 4 votes vote down vote up
def get_function_args_count(self, function_ea, local_vars):
        """
        The function returns count of function arguments
        @function_ea - function entry point
        @local_vars - local variables dictionary
        @return - function arguments count
        """
        # i#9 Now, we can't identify fastcall functions.

        function_args_count = 0
        args_dict = dict()
        for local_var in local_vars:
            usage_list = local_vars.get(local_var, None)
            if usage_list == None:
                print "WARNING: empty usage list for ", local_var
                continue
            for head in usage_list:
                ops = self.get_instr_operands(int(head, 16))
                for idx, (op,type) in enumerate(ops):
                    if op.count("+") == 1:
                        value = idc.GetOperandValue(int (head, 16), idx)
                        if value < (15 * ARGUMENT_SIZE) and "ebp" in op:
                            args_dict.setdefault(local_var, []).append(head)
                    elif op.count("+") == 2:
                        if "arg" in local_var:
                            args_dict.setdefault(local_var, []).append(head)
                    else:
                        continue

        function_args_count = len(args_dict)
        if function_args_count:
            return function_args_count, args_dict

        #TODO Check previous algorithm here
        f_end = idc.FindFuncEnd(function_ea)
        f_end = idc.PrevHead(f_end, 0)
        instr_mnem = idc.GetMnem(f_end)
        #stdcall ?
        if "ret" in instr_mnem:
            ops = self.get_instr_operands(f_end)
            if len(ops) == 1:
                for op,type in ops:
                    op = op.replace("h", "")
                    function_args_count = int(op,16)/ARGUMENT_SIZE
                    return function_args_count, args_dict
        #cdecl ?
        refs = idautils.CodeRefsTo(function_ea, 0)
        for ref in refs:
            #trying to find add esp,x signature after call
            head = idc.NextHead(ref, 0xFFFFFFFF)
            if head:
                disasm = idc.GetDisasm(head)
                if "add" in disasm and "esp," in disasm:
                    ops = self.get_instr_operands(head)
                    op,type = ops[1]
                    if op:
                        op = op.replace("h", "")
                        function_args_count = int(op,16)/ARGUMENT_SIZE
                        return function_args_count, args_dict
        return function_args_count, args_dict 
Example #17
Source File: 13_注释和重命名.py    From IDAPython_Note with MIT License 4 votes vote down vote up
def check_for_wrapper(func):
    flags = idc.GetFunctionFlags(func)
    #跳过库函数和简单的跳转函数
    if flags & FUNC_LIB or flags & FUNC_THUNK:
        return
    dism_addr = list(idautils.FuncItems(func))
    #获取函数的长度
    func_length = len(dism_addr)
    #如果函数的超过32条指令则返回
    if func_length > 0x20:
        return
    
    func_call = 0
    instr_cmp = 0
    op = None
    op_addr = None
    op_type = None
    
    #遍历函数中的每条指令
    for ea in dism_addr:
        m = idc.GetMnem(ea)
        if m == 'call' or m == 'jmp':
            if m == 'jmp':
                temp = idc.GetOperandValue(ea, 0)
                # 忽略函数边界内的跳转
                if temp in dism_addr:
                    continue
            func_call += 1
            #封装函数内不会包含多个函数调用
            if func_call == 2:
                return
            op_addr = idc.GetOperandValue(ea, 0)
            op_type = idc.GetOpType(ea, 0)
        elif m == 'cmp' or m == 'test':
            # 封装函数内不应该包含太多的逻辑运算
            instr_cmp += 1
            if instr_cmp == 3:
                return
        else:
            continue
    
    # 所有函数内的指令都被分析过了
    if op_addr == None:
        return
    
    name = idc.Name(op_addr)
    #跳过名称粉碎的函数名称
    if "[" in name or "$" in name or "?" in name or "@" in name or name == "":
        return
    name = "w_" + name
    if op_type == o_near:
        if idc.GetFunctionFlags(op_addr) & FUNC_THUNK:
            rename_wrapper(name, func)
            return
    if op_type == o_mem or op_type == o_far:
        rename_wrapper(name, func)
        return 
Example #18
Source File: argtracker.py    From flare-ida with Apache License 2.0 4 votes vote down vote up
def processWriteLog(self, tracker, cVa):
        wlogEntry = tracker.va_write_map.get(cVa, None)
        if (wlogEntry is None):
            return
        pc, writeVa, bytes = wlogEntry
        if (writeVa in self.stackArgLocs) and (self.getStackArgNum(writeVa) not in self.resultArgs.keys()):
            #it's a stack arg value
            pc, value = transformWriteLogEntry(wlogEntry)
            #self.tracker.logger.debug('writelog 0x%08x: Found stack arg %d: 0x%08x', pc, self.getStackArgNum(writeVa), value)
            self.saveResult(writeVa, pc, value)
            return

        if writeVa not in self.tempMapping.keys():
            #self.tracker.logger.debug('writelog 0x%08x: not interesting', pc)
            return

        #argName: the actual value we're tracing back
        argName = self.tempMapping.pop(writeVa)
        pc, value = transformWriteLogEntry(wlogEntry)

        #we found a temp value tracing backwards, but need to determine if it's a constant
        # or if we need to continue tracing backwards. basically as long as it's not
        # a register, we stop?
        mnem = idc.GetMnem(pc)
        srcOpIdx = 0
        if mnem.startswith('push'):
            srcOpIdx = 0
        elif mnem.startswith('mov'):
            srcOpIdx = 1
        else:
            #TODO: any other data movement instructions need to be traced rahter
            # than using the observed write log value?
            #self.tracker.logger.debug('writelog 0x%08x: found (default): 0x%08x', pc, value)
            self.saveResult(argName, pc, value)
            return

        #process data movements instructions:
        optype = idc.GetOpType(pc, srcOpIdx)
        if optype == idc.o_reg:
            #need to trace the new reg now
            newReg = idc.GetOpnd(pc, srcOpIdx)
            #self.tracker.logger.debug('writelog 0x%08x tracing: (%s): %s', pc, self.getArgNameRep(argName), newReg)
            self.tempMapping[newReg] = argName
        else:
            #not a register, so currently assuming we can use the stored value
            #self.tracker.logger.debug('writelog 0x%08x: found (non-reg): 0x%08x', pc, value)
            self.saveResult(argName, pc, value) 
Example #19
Source File: argtracker.py    From flare-ida with Apache License 2.0 4 votes vote down vote up
def processRegMon(self, tracker, cVa):
        if tracker.regMon is None:
            #tracker.logger.debug('regmon: regMon is empty')
            return
        regMods = tracker.regMon.reg_map.get(cVa)
        if regMods is None:
            #tracker.logger.debug('regmon 0x%08x: no entry in reg_map', cVa)
            return
        #figure out if one of the monitored regs is modified in this instruction
        # and if has not already been stored -> just want the first reg value
        regMods = self.tracker.regMon.reg_map[cVa]
        #self.tracker.logger.debug('regmon 0x%08x: examining %d items: %r', cVa, len(regMods), regMods)
        for reg in regMods:
            interesting1 = (reg in self.regs) and (reg not in self.resultArgs.keys())
            interesting2 = (reg in self.tempMapping.keys())
            if (not interesting1) and (not interesting2):
                #modified reg isn't interesting: either a function arg or a temp traced value
                #self.tracker.logger.debug('regmon 0x%08x: not interesting: %s', cVa, reg)
                continue
            mnem = idc.GetMnem(cVa)
            argName = reg
            if interesting1:
                self.regs.remove(reg)
            if interesting2:
                argName = self.tempMapping.pop(reg)
            if mnem.startswith('pop'):
                #add the current stack read address to the temporary tracking
                rlogEntry = tracker.va_read_map.get(cVa, None)
                if rlogEntry is None:
                    raise RuntimeError('readlog entry does not exist for a pop')
                pc, readVa, bytes = rlogEntry
                #self.tracker.logger.debug('regmon 0x%08x tracing (pop): %s (%s): 0x%x', cVa, argName, reg, readVa)
                self.tempMapping[readVa] = argName
            elif mnem.startswith('mov'):
                if idc.GetOpType(cVa, 1) == idc.o_reg:
                    #change to track this reg backwards
                    newReg = idc.GetOpnd(cVa, 1)
                    #self.tracker.logger.debug('regmon 0x%08x tracing (mov): %s (%s)', cVa, argName, newReg)
                    self.tempMapping[newReg] = argName
                else:
                    #not a register, use the modified result otherwise?
                    #self.tracker.logger.debug('regmon 0x%08x found (mov): %s (%s): 0x%x', cVa, argName, reg, regMods[reg])
                    self.saveResult(argName, cVa, regMods[reg])
            else:
                #TODO: any other data movement instructions that should be traced back?
                #self.tracker.logger.debug('regmon 0x%08x found (default): %s (%s): 0x%x', cVa, argName, reg, regMods[reg])
                self.saveResult(argName, cVa, regMods[reg]) 
Example #20
Source File: __init__.py    From flare-ida with Apache License 2.0 4 votes vote down vote up
def rename_constant(arg_ea, fct_name, arg_name, arg_enums):
    """ Rename constants to values from standard enumerations. """
    instruction = idc.GetMnem(arg_ea)
    if instruction == 'push':
        op_num = 0
    elif instruction == 'mov':
        op_num = 1
    else:
        raise RenamingException('Constant: unhandled instruction ' +
                                instruction)

    op_val = idc.GetOperandValue(arg_ea, op_num)
    # NULL
    if op_val == 0:
        targetid = idc.GetConstByName('NULL_{}_{}'.format(arg_name, fct_name))
        serial = 0
        enumid = idc.GetEnum(NULL_ENUM_NAME)
        constid = idc.GetConstEx(enumid, 0, serial, -1)
        while constid != idaapi.BADADDR:
            if constid == targetid:
                idc.OpEnumEx(arg_ea, op_num, enumid, serial)
                return
            serial = serial + 1
            constid = idc.GetConstEx(enumid, 0, serial, -1)

    # All other constants
    op_type = idc.GetOpType(arg_ea, op_num)
    if op_type == idaapi.o_imm:
        # only one choice
        if len(arg_enums) == 1:
            enumid = idc.GetEnum(arg_enums[0])
            idc.OpEnumEx(arg_ea, op_num, enumid, 0)
            return

        for enum in arg_enums:
            enumid = idc.GetEnum(enum)
            constid = get_constant_id(enumid, op_val)
            if constid == idaapi.BADADDR:
                # Not in this enum
                continue
            else:
                # Found the right enum
                idc.OpEnumEx(arg_ea, op_num, enumid, 0)
                return