idautils: added Strings class to enumerate strings (check ex_strings.py)

gdl.i: added FlowChart and BasicBlock classes (check examples / ex_gdl_qflow_chart)
idc.py : fixed MakeName() and AnalyseArea() (they were not returning return values)
This commit is contained in:
elias.bachaalany 2009-09-16 14:00:31 +00:00
parent e51eb69e3a
commit e27524cca5
6 changed files with 216 additions and 31 deletions

View File

@ -2,7 +2,7 @@
#------------------------------------------------------------
# IDAPython - Python plugin for Interactive Disassembler Pro
#
# Copyright (c) 2004-2009 Gergely Erdelyi <dyce@d-dome.net>
# Copyright (c) 2004-2009 Gergely Erdelyi <dyce@d-dome.net>
#
# All rights reserved.
#
@ -70,6 +70,8 @@ BINDIST_MANIFEST = [
"examples/ex1_idautils.py",
"examples/hotkey.py",
"examples/structure.py",
"examples/ex_gdl_qflow_chart.py",
"examples/ex_strings.py",
]
# List files for the source distribution (appended to binary list)
@ -220,10 +222,10 @@ class MSVCBuilder(BuilderBase):
self.linker = "link"
self.source_extension = ".cpp"
self.object_extension = ".obj"
def compiler_in_string(self, filename):
return "/c %s" % filename
def compiler_out_string(self, filename):
return "/Fo%s" % filename
@ -244,7 +246,7 @@ def build_distribution(manifest, distrootdir, ea64, nukeold):
# Also make a ZIP archive of the build
zippath = distrootdir + ".zip"
zip = zipfile.ZipFile(zippath, nukeold and "w" or "a", zipfile.ZIP_DEFLATED)
# Copy files, one by one
for f in manifest:
if type(f) == types.TupleType:
@ -259,11 +261,11 @@ def build_distribution(manifest, distrootdir, ea64, nukeold):
if srcdir == "":
dstdir = distrootdir
else:
dstdir = distrootdir + os.sep + srcdir
dstdir = distrootdir + os.sep + srcdir
if not os.path.exists(dstdir):
os.makedirs(dstdir)
dstfilepath = dstdir + os.sep + srcfilename
shutil.copyfile(srcfilepath, dstfilepath)
zip.write(dstfilepath)
@ -348,7 +350,7 @@ def build_binary_package(ea64, nukeold):
system = "Windows"
platform_string = "win32"
plugin_name = ea64 and "python.p64" or "python.plw"
if system == "Linux":
platform_string = "linux"
plugin_name = ea64 and "python.plx64" or "python.plx"
@ -357,10 +359,10 @@ def build_binary_package(ea64, nukeold):
platform_string = "macosx"
plugin_name = ea64 and "python.pmc64" or "python.pmc"
BINDISTDIR = "idapython-%d.%d.%d_ida%d.%d_py%d.%d_%s" % (VERSION_MAJOR,
VERSION_MINOR,
VERSION_PATCH,
IDA_MAJOR_VERSION,
BINDISTDIR = "idapython-%d.%d.%d_ida%d.%d_py%d.%d_%s" % (VERSION_MAJOR,
VERSION_MINOR,
VERSION_PATCH,
IDA_MAJOR_VERSION,
IDA_MINOR_VERSION,
PYTHON_MAJOR_VERSION,
PYTHON_MINOR_VERSION,
@ -378,9 +380,9 @@ def build_binary_package(ea64, nukeold):
def build_source_package():
""" Build a directory and a ZIP file with all the sources """
SRCDISTDIR = "idapython-%d.%d.%d" % (VERSION_MAJOR,
VERSION_MINOR,
VERSION_PATCH)
SRCDISTDIR = "idapython-%d.%d.%d" % (VERSION_MAJOR,
VERSION_MINOR,
VERSION_PATCH)
# Build the source distribution
srcmanifest = []
srcmanifest.extend(BINDIST_MANIFEST)
@ -391,7 +393,7 @@ def build_source_package():
if __name__ == "__main__":
# Do 64-bit build?
ea64 = '--ea64' in sys.argv
ea64 = '--ea64' in sys.argv
build_binary_package(ea64=False, nukeold=True)
if ea64:
build_binary_package(ea64=True, nukeold=False)

View File

@ -0,0 +1,35 @@
import idaapi
# -----------------------------------------------------------------------
# Using raw IDAAPI
def raw_main(p=True):
global q
f = idaapi.get_func(here())
if not f:
return
q = idaapi.qflow_chart_t("The title", f, 0, 0, idaapi.FC_PREDS)
for n in xrange(0, q.size()):
b = q[n]
if p: print "%x - %x [%d]:" % (b.startEA, b.endEA, n)
for ns in xrange(0, q.nsucc(n)):
if p: print " %d->%d" % (n, q.succ(n, ns))
for ns in xrange(0, q.npred(n)):
if p: print " %d->%d" % (n, q.pred(n, ns))
# -----------------------------------------------------------------------
# Using the class
def cls_main(p=True):
global f
f = idaapi.FlowChart(idaapi.get_func(here()))
for block in f:
if p: print "%x - %x [%d]:" % (block.startEA, block.endEA, block.id)
for succ_block in block.succs():
if p: print " %x - %x [%d]:" % (succ_block.startEA, succ_block.endEA, succ_block.id)
for pred_block in block.preds():
if p: print " %x - %x [%d]:" % (pred_block.startEA, pred_block.endEA, pred_block.id)
q = None
f = None
raw_main(False)
cls_main(True)

6
examples/ex_strings.py Normal file
View File

@ -0,0 +1,6 @@
import idautils
s = Strings(False)
s.setup(strtypes=Strings.STR_UNICODE | Strings.STR_C)
for i in s:
print "%x: len=%d type=%d -> '%s'" % (i.ea, i.length, i.type, str(i))

View File

@ -1,7 +1,7 @@
#------------------------------------------------------------
# IDAPython - Python plugin for Interactive Disassembler Pro
#
# Copyright (c) 2004-2009 Gergely Erdelyi <dyce@d-dome.net>
# Copyright (c) 2004-2009 Gergely Erdelyi <dyce@d-dome.net>
#
# All rights reserved.
#
@ -40,9 +40,9 @@ def CodeRefsTo(ea, flow):
print ref
"""
if flow == 1:
return refs(ea, idaapi.get_first_cref_to, idaapi.get_next_cref_to)
return refs(ea, idaapi.get_first_cref_to, idaapi.get_next_cref_to)
else:
return refs(ea, idaapi.get_first_fcref_to, idaapi.get_next_fcref_to)
return refs(ea, idaapi.get_first_fcref_to, idaapi.get_next_fcref_to)
def CodeRefsFrom(ea, flow):
@ -61,9 +61,9 @@ def CodeRefsFrom(ea, flow):
print ref
"""
if flow == 1:
return refs(ea, idaapi.get_first_cref_from, idaapi.get_next_cref_from)
return refs(ea, idaapi.get_first_cref_from, idaapi.get_next_cref_from)
else:
return refs(ea, idaapi.get_first_fcref_from, idaapi.get_next_fcref_from)
return refs(ea, idaapi.get_first_fcref_from, idaapi.get_next_fcref_from)
def DataRefsTo(ea):
@ -79,7 +79,7 @@ def DataRefsTo(ea):
for ref in DataRefsTo(ScreenEA(), 1):
print ref
"""
return refs(ea, idaapi.get_first_dref_to, idaapi.get_next_dref_to)
return refs(ea, idaapi.get_first_dref_to, idaapi.get_next_dref_to)
def DataRefsFrom(ea):
@ -95,7 +95,7 @@ def DataRefsFrom(ea):
for ref in DataRefsFrom(ScreenEA(), 1):
print ref
"""
return refs(ea, idaapi.get_first_dref_from, idaapi.get_next_dref_from)
return refs(ea, idaapi.get_first_dref_from, idaapi.get_next_dref_from)
def XrefTypeName(typecode):
@ -104,9 +104,9 @@ def XrefTypeName(typecode):
@param typecode: cross-reference type code
"""
ref_types = {
ref_types = {
0 : 'Data_Unknown',
1 : 'Data_Offset',
1 : 'Data_Offset',
2 : 'Data_Write',
3 : 'Data_Read',
4 : 'Data_Text',
@ -233,7 +233,7 @@ def Segments():
@return: List of segment start addresses.
"""
for n in range(idaapi.get_segm_qty()):
for n in xrange(idaapi.get_segm_qty()):
seg = idaapi.getnseg(n)
if seg:
yield seg.startEA
@ -298,7 +298,7 @@ def DecodeInstruction(ea):
setattr(self, x, getattr(op, x))
r = dup(insn)
r.Operands = []
for n in range(0, idaapi.UA_MAXOP):
for n in xrange(0, idaapi.UA_MAXOP):
t = idaapi.get_instruction_operand(insn, n)
if t.type == idaapi.o_void:
break
@ -359,4 +359,72 @@ class _cpu:
#print "cpu.set(%s)"%name
return idc.SetRegValue(value, name)
class Strings:
"""
Returns the string list.
Example:
s = Strings()
for i in s:
print "%x: len=%d type=%d -> '%s'" % (i.ea, i.length, i.type, str(i))
"""
class StringItem:
"""
Class representing each string item.
The attributes are:
ea - string ea
type - string type (ASCSTR_xxxxx)
str() - returns the actual string
"""
def __init__(self, si):
self.ea = si.ea
self.type = si.type
self.length = si.length
def __str__(self):
return idc.GetString(self.ea, self.length, self.type)
STR_C = 0x0001 # C-style ASCII string
STR_PASCAL = 0x0002 # Pascal-style ASCII string (length byte)
STR_LEN2 = 0x0004 # Pascal-style, length is 2 bytes
STR_UNICODE = 0x0008 # Unicode string
STR_LEN4 = 0x0010 # Pascal-style, length is 4 bytes
STR_ULEN2 = 0x0020 # Pascal-style Unicode, length is 2 bytes
STR_ULEN4 = 0x0040 # Pascal-style Unicode, length is 4 bytes
def clear_cache():
"""Clears the strings list cache"""
self.refresh(0, 0) # when ea1=ea2 the kernel will clear the cache
def __init__(self, default_setup=True):
if default_setup:
self.setup()
self._si = idaapi.string_info_t()
def refresh(self, ea1=idaapi.cvar.inf.minEA, ea2=idaapi.cvar.inf.maxEA):
"""Refreshes the strings list"""
idaapi.refresh_strlist(ea1, ea2)
self.size = idaapi.get_strlist_qty()
def setup(self, strtypes=STR_C, minlen=5, only_7bit=True, ignore_instructions=False, ea1=idaapi.cvar.inf.minEA, ea2=idaapi.cvar.inf.maxEA, display_only_existing_strings=False):
t = idaapi.strwinsetup_t()
t.strtypes = strtypes
t.minlen = minlen
t.only_7bit = only_7bit
t.ea1 = ea1
t.ea2 = ea2
t.display_only_existing_strings = display_only_existing_strings
idaapi.set_strlist_options(t)
# automatically refreshes
self.refresh()
def __getitem__(self, index):
"""Returns string items"""
if index >= self.size:
raise StopIteration
if idaapi.get_strlist_item(index, self._si):
return Strings.StringItem(self._si)
return None
cpu = _cpu()

View File

@ -3741,7 +3741,7 @@ def LoadFile(filepath, pos, ea, size):
else:
return 0
def loadfile(filepath, pos, ea, size): LoadFile(filepath, pos, ea, size)
def loadfile(filepath, pos, ea, size): return LoadFile(filepath, pos, ea, size)
def SaveFile(filepath, pos, ea, size):
@ -3764,7 +3764,7 @@ def SaveFile(filepath, pos, ea, size):
else:
return 0
def savefile(filepath, pos, ea, size): SaveFile(filepath, pos, ea, size)
def savefile(filepath, pos, ea, size): return SaveFile(filepath, pos, ea, size)
def fgetc(handle):
@ -7460,12 +7460,12 @@ def OpStroff(ea,n,strid): return OpStroffEx(ea,n,strid,0)
def OpEnum(ea,n,enumid): return OpEnumEx(ea,n,enumid,0)
def DelConst(constid, v, mask): return DelConstEx(constid, v, 0, mask)
def GetConst(constid, v, mask): return GetConstEx(constid, v, 0, mask)
def AnalyseArea(sEA, eEA): AnalyzeArea(sEA,eEA)
def AnalyseArea(sEA, eEA): return AnalyzeArea(sEA,eEA)
def MakeStruct(ea,name): return MakeStructEx(ea, -1, name)
def Name(ea): return NameEx(BADADDR, ea)
def GetTrueName(ea): return GetTrueNameEx(BADADDR, ea)
def MakeName(ea, name): MakeNameEx(ea,name,SN_CHECK)
def MakeName(ea, name): return MakeNameEx(ea,name,SN_CHECK)
#def GetFrame(ea): return GetFunctionAttr(ea, FUNCATTR_FRAME)
#def GetFrameLvarSize(ea): return GetFunctionAttr(ea, FUNCATTR_FRSIZE)

View File

@ -18,8 +18,82 @@
%ignore node_set_t::intersect;
%ignore node_set_t::node_set_t;
%ignore node_set_t::sub;
%ignore qflow_chart_t::blocks;
%ignore flow_chart_t;
%ignore setup_graph_subsystem;
%ignore qbasic_block_t::succ;
%ignore qbasic_block_t::pred;
%include "gdl.hpp"
%extend qflow_chart_t
{
qbasic_block_t *__getitem__(int n)
{
return &(self->blocks[n]);
}
}
%pythoncode %{
# -----------------------------------------------------------------------
class BasicBlock:
def __init__(self, id, bb, f):
self._f = f
self.id = id
"""Basic block ID"""
self.startEA = bb.startEA
"""startEA of basic block"""
self.endEA = bb.endEA
"""endEA of basic block"""
self.type = self._f._q.calc_block_type(self.id)
"""Block type (check fc_block_type_t enum)"""
def preds(self):
"""
Iteratres the predecessors list
"""
q = self._f._q
for i in xrange(0, self._f._q.npred(self.id)):
yield self._f[q.pred(self.id, i)]
def succs(self):
"""
Iteratres the successors list
"""
q = self._f._q
for i in xrange(0, q.nsucc(self.id)):
yield self._f[q.succ(self.id, i)]
# -----------------------------------------------------------------------
class FlowChart:
"""
Flowchart class used to determine basic blocks
"""
def __init__(self, f=None, bounds=None, flags=0):
"""
Constructor
@param f: A func_t type, use get_func(ea) to get a reference
@param bounds: A tuple of the form (start, end). Used if "f" is None
@param flags: one of the FC_xxxx flags. One interesting flag is FC_PREDS
"""
if (not f) and (not bounds or type(bounds) != types.TupleType):
raise Exception("Please specifiy either a function or start/end pair")
if not bounds:
bounds = (BADADDR, BADADDR)
# create the flowchart
self._q = qflow_chart_t("", f, bounds[0], bounds[1], flags)
self.size = self._q.size()
def refresh():
self._q.refresh()
self.size = self._q.size()
def __getitem__(self, index):
"""
Returns a basic block
@return: BasicBlock
"""
if index >= self.size:
raise StopIteration
return BasicBlock(index, self._q[index], self)
%}