def has_locals(ea, lvar_size=1, count_from_first_var=False): frame = idaapi.get_frame(ea) if frame is None or frame.memqty <= 1: return False if count_from_first_var: sida = frame.id offset = idc.GetFirstMember(sida) return idc.GetFrameLvarSize(ea) > lvar_size+offset else: return idc.GetFrameLvarSize(ea) > lvar_size
def stringify(): ea = idc.here() size_data = get_bitness_bytes(ea) f = idaapi.get_func(ea) frsize = idc.GetFrameLvarSize(ea) position = f.startEA size = 0 while position < f.endEA: instr = idautils.DecodeInstruction(position) if instr is None: print("%x: Not and instruction found" % position) break mnem = instr.get_canon_mnem() if mnem == "mov": if instr.Op2.type == idaapi.o_imm and instr.Op1.type == idaapi.o_reg: #this may be string load is_string, size_s = is_this_a_real_string( position + instr.size, instr, size_data) if is_string is True: make_string(instr.Op2.value, size_s) elif mnem == "lea": if instr.Op2.type == idaapi.o_mem and instr.Op1.type == idaapi.o_reg: is_string, size_s = is_this_a_real_string( position + instr.size, instr, size_data) if is_string is True: make_string(instr.Op2.addr, size_s) position += instr.size
def walk_members(ea): global num_stackframes, num_default_stackframe_members frame = idaapi.get_frame(ea) if not frame: return num_stackframes += 1 sid = frame.id s = idaapi.get_struc(sid) if s is None or s == idaapi.BADADDR: return known = set() base = idc.GetFrameLvarSize(ea) for idx in xrange(0, s.memqty): ea = yatools.get_struc_member_by_idx(s, idx) if ea in known: continue m = idaapi.get_member(frame, ea) if not m or idaapi.is_special_member(m.id): continue is_data = m.flag == idaapi.FF_DATA is_default_name = idc.GetMemberName( sid, ea) == get_default_struc_member_name(False, ea, base) size = idaapi.get_member_size(m) no_comment = is_nil(idaapi.get_member_cmt(m.id, 0)) no_repeated = is_nil(idaapi.get_member_cmt(m.id, 1)) if not s.is_union( ) and is_data and size == 1 and is_default_name and no_comment and no_repeated: num_default_stackframe_members += 1 continue if m and not idaapi.is_special_member(m.id): known.add(ea) yield m
def factory(cls, string_location, string_reference, size=INVALID, offset=INVALID, key=INVALID): """ Factory function to generate an EncodedString or EncodedStackString based on type. :param string_location: Data segment pointer for static strings or stack pointer for stack strings. :param string_reference: The location the string is referenced from. This is required to pull the stack frame when string_location is a stack pointer. :param size: The size of the string. Required to use self.get_bytes. :param offset: Used when there is an offset based accessing scheme. :param key: Used when there is a key that can vary by string. """ if idc.isLoaded(string_location): return EncodedString( string_location, string_reference, size=size, offset=offset, key=key) # otherwise assume string_location is a pointer within the stack # (using function_tracingutils's CPU emulator) and create an EncodedStackString object. stack = idc.GetFrame(string_reference) # FIXME: This method isn't always super accurate because... IDA stack_offset = ( string_location + function_tracingutils.RSP_OFFSET + idc.GetFrameLvarSize(string_reference) - function_tracingutils.STACK_BASE ) return EncodedStackString( stack, stack_offset, string_reference=string_reference, size=size, offset=offset, key=key)
def append_lvar_comment(fva, frame_offset, s, repeatable=False): ''' add the given string as a (possibly repeatable) stack variable comment to the given function. does not add the comment if it already exists. adds the comment on its own line. Args: fva (int): the address of the function with the stack variable. frame_offset (int): the offset into the stack frame at which the variable is found. s (str): the comment text. repeatable (bool): if True, set a repeatable comment. Raises: UnicodeEncodeError: if the given string is not ascii. ''' s = s.encode('ascii') stack = idc.GetFrame(fva) if not stack: raise RuntimeError('failed to find stack frame for function: ' + hex(fva)) lvar_offset = idc.GetFrameLvarSize(fva) - frame_offset if not lvar_offset: raise RuntimeError('failed to compute local variable offset') if lvar_offset <= 0: raise RuntimeError('failed to compute positive local variable offset') string = idc.GetMemberComment(stack, lvar_offset, repeatable) if not string: string = s else: if s in string: # ignore duplicates return string = string + "\\n" + s if not idc.SetMemberComment(stack, lvar_offset, string, repeatable): raise RuntimeError('failed to set comment')
def locals_size(self): return idc.GetFrameLvarSize(self.func_addr)
def detect_prologue(self): """Check wheater the function prologue is present or not.""" # # Common prologue is as follows: # # mflr %r0 ; if not leaf proc, get ret address # stwu %sp, -0x1A8(%sp) ; allocate stack space # stmw %r28, 0x1A8+var_10(%sp); store temp regs # stw %r0, 0x1A8+arg_4(%sp) ; store ret address # try: # Check the instructions from the first basic block # to find common function prologue bb = self.lir_function[0] # Check only in the first three instructions for inst in bb: # STEP 1.A # # Check if it modifies %sp and get the number of allocated # bytes. if inst.analyzed: continue if inst.type == self.iset.PPC_stwu and \ inst[0].is_reg_n(self.iset.SP) and \ inst[1].is_displ and \ inst[1].value[0] == self.iset.SP: # # Mark instruction as already analyzed and as part of the # standard prologue instruction to avoid output representation. # inst.analyzed = True self.lir_function.add_prologue_address(inst.address) # Add the stack size found. stack_size = abs(self.get_signed_value( inst[1].value[1] )) self.lir_function.stack_size = stack_size break if self.lir_function.stack_size != 0: print " Stack allocation found 0x%X (%d) bytes. Double check: " % \ (self.lir_function.stack_size, self.lir_function.stack_size), # TODO: Check any difference with get_frame_size() frame_size = self.debugger.get_frame_size(inst.address) if self.lir_function.stack_size == frame_size: print "OK" else: print "INVALID (should be %d bytes)" % frame_size else: print "[-] Stack allocation NOT found. Using debugger detection:", # TODO : Remove IDA specific function call. frame_size = idc.GetFrameLvarSize(inst.address) self.lir_function.stack_size = frame_size print "OK (%d bytes)" % frame_size # STEP 1.B # # Obtain information about the method used to access # local variables. # # If we can't find a register used as a copy of sp, then # we asume IOS-style using SP like this: # # add rd, sp, imm # # TODO : why is there a slice in the enum below? for index, inst in enumerate(bb[1 : ], 1): # Start generating the high-level representation # of the current function to decompile the binary. # Indicate the prologue-related addresses to avoid # decompiling them. if inst.type == self.iset.PPC_mr and inst[1].is_reg_n(self.iset.SP): # Seems that we've found an SP being moved to another # register. self.lir_function.add_prologue_address(inst.address) self.lir_function.add_stack_access_register(inst[0].value) # Mark the instruction but before stop looking, confirm the # finding by looking for that store operation on that # register (backup). # # 018000BC stw %r31, 28(%sp) ; Find this STW given # 018000C0 mr %r31, %sp ; this MR instruction. # # TODO: stack pointer definition !!!!!!!!!!!!! inst.analyzed = True for i in bb[index : 0 : -1]: # walk backwards. op0_value = i[0].value if i.type in [self.iset.PPC_stw, self.iset.PPC_stwu] and \ op0_value in self.lir_function.stack_access_registers: # Stack register backup operation found i.analyzed = True self.lir_function.add_prologue_address(i.address) break # Output stack access information found. stack_access_registers = self.lir_function.stack_access_registers stack_access_registers = [ self.iset.GPR_NAMES[r] for r in stack_access_registers] if self.iset.SP in self.lir_function.stack_access_registers: stack_access_type = " Stack accessed via stack-pointer: " else: stack_access_type = " Stack accessed via frame-pointer: " print "%s %s" % (stack_access_type, ", ".join(stack_access_registers)) # STEP 2 # Another instruction should save %lr in case we aren't processing # a leaf procedure. # Look for the second isntruction of this sequence: # # mflr %r0 # ... # stw %r0, 0xE0+arg for inst in bb: if inst.analyzed or not inst.type == self.iset.PPC_mflr: continue lr_backup_reg = inst[0].value # dest reg for %lr lr_store_found = False # flag inst.analyzed = True self.lir_function.add_prologue_address(inst.address) # Check only in the first n instructions for inst in bb: if inst.analyzed: continue if inst.type == self.iset.PPC_stw and \ inst[0].is_reg_n(lr_backup_reg): # Found LR store operation from previous move self.lir_function.add_prologue_address(inst.address) inst.analyzed = True lr_store_found = True self.lir_function.leaf_procedure = False break if not lr_store_found: raise PowerPc32GccIdiomAnalyzerException( "Could not locate link register backup instruction") if self.lir_function.leaf_procedure is True: print " Current function is a leaf procedure." else: print " Current function is NOT a leaf procedure." except MiddleIrException, err: print format_exc() + '\n' raise PowerPc32GccIdiomAnalyzerException(err)