def create_containing_record(self, expression, index, offset): negative_lvar = self.negative_lvars[index] # print "[DEBUG] Rebuilding negative offset", negative_lvar.offset, offset, negative_lvar.parent_tinfo.dstr() diff = negative_lvar.offset + offset arg_address = idaapi.carg_t() if expression.op == idaapi.cot_var: arg_address.consume_cexpr(expression) else: arg_address.consume_cexpr(expression.x) arg_type = idaapi.carg_t() cexpr_helper = idaapi.create_helper(True, self.pvoid_tinfo, negative_lvar.parent_tinfo.dstr()) arg_type.consume_cexpr(cexpr_helper) arg_field = idaapi.carg_t() cexpr_helper = idaapi.create_helper(True, self.pvoid_tinfo, negative_lvar.member_name) arg_field.consume_cexpr(cexpr_helper) return_tinfo = idaapi.tinfo_t(negative_lvar.parent_tinfo) return_tinfo.create_ptr(return_tinfo) new_cexpr_call = idaapi.call_helper(return_tinfo, None, "CONTAINING_RECORD") new_cexpr_call.a.push_back(arg_address) new_cexpr_call.a.push_back(arg_type) new_cexpr_call.a.push_back(arg_field) # new_cexpr_call.ea = expression.ea # new_cexpr_call.x.ea = expression.ea parent = reversed(self.parents).next().cexpr if diff: number = idaapi.make_num(diff) new_cexpr_add = idaapi.cexpr_t(idaapi.cot_add, new_cexpr_call, number) new_cexpr_add.thisown = False new_cexpr_add.type = return_tinfo if parent.op == idaapi.cot_ptr: tmp_tinfo = idaapi.tinfo_t() tmp_tinfo.create_ptr(parent.type) new_cexpr_cast = idaapi.cexpr_t(idaapi.cot_cast, new_cexpr_add) new_cexpr_cast.thisown = False new_cexpr_cast.type = tmp_tinfo expression.replace_by(new_cexpr_cast) else: expression.replace_by(new_cexpr_add) else: if parent.op == idaapi.cot_ptr: tmp_tinfo = idaapi.tinfo_t() tmp_tinfo.create_ptr(parent.type) new_cexpr_cast = idaapi.cexpr_t(idaapi.cot_cast, new_cexpr_call) new_cexpr_cast.thisown = False new_cexpr_cast.type = tmp_tinfo expression.replace_by(new_cexpr_cast) else: expression.replace_by(new_cexpr_call)
def visit_insn(self, instruction): if instruction.op == idaapi.cit_block: while True: cblock = instruction.cblock size = cblock.size() if size >= 2: # Find block that has "If" and "return" as last 2 statements if cblock.back().op == idaapi.cit_return and \ cblock.at(size - 2).op == idaapi.cit_if and not cblock.at(size - 2).cif.ielse: cit_then = cblock.at(size - 2).cif.ithen # Skip if only one (not "if") statement in "then" branch if cit_then.cblock.size( ) == 1 and cit_then.cblock.front().op != idaapi.cit_if: return 0 # Replacing condition to opposite cit_if_condition = cblock.at(size - 2).cif.expr if cit_if_condition.op == idaapi.cot_lnot: # Ida has following bug: # when return type of call cexpr_t is not signed int, function idaapi.lnot leads to crash new_if_condition = idaapi.cexpr_t( cit_if_condition.x) else: new_if_condition = idaapi.cexpr_t( idaapi.lnot(cit_if_condition)) new_if_condition.thisown = False cblock.at(size - 2).cif.expr = new_if_condition del cit_if_condition # Take return from list of statements and later put it back cit_return = idaapi.cinsn_t(instruction.cblock.back()) cit_return.thisown = False instruction.cblock.pop_back() # Fill main block with statements from "Then" branch while cit_then.cblock: instruction.cblock.push_back( cit_then.cblock.front()) cit_then.cblock.pop_front() # Put back main return if there's no another return or "GOTO" already if instruction.cblock.back().op not in ( idaapi.cit_return, idaapi.cit_goto): new_return = idaapi.cinsn_t(cit_return) new_return.thisown = False instruction.cblock.push_back(new_return) # Put return into "Then" branch cit_then.cblock.push_back(cit_return) continue break return 0
def inverse_if(cif): idaapi.qswap(cif.ithen, cif.ielse) cit_if_condition = cif.expr if cit_if_condition.op == idaapi.cot_lnot: new_if_condition = idaapi.cexpr_t(cit_if_condition.x) else: new_if_condition = idaapi.cexpr_t(idaapi.lnot(cit_if_condition)) new_if_condition.thisown = False cif.expr = new_if_condition del cit_if_condition
def visit_expr(self, expr): """ Search for simple assignents to stack vars """ if expr.op != ida_hexrays.cot_asg: return 0 _x = expr.x _y = expr.y if _x.op == ida_hexrays.cot_var and _y.op == ida_hexrays.cot_num: # Something like "v1 = 65" num_value = _y.n.value(_y.type) # Bail out soon if num_value < 1 or num_value > 255: return 0 if chr(num_value) not in string.printable: return 0 # Create a new expr object to replace _y # This will be of type cot_str z = idaapi.cexpr_t() # In order to modify an existing cexpr # you have to swap it with a newly created one z.swap(_y) _y.op = ida_hexrays.cot_str _y.string = chr(num_value) return 0
def inverse_if_condition(cif): # cexpr_t has become broken but fortunately still exist `assing` method which copies one expr into another cit_if_condition = cif.expr tmp_cexpr = idaapi.cexpr_t() tmp_cexpr.assign(cit_if_condition) new_if_condition = idaapi.lnot(tmp_cexpr) cif.expr.swap(new_if_condition) del cit_if_condition
def leave_expr(self, e): if e.op == idaapi.cot_call: self.reset() elif self.func is not None and e.is_child_of(self.func): if (self.viable is False or self.cast_type is None or self.func is None or self.type is None): self.reset() return 0 else: self.type.remove_ptr_or_array() # Currently we do this so that base classes have a # cast_type that is equal to this_type, but maybe # it causes problems sometimes? self.cast_type.remove_ptr_or_array() this_type = get_type_by_name(self.type.dstr()) cast_type = get_type_by_name(self.cast_type.dstr()) if cast_type != this_type: table = this_type.table_for_cast(cast_type) else: table = this_type.tablegroup.primary_table() if self.index is None: self.index = 0 func = table.functions[self.index] # Create a new cot_obj expression and fill it with # the ea of the function. Also use the type of the # function. obj = idaapi.cexpr_t() obj.op = idaapi.cot_obj t = tinfo_for_ea(func) if t is not None: t.create_ptr(t) obj.type = t #FIXME: this is a quick fix to correct the number of # args to agree with the function type. Type info is # still not propagated correctly. This might be fixed # by running the visitor at an earlier maturity, but # it is more difficult to identify virtual calls at # earlier stages. self.func.a.resize(t.get_nargs()) else: obj.type = self.func.x.type set_obj_ea(obj, func) # Replace the existing func object (the virtual function # pointer) with the new cot_obj obj.swap(self.func.x) self.reset() return 0
def my_cexpr_t(*args, **kwargs): """ Replacement of bugged cexpr_t() function """ if len(args) == 0: return idaapi.cexpr_t() if len(args) != 1: raise NotImplementedError cexpr = idaapi.cexpr_t() cexpr.thisown = False if type(args[0]) == idaapi.cexpr_t: cexpr.assign(args[0]) else: op = args[0] cexpr._set_op(op) if 'x' in kwargs: cexpr._set_x(kwargs['x']) if 'y' in kwargs: cexpr._set_y(kwargs['y']) if 'z' in kwargs: cexpr._set_z(kwargs['z']) return cexpr
def invert_if(self, cfunc, insn): if insn.opname != 'if': return False cif = insn.details if not cif.ithen or not cif.ielse: return False idaapi.qswap(cif.ithen, cif.ielse) cond = idaapi.cexpr_t(cif.expr) notcond = idaapi.lnot(cond) cif.expr.swap(notcond) return True
def invert_if(self, cfunc, insn): if insn.opname != 'if': return False cif = insn.details if not cif.ithen or not cif.ielse: return False idaapi.qswap(cif.ithen, cif.ielse) cond = idaapi.cexpr_t(cif.expr) notcond = idaapi.lnot(cond) cond.thisown = 0 # the new wrapper 'notcond' now holds the reference to the cexpr_t cif.expr.swap(notcond) return True
def invert_if(self, cfunc, insn): if insn.opname != 'if': return False cif = insn.details if not cif.ithen or not cif.ielse: return False idaapi.qswap(cif.ithen, cif.ielse) cond = idaapi.cexpr_t(cif.expr) notcond = idaapi.lnot(cond) cond.thisown = 0 # the new wrapper 'notcond' now holds the reference to the cexpr_t cif.expr.swap(notcond) return True
def invert_if(self, cfunc, insn): if insn.opname != 'if': return False cif = insn.details if not cif.ithen or not cif.ielse: return False idaapi.qswap(cif.ithen, cif.ielse) # Make a copy of 'cif.expr': 'lnot' might destroy its toplevel # cexpr_t and return a pointer to its direct child (but we'll want to # 'swap' it later, the 'cif.expr' cexpr_t object must remain valid.) cond = idaapi.cexpr_t(cif.expr) notcond = idaapi.lnot(cond) cif.expr.swap(notcond) return True
def visit_expr(self, expr): try: if expr.op == idaapi.cot_call and expr.x.op == idaapi.cot_helper: #print idaapi.tag_remove(expr.x.print1(None)) if expr.x.helper == "ARM64_SYSREG" and len(expr.a) == 5: # and idaapi.getseg(expr.ea).use64(): reg = 0 for j, i in enumerate(expr.a): if i.type != inttype: break #print i.n.value(i.type) reg = reg | (i.numval() << shifts[j]) else: if reg in regs64.keys(): n = idaapi.cexpr_t() n.op = idaapi.cot_helper n.helper = regs64[reg] n.exflags = idaapi.EXFL_ALONE expr.cleanup() expr.replace_by(n) #print "ok" elif expr.x.helper == "__mrc" and len(expr.a) == 5: # and not idaapi.getseg(expr.ea).use64(): reg = 0 for j, i in enumerate(expr.a): if i.type != inttype: break reg = reg | (i.numval() << shifts[j]) else: if reg in regs32.keys(): n = idaapi.cexpr_t() n.op = idaapi.cot_helper n.helper = regs32[reg] n.exflags = idaapi.EXFL_ALONE #expr.x.helper = "_ReadSystemReg" while len(expr.a) > 1: expr.a.pop_back() expr.a[0].cleanup() expr.a[0].replace_by(n) elif expr.x.helper == "__mcr" and len(expr.a) == 6: # and not idaapi.getseg(expr.ea).use64(): reg = 0 for j, i in enumerate(expr.a): if shiftz[j] < 0: continue if i.type != inttype: break reg = reg | (i.numval() << shiftz[j]) else: if reg in regs32.keys(): n = idaapi.cexpr_t() n.op = idaapi.cot_helper n.helper = regs32[reg] n.exflags = idaapi.EXFL_ALONE #expr.x.helper = "_WriteSystemReg" expr.a[1] = expr.a[2] while len(expr.a) > 2: expr.a.pop_back() expr.a[0].cleanup() expr.a[0].replace_by(n) print "ok" except: traceback.print_exc() return 0
def visit_expr(self, expression): global Storage self.nodes.append(expression) if expression.op == idaapi.cot_obj: for start, end, off, func in Storage: if expression.obj_ea >= start and expression.obj_ea <= end: if func and self.cfunc.entry_ea != func: return 0 target_ea = expression.obj_ea + off head_ea = idaapi.get_item_head(target_ea) if head_ea != target_ea and idaapi.isStruct(idaapi.getFlags(head_ea)): ref_parent = self.cfunc.body.find_parent_of(expression) if ref_parent.op == idaapi.cot_ref: parent = self.cfunc.body.find_parent_of(ref_parent) if parent.op == idaapi.cot_add: v = target_ea - head_ea num_node = idaapi.make_num(v) num_node.thisown = False num_node.n.thisown = False parent = parent.cexpr # parent.thisown = False tif = idaapi.tinfo_t() if not idaapi.get_tinfo(tif, head_ea): idaapi.guess_tinfo(tif, head_ea) if parent.x == ref_parent.cexpr: # ref_parent.thisown = False # ref_parent.cexpr.thisown = False ref_parent = parent.x # expression = ref_parent.x ref_new = idaapi.cexpr_t(ref_parent) ref_new.thisown = False # expression.thisown = False # expression_new.type.thisown = False # tif.thisown = False element_tif = tif.get_ptrarr_object() element_tif.create_ptr(element_tif) ref_new.type = element_tif ref_new.x.type = tif ref_new.x.obj_ea = head_ea expr_add = idaapi.cexpr_t(idaapi.cot_add, ref_new, num_node) expr_add.thisown = False # expr_add.type = element_tif ref_parent.cexpr.assign(expr_add) # parent.x.thisown = False # parent.x.swap(expr_add) # ref_parent1 = idaapi.cexpr_t(ref_parent.cexpr) # parent.x.swap(ref_parent1) elif parent.y == ref_parent.cexpr: ref_parent.thisown = False ref_parent.cexpr.thisown = False ref_parent = idaapi.cexpr_t(ref_parent.cexpr) expression.thisown = False expression = idaapi.cexpr_t(expression) ref_parent.x.replace_by(expression) expr_add = idaapi.cexpr_t(idaapi.cot_add, ref_parent, num_node) parent.y.thisown = False parent.y.replace_by(expr_add) else: print "F**K!" rc = self.recalc_parent_types() # parent = self.nodes[-2] # parent = self.nodes[-3] # parent = self.nodes[-4] return 0