def get_func_code_refs_from(func_ea, iaddrs):
"""Returns a set with the code references from this function"""
code_refs = set()
for addr in iaddrs:
ref = idaapi.BADADDR
for r in idautils.XrefsFrom(addr, idaapi.XREF_FAR):
if r.iscode:
to_func = idaapi.get_func(r.to)
if not to_func or to_func.startEA != func_ea:
ref = r.to
else:
ref = r.to
if (ref != idaapi.BADADDR or idaapi.is_call_insn(addr) or idaapi.is_indirect_jump_insn(addr)):
#print hex(i.addr), i, hex(ref)
code_refs.add(ref)
return code_refs
python类get_func()的实例源码
def get_func_code_refs_to(func_ea):
"""Returns a set with the code references to this function"""
code_refs = set()
for ref in idautils.CodeRefsTo(func_ea, 0): #callers
func_ida = idaapi.get_func(ref)
if not func_ida:
#print "BUG?: coderef came from no function! %X->%X"%(ref, addr)
continue
#if func_ida.startEA not in functions:
# print "BUG?: function %X not in our set (r=%X)!"%(func_ida.startEA, ref)
# continue
code_refs.add((ref, func_ida.startEA))
return code_refs
def enum_function_addrs(fva):
'''
yield the effective addresses of each instruction in the given function.
these addresses are not guaranteed to be in any order.
Args:
fva (int): the starting address of a function
Returns:
sequence[int]: the addresses of each instruction
'''
f = idaapi.get_func(fva)
if not f:
raise ValueError('not a function')
for block in idaapi.FlowChart(f):
ea = block.startEA
while ea <= block.endEA:
yield ea
ea = idc.NextHead(ea)
def rename(ea, newname):
fl = database.type.flags(ea)
labelQ, customQ = (fl & n == n for n in (idaapi.FF_LABL,idaapi.FF_NAME))
#r, fn = database.xref.up(ea), idaapi.get_func(ea)
fn = idaapi.get_func(ea)
# figure out whether a global or function name is being changed, otherwise it's the function's contents
ctx = internal.comment.globals if not fn or (fn.startEA == ea) else internal.comment.contents
# if a name is being removed
if not newname:
# if it's a custom name
if (not labelQ and customQ):
ctx.dec(ea, '__name__')
return
# if it's currently a label or is unnamed
if (labelQ and not customQ) or all(not n for n in (labelQ,customQ)):
ctx.inc(ea, '__name__')
return
def extra_cmt_changed(ea, line_idx, cmt):
# FIXME: persist state for extra_cmts in order to determine
# what the original value was before modification
oldcmt = internal.netnode.sup.get(ea, line_idx)
ctx = internal.comment.contents if idaapi.get_func(ea) else internal.comment.globals
MAX_ITEM_LINES = (idaapi.E_NEXT-idaapi.E_PREV) if idaapi.E_NEXT > idaapi.E_PREV else idaapi.E_PREV-idaapi.E_NEXT
prefix = (idaapi.E_PREV, idaapi.E_PREV+MAX_ITEM_LINES, '__extra_prefix__')
suffix = (idaapi.E_NEXT, idaapi.E_NEXT+MAX_ITEM_LINES, '__extra_suffix__')
for l,r,key in (prefix,suffix):
if l <= line_idx < r:
if oldcmt is None and cmt: ctx.inc(ea, key)
elif oldcmt and cmt is None: ctx.dec(ea, key)
continue
return
### function scope
def check_global(ea):
if idaapi.get_func(ea): return False
cache = internal.comment.decode(db.get_comment(db.top()))
cache.update( internal.comment.decode(db.get_comment(db.bottom())) )
node = internal.netnode.get(internal.comment.globals.Node)
tag = internal.comment.decode(db.get_comment(ea))
if cache and '__address__' not in cache: return False
if not cache and tag: return False
count = internal.netnode.alt.get(node, ea)
if tag and not count: return False
if len(tag['__address__']) != count: return False
keys = tag['__tags__']
if any(t not in cache for t in keys): return False
return True
def __init__(self, location):
self.at = location
# self.name = GetFunctionName(location)
self.name = GetFuncOffset(location)
self.start = 0
self.end = 0
self.func_offset = 0
try:
_func = idaapi.get_func(location)
self.start = _func.startEA
self.end = _func.endEA # ==FindFuncEnd(location)
self.func_offset = self.start - self.at
except Exception, e:
logger.exception(e)
if not self.name:
self.indirect = True
else:
self.indirect = False
def FuncItems(start):
"""
Get a list of function items
@param start: address of the function
@return: ea of each item in the function
"""
func = idaapi.get_func(start)
if not func:
return
fii = idaapi.func_item_iterator_t()
ok = fii.set(func)
while ok:
yield fii.current()
ok = fii.next_code()
def DeleteAll():
"""
Delete all segments, instructions, comments, i.e. everything
except values of bytes.
"""
ea = idaapi.cvar.inf.minEA
# Brute-force nuke all info from all the heads
while ea != BADADDR and ea <= idaapi.cvar.inf.maxEA:
idaapi.del_local_name(ea)
idaapi.del_global_name(ea)
func = idaapi.get_func(ea)
if func:
idaapi.del_func_cmt(func, False)
idaapi.del_func_cmt(func, True)
idaapi.del_func(ea)
idaapi.del_hidden_area(ea)
seg = idaapi.getseg(ea)
if seg:
idaapi.del_segment_cmt(seg, False)
idaapi.del_segment_cmt(seg, True)
idaapi.del_segm(ea, idaapi.SEGDEL_KEEP | idaapi.SEGDEL_SILENT)
ea = idaapi.next_head(ea, idaapi.cvar.inf.maxEA)
def SetFunctionFlags(ea, flags):
"""
Change function flags
@param ea: any address belonging to the function
@param flags: see GetFunctionFlags() for explanations
@return: !=0 - ok
"""
func = idaapi.get_func(ea)
if not func:
return 0
else:
func.flags = flags
idaapi.update_func(func)
return 1
def GetFunctionCmt(ea, repeatable):
"""
Retrieve function comment
@param ea: any address belonging to the function
@param repeatable: 1: get repeatable comment
0: get regular comment
@return: function comment string
"""
func = idaapi.get_func(ea)
if not func:
return ""
else:
comment = idaapi.get_func_cmt(func, repeatable)
if not comment:
return ""
else:
return comment
def GetFrameSize(ea):
"""
Get full size of function frame
@param ea: any address belonging to the function
@returns: Size of function frame in bytes.
This function takes into account size of local
variables + size of saved registers + size of
return address + size of function arguments
If the function doesn't have a frame, return size of
function return address in the stack.
If the function does't exist, return 0
"""
func = idaapi.get_func(ea)
if not func:
return 0
else:
return idaapi.get_frame_size(func)
def GetSpd(ea):
"""
Get current delta for the stack pointer
@param ea: end address of the instruction
i.e.the last address of the instruction+1
@return: The difference between the original SP upon
entering the function and SP for the specified address
"""
func = idaapi.get_func(ea)
if not func:
return None
return idaapi.get_spd(func, ea)
def GetSpDiff(ea):
"""
Get modification of SP made by the instruction
@param ea: end address of the instruction
i.e.the last address of the instruction+1
@return: Get modification of SP made at the specified location
If the specified location doesn't contain a SP change point, return 0
Otherwise return delta of SP modification
"""
func = idaapi.get_func(ea)
if not func:
return None
return idaapi.get_sp_delta(func, ea)
def SetFchunkOwner(tailea, funcea):
"""
Change the function chunk owner
@param tailea: any address in the function chunk
@param funcea: the starting address of the new owner
@return: 0 if failed, 1 if success
@note: The new owner must already have the chunk appended before the call
"""
tail = idaapi.get_func(tailea)
if not tail:
return 0
else:
return idaapi.set_tail_owner(tail, funcea)
def FirstFuncFchunk(funcea):
"""
Get the first function chunk of the specified function
@param funcea: any address in the function
@return: the function entry point or BADADDR
@note: This function returns the first (main) chunk of the specified function
"""
func = idaapi.get_func(funcea)
fci = idaapi.func_tail_iterator_t(func, funcea)
if fci.main():
return fci.chunk().startEA
else:
return BADADDR
def find_all_ioctls():
"""
From the currently selected address attempts to traverse all blocks inside the current function to find all immediate values which
are used for a comparison/sub immediately before a jz. Returns a list of address, second operand pairs.
"""
ioctls = []
# Find the currently selected function and get a list of all of it's basic blocks
addr = idc.ScreenEA()
f = idaapi.get_func(addr)
fc = idaapi.FlowChart(f, flags=idaapi.FC_PREDS)
for block in fc:
# grab the last two instructions in the block
last_inst = idc.PrevHead(block.endEA)
penultimate_inst = idc.PrevHead(last_inst)
# If the penultimate instruction is cmp or sub against an immediate value immediatly preceding a 'jz'
# then it's a decent guess that it's an IOCTL code (if this is a disptach function)
if idc.GetMnem(penultimate_inst) in ['cmp', 'sub'] and idc.GetOpType(penultimate_inst, 1) == 5:
if idc.GetMnem(last_inst) == 'jz':
ioctl_tracker.add_ioctl(penultimate_inst)
for inst in ioctl_tracker.ioctl_locs:
value = get_operand_value(inst)
ioctls.append((inst, value))
return ioctls
def find_dispatch_by_struct_index():
"""Attempts to locate the dispatch function based off it being loaded in a structure
at offset 70h, based off of https://github.com/kbandla/ImmunityDebugger/blob/master/1.73/Libs/driverlib.py """
out = set()
for function_ea in idautils.Functions():
flags = GetFunctionFlags(function_ea)
# skip library functions
if flags & FUNC_LIB:
continue
func = idaapi.get_func(function_ea)
addr = func.startEA
while addr < func.endEA:
if GetMnem(addr) == 'mov':
if '+70h' in GetOpnd(addr, 0) and idc.GetOpType(addr, 1) == 5:
out.add(GetOpnd(addr, 1))
addr = idc.NextHead(addr)
return out
def handleHookFuncLinkMemory(self):
if self.hookedFunction() == False:
return
func = get_func(ScreenEA())
if func is None:
return
address = func.startEA;
self.idbHookMap[address].mem_list = self.linkMemoryRanges();
entry = self.idbHookMap[address]
outJSON = json.dumps({
"req_id": kFridaLink_UpdHookRequest,
"data": entry.genUpdRequest(HookEntry.UPD_MEMLIST)
})
self.clientSocket.sendto(outJSON, self.clientAddress)
def handleUnhookFunc(self, screenEA = None):
if screenEA is not None:
func = get_func(screenEA)
else:
func = get_func(ScreenEA())
if func is None:
return
address = func.startEA;
if self.hookedFunction(address) == False:
return
entry = self.idbHookMap[address]
outJSON = json.dumps({
"req_id": kFridaLink_DelHookRequest,
"data": entry.genDelRequest()
})
del self.idbHookMap[address]
self.clientSocket.sendto(outJSON, self.clientAddress)
SetColor(address, CIC_FUNC, kIDAViewColor_Reset)
refresh_idaview_anyway()
self.idbHooksView.setContent(self.idbHookMap)
def hookedFunction(self, screenEA = None):
if screenEA is not None:
func = get_func(screenEA)
else:
func = get_func(ScreenEA())
if func is None:
return False;
address = func.startEA;
if address in self.idbHookMap:
# can be start of the function, check hook type
if self.idbHookMap[func.startEA].hook.type == "func":
return True
else:
return False
else:
return False
def resolveStackAddress(self, address, symbol):
if symbol[0] == "0x0":
return None
info = {}
info['module'] = str(symbol[1])
segm = get_segm_by_name(info['module'])
if segm is not None:
locEA = segm.startEA
delta = address - int(symbol[0], 16) + locEA
func = get_func(delta)
if func is not None:
info['symbol'] = str(get_func_name(delta))
else:
info['symbol'] = str(GetDisasm(delta))
elif symbol[2] != '':
if symbol[2] == '<redacted>':
info['symbol'] = "+0x%X" % (address - int(symbol[0], 16))
else:
info['symbol'] = str(symbol[2])
else:
info['symbol'] = ''
return info
def GetIDX(self,ea):
DEBUG_PRINT('IN GetIDX')
idx = -1
comm = str(idc.GetCommentEx(ea, 0))
if '__' not in comm:
print 'no comment here'
return -1
DEBUG_PRINT(comm)
start = comm.find(self._commMarker)+len(self._commMarker)
if self._global == 1:
end = comm.find('_g')
idx = int(comm[start:end])
else:
end = comm.find('_L')
idx = int(comm[start:end]) + self._dbDict[idaapi.get_func(ea).startEA]._idx_list[0][0]
return idx
def get_cursor_func_ref():
current_tform = idaapi.get_current_tform()
tform_type = idaapi.get_tform_type(current_tform)
# get the hexrays vdui (if available)
vu = idaapi.get_tform_vdui(current_tform)
if vu:
cursor_addr = vu.item.get_ea()
elif tform_type == idaapi.BWN_DISASM:
cursor_addr = idaapi.get_screen_ea()
op_addr = idc.GetOperandValue(cursor_addr, idaapi.get_opnum())
op_func = idaapi.get_func(op_addr)
if op_func and op_func.startEA == op_addr:
return op_addr
else:
return idaapi.BADADDR
cursor_func = idaapi.get_func(cursor_addr)
if cursor_func and cursor_func.startEA == cursor_addr:
return cursor_addr
return idaapi.BADADDR
def log_stack_chains(chains):
f = open("%s/%s" % (LOG_PATH, "stack_chains"), "wb")
long_chains = 0
for c in chains:
if len(c) > 3:
long_chains += 1
for a in c:
if type(a) == type("x"):
s = a
else:
s = "[0x%08x] %s+0x%x" % (a, str(idc.GetFunctionName(Dword(a))), Dword(a) - idaapi.get_func(Dword(a)).startEA)
#print s
f.write(s)
f.write("\n")
f.write("\n")
print "%d chains found" % len(chains)
print "%d long chains" % long_chains
f.close()
def str_fun_xrefs():
str_fun_xref = {}
for s in IDAStrings:
for ref in idautils.DataRefsTo(s.ea):
f = idaapi.get_func(ref)
if not f:
continue
if idc.GetMnem(ref) == "":
continue
f_ea = f.startEA
try:
#because we are only carrying the string value itself, duplications should be removed.
#This is important because of OFFS/ADR instruction double references being very typical,
#and multiple allocations/frees in same function causing extra references too.
str_fun_xref[f_ea].add(str(s))
except:
str_fun_xref[f_ea] = set([str(s)])
return str_fun_xref
def ret_addr(ea):
#we can't assume Thumb only, so we also keep ARM cases, just adjust addr in Thumb cases
if (ea % 2) != 0:
ea -= 1
f_ea = idaapi.get_func(ea)
if not f_ea:
return False
#Preceding or Previous?
# Not necessarily all preceding will be a call to a ret instruction,
# but "the" prev should be always the one.
i = idautils.DecodePreviousInstruction(ea)
if i and "BL" in idc.GetMnem(i.ea):
return True
return False
def output_symbols(out):
"""Dump symbols."""
try:
from idaapi import get_func_name2 as get_func_name
# Since get_func_name is deprecated (at least from IDA 6.9)
except ImportError:
from idaapi import get_func_name
# Older versions of IDA don't have get_func_name2
# so we just use the older name get_func_name
def func_name_propagate_thunk(ea):
current_name = get_func_name(ea)
if current_name[0].isalpha():
return current_name
func = idaapi.get_func(ea)
temp_ptr = idaapi.ea_pointer()
ea_new = idaapi.BADADDR
if func.flags & idaapi.FUNC_THUNK == idaapi.FUNC_THUNK:
ea_new = idaapi.calc_thunk_func_target(func, temp_ptr.cast())
if ea_new != idaapi.BADADDR:
ea = ea_new
propagated_name = get_func_name(ea) or '' # Ensure it is not `None`
if len(current_name) > len(propagated_name) > 0:
return propagated_name
else:
return current_name
# Fallback to non-propagated name for weird times that IDA gives
# a 0 length name, or finds a longer import name
for ea in idautils.Segments():
fs = idautils.Functions(idc.SegStart(ea), idc.SegEnd(ea))
for f in fs:
out.write('("%s" 0x%x 0x%x)\n' % (
func_name_propagate_thunk(f),
idc.GetFunctionAttr(f, idc.FUNCATTR_START),
idc.GetFunctionAttr(f, idc.FUNCATTR_END)))
def find_cfunc(ea):
"""Get cfuncptr_t from EA."""
func = idaapi.get_func(ea)
if func:
return idaapi.decompile(func)
def find_tight_loops(fva):
""" Code from Willi Ballenthin """
tight_loops = []
function = idaapi.get_func(fva)
for bb in idaapi.FlowChart(function):
# bb.endEA is the first addr not in the basic block
bb_end = idc.PrevHead(bb.endEA)
for x in idautils.XrefsFrom(bb_end):
if x.to == bb.startEA and bb.startEA < bb_end:
tight_loops.append((bb.startEA, bb_end))
if tight_loops:
g_logger.debug("Tight loops in 0x%x: %s", fva, ["0x%x - 0x%x" % (s, e) for (s, e) in tight_loops])
return tight_loops