def iterFuncChunks(self, ea): start = self.funcStart(ea) end = self.funcEnd(ea) if not start or not end: return [] current = idc.FirstFuncFchunk(start) chunks = [current] while True: next = idc.NextFuncFchunk(start, current) if next != idc.BADADDR: current = next chunks.append(next) else: break res = [] for chunk in chunks: chunk_end = idc.GetFchunkAttr(chunk, idc.FUNCATTR_END) res.extend(list(self.iterInstructions(chunk, chunk_end))) return res
def __chunks(cls, ea): '''enumerates all chunks in a function ''' res = idc.FirstFuncFchunk(ea) while res != idc.BADADDR: (start, end) = idc.GetFchunkAttr(res, idc.FUNCATTR_START), idc.GetFchunkAttr(res, idc.FUNCATTR_END) yield start,end res = idc.NextFuncFchunk(ea, res) return
def _convert_address_to_function(func): """Convert an address that IDA has classified incorrectly into a proper function.""" # If everything goes wrong, we'll try to restore this function. orig = idc.FirstFuncFchunk(func) # If the address is not code, let's undefine whatever it is. if not idc.isCode(idc.GetFlags(func)): if not is_mapped(func): # Well, that's awkward. return False item = idc.ItemHead(func) itemend = idc.ItemEnd(func) if item != idc.BADADDR: _log(1, 'Undefining item {:#x} - {:#x}', item, itemend) idc.MakeUnkn(item, idc.DOUNK_EXPAND) idc.MakeCode(func) # Give IDA a chance to analyze the new code or else we won't be able to create a # function. idc.Wait() idc.AnalyseArea(item, itemend) else: # Just try removing the chunk from its current function. IDA can add it to another function # automatically, so make sure it's removed from all functions by doing it in loop until it # fails. for i in range(1024): if not idc.RemoveFchunk(func, func): break # Now try making a function. if idc.MakeFunction(func) != 0: return True # This is a stubborn chunk. Try recording the list of chunks, deleting the original function, # creating the new function, then re-creating the original function. if orig != idc.BADADDR: chunks = list(idautils.Chunks(orig)) if idc.DelFunction(orig) != 0: # Ok, now let's create the new function, and recreate the original. if idc.MakeFunction(func) != 0: if idc.MakeFunction(orig) != 0: # Ok, so we created the functions! Now, if any of the original chunks are not # contained in a function, we'll abort and undo. if all(idaapi.get_func(start) for start, end in chunks): return True # Try to undo the damage. for start, _ in chunks: idc.DelFunction(start) # Everything we've tried so far has failed. If there was originally a function, try to restore # it. if orig != idc.BADADDR: _log(0, 'Trying to restore original function {:#x}', orig) idc.MakeFunction(orig) return False
def FunctionChunks(addr): result = [] entry = idc.GetFunctionAttr(addr, idc.FUNCATTR_START) chunk = idc.FirstFuncFchunk(entry) if chunk == BADADDR: return result # list the function chunks result.append([chunk, idc.GetFchunkAttr(chunk, idc.FUNCATTR_END)]) while chunk != BADADDR: chunk = idc.NextFuncFchunk(entry, chunk) if chunk != BADADDR: result.append([chunk, idc.GetFchunkAttr(chunk, idc.FUNCATTR_END)]) return result
def enumerate_function_chunks(f_start): """ The function gets a list of chunks for the function. @f_start - first address of the function @return - list of chunks """ # Enumerate all chunks in the function chunks = list() first_chunk = idc.FirstFuncFchunk(f_start) chunks.append((first_chunk, idc.GetFchunkAttr(first_chunk, idc.FUNCATTR_END))) next_chunk = first_chunk while next_chunk != 0xffffffffL: next_chunk = idc.NextFuncFchunk(f_start, next_chunk) if next_chunk != 0xffffffffL: chunks.append( (next_chunk, idc.GetFchunkAttr(next_chunk, idc.FUNCATTR_END))) return chunks
def deobfuscate_function(addr): if addr != idc.FirstFuncFchunk(addr): print "[DEOBF] Address %X is not the start of a function." % addr return # Static data. func_start = addr func_end = idc.FindFuncEnd(addr) # 1. Find MOV PC (mov_addr, mov_match) = search_forward(func_start, func_end, regex_mov) if mov_addr is None: # print "[DEOBF] No MOV PC was found in %s" % idc.GetFunctionName(func_start) return # 2. Find LDR.W .. ldr_addr = search_register_modifier_backward(mov_addr, func_start, mov_match.group(1)) ldr_match = regex_ldrw.match( idc.GetDisasm(ldr_addr)) if ldr_addr is not None else None if ldr_addr is None: print "[DEOBF] No LDR.W was found in %s" % idc.GetFunctionName( func_start) return if ldr_match is None: print "[DEOBF] Modifier of %s found from %X is not a LDR.W" % ( mov_match.group(1), mov_addr) return # 3. Find table offset add_addr = search_register_modifier_backward(ldr_addr, func_start, ldr_match.group(2)) # add_match = regex_table.match(idc.GetDisasm(add_addr)) if add_addr is not None else None # # print idc.GetEnum(add_match.group(2) + 'asd') if add_addr is None: # TODO: Check if belongs to a previously found graph. # print "[DEOBF] No ADD was found above %X" % ldr_addr return if idc.GetOpnd(add_addr, 1) != 'PC': print "[DEOBF] ADD does not use PC at %X" % add_addr return ldr2_addr = search_register_modifier_backward(idc.PrevHead(add_addr), func_start, idc.GetOpnd(add_addr, 0)) opp_val = idc.GetOperandValue(ldr2_addr, 1) # Address to loc_80054 opp_val = idc.Dword(opp_val) # loc_80054 opp_val = opp_val + idc.NextHead(add_addr) + 2 # Address of the table. # 4. Read table. table = [] table_addr = opp_val while True: table_entry = idc.Dword(table_addr) if table_entry > 0: table.append(table_entry) table_addr = table_addr + 4 if idc.Name(table_addr): break # - We also have to add the starting block to the table. table.append(func_start) # 5. Find subroutine boundary (sub_start, sub_end) = find_subroutine_boundary(opp_val, table) print "Start: %X - End: %X" % (sub_start, sub_end)