mirror of
https://github.com/vivisect/vivisect
synced 2026-06-08 18:04:23 +00:00
80de840881
A lot of cleanup things in prep for a python 3 transition. Getting rid of the old exception syntax, converting prints over to logging, cutting random scraps of code to be proper unit tests, cut away some older bits of code, etc. This still works in python2. It's just a lot of tidying up. There are no major functionality changes.
813 lines
25 KiB
Python
813 lines
25 KiB
Python
"""
|
|
The vivisect CLI.
|
|
"""
|
|
import re
|
|
import sys
|
|
import shlex
|
|
import pprint
|
|
import socket
|
|
import logging
|
|
import binascii
|
|
import traceback
|
|
from getopt import getopt
|
|
|
|
import vtrace
|
|
import vivisect
|
|
import vivisect.vamp as viv_vamp
|
|
import vivisect.vector as viv_vector
|
|
import vivisect.reports as viv_reports
|
|
import vivisect.tools.graphutil as viv_graph
|
|
|
|
import vivisect.tools.fscope as v_t_fscope
|
|
import vivisect.tools.graphutil as v_t_graph
|
|
|
|
import visgraph.pathcore as vg_path
|
|
|
|
import vtrace.envitools as vt_envitools
|
|
|
|
import vdb
|
|
|
|
import envi.cli as e_cli
|
|
import envi.common as e_common
|
|
import envi.memory as e_mem
|
|
import envi.expression as e_expr
|
|
import envi.memcanvas as e_canvas
|
|
import envi.memcanvas.renderers as e_render
|
|
|
|
from vivisect.const import *
|
|
|
|
logger = logging.getLogger(__name__)
|
|
e_common.setLogging(logger, 'WARNING')
|
|
|
|
|
|
class VivCli(vivisect.VivWorkspace, e_cli.EnviCli):
|
|
'''
|
|
A class that builds upon the VivWorkspace to provide command line capabilities so that
|
|
things like the Vivisect UI can provide a cleaner interface that just a direct python
|
|
shell. It inherits the same parameters as the VivWorkspace (autosave and confdir currently)
|
|
|
|
To add a new command, simply add a new function called `do_<cmdname>`.
|
|
'''
|
|
def __init__(self, **kwargs):
|
|
e_cli.EnviCli.__init__(self, self, symobj=self)
|
|
vivisect.VivWorkspace.__init__(self, **kwargs)
|
|
self.canvas.addRenderer("bytes", e_render.ByteRend())
|
|
self.canvas.addRenderer("u_int_16", e_render.ShortRend())
|
|
self.canvas.addRenderer("u_int_32", e_render.LongRend())
|
|
self.canvas.addRenderer("u_int_64", e_render.QuadRend())
|
|
import vivisect.renderers as viv_rend
|
|
self.canvas.addRenderer("viv", viv_rend.WorkspaceRenderer(self))
|
|
self.prompt = "viv> "
|
|
self.addScriptPathEnvVar('VIV_SCRIPT_PATH')
|
|
|
|
def getExpressionLocals(self):
|
|
locs = e_cli.EnviCli.getExpressionLocals(self)
|
|
locs['vw'] = self
|
|
locs['vprint'] = self.vprint
|
|
locs['vivisect'] = vivisect
|
|
return locs
|
|
|
|
def do_report(self, line):
|
|
"""
|
|
Fire a report module by python path name.
|
|
|
|
Usage: report <python.path.to.report.module>
|
|
"""
|
|
if not line:
|
|
self.vprint("Report Modules")
|
|
for descr, modname in viv_reports.listReportModules():
|
|
self.vprint("%32s %s" % (modname, descr))
|
|
return
|
|
|
|
mod = self.loadModule(line)
|
|
cols, results = mod.report(self)
|
|
for row in results:
|
|
for i in range(len(cols)+1):
|
|
val = row[i]
|
|
if i == 0:
|
|
name = self.arch.pointerString(val)
|
|
self.canvas.addVaText(name, val)
|
|
|
|
else:
|
|
self.canvas.addText(": %s" % val)
|
|
|
|
for va, pri, info in mod.report(self):
|
|
name = self.getName(va)
|
|
if name is None:
|
|
name = self.arch.pointerString(va)
|
|
self.canvas.addVaText(name, va)
|
|
self.canvas.addText(": %s\n" % info)
|
|
|
|
def do_pathcount(self, line):
|
|
'''
|
|
Mostly for testing the graph stuff... this will likely be removed.
|
|
|
|
(does not count paths with loops currently...)
|
|
|
|
Usage: pathcount <func_expr>
|
|
'''
|
|
fva = self.parseExpression(line)
|
|
if not self.isFunction(fva):
|
|
self.vprint('Not a function!')
|
|
return
|
|
|
|
g = v_t_graph.buildFunctionGraph(self, fva)
|
|
# Lets find the "bottom" nodes...
|
|
endblocks = []
|
|
for nid, ninfo in g.getNodes():
|
|
if len(g.getRefsFrom(nid)) == 0:
|
|
endblocks.append((nid, ninfo))
|
|
|
|
for nid, ninfo in endblocks:
|
|
paths = list(g.pathSearch(0, toid=nid))
|
|
self.vprint('paths to 0x%.8x: %d' % (ninfo.get('cbva'), len(paths)))
|
|
|
|
def do_symboliks(self, line):
|
|
'''
|
|
Use the new symboliks subsystem. (NOTE: i386 only for a bit...)
|
|
|
|
Usage: symboliks [ options ]
|
|
|
|
-A Run the emu and show the state of the machine for all found paths
|
|
to the given address
|
|
|
|
'''
|
|
|
|
watchaddr = None
|
|
|
|
argv = e_cli.splitargs(line)
|
|
try:
|
|
opts, argv = getopt(argv, 'A:')
|
|
except Exception:
|
|
return self.do_help('symboliks')
|
|
|
|
for opt, optarg in opts:
|
|
if opt == '-A':
|
|
# TODO: USE THIS
|
|
watchaddr = self.parseExpression(optarg)
|
|
|
|
va = self.parseExpression(argv[0])
|
|
fva = self.getFunction(va)
|
|
|
|
import vivisect.symboliks as viv_symboliks
|
|
import vivisect.symboliks.common as sym_common
|
|
import vivisect.symboliks.effects as viv_sym_effects
|
|
import vivisect.symboliks.analysis as vsym_analysis
|
|
|
|
symctx = vsym_analysis.getSymbolikAnalysisContext(self)
|
|
|
|
for emu, effects in symctx.getSymbolikPaths(fva):
|
|
|
|
self.vprint('PATH %s' % ('='*60))
|
|
|
|
for eff in effects:
|
|
|
|
eff.reduce(emu)
|
|
if eff.efftype in (EFFTYPE_CONSTRAIN, EFFTYPE_CALLFUNC):
|
|
self.vprint(str(eff))
|
|
|
|
for addrsym, valsym in emu._sym_mem.values():
|
|
addrsym = addrsym.reduce(emu=emu)
|
|
valsym = valsym.reduce(emu=emu)
|
|
if emu.isLocalMemory(addrsym):
|
|
continue
|
|
self.vprint('[ %s ] = %s' % (addrsym, valsym))
|
|
self.vprint('RETURN', emu.getFunctionReturn().reduce())
|
|
|
|
def do_names(self, line):
|
|
'''
|
|
Show any names which contain the given argument.
|
|
|
|
Usage: names <name_regex>
|
|
|
|
FIXME unify do_sym from vdb into symbol context!
|
|
'''
|
|
if not line:
|
|
return self.do_help('names')
|
|
|
|
regex = re.compile(line, re.I)
|
|
for va, name in self.getNames():
|
|
if regex.search(name):
|
|
self.vprint('0x%.8x: %s' % (va, name))
|
|
|
|
def do_save(self, line):
|
|
"""
|
|
Save the current workspace.
|
|
|
|
Usage: save
|
|
"""
|
|
self.vprint("Saving workspace...")
|
|
self.saveWorkspace()
|
|
self.vprint("...save complete!")
|
|
|
|
def do_xrefs(self, line):
|
|
"""
|
|
Show xrefs for a particular location.
|
|
|
|
Usage: xrefs [options] <va_expr>
|
|
-T Show xrefs *to* the given address
|
|
-F Show xrefs *from* the given address (default)
|
|
"""
|
|
parser = e_cli.VOptionParser()
|
|
parser.add_option('-T', action='store_true', dest='xrto')
|
|
parser.add_option('-F', action='store_true', dest='xrfrom')
|
|
argv = shlex.split(line)
|
|
try:
|
|
options, argv = parser.parse_args(argv)
|
|
except Exception as e:
|
|
self.vprint(repr(e))
|
|
return self.do_help('xrefs')
|
|
|
|
if len(argv) < 1:
|
|
self.vprint('Supply a va_expr')
|
|
return self.do_help('xrefs')
|
|
|
|
va = self.parseExpression(argv[0])
|
|
|
|
fptr = []
|
|
if options.xrto:
|
|
fptr.append(self.getXrefsTo)
|
|
if options.xrfrom:
|
|
fptr.append(self.getXrefsFrom)
|
|
|
|
for func in fptr:
|
|
for xrfr, xrto, rtype, rflags in func(va):
|
|
xrfr = hex(xrfr)
|
|
xrto = hex(xrto)
|
|
rflags = hex(rflags)
|
|
tname = ref_type_names.get(rtype, 'Unknown')
|
|
self.vprint('\tFrom: %s, To: %s, Type: %s, Flags: %s' % (xrfr, xrto, tname, rflags))
|
|
|
|
|
|
def do_searchopcodes(self, line):
|
|
'''
|
|
search opcodes/function for a pattern
|
|
|
|
searchopcodes [-f <funcva>] [options] <pattern>
|
|
-f [fva] - focus on one function
|
|
-c - search comments
|
|
-o - search operands
|
|
-t - search text
|
|
-M <color> - mark opcodes (default = orange)
|
|
-R - pattern is REGEX (otherwise just text)
|
|
|
|
'''
|
|
parser = e_cli.VOptionParser()
|
|
parser.add_option('-f', action='store', dest='funcva', type='long')
|
|
parser.add_option('-c', action='store_true', dest='searchComments')
|
|
parser.add_option('-o', action='store_true', dest='searchOperands')
|
|
parser.add_option('-t', action='store_true', dest='searchText')
|
|
parser.add_option('-M', action='store', dest='markColor', default='orange')
|
|
parser.add_option('-R', action='store_true', dest='is_regex')
|
|
|
|
argv = shlex.split(line)
|
|
try:
|
|
options, args = parser.parse_args(argv)
|
|
except Exception as e:
|
|
self.vprint(repr(e))
|
|
return self.do_help('searchopcodes')
|
|
|
|
pattern = ' '.join(args)
|
|
if len(pattern) == 0:
|
|
self.vprint('you must specify a pattern')
|
|
return self.do_help('searchopcodes')
|
|
|
|
# generate our interesting va list
|
|
valist = []
|
|
if options.funcva:
|
|
# setup valist from function data
|
|
try:
|
|
fva = int(args[0], 0)
|
|
graph = viv_graph.buildFunctionGraph(self, fva)
|
|
except Exception as e:
|
|
self.vprint(repr(e))
|
|
return
|
|
|
|
for nva, node in graph.getNodes():
|
|
va = nva
|
|
endva = va + node.get('cbsize')
|
|
while va < endva:
|
|
lva, lsz, ltype, ltinfo = self.getLocation(va)
|
|
valist.append(va)
|
|
va += lsz
|
|
|
|
else:
|
|
# the whole workspace is our oyster
|
|
valist = [va for va, lvsz, ltype, ltinfo in self.getLocations(LOC_OP)]
|
|
|
|
res = []
|
|
canv = e_canvas.StringMemoryCanvas(self)
|
|
|
|
defaultSearchAll = True
|
|
for va in valist:
|
|
try:
|
|
addthis = False
|
|
op = self.parseOpcode(va)
|
|
|
|
# search comment
|
|
if options.searchComments:
|
|
defaultSearchAll = False
|
|
cmt = self.getComment(va)
|
|
if cmt is not None:
|
|
|
|
if options.is_regex:
|
|
if len(re.findall(pattern, cmt)):
|
|
addthis = True
|
|
|
|
else:
|
|
if pattern in cmt:
|
|
addthis = True
|
|
|
|
# search operands
|
|
if options.searchOperands:
|
|
defaultSearchAll = False
|
|
for opidx, oper in enumerate(op.opers):
|
|
# we're writing to a temp canvas, so clear it before each test
|
|
canv.clearCanvas()
|
|
oper = op.opers[opidx]
|
|
oper.render(canv, op, opidx)
|
|
operepr = canv.strval
|
|
|
|
if options.is_regex:
|
|
if len(re.findall(pattern, operepr)):
|
|
addthis = True
|
|
|
|
else:
|
|
if pattern in operepr:
|
|
addthis = True
|
|
|
|
# if we're doing non-regex, let's test against real numbers
|
|
# (instead of converting to hex and back)
|
|
numpattrn = pattern
|
|
try:
|
|
numpattrn = int(numpattrn, 0)
|
|
except:
|
|
pass
|
|
|
|
if numpattrn in vars(oper).values():
|
|
addthis = True
|
|
|
|
# search full text
|
|
if options.searchText or defaultSearchAll:
|
|
canv.clearCanvas()
|
|
op.render(canv)
|
|
oprepr = canv.strval
|
|
|
|
if options.is_regex:
|
|
if len(re.findall(pattern, oprepr)):
|
|
addthis = True
|
|
|
|
else:
|
|
if pattern in oprepr:
|
|
addthis = True
|
|
# only want one listing of each va, no matter how many times it matches
|
|
if addthis:
|
|
res.append(va)
|
|
except:
|
|
self.vprint(''.join(traceback.format_exception(*sys.exc_info())))
|
|
|
|
if len(res) == 0:
|
|
self.vprint('pattern not found: %s (%s)' % (binascii.hexlify(pattern), repr(pattern)))
|
|
return
|
|
|
|
# set the color for each finding
|
|
color = options.markColor
|
|
colormap = {va: color for va in res}
|
|
if self._viv_gui is not None:
|
|
from vqt.main import vqtevent
|
|
vqtevent('viv:colormap', colormap)
|
|
|
|
self.vprint('matches for: %s (%s)' % (binascii.hexlify(pattern), repr(pattern)))
|
|
for va in res:
|
|
mbase, msize, mperm, mfile = self.memobj.getMemoryMap(va)
|
|
pname = e_mem.reprPerms(mperm)
|
|
sname = self.reprPointer(va)
|
|
|
|
op = self.parseOpcode(va)
|
|
self.canvas.renderMemory(va, len(op))
|
|
cmt = self.getComment(va)
|
|
if cmt is not None:
|
|
self.canvas.addText('\t\t; %s (Perms: %s, Smartname: %s)' % (cmt, pname, sname))
|
|
|
|
self.canvas.addText('\n')
|
|
|
|
self.vprint('done (%d results).' % len(res))
|
|
|
|
def do_imports(self, line):
|
|
"""
|
|
Show the imports in the workspace (or potentially just one file)
|
|
|
|
Usage: imports [fname]
|
|
"""
|
|
self.canvas.addText("Imports:\n")
|
|
for va, size, ltype, tinfo in self.getImports():
|
|
# FIXME warn them...
|
|
# (but should we though?)
|
|
if not tinfo.startswith(line):
|
|
continue
|
|
vastr = self.arch.pointerString(va)
|
|
self.canvas.addVaText(vastr, va)
|
|
self.canvas.addText(" ")
|
|
self.canvas.addNameText(tinfo, tinfo)
|
|
self.canvas.addText("\n")
|
|
|
|
def do_fscope(self, line):
|
|
'''
|
|
The fscope command can be used to enumerate things from the
|
|
scope of one function and down it's calling graph.
|
|
|
|
Usage: fscope [options] <func_addr_expr>
|
|
|
|
-I - Show import calls from this function scope
|
|
-S - Show strings from this function scope
|
|
|
|
Example: fscope -I kernel32.CreateFileW
|
|
(Show imports called by CreateFileW and down...)
|
|
|
|
'''
|
|
showimp = False
|
|
showstr = False
|
|
|
|
argv = e_cli.splitargs(line)
|
|
try:
|
|
opts, args = getopt(argv, 'IS')
|
|
except Exception:
|
|
return self.do_help('fscope')
|
|
|
|
if not len(args) or not len(opts):
|
|
return self.do_help('fscope')
|
|
|
|
for opt, optarg in opts:
|
|
if opt == '-I':
|
|
showimp = True
|
|
elif opt == '-S':
|
|
showstr = True
|
|
|
|
for expr in args:
|
|
|
|
va = self.parseExpression(expr)
|
|
|
|
if showimp:
|
|
for callva, impname in v_t_fscope.getImportCalls(self, va):
|
|
pstr = self.arch.pointerString(callva)
|
|
self.canvas.addVaText(pstr, callva)
|
|
# FIXME best name symbol etc?
|
|
self.canvas.addText(' %s\n' % impname)
|
|
|
|
if showstr:
|
|
for refva, strva, strbytes in v_t_fscope.getStringRefs(self, va):
|
|
pstr = self.arch.pointerString(refva)
|
|
self.canvas.addVaText(pstr, refva)
|
|
self.canvas.addText(' ')
|
|
self.canvas.addVaText(strbytes, strva)
|
|
self.canvas.addText('\n')
|
|
|
|
def do_exports(self, line):
|
|
"""
|
|
List the exports in the workspace (or in a specific file).
|
|
|
|
Usage: exports [fname]
|
|
"""
|
|
edict = {}
|
|
for va, etype, name, filename in self.getExports():
|
|
exps = edict.get(filename)
|
|
if exps is None:
|
|
edict[filename] = []
|
|
exps.append((name, va))
|
|
|
|
if line:
|
|
x = edict.get(line)
|
|
if x is None:
|
|
self.vprint("Unknown fname: %s" % line)
|
|
return
|
|
edict = {line: x}
|
|
|
|
fnames = edict.keys()
|
|
fnames.sort()
|
|
for fname in fnames:
|
|
self.canvas.addNameText(fname, fname)
|
|
self.canvas.addText(":\n")
|
|
exports = edict.get(fname)
|
|
exports.sort()
|
|
for ename, eva in exports:
|
|
pstr = self.arch.pointerString(eva)
|
|
self.canvas.addText(" ")
|
|
self.canvas.addVaText(pstr, eva)
|
|
self.canvas.addText(" ")
|
|
self.canvas.addNameText(ename, ename)
|
|
self.canvas.addText("\n")
|
|
|
|
def do_filemeta(self, line):
|
|
|
|
'''
|
|
Show/List file metadata.
|
|
|
|
Usage: filemeta [ fname [ keyname ] ]
|
|
|
|
Example: filemeta kernel32
|
|
Example: filemeta kernel32 md5
|
|
'''
|
|
|
|
argv = e_cli.splitargs(line)
|
|
if len(argv) == 0:
|
|
|
|
self.vprint('Loaded Files:')
|
|
for fname in self.getFiles():
|
|
self.vprint(' %s' % fname)
|
|
|
|
elif len(argv) == 1:
|
|
d = self.getFileMetaDict(argv[0])
|
|
self.vprint(pprint.pformat(d))
|
|
|
|
elif len(argv) == 2:
|
|
val = self.getFileMeta(argv[0], argv[1])
|
|
self.vprint('%s (%s):' % (argv[1], argv[0]))
|
|
self.vprint(pprint.pformat(val))
|
|
|
|
else:
|
|
self.do_help('filemeta')
|
|
|
|
def do_funcmeta(self, line):
|
|
"""
|
|
Show/Set function metadata.
|
|
Usage: funcmeta <func_expr> [key <value_expr>]
|
|
|
|
"""
|
|
# FIXME make a search thing here!
|
|
argv = e_cli.splitargs(line)
|
|
if len(argv) == 0:
|
|
return self.do_help("funcmeta")
|
|
|
|
if len(argv) == 1:
|
|
va = self.parseExpression(argv[0])
|
|
meta = self.getFunctionMetaDict(va)
|
|
self.vprint(pprint.pformat(meta))
|
|
|
|
elif len(argv) == 3:
|
|
va = self.parseExpression(argv[0])
|
|
name = argv[1]
|
|
locs = self.getExpressionLocals()
|
|
val = e_expr.evaluate(argv[2], locs)
|
|
self.setFunctionMeta(va, name, val)
|
|
|
|
def do_loc(self, line):
|
|
"""
|
|
Display the repr of a single location by va.
|
|
|
|
Usage: loc <va_expr>
|
|
"""
|
|
if not line:
|
|
return self.do_help("loc")
|
|
|
|
addr = self.parseExpression(line)
|
|
loc = self.getLocation(addr)
|
|
if loc is None:
|
|
s = self.arch.pointerString(addr)
|
|
self.vprint("Unknown location: %s" % s)
|
|
r = self.reprLocation(loc)
|
|
self.vprint(r)
|
|
|
|
def do_make(self, line):
|
|
"""
|
|
Create new instances of locations in the vivisect workspace.
|
|
|
|
Usage: make [options] <va_expr>
|
|
-c Make code
|
|
-f Make function
|
|
-s Make a string
|
|
-u Make a unicode string
|
|
-n <size> Make a number
|
|
-p <size> Make a pad
|
|
-S <structname> Make a structure
|
|
"""
|
|
argv = e_cli.splitargs(line)
|
|
try:
|
|
opts, args = getopt(argv, "csup:S:")
|
|
except Exception as e:
|
|
logger.warning(str(e))
|
|
return self.do_help("make")
|
|
|
|
if len(args) != 1 or len(opts) != 1:
|
|
return self.do_help("make")
|
|
|
|
addr = self.parseExpression(args[0])
|
|
opt, optarg = opts[0]
|
|
|
|
if opt == "-f":
|
|
logger.debug('new function (manual-cli): 0x%x', addr)
|
|
self.makeFunction(addr)
|
|
|
|
elif opt == "-c":
|
|
self.makeCode(addr)
|
|
|
|
elif opt == "-s":
|
|
self.makeString(addr)
|
|
|
|
elif opt == "-u":
|
|
self.makeUnicode(addr)
|
|
|
|
elif opt == "-n":
|
|
size = self.parseExpression(optarg)
|
|
self.makeNumber(addr, size)
|
|
|
|
elif opt == "-p":
|
|
size = self.parseExpression(optarg)
|
|
self.makePad(addr, size)
|
|
|
|
elif opt == "-S":
|
|
self.makeStructure(addr, optarg)
|
|
|
|
else:
|
|
return self.do_help("make")
|
|
|
|
def do_emulate(self, line):
|
|
"""
|
|
Create an emulator for the given function, and drop into a vdb
|
|
interface to step through the code.
|
|
|
|
(vdb CLI will appear in controlling terminal...)
|
|
|
|
Usage: emulate <va_expr>
|
|
"""
|
|
if not line:
|
|
return self.do_help("emulate")
|
|
|
|
emu = self.getEmulator()
|
|
addr = self.parseExpression(line)
|
|
emu.setProgramCounter(addr)
|
|
|
|
trace = vt_envitools.TraceEmulator(emu)
|
|
|
|
db = vdb.Vdb(trace=trace)
|
|
db.cmdloop()
|
|
|
|
def do_argtrack(self, line):
|
|
"""
|
|
Track input arguments to the given function by name or address.
|
|
|
|
Usage: argtrack <func_addr_expr> <arg_idx>
|
|
"""
|
|
if not line:
|
|
return self.do_help("argtrack")
|
|
|
|
argv = e_cli.splitargs(line)
|
|
if len(argv) != 2:
|
|
return self.do_help("argtrack")
|
|
|
|
try:
|
|
fva = self.parseExpression(argv[0])
|
|
except Exception:
|
|
self.vprint("Invalid Address Expression: %s" % argv[0])
|
|
return
|
|
|
|
try:
|
|
idx = self.parseExpression(argv[1])
|
|
except Exception:
|
|
self.vprint("Invalid Index Expression: %s" % argv[1])
|
|
return
|
|
|
|
if self.getFunction(fva) != fva:
|
|
self.vprint("Invalid Function Address: (0x%.8x) %s" % (fva, line))
|
|
|
|
for pleaf in viv_vector.trackArgOrigin(self, fva, idx):
|
|
|
|
self.vprint('='*80)
|
|
|
|
path = vg_path.getPathToNode(pleaf)
|
|
path.reverse()
|
|
|
|
for pnode in path:
|
|
fva = vg_path.getNodeProp(pnode, 'fva')
|
|
argv = vg_path.getNodeProp(pnode, 'argv')
|
|
callva = vg_path.getNodeProp(pnode, 'cva')
|
|
argidx = vg_path.getNodeProp(pnode, 'argidx')
|
|
if callva is not None:
|
|
aval, amagic = argv[argidx]
|
|
arepr = '0x%.8x' % aval
|
|
if amagic is not None:
|
|
arepr = repr(amagic)
|
|
frepr = 'UNKNOWN'
|
|
if fva is not None:
|
|
frepr = '0x%.8x' % fva
|
|
self.vprint('func: %s calls at: 0x%.8x with his own: %s' % (frepr, callva, arepr))
|
|
self.vprint("="*80)
|
|
|
|
def do_chat(self, line):
|
|
"""
|
|
Echo a message to any other users of a shared workspace.
|
|
|
|
Usage: chat oh hai! Checkout 0x7c778030
|
|
"""
|
|
if len(line) == 0:
|
|
return self.do_help('chat')
|
|
|
|
self.chat(line)
|
|
|
|
def do_codepath(self, line):
|
|
"""
|
|
Enumerate and show any known code paths from the specified
|
|
from address expression to the to address expression.
|
|
Usage: codepath <from_expr> <to_expr>
|
|
"""
|
|
if not line:
|
|
return self.do_help("codepath")
|
|
|
|
argv = e_cli.splitargs(line)
|
|
if len(argv) != 2:
|
|
return self.do_help("codepath")
|
|
|
|
try:
|
|
frva = self.parseExpression(argv[0])
|
|
except Exception:
|
|
self.vprint("Invalid From Va: %s" % argv[0])
|
|
return
|
|
|
|
try:
|
|
tova = self.parseExpression(argv[1])
|
|
except Exception:
|
|
self.vprint("Invalid To Va: %s" % argv[1])
|
|
return
|
|
|
|
self.vprint("Tracking Paths From 0x%.8x to 0x%.8x" % (frva, tova))
|
|
|
|
paths = viv_vector.getCodePaths(self, frva, tova)
|
|
self.vprint("Function VA\tBlock VA\tSize\tFunction Name")
|
|
count = 0
|
|
for blist in paths:
|
|
count += 1
|
|
self.vprint("="*30)
|
|
for bva, bsize, fva in blist:
|
|
fname = self.getName(fva)
|
|
self.vprint("0x%.8x\t0x%.8x\t%4d\t%s" % (fva, bva, bsize, fname))
|
|
if count == 0:
|
|
self.vprint("None!")
|
|
return
|
|
|
|
def do_vampsig(self, line):
|
|
"""
|
|
Generate a vamp signature string for the given function's first block.
|
|
"""
|
|
if not line:
|
|
return self.do_help("vampsig")
|
|
|
|
va = self.parseExpression(line)
|
|
|
|
fva = self.getFunction(va)
|
|
if fva is None:
|
|
self.vprint("Invalid Function Address: 0x%.8x (%s)" % (va, line))
|
|
|
|
sig, mask = viv_vamp.genSigAndMask(self, fva)
|
|
self.vprint("SIGNATURE: %s" % binascii.hexlify(sig))
|
|
self.vprint("MASK: %s" % binascii.hexlify(mask))
|
|
|
|
def do_vdb(self, line):
|
|
'''
|
|
Execute vdb GUI from within vivisect (allowing special hooks between them...)
|
|
(Optionally, specify a host to use for remote vdb debugging)
|
|
|
|
Usage: vdb [<remote_host>]
|
|
'''
|
|
if line:
|
|
try:
|
|
socket.gethostbyname(line)
|
|
except Exception:
|
|
self.vprint('Invalid Remote Host: %s' % line)
|
|
|
|
vtrace.remote = line
|
|
|
|
import vivisect.vdbext as viv_vdbext
|
|
viv_vdbext.runVdb(self._viv_gui)
|
|
|
|
def do_plt(self, line):
|
|
'''
|
|
Parse an entire PLT Section
|
|
|
|
Usage: plt <pltva> <pltsize>
|
|
'''
|
|
if not line:
|
|
return self.do_help("plt")
|
|
|
|
argv = e_cli.splitargs(line)
|
|
if len(argv) != 2:
|
|
return self.do_help("plt")
|
|
|
|
sva = self.parseExpression(argv[0])
|
|
ssize = self.parseExpression(argv[1])
|
|
|
|
import vivisect.analysis.elf.elfplt as vaee
|
|
vaee.analyzePLT(self, sva, ssize)
|
|
|
|
def do_plt_function(self, line):
|
|
'''
|
|
Make a PLT function at a virtual address
|
|
|
|
Usage: plt_function <va>
|
|
'''
|
|
if not line:
|
|
return self.do_help("plt_function")
|
|
|
|
fva = self.parseExpression(line)
|
|
|
|
import vivisect.analysis.elf.elfplt as vaee
|
|
vaee.analyzeFunction(self, fva)
|