def find_unusual_xors(functions):
# TODO find xors in tight loops
candidate_functions = []
for fva in functions:
cva = fva
while cva != idaapi.BADADDR and cva < idc.FindFuncEnd(fva):
if idc.GetMnem(cva) == "xor":
if idc.GetOpnd(cva, 0) != idc.GetOpnd(cva, 1):
g_logger.debug("suspicious XOR instruction at 0x%08X in function 0x%08X: %s", cva, fva,
idc.GetDisasm(cva))
ph = idc.PrevHead(cva)
nh = idc.NextHead(cva)
ip = idc.GetDisasm(ph)
ia = idc.GetDisasm(nh)
if ip and ia:
g_logger.debug("Instructions: %s; %s; %s", ip, idc.GetDisasm(cva), ia)
if ph or nh:
if is_security_cookie(cva, ph, nh):
g_logger.debug("XOR related to security cookie: %s", idc.GetDisasm(cva))
else:
g_logger.debug("unusual XOR: %s", idc.GetDisasm(cva))
candidate_functions.append(fva)
break
cva = idc.NextHead(cva)
return candidate_functions
python类BADADDR的实例源码
def extract_addresses(self):
'''A set of addresses associated with the line'''
anchor = idaapi.ctree_anchor_t()
line = copy(self.widget.line)
addresses = set()
while len(line) > 0:
skipcode_index = idaapi.tag_skipcode(line)
if skipcode_index == 0: # No code found
line = line[1:] # Skip one character ahead
else:
if tag_addrcode(line):
addr_tag = int(line[2:skipcode_index], 16)
anchor.value = addr_tag
if anchor.is_citem_anchor() \
and not anchor.is_blkcmt_anchor():
address = self.parent.treeitems.at(addr_tag).ea
if address != idaapi.BADADDR:
addresses.add(address)
line = line[skipcode_index:] # Skip the colorcodes
return addresses
def notify_auto_empty_finally(self):
"""
Info: all analysis queues are empty definitively
"""
ss = strwinsetup_t()
ss.minlen = 7
ss.strtypes = 9
ss.ignore_heads = 1
ss.ea1 = 0
SetLongPrm(INF_STRTYPE, ASCSTR_UNICODE)
set_strlist_options(ss)
refresh_strlist(0, BADADDR)
si = string_info_t()
for i in range(get_strlist_qty()):
if get_strlist_item(i, si):
if not isCode(GetFlags(si.ea)):
ea = get_start(si.ea)
s = make_str(ea)
hd = ItemHead(si.ea)
do_unknown(hd, 0)
make_ascii_string(ea, len(s) + 1, ASCSTR_UNICODE)
MakeRptCmt(ea, "\"%s\"" % s)
def find_shifts(functions):
candidate_functions = {}
# TODO better to compare number of shifts to overall instruction count?
# TODO find shifts in tight loops
shift_mnems = set(["shl", "shr", "sar", "sal", "rol", "ror"])
shift_mnems_len = len(shift_mnems)
for fva in functions:
found_shifts = set([])
cva = fva
while cva != idaapi.BADADDR and cva < idc.FindFuncEnd(fva):
i = idc.GetMnem(cva)
if i in shift_mnems:
found_shifts.add(i)
g_logger.debug("shift instruction: %s va: 0x%x function: 0x%x", idc.GetDisasm(cva), cva, fva)
cva = idc.NextHead(cva)
candidate_functions[fva] = 1 - ((shift_mnems_len - len(found_shifts)) / float(shift_mnems_len))
return candidate_functions
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
def __init__(self, start_ea, end_ea, node_id=idaapi.BADADDR):
# node metadata
self.size = end_ea - start_ea
self.address = start_ea
self.instruction_count = 0
# flowchart node_id
self.id = node_id
# parent function_metadata
self.function = None
# instruction addresses
self.instructions = []
#----------------------------------------------------------------------
# collect metdata from the underlying database
self._build_metadata()
#--------------------------------------------------------------------------
# Metadata Population
#--------------------------------------------------------------------------
def _init(self):
"""
Initialize plugin members.
"""
# plugin color palette
self.palette = LighthousePalette()
# the coverage engine
self.director = CoverageDirector(self.palette)
# the coverage painter
self.painter = CoveragePainter(self.director, self.palette)
# the coverage overview widget
self._ui_coverage_overview = None
# menu entry icons
self._icon_id_file = idaapi.BADADDR
self._icon_id_batch = idaapi.BADADDR
self._icon_id_overview = idaapi.BADADDR
# the directory to start the coverage file dialog in
self._last_directory = idautils.GetIdbDir()
def _uninstall_load_file(self):
"""
Remove the 'File->Load file->Code coverage file...' menu entry.
"""
# remove the entry from the File-> menu
result = idaapi.detach_action_from_menu(
"File/Load file/",
self.ACTION_LOAD_FILE
)
if not result:
return False
# unregister the action
result = idaapi.unregister_action(self.ACTION_LOAD_FILE)
if not result:
return False
# delete the entry's icon
idaapi.free_custom_icon(self._icon_id_file)
self._icon_id_file = idaapi.BADADDR
logger.info("Uninstalled the 'Code coverage file' menu entry")
def _uninstall_load_batch(self):
"""
Remove the 'File->Load file->Code coverage batch...' menu entry.
"""
# remove the entry from the File-> menu
result = idaapi.detach_action_from_menu(
"File/Load file/",
self.ACTION_LOAD_BATCH
)
if not result:
return False
# unregister the action
result = idaapi.unregister_action(self.ACTION_LOAD_BATCH)
if not result:
return False
# delete the entry's icon
idaapi.free_custom_icon(self._icon_id_batch)
self._icon_id_batch = idaapi.BADADDR
logger.info("Uninstalled the 'Code coverage batch' menu entry")
def list(cls, **type):
"""List all of the names in the database that match ``type``.
Search can be constrained by the named argument ``type``.
like = glob match against name
ea, address = name is at address
name = exact name match
regex = regular-expression against name
index = name at index
pred = function predicate
"""
res = __builtin__.list(cls.__iterate__(**type))
maxindex = max(res or [1])
maxaddr = max(__builtin__.map(idaapi.get_nlist_ea, res) or [idaapi.BADADDR])
cindex = math.ceil(math.log(maxindex)/math.log(10))
caddr = math.floor(math.log(maxaddr)/math.log(16))
for index in res:
print "[{:>{:d}d}] {:0{:d}x} {:s}".format(index, int(cindex), idaapi.get_nlist_ea(index), int(caddr), idaapi.get_nlist_name(index))
return
def list(cls, **type):
"""List all of the imports in the database that match ``type``.
Search can be constrained by the named argument ``type``.
like = glob match against import short name
ea, address = import is at address
fullname = glob match against import long name -> MODULE!function
module = glob match against module
ordinal = exact match against import ordinal number
name = exact match against import name
regex = regular-expression against import name
index = import name at index
pred = function predicate
"""
res = __builtin__.list(cls.iterate(**type))
maxaddr = max(__builtin__.map(utils.first, res) or [idaapi.BADADDR])
maxmodule = max(__builtin__.map(utils.compose(utils.second, utils.first, len), res) or [''])
caddr = math.floor(math.log(maxaddr)/math.log(16))
cordinal = max(__builtin__.map(utils.compose(utils.second, operator.itemgetter(2), "{:d}".format, len), res) or [1])
for ea,(module,name,ordinal) in res:
print "{:0{:d}x} {:s}<{:<d}>{:s} {:s}".format(ea, int(caddr), module, ordinal, ' '*(cordinal-len("{:d}".format(ordinal)) + (maxmodule-len(module))), name)
return
def dissolve(cls, flag, typeid, size):
dt = flag & cls.FF_MASKSIZE
sf = -1 if flag & idaapi.FF_SIGN == idaapi.FF_SIGN else +1
if dt == idaapi.FF_STRU and isinstance(typeid,six.integer_types):
# FIXME: figure out how to fix this recursive module dependency
t = sys.modules.get('structure', __import__('structure')).instance(typeid)
sz = t.size
return t if sz == size else [t,size // sz]
if dt not in cls.inverted:
logging.warn("{:s}.dissolve({!r}, {!r}, {!r}) : Unable to identify a pythonic type.".format('.'.join(('internal',__name__,cls.__name__)), dt, typeid, size))
t,sz = cls.inverted[dt]
# if the type and size are the same, then it's a string or pointer type
if not isinstance(sz,six.integer_types):
count = size // idaapi.get_data_elsize(idaapi.BADADDR, dt, idaapi.opinfo_t())
return [t,count] if count > 1 else t
# if the size matches, then we assume it's a single element
elif sz == size:
return t,(sz*sf)
# otherwise it's an array
return [(t,sz*sf),size // sz]
def populate(self):
address = self.address
while True:
if Const.EA64:
func_address = idaapi.get_64bit(address)
else:
func_address = idaapi.get_32bit(address)
if Helper.is_code_ea(func_address):
self.virtual_functions.append(VirtualFunction(func_address, address - self.address))
elif Helper.is_imported_ea(func_address):
self.virtual_functions.append(ImportedVirtualFunction(func_address, address - self.address))
else:
break
address += Const.EA_SIZE
if idaapi.get_first_dref_to(address) != idaapi.BADADDR:
break
def revise_syscall(rename=False):
if not rename:
print('Change the function name with `CGCHeler.revise_syscall(True)`.')
# visit all instructions
start_ea, end_ea = utils.get_seg_range('.text')
eax = -1
ip = start_ea
while ip < end_ea and ip != idaapi.BADADDR:
if 'int' in idc.GetMnem(ip) and '80h' == idc.GetOpnd(ip, 0):
if eax != -1:
# fix comment and function name
print('{}: {}'.format(hex(ip), syscall_table[eax]))
idc.MakeComm(ip, 'CGC syscall: {}'.format(syscall_table[eax]))
if rename:
print('Change {} to {}'.format(idc.GetFunctionName(ip), syscall_table[eax]))
idc.MakeName(idc.GetFunctionAttr(ip, idc.FUNCATTR_START), syscall_table[eax])
elif 'mov' in idc.GetMnem(ip) and 'eax' == idc.GetOpnd(ip, 0) and 5 == idc.GetOpType(ip, 1):
value = idc.GetOpnd(ip, 1)
if re.search('^[0-9]+$', value) != None:
eax = int(value)
if eax > 7 or eax < 1:
eax = -1
ip = idc.NextHead(ip)
def Heads(start=None, end=None):
"""
Get a list of heads (instructions or data)
@param start: start address (default: inf.minEA)
@param end: end address (default: inf.maxEA)
@return: list of heads between start and end
"""
if not start: start = idaapi.cvar.inf.minEA
if not end: end = idaapi.cvar.inf.maxEA
ea = start
if not idc.isHead(idc.GetFlags(ea)):
ea = idaapi.next_head(ea, end)
while ea != idaapi.BADADDR:
yield ea
ea = idaapi.next_head(ea, end)
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.GetFirstMember(sid)
if m == -1:
raise Exception("No structure with ID: 0x%x" % sid)
while (m != idaapi.BADADDR):
name = idc.GetMemberName(sid, m)
if name:
yield (m, name, idc.GetMemberSize(sid, m))
m = idc.GetStrucNextOff(sid, m)
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 MakeStr(ea, endea):
"""
Create a string.
This function creates a string (the string type is determined by the
value of GetLongPrm(INF_STRTYPE))
@param ea: linear address
@param endea: ending address of the string (excluded)
if endea == BADADDR, then length of string will be calculated
by the kernel
@return: 1-ok, 0-failure
@note: The type of an existing string is returned by GetStringType()
"""
return idaapi.make_ascii_string(ea, 0 if endea == BADADDR else endea - ea, GetLongPrm(INF_STRTYPE))
def LocByNameEx(fromaddr, name):
"""
Get linear address of a name
@param fromaddr: the referring address. Allows to retrieve local label
addresses in functions. If a local name is not found,
then address of a global name is returned.
@param name: name of program byte
@return: address of the name (BADADDR - no such name)
@note: Dummy names (like byte_xxxx where xxxx are hex digits) are parsed by this
function to obtain the address. The database is not consulted for them.
"""
return idaapi.get_name_ea(fromaddr, name)
def SegByBase(base):
"""
Get segment by segment base
@param base: segment base paragraph or selector
@return: linear address of the start of the segment or BADADDR
if no such segment
"""
sel = idaapi.find_selector(base)
seg = idaapi.get_segm_by_sel(sel)
if seg:
return seg.startEA
else:
return BADADDR
def NameEx(fromaddr, ea):
"""
Get visible name of program byte
This function returns name of byte as it is displayed on the screen.
If a name contains illegal characters, IDA replaces them by the
substitution character during displaying. See IDA.CFG for the
definition of the substitution character.
@param fromaddr: the referring address. May be BADADDR.
Allows to retrieve local label addresses in functions.
If a local name is not found, then a global name is
returned.
@param ea: linear address
@return: "" - byte has no name
"""
name = idaapi.get_name(fromaddr, ea)
if not name:
return ""
else:
return name
def GetStringType(ea):
"""
Get string type
@param ea: linear address
@return: One of ASCSTR_... constants
"""
ti = idaapi.opinfo_t()
if idaapi.get_opinfo(ea, 0, GetFlags(ea), ti):
return ti.strtype
else:
return None
# The following functions search for the specified byte
# ea - address to start from
# flag is combination of the following bits
# returns BADADDR - not found
def FindBinary(ea, flag, searchstr, radix=16):
"""
@param ea: start address
@param flag: combination of SEARCH_* flags
@param searchstr: a string as a user enters it for Search Text in Core
@param radix: radix of the numbers (default=16)
@return: ea of result or BADADDR if not found
@note: Example: "41 42" - find 2 bytes 41h,42h (radix is 16)
"""
endea = flag & 1 and idaapi.cvar.inf.maxEA or idaapi.cvar.inf.minEA
return idaapi.find_binary(ea, endea, searchstr, radix, flag)
#----------------------------------------------------------------------------
# G L O B A L S E T T I N G S M A N I P U L A T I O N
#----------------------------------------------------------------------------
def MakeFunction(start, end = idaapi.BADADDR):
"""
Create a function
@param start: function bounds
@param end: function bounds
If the function end address is BADADDR, then
IDA will try to determine the function bounds
automatically. IDA will define all necessary
instructions to determine the function bounds.
@return: !=0 - ok
@note: an instruction should be present at the start address
"""
return idaapi.add_func(start, end)
def FindFuncEnd(ea):
"""
Determine a new function boundaries
@param ea: starting address of a new function
@return: if a function already exists, then return its end address.
If a function end cannot be determined, the return BADADDR
otherwise return the end address of the new function
"""
func = idaapi.func_t()
res = idaapi.find_func_bounds(ea, func, idaapi.FIND_FUNC_DEFINE)
if res == idaapi.FIND_FUNC_UNDEF:
return BADADDR
else:
return func.endEA
def GetFirstStrucIdx():
"""
Get index of first structure type
@return: BADADDR if no structure type is defined
index of first structure type.
Each structure type has an index and ID.
INDEX determines position of structure definition
in the list of structure definitions. Index 1
is listed first, after index 2 and so on.
The index of a structure type can be changed any
time, leading to movement of the structure definition
in the list of structure definitions.
ID uniquely denotes a structure type. A structure
gets a unique ID at the creation time and this ID
can't be changed. Even when the structure type gets
deleted, its ID won't be resued in the future.
"""
return idaapi.get_first_struc_idx()
def GetStrucNextOff(sid, offset):
"""
Get next offset in a structure
@param sid: structure type ID
@param offset: current offset
@return: -1 if bad structure type ID is passed,
idaapi.BADADDR if no (more) offsets in the structure,
otherwise returns next offset in a structure.
@note: IDA allows 'holes' between members of a
structure. It treats these 'holes'
as unnamed arrays of bytes.
This function returns a member offset or a hole offset.
It will return size of the structure if input
'offset' belongs to the last member of the structure.
@note: Union members are, in IDA's internals, located
at subsequent byte offsets: member 0 -> offset 0x0,
member 1 -> offset 0x1, etc...
"""
s = idaapi.get_struc(sid)
return -1 if not s else idaapi.get_struc_next_offset(s, offset)
def GetLastMember(sid):
"""
Get offset of the last member of a structure
@param sid: structure type ID
@return: -1 if bad structure type ID is passed,
idaapi.BADADDR if structure has no members,
otherwise returns offset of the last member.
@note: IDA allows 'holes' between members of a
structure. It treats these 'holes'
as unnamed arrays of bytes.
@note: Union members are, in IDA's internals, located
at subsequent byte offsets: member 0 -> offset 0x0,
member 1 -> offset 0x1, etc...
"""
s = idaapi.get_struc(sid)
if not s:
return -1
return idaapi.get_struc_last_offset(s)
def AddStrucEx(index, name, is_union):
"""
Define a new structure type
@param index: index of new structure type
If another structure has the specified index,
then index of that structure and all other
structures will be incremented, freeing the specifed
index. If index is == -1, then the biggest index
number will be used.
See GetFirstStrucIdx() for the explanation of
structure indices and IDs.
@param name: name of the new structure type.
@param is_union: 0: structure
1: union
@return: -1 if can't define structure type because of
bad structure name: the name is ill-formed or is
already used in the program.
otherwise returns ID of the new structure type
"""
if index == -1:
index = BADADDR
return idaapi.add_struc(index, name, is_union)
def NextFchunk(ea):
"""
Get next function chunk
@param ea: any address
@return: the starting address of the next function chunk or BADADDR
@note: This function enumerates all chunks of all functions in the database
"""
func = idaapi.get_next_fchunk(ea)
if func:
return func.startEA
else:
return BADADDR