def parse_function_args(ea: int) -> str: local_variables = [] arguments = [] current = local_variables frame = idc.get_func_attr(ea, FUNCATTR_FRAME) arg_string = "" if frame is None: return "" start = idc.get_first_member(frame) end = idc.get_last_member(frame) count = 0 max_count = 10000 args_str = "" while start <= end and count <= max_count: size = idc.get_member_size(frame, start) count = count + 1 if size is None: start = start + 1 continue name = idc.get_member_name(frame, start) start += size if name in [" r", " s"]: # Skip return address and base pointer current = arguments continue arg_string += f" {name}" current.append(name) args_str = ", ".join(arguments) if len(args_str) == 0: args_str = "void" return f"({args_str})"
def name(self): if self.is_stack: name = idc.get_member_name(self.frame_id, self.stack_offset) else: name = idc.get_name(self.addr) if not name: return '' return name
def build_stack_variable(func_ea): stack_vars = dict() frame = idc.get_func_attr(func_ea, idc.FUNCATTR_FRAME) if not frame: return stack_vars f_name = get_symbol_name(func_ea) #grab the offset of the stored frame pointer, so that #we can correlate offsets correctly in referent code # e.g., EBP+(-0x4) will match up to the -0x4 offset delta = idc.GetMemberOffset(frame, " s") if delta == -1: delta = 0 if f_name not in _FUNC_UNSAFE_LIST: offset = idc.get_first_member(frame) while -1 != _signed_from_unsigned(offset): member_name = idc.get_member_name(frame, offset) if member_name is None: offset = idc.get_next_offset(frame, offset) continue if (member_name == " r" or member_name == " s"): offset = idc.get_next_offset(frame, offset) continue member_size = idc.GetMemberSize(frame, offset) if offset >= delta: offset = idc.get_next_offset(frame, offset) continue member_flag = idc.GetMemberFlag(frame, offset) flag_str = _get_flags_from_bits(member_flag) member_offset = offset-delta stack_vars[member_offset] = {"name": member_name, "size": member_size, "flags": flag_str, "writes": list(), "referent": list(), "reads": list(), "safe": False } offset = idc.get_next_offset(frame, offset) else: offset = idc.get_first_member(frame) frame_size = idc.get_func_attr(func_ea, idc.FUNCATTR_FRSIZE) flag_str = "" member_offset = _signed_from_unsigned(offset) - delta stack_vars[member_offset] = {"name": f_name, "size": frame_size, "flags": flag_str, "writes": list(), "referent": list(), "reads": list(), "safe": False } return stack_vars
def build_stack_variable(func_ea): stack_vars = dict() frame = idc.get_func_attr(func_ea, idc.FUNCATTR_FRAME) if not frame: return stack_vars f_name = get_symbol_name(func_ea) #grab the offset of the stored frame pointer, so that #we can correlate offsets correctly in referent code # e.g., EBP+(-0x4) will match up to the -0x4 offset delta = idc.GetMemberOffset(frame, " s") if delta == -1: delta = 0 if f_name not in _FUNC_UNSAFE_LIST: offset = idc.get_first_member(frame) while -1 != _signed_from_unsigned(offset): member_name = idc.get_member_name(frame, offset) if member_name is None: offset = idc.get_next_offset(frame, offset) continue if (member_name == " r" or member_name == " s"): offset = idc.get_next_offset(frame, offset) continue member_size = idc.GetMemberSize(frame, offset) if offset >= delta: offset = idc.get_next_offset(frame, offset) continue member_flag = idc.GetMemberFlag(frame, offset) flag_str = _get_flags_from_bits(member_flag) member_offset = offset-delta stack_vars[member_offset] = {"name": member_name, "size": member_size, "flags": flag_str, "writes": list(), "referent": list(), "reads": list(), "safe": False } offset = idc.get_next_offset(frame, offset) else: offset = idc.get_first_member(frame) frame_size = idc.get_func_attr(func_ea, idc.FUNCATTR_FRSIZE) flag_str = "" member_offset = _signed_from_unsigned(offset) - delta stack_vars[member_offset] = {"name": f_name, "size": frame_size, "flags": flag_str, "writes": list(), "referent": list(), "reads": list(), "safe": False } return stack_vars
def add_member(self, offset, name, size): if get_member_name(self._sid, 0) == "Dummy": del_struc_member(self._sid, 0) flag = {1: FF_BYTE, 2: FF_WORD, 4: FF_DWORD, 8: FF_QWORD}.get(size) if flag is None: raise ValueError("size") err_code = add_struc_member(self._sid, name, offset, flag | FF_DATA, -1, size) if err_code != 0: raise Exception("err_code = %d" % err_code)
def get_struc_name(self): x = self.target.operands['x'] m = self.target.operands['m'] xtype = x.type xtype.remove_ptr_or_array() typename = idaapi.print_tinfo('', 0, 0, idaapi.PRTYPE_1LINE, xtype, '', '') sid = idc.get_struc_id(typename) member = idc.get_member_name(sid, m) return '%s::%s' % (typename, member)
def get_struc_name(self): x = self.target.operands['x'] m = self.target.operands['m'] xtype = x.type xtype.remove_ptr_or_array() typename = idaapi.print_tinfo('', 0, 0, idaapi.PRTYPE_1LINE, xtype, '', '') sid = idc.get_struc_id(typename) member = idc.get_member_name(sid, m) return '%s::%s' % (typename, member)
def loadMembersIDA7(struc, sid): '''Returns list of tuples of (offset, memberName, member)''' #mixing idc & idaapi, kinda annoying but need low-level idaapi for a # type access, but cant dig into structs... members = [] off = idaapi.get_struc_first_offset(struc) while off != idc.BADADDR: logger.debug('struc offset: 0x%x (%d)', off, off) member = idaapi.get_member(struc, off) if (member == 0) or (member is None): pass #not really an error, i guess else: members.append((off, idc.get_member_name(sid, off), member)) off = idaapi.get_struc_next_offset(struc, off) members.sort(key=lambda mem: mem[0]) return members
def loadMembersIDA7(struc, sid): '''Returns list of tuples of (offset, memberName, member)''' #mixing idc & idaapi, kinda annoying but need low-level idaapi for a # type access, but cant dig into structs... members = [] off = idaapi.get_struc_first_offset(struc) while off != idc.BADADDR: logger.debug('struc offset: 0x%x (%d)', off, off) member = idaapi.get_member(struc, off) if (member == 0) or (member is None): pass #not really an error, i guess else: members.append( (off, idc.get_member_name(sid, off), member) ) off = idaapi.get_struc_next_offset(struc, off ) members.sort(key = lambda mem: mem[0]) return members
def get_stackVariables(func_addr): #print func_addr args = [] stack = idc.get_frame_id(func_addr) if not stack: return 0 firstM = idc.get_first_member(stack) lastM = idc.get_last_member(stack) i = firstM while i <=lastM: mName = idc.get_member_name(stack,i) mSize = idc.get_member_size(stack,i) if mSize: i = i + mSize else: i = i+4 if mName not in args and mName and 'var_' in mName: args.append(mName) return len(args)
def get_stack_arg(func_addr): print func_addr args = [] stack = idc.get_frame_id(func_addr) if not stack: return [] firstM = idc.get_first_member(stack) lastM = idc.get_last_member(stack) i = firstM while i <= lastM: mName = idc.get_member_name(stack, i) mSize = idc.get_member_size(stack, i) if mSize: i = i + mSize else: i = i + 4 if mName not in args and mName and ' s' not in mName and ' r' not in mName: args.append(mName) return args
def StructMembers(sid): """ Get a list of structure members information (or stack vars if given a frame). @param sid: ID of the structure. @return: List of tuples (offset, name, size) @note: If 'sid' does not refer to a valid structure, an exception will be raised. @note: This will not return 'holes' in structures/stack frames; it only returns defined structure members. """ m = idc.get_first_member(sid) if m == -1: raise Exception("No structure with ID: 0x%x" % sid) while (m != ida_idaapi.BADADDR): name = idc.get_member_name(sid, m) if name: yield (m, name, idc.get_member_size(sid, m)) m = idc.get_next_offset(sid, m)
def StructMembers(sid): """ Get a list of structure members information (or stack vars if given a frame). @param sid: ID of the structure. @return: List of tuples (offset, name, size) @note: If 'sid' does not refer to a valid structure, an exception will be raised. @note: This will not return 'holes' in structures/stack frames; it only returns defined structure members. """ sptr = ida_struct.get_struc(sid) if sptr is None: raise Exception("No structure with ID: 0x%x" % sid) for m in sptr.members: name = idc.get_member_name(sid, m.soff) if name: size = ida_struct.get_member_size(m) yield (m.soff, name, size)
def get_member_name(sid, cur_offset): if idaapi.IDA_SDK_VERSION <= 699: mn = idc.GetMemberName(sid, cur_offset) else: mn = idc.get_member_name(sid, cur_offset) return mn
def fill_function(self, ida_func, user=None, state=None): """ Grab all relevant information from the specified user and fill the @ida_func. """ # == function name === # _func = self.pull_function(ida_func, user=user, state=state) if _func is None: return if compat.get_func_name(ida_func.start_ea) != _func.name: compat.set_ida_func_name(ida_func.start_ea, _func.name) # === comments === # # set the func comment func_comment = self.pull_comment(_func.addr, user=user, state=state) if func_comment is None: func_comment = "" #idc.set_func_cmt(_func.addr, func_comment, 1) #compat.set_ida_comment(_func.addr, func_comment, 1, func_cmt=True) # set the disassembly comments func_cmt_end = "\n" for start_ea, end_ea in idautils.Chunks(ida_func.start_ea): for head in idautils.Heads(start_ea, end_ea): if head == _func.addr: continue comment = self.pull_comment(head, user=user, state=state) if comment is not None: func_cmt_end += f"\n{hex(head)}: {comment}" #compat.set_decomp_comments(_func.addr, {head: comment}) #compat.set_ida_comment(head, comment, 0, func_cmt=False) func_comment += func_cmt_end compat.set_ida_comment(_func.addr, func_comment, 1, func_cmt=True) # === stack variables === # existing_stack_vars = {} frame = idaapi.get_frame(ida_func.start_ea) if frame is None or frame.memqty <= 0: _l.debug( "Function %#x does not have an associated function frame. Skip variable name sync-up.", ida_func.start_ea) return frame_size = idc.get_struc_size(frame) last_member_size = idaapi.get_member_size( frame.get_member(frame.memqty - 1)) for i in range(frame.memqty): member = frame.get_member(i) stack_offset = member.soff - frame_size + last_member_size existing_stack_vars[stack_offset] = member for offset, stack_var in self.pull_stack_variables( ida_func, user=user, state=state).items(): ida_offset = stack_var.get_offset(StackOffsetType.IDA) # skip if this variable already exists if ida_offset in existing_stack_vars: type_str = self._get_type_str( existing_stack_vars[ida_offset].flag) else: type_str = None if ida_offset in existing_stack_vars: if idc.get_member_name(frame.id, existing_stack_vars[ida_offset].soff) == stack_var.name \ and type_str is not None \ and stack_var.type == type_str: continue # rename the existing variable idaapi.set_member_name(frame, existing_stack_vars[ida_offset].soff, stack_var.name) # TODO: retype the existing variable # ===== update the psuedocode ==== # compat.refresh_pseudocode_view(_func.addr)
def test_cpu_context(): """Tests function_tracer and and cpu_context.""" import idc from kordesii.utils import function_tracing # Test on encryption function. tracer = function_tracing.get_tracer(0x00401024) context = tracer.context_at(0x00401024) operands = context.operands assert len(operands) == 2 assert operands[0].text == '[ebp+arg_0]' assert operands[0].value == 0 # arg_0 should be 8 bytes from stack pointer. assert operands[0].addr == context.registers.esp + 8 == 0x117f804 assert operands[1].text == 'eax' assert operands[1].value == context.registers.eax == 1 # Test get_original_location() # context = tracer.context_at(0x00401017) # data_ptr = context.registers.edx data_ptr = operands[0].addr assert context.get_variable_name(data_ptr) == '$ F401000.arg_0' ip, orig_location = context.get_original_location(data_ptr) assert ip is None # ip is None, because arg_0 never gets copied explicictly. assert isinstance(orig_location, tuple) frame_id, stack_offset = orig_location assert idc.get_member_name(frame_id, stack_offset) == 'arg_0' # Now execute this instruction and see if arg_0 has be set with the 1 from eax. context.execute(context.ip) assert operands[0].value == 1 # Test getting all possible values passed into arg_0 using using depth. strings = [] for context in tracer.iter_context_at(0x00401003, depth=1): assert context.ip == 0x00401003 # mov eax, [ebp+arg_0] strings.append(context.read_data(context.operands[1].value)) assert strings == [ 'Idmmn!Vnsme ', 'Vgqv"qvpkle"ukvj"ig{"2z20', 'Wkf#rvj`h#aqltm#el{#ivnsp#lufq#wkf#obyz#gld-', 'Keo$mw$wpvkjc$ej`$ehwk$cmraw$wle`a*', 'Dfla%gpwkv%mji`v%lk%rjji%fijqm+', 'Egru&ghb&biau&cgen&ngrc&rnc&irnct(', '\\cv}3g{v3pargv3qfg3w|}4g3qavrx3g{v3t\x7fr``=', 'C\x7frer7c\x7fr7q{xxs7zve|7~d7cry7~yt\x7frd9', '+()./,-"#*', '`QFBWFsQL@FPPb', 'tSUdFS', '\x01\x13\x10n\x0e\x05\x14', '-",5 , v,tr4v,trv4t,v\x7f,ttt', '@AKJDGBA@KJGDBJKAGDC', '!\x1d\x10U\x05\x14\x06\x01U\x02\x1c\x19\x19U\x19\x1a\x1a\x1eU\x17\x07\x1c\x12\x1d\x01\x10\x07U\x01\x1a\x18\x1a\x07\x07\x1a\x02[', '4\x16\x05\x04W\x16\x19\x13W\x15\x02\x04\x04\x12\x04W\x04\x03\x16\x1b\x1b\x12\x13W\x1e\x19W\x04\x16\x19\x13W\x13\x05\x1e\x11\x03\x04Y', '.\x12\x1fZ\x10\x1b\x19\x11\x1f\x0eZ\x12\x0f\x14\x1dZ\x15\x14Z\x0e\x12\x1fZ\x18\x1b\x19\x11Z\x15\x1cZ\x0e\x12\x1fZ\r\x13\x1e\x1fZ\x19\x12\x1b\x13\x08T', 'LMFOGHKNLMGFOHKFGNLKHNMLOKGNKGHFGLHKGLMHKGOFNMLHKGFNLMJNMLIJFGNMLOJIMLNGFJHNM' ] # Test pulling arguments from a call. tracer = function_tracing.get_tracer(0x0040103A) context = tracer.context_at(0x0040103A) operands = context.operands assert len(operands) == 1 assert operands[0].is_func_ptr assert operands[0].value == 0x00401000 # First, attempt to pull the arguments from the stack without get_function_args() first_arg_ptr = context.read_data(context.registers.esp, data_type=function_tracing.DWORD) second_arg = context.read_data(context.registers.esp + 4, data_type=function_tracing.BYTE) assert context.read_data(first_arg_ptr) == "Idmmn!Vnsme " assert second_arg == 1 # Now try with get_function_args() args = context.get_function_args() assert len(args) == 2 assert context.read_data(args[0]) == "Idmmn!Vnsme " assert args[1] == 1
def name(self): return get_member_name(self._sid, self._offset)