ghidra/Ghidra/Features/Base/ghidra_scripts/RecursiveStringFinder.py

148 lines
4.8 KiB
Python

#Given a function, find all strings used within all called funtions.
# @category: Strings
# Handles only functions, not subroutines, as of now. Hopefully this will change later
import ghidra.app.script.GhidraScript
import ghidra.program.model.data.StringDataType as StringDataType
import exceptions
class Node:
def __str__(self):
raise NotImplementedError("Must sub-class")
def indentedString(self, depth=0):
raise NotImplementedError("")
def __str__(self):
return self.indentedString(depth=0)
class ReferenceNode(Node):
def __init__(self, fromAddr, toAddr):
self.fromAddr = fromAddr
self.toAddr = toAddr
def indentedString(self, depth=0):
raise NotImplementedError("")
class StringNode(ReferenceNode):
def __init__(self, fromAddr, toAddr, string):
ReferenceNode.__init__(self, fromAddr, toAddr)
self.string = string
def __str__(self):
return self.indentedString(depth=0)
def indentedString(self, depth=0):
string = "%s\n" % ( self.string)
return string
def hasString(self):
return True
class FunctionNode(ReferenceNode):
def __init__(self, fromAddr, toAddr):
ReferenceNode.__init__(self, fromAddr, toAddr)
self.fn = getFunctionContaining(toAddr)
self.references = []
def hasString(self):
for r in self.references:
if isinstance(r, StringNode) or r.hasString():
return True
return False
def indentedString(self, depth=0):
string = "%s()\n" % (self.fn.getName())
for r in self.references:
if r.hasString():
string += "%s@%s - %s" % (" " * (depth+1), r.fromAddr, r.indentedString(depth=depth+1))
return string
def getAddresses(self):
return self.fn.getBody().getAddresses(True)
def addReference(self, reference):
rlist = []
if not isinstance(reference, list):
rlist.append(reference)
for r in rlist:
if not isinstance(r, ReferenceNode):
raise ValueError("Must only add ReferenceNode type")
else:
self.references.append(r)
def getName(self):
if self.fn is not None:
return self.fn.getName()
else:
return "fun_%s" % (self.toAddr)
def process(self, processed=[]):
if self.fn is None:
return processed
print "Processing %s -> %s" % (str(self.fromAddr), str(self.toAddr))
if self.getName() in processed:
return processed
addresses = self.getAddresses()
print str(type(addresses))
while addresses.hasNext():
#for a in addresses:
a = addresses.next()
insn = getInstructionAt(a)
if insn is not None:
refs = getReferences(insn)
for r in refs:
self.addReference(r)
processed.append(self.getName())
for r in self.references:
if isinstance(r, FunctionNode):
processed = r.process(processed=processed)
return processed
class FunctionNotFoundException(exceptions.Exception):
pass
def getStringAtAddr(addr):
"""Get string at an address, if present"""
data = getDataAt(addr)
if data is not None:
dt = data.getDataType()
if isinstance(dt, StringDataType):
return str(data)
return None
def getStringReferences(insn):
"""Get strings referenced in any/all operands of an instruction, if present"""
numOperands = insn.getNumOperands()
found = []
for i in range(numOperands):
opRefs = insn.getOperandReferences(i)
for o in opRefs:
if o.getReferenceType().isData():
string = getStringAtAddr(o.getToAddress())
if string is not None:
found.append( StringNode(insn.getMinAddress(), o.getToAddress(), string) )
return found
def getFunctionReferences(insn):
"""Return a list of functions referenced in the given instruction"""
numOperands = insn.getNumOperands()
lst = []
for i in range(numOperands):
opRefs = insn.getOperandReferences(i)
for o in opRefs:
if o.getReferenceType().isCall():
lst.append( FunctionNode(insn.getMinAddress(), o.getToAddress()) )
return lst
def getReferences(insn):
refs = []
refs += getStringReferences(insn)
refs += getFunctionReferences(insn)
return refs
bigfunc = getFunctionContaining(currentAddress)
if bigfunc is None:
print "Please place the cursor within a function!"
else:
AddrSetView = bigfunc.getBody()
func = FunctionNode(None, AddrSetView.getMinAddress())
func.process()
print str(func.indentedString())
#findStrings(func)
print "Done!"