def define_functions(): native_rvas = [ 0x1930, 0x3A90, 0x44b0, ] native_rvas = [(0x400000 + x) for x in native_rvas] for ea in native_rvas: if ea == 0x401930: # undefine and force convert to code as IDA doesn't analyse it at first print "Defining fcn GODDAG at 0x%x" % ea print "Making", ea, "unknown and defining it to code..." idc.MakeUnkn(ea, 1) idc.MakeCode(ea) idc.MakeUnkn(ea + 8, 1) idc.MakeCode(ea + 7) else: if ea == 0x403A90: fcn_name = "NativeGRUNDTAL_NORRVIKEN" print "Defining fcn %s at 0x%x" % (fcn_name, ea) elif ea == 0x4044B0: fcn_name = "FYRKANTIGImpl" print "Defining fcn %s at 0x%x" % (fcn_name, ea) idc.MakeFunction(ea) idc.MakeNameEx(ea, fcn_name, idc.SN_NOWARN)
def main(): for segstart, segend, segname in enum_segments(): if segname not in ('.text', '.data'): continue for src, dst in find_pointers(segstart, segend): if is_code(src): # ignore instructions like: # # call ds:__vbaGenerateBoundsError #print('code pointer: 0x%x -> 0x%x' % (src, dst)) continue # TODO: fix this: just look at the few previous bytes and ensure they are ASCII/Unicode if is_in_string(src): # for example, the following contains 0x444974 (a common valid offset): # # text:004245B0 aRequestid db 'requestID', # # enable or disable this behavior as you wish print('string pointer: 0x%x -> 0x%x' % (src, dst)) pass #continue print('pointer from 0x%x to 0x%x' % (src, dst)) if is_unknown(dst): print('destination unknown, making byte: 0x%x' % (dst)) idc.MakeByte(dst) elif is_head(dst): # things are good pass else: # need to undefine head, and make byte head_va = get_head(dst) print('destination overlaps with head: 0x%x' % (head_va)) idc.MakeUnkn(head_va, dst - head_va) idc.MakeByte(head_va) idc.MakeByte(dst) idc.MakeUnkn(src, 4) idc.MakeDword(src) # this doesn't seem to always work :-( # ref: https://reverseengineering.stackexchange.com/questions/17798/how-can-i-mark-a-global-variable-as-an-offset-using-idapython #idc.OpOffset(src, 0) ida_offset.op_offset(src, 0, idc.REF_OFF32)
def main(): for segstart, segend, segname in enum_segments(): if segname not in ('.text', '.data'): continue for src, dst in find_pointers(segstart, segend): if is_code(src): # ignore instructions like: # # call ds:__vbaGenerateBoundsError #print('code pointer: 0x%x -> 0x%x' % (src, dst)) continue if is_in_string(src): # for example, the following contains 0x444974 (a common valid offset): # # text:004245B0 aRequestid db 'requestID', # # enable or disable this behavior as you wish print('string pointer: 0x%x -> 0x%x' % (src, dst)) pass #continue print('pointer from 0x%x to 0x%x' % (src, dst)) if is_unknown(dst): print('destination unknown, making byte: 0x%x' % (dst)) idc.MakeByte(dst) elif is_head(dst): # things are good pass else: # need to undefine head, and make byte head_va = get_head(dst) print('destination overlaps with head: 0x%x' % (head_va)) idc.MakeUnkn(head_va, dst - head_va) idc.MakeByte(head_va) idc.MakeByte(dst) idc.MakeUnkn(src, 4) idc.MakeDword(src) # this doesn't seem to always work :-( idc.OpOffset(src, 0)
def assign_struct_to_address(address, struct_name): idc.ApplyType(address, get_Tinfo_from_name(struct_name)) struct_id = idaapi.get_struc_id(struct_name) if struct_id != 0xffffffffffffffff: struct_size = idaapi.get_struc_size(struct_id) for i in range(struct_size): idc.MakeUnkn(address+i, 0) return idaapi.doStruct(address, struct_size, struct_id) return False
def parse_pclntable(module_data): pPcHeader = module_data.pPcHeader pc_header = parse_pc_header(pMem=pPcHeader) ptrSize = pc_header.ptrSize numberOfFuncs = pc_header.nFunc log._info("Number of Functions : %d" % numberOfFuncs) pclntable_start = module_data.pPclnTable cur_addr = pclntable_start for idx in range(numberOfFuncs): cur_addr = pclntable_start + (2 * ptrSize) * idx func_rva = common.mem_read_integer(addr=cur_addr, read_size=ptrSize) _func_structure_offset = common.mem_read_integer(addr=cur_addr + ptrSize, read_size=ptrSize) _func_addr = pclntable_start + _func_structure_offset if not idc.GetFunctionName(func_rva): log._info("Unk Func @0x%x" % func_rva) idc.MakeUnkn(func_rva, idc.DOUNK_EXPAND) idaapi.autoWait() idc.MakeCode(func_rva) idaapi.autoWait() if idc.MakeFunction(func_rva): idaapi.autoWait() log._info("Create Func @0x%x" % func_rva) _func = parse__func(pMem=_func_addr) #args=_func.args #func_id=_func.args func_name_addr = module_data.pFuncNameTable + _func.nameoff func_name = idc.GetString(func_name_addr) if func_name: clean_func_name = utils.clean_function_name(func_name) log._info("@0x%x Name : [%s]" % (func_rva, func_name)) idc.MakeComm(func_rva, "@0x" + str(hex(func_rva)) + " entry") idaapi.autoWait() if idc.MakeStr(func_name_addr, func_name_addr + len(func_name) + 1): idaapi.autoWait() else: log._error("@0x%x Name : [%s] Failed..." % (func_rva, func_name)) _func_addr = idaapi.get_func(func_rva) if _func_addr is not None: if idc.MakeNameEx(_func_addr.startEA, func_name, flags=idaapi.SN_FORCE): idaapi.autoWait() log._info("@0x%x Name : [%s]" % (func_rva, func_name)) else: log._error("@0x%x Name : [%s] Failed..." % (func_rva, func_name))
def renameDword(self): proc_addr = self._import_table.item(self._import_table.currentRow(), 3).text() proc_name = str(self._import_table.item(self._import_table.currentRow(), 2).text()) renamed = 0 if proc_addr: try: proc_addr = int(proc_addr, 16) proc_bin_str = " ".join([x.encode("hex") for x in struct.pack("<I", proc_addr)]) next_dword = idc.FindBinary(idc.MinEA(), idc.SEARCH_DOWN|idc.SEARCH_NEXT, proc_bin_str) while next_dword != idc.BADADDR: log.debug("Trying to fix-up 0x{:08x}".format(next_dword)) # DWORDs can be "inaccessible" for many reasons and it requires "breaking up" the data blobs # and manually fixing them # Reason 1: In a dword array in an unknown section if idc.isUnknown(next_dword): idc.MakeUnkn(next_dword, idc.DOUNK_EXPAND) idc.MakeDword(next_dword) # Reason 2: In a dword array in a data section elif idc.isData(next_dword): hd = idc.ItemHead(next_dword) idc.MakeDword(hd) idc.MakeDword(next_dword) # Reason 3: In a dword array in a code section (validate via "dd <dword>,") elif idc.isCode(next_dword) and idc.GetDisasm(next_dword).startswith("dd "): hd = idc.ItemHead(next_dword) idc.MakeDword(hd) idc.MakeDword(next_dword) # Only perform if idc.Name(next_dword).startswith(("off_", "dword_")) or idc.Name(next_dword) == "": success = idc.MakeNameEx(next_dword, proc_name, idc.SN_NOWARN|idc.SN_NON_AUTO) i = 0 new_proc_name = proc_name while not success and i < 10: new_proc_name = "{}{}".format(proc_name, i) success = idc.MakeNameEx(next_dword, new_proc_name, idc.SN_NOWARN|idc.SN_NON_AUTO) i += 1 if success: renamed += 1 item = self._import_table.item(self._import_table.currentRow(), 5) item.setText("{}, {}".format(str(item.text()), new_proc_name)) log.debug("DWORD @ 0x{:08x} now has name {}".format(next_dword, new_proc_name)) else: log.error("Unable to auto-rename successfully, terminating search") break else: log.debug("Value at 0x{:08x} does not meet renaming requirements".format(next_dword)) next_dword = idc.FindBinary(next_dword+4, idc.SEARCH_DOWN|idc.SEARCH_NEXT, proc_bin_str) except Exception, e: log.error("Error encountered: {}".format(e)) log.debug("Renamed {:d} instances of {}".format(renamed, proc_name))
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 origFun(self, ip): print('look for fun having ip 0x%x' % ip) fun = self.getFun(ip) if fun is None: simicsString = gdbProt.Evalx( 'SendGDBMonitor("@cgc.getSO(0x%x)");' % ip) print('No function found. Check load for: %s' % simicsString) if ':' in simicsString: sofile, start_end = str(simicsString).rsplit(':', 1) print('sofile is %s start_end is %s' % (sofile, start_end)) if '-' not in start_end: print('Bad response from getSO: %s' % simicsString) return full = os.path.join(self.root_prefix, sofile[1:]) sopath = self.getFunPath(full) start, end = start_end.split('-') start = int(start, 16) end = int(end, 16) self.add(sopath, start) fun = self.getFun(ip) print('start 0x%x end 0x%x' % (start, end)) idaapi.analyze_area(start, end) for fun in sorted(self.funs): if fun >= start and fun <= end: name = str(self.funs[fun]['name']) nea = idaapi.get_name_ea(idaapi.BADADDR, name) if nea != idaapi.BADADDR: name = name + '_so' idc.MakeName(int(fun), name) print('made name for 0x%x %s' % (int(fun), name)) for fun in self.funs: if fun >= start and fun <= end: #print('fun 0x%x name <%s>' % (fun, name)) idc.MakeFunction(fun, idaapi.BADADDR) elif fun is not None: print('Do one fun 0x%x' % fun) for i in range(self.funs[fun]['start'], self.funs[fun]['end']): idc.MakeUnkn(i, 1) idaapi.auto_mark_range(self.funs[fun]['start'], self.funs[fun]['end'], 25) idaapi.autoWait() return fun return None
def parse_funcs(self): ''' Parse function struct and rename function ''' self.func_num = common.read_mem(self.start_addr + 8, forced_addr_sz=self.ptr_sz) common._info("Total functions number: %d\n" % self.func_num) self.func_tbl_sz = self.func_num * 2 * self.ptr_sz funcs_entry = self.start_addr + 8 self.func_tbl_addr = funcs_entry + self.ptr_sz idc.MakeComm(funcs_entry, "Functions number") idc.MakeNameEx(funcs_entry, "funcs_entry", flags=idaapi.SN_FORCE) idaapi.autoWait() idc.MakeNameEx(self.func_tbl_addr, "pc0", flags=idaapi.SN_FORCE) idaapi.autoWait() for func_idx in xrange(self.func_num): curr_addr = self.func_tbl_addr + func_idx * 2 * self.ptr_sz func_addr = common.read_mem(curr_addr, forced_addr_sz=self.ptr_sz) if not idc.GetFunctionName(func_addr): common._debug("Creating function @ %x" % func_addr) idc.MakeUnkn(func_addr, idc.DOUNK_EXPAND) idaapi.autoWait() idc.MakeCode(func_addr) idaapi.autoWait() if idc.MakeFunction(func_addr): idaapi.autoWait() common._info("Create function @ 0x%x" % func_addr) name_off = common.read_mem(curr_addr + self.ptr_sz, forced_addr_sz=self.ptr_sz) name_addr = self.start_addr + self.ptr_sz + name_off func_st_addr = name_addr - self.ptr_sz func_st = FuncStruct(func_st_addr, self) func_st.parse() # Make comment for name offset idc.MakeComm(curr_addr + self.ptr_sz, "Func Struct @ 0x%x" % func_st_addr) idaapi.autoWait()
def fix_names(self): """ Fix the table of imports and map enums to apis. """ start_addr = idc.AskAddr(idc.here(), "Enter table start address") ## check if address is within the base address and maximum address if (start_addr < idc.MinEA()) or (start_addr > idc.MaxEA()): idc.Warning("You have entered an invalid start address") idc.Exit self.start_addr = start_addr current_addr = self.start_addr #Current size of PoisonIvy IAT end_addr = current_addr + 568 # Walk the table 8 bytes at a time while current_addr <= end_addr: idc.MakeQword(current_addr) print "DEBUG: Current address - 0x%08x" % current_addr addr = idc.Qword(current_addr) print "DEBUG: address - 0x%08x" % addr if addr == -1: print "[!] Skipping address 0x%08x - 0x%08x" % (current_addr, addr) current_addr += 8 continue # Make the current address an offset idc.OpOff(current_addr,0,0) # We need to undefine the bytes incase IDA autoanalysis had converted an incorrect byte idc.MakeUnkn(addr, 1) # Create code at this address idc.MakeCode(addr) # Create function at the same address idc.MakeFunction(addr, addr+16) # Read the second operand at the address which should be the negative API address value imp_addr = idc.GetOperandValue(addr, 1) if imp_addr == -1: print "[!] Couldn't get operand at address - 0x%08x" % addr current_addr +=8 continue # try: # int_addr = int(imp_addr,16) # except ValueError as e: # print "[!] Failed on: %s - %s\n" % (imp_addr, e) # current_addr +=8 # continue # if we know about this value then let's do the work if imp_addr in self.enums.keys(): enum_id = self.enums[imp_addr] # Convert operand to enum idc.OpEnumEx(addr, 1, enum_id,0) const_id = idc.GetConstEx(enum_id, imp_addr, 0, -1) fn_name = "fn_"+idc.GetConstName(const_id) off_name = "ptr_"+idc.GetConstName(const_id) # Rename the function to the symbol name. # We append fn_ to the symbol for the function name # and ptr_ to the offset in the table. if not idc.MakeNameEx(addr, fn_name, idaapi.SN_NOWARN): print "[!] Failed to rename function %s at 0x%08x\n" % (fn_name, addr) if not idc.MakeNameEx(current_addr, off_name, idaapi.SN_NOWARN): print "[!] Failed to rename offset %s at 0x%08x\n" % (off_name,current_addr) current_addr += 8 return
def make_data(self, object_version, address): size = 0 try: size = object_version.get_size() except KeyError: pass flags = None try: flags = object_version.get_object_flags() except KeyError: pass if size == 0: idc.MakeUnkn(address, idc.DOUNK_EXPAND) else: if flags is not None: if idc.isASCII(flags): try: str_type = object_version.get_string_type() YaToolIDATools.check_and_set_str_type(str_type) except KeyError: pass idc.MakeStr(address, address + size) idc.SetFlags(address, flags) if idc.isStruct(flags): found = False for xref_offset_operand, xref_id_attr in object_version.get_xrefed_id_map( ).iteritems(): (xref_offset, xref_operand) = xref_offset_operand for xref_hash, xref_attrs in xref_id_attr: if xref_hash in self.struc_ids: struc_id = self.struc_ids[xref_hash] if DEBUG_EXPORTER: logger.debug( "making unknown from 0x%08X to 0x%08X" % (address, address + size)) idaapi.do_unknown_range( address, size, idc.DOUNK_DELNAMES) # idc.MakeUnkn(address, DOUNK_SIMPLE | idc.DOUNK_DELNAMES) # for i in xrange(1, size): # MakeName(address + i, "") # idc.MakeUnkn(address + i, DOUNK_SIMPLE | idc.DOUNK_DELNAMES) # idc.MakeStructEx uses idaapi.doStruct (but asks for name while # we already have the struc id) if DEBUG_EXPORTER: logger.debug( "Making struc at %s : %s (sizeof(%s)=0x%08X, size=0x%08X, flags=0x%08X" % (self.yatools.address_to_hex_string( address), self.yatools.address_to_hex_string( struc_id), idaapi.get_struc_name(struc_id), idc.GetStrucSize(struc_id), size, flags)) idc.SetCharPrm(idc.INF_AUTO, True) idc.Wait() if idaapi.doStruct(address, size, struc_id) == 0: if DEBUG_EXPORTER: logger.warning("Making struc failed") idc.SetCharPrm(idc.INF_AUTO, False) # idc.SetFlags(address, flags) found = True else: logger.error( "bad struc flags : idc.isStruct is true but no xref available for object %s" % self.hash_provider.hash_to_string( object_version.get_id())) if not found: logger.error( "bad struc flags : idc.isStruct is true " "but no struc available for object %s (%s)" % (self.hash_provider.hash_to_string( object_version.get_id()), object_version.get_name())) else: idc.MakeData(address, flags & (idc.DT_TYPE | idc.MS_0TYPE), size, 0) else: idc.MakeData(address, idc.FF_BYTE, size, 0) self.make_name(object_version, address, False) self.set_type(object_version, address)
def undefBytes(ea, length) : curr = ea while curr < ea + length : idc.MakeUnkn(curr, 0) curr += 1
def AsmAndWrite(self, mnem, instr=None, write_ea=None, function=None): if mnem == '': return if write_ea != None: ea_write = write_ea else: ea_write = self.free_ea idc.MakeUnkn(ea_write, 0) #tmp = idaapi.assemble(self.free_ea, self.segment_start, self.free_ea, 1, mnem) if debug: print ">Assemble:AsmAndWrite - !Writing @ ea[%08x] ip[%08x] instr[%s]" % ( ea_write, ea_write, mnem) tmp = idaapi.assemble(ea_write, 0, ea_write, 1, mnem) if instr != None: idaapi.set_cmt(ea_write, "%08x" % instr.GetOriginEA(), 0) if tmp == 0: if instr == None and function != None: raise MiscError if debug: print '>Assemble:AsmAndWrite - !Messy instruction', mnem print '>Assemble:AsmAndWrite - Trying original opcodes!' refs_from = [ x for x in function.GetRefsFrom(instr.GetOriginEA()) if x != None ] if len(refs_from) == 0: if instr.GetIsModified() == True: raise MiscError instr_op = instr.GetOpcode() for pos in xrange(0, len(instr_op)): idc.PatchByte(ea_write + pos, ord(instr_op[pos])) if idc.MakeCode(ea_write) == 0: raise MiscError ea_write += idc.ItemSize(ea_write) elif len(refs_from) == 1: instr_op = instr.GetOpcode() for pos in xrange(0, len(instr_op)): idc.PatchByte(ea_write + pos, ord(instr_op[pos])) if idc.MakeCode(ea_write) == 0: raise MiscError ea_write += idc.ItemSize(ea_write) else: #print '>Assemble:AsmAndWrite - GetRefsFrom(%08x)' % instr.GetOriginEA(), [hex(x) for x in function.GetRefsFrom(instr.GetOriginEA()) if x != None] print '>Assemble:AsmAndWrite - refs_from', refs_from print '>Assemble:AsmAndWrite - ea_write [%08x]' % ea_write print '>Assemble:AsmAndWrite - mnem', mnem print '>Assemble:AsmAndWrite - instr.GetMnem', instr.GetMnem() print '>Assemble:AsmAndWrite - instr.GetDisasm', instr.GetDisasm( ) raise MiscError else: if idc.MakeCode(ea_write) == 0: raise MiscError ea_write += idc.ItemSize(ea_write) if write_ea == None: self.free_ea = ea_write
def __call__(self): try: l.debug("Making unknown at " + hex(self.address)) self.result = idc.MakeUnkn(self.address, self.size) except Exception: self.exception = True
def undefBytes(ea, count): for i in range(count): idc.MakeUnkn(ea + i, 1)