290 lines
8.5 KiB
Python
Executable File
290 lines
8.5 KiB
Python
Executable File
#!/usr/bin/env python
|
|
import os.path
|
|
|
|
import yaml
|
|
import sys
|
|
|
|
import MySQLdb
|
|
import MySQLdb.cursors
|
|
|
|
from app.detaildealer import detaildealer
|
|
|
|
from pprint import pprint
|
|
from . import data, details
|
|
|
|
"""Get command line options"""
|
|
from optparse import OptionParser
|
|
|
|
parser = OptionParser()
|
|
parser.add_option(
|
|
"-c",
|
|
"--conf",
|
|
type="string",
|
|
help="MySQL config file",
|
|
dest="config",
|
|
default=os.path.join(os.path.expanduser("~"), ".my.cnf"),
|
|
)
|
|
parser.add_option(
|
|
"-s",
|
|
"--host",
|
|
type="string",
|
|
help="Webserver hostname",
|
|
dest="host",
|
|
default="localhost",
|
|
)
|
|
parser.add_option(
|
|
"-d",
|
|
"--details",
|
|
type="string",
|
|
help="Detailed information (YAML configuration file)",
|
|
dest="details",
|
|
default=None,
|
|
)
|
|
parser.add_option(
|
|
"-p", "--port", type="string", help="Webserver port", dest="port", default="5000"
|
|
)
|
|
opts, args = parser.parse_args()
|
|
|
|
"""Check if configuration files exist"""
|
|
|
|
|
|
def checkConfigFile(msg, fname):
|
|
if not os.path.isfile(fname):
|
|
sys.exit("Error: '" + fname + "' not found")
|
|
else:
|
|
print(msg, "->", fname)
|
|
|
|
|
|
# Check sql config
|
|
sqlconfig = opts.config
|
|
checkConfigFile("MySQL config", sqlconfig)
|
|
|
|
# Check details file
|
|
if opts.details:
|
|
checkConfigFile("Details", opts.details)
|
|
|
|
# Instantiate global detail dealer, will be initialized in reloadOverview
|
|
# detaildealer = details.DetailDealer()
|
|
|
|
|
|
"""Remove all characters from string except alphanuermics and _"""
|
|
|
|
|
|
def scrub(table_name):
|
|
return "".join(chr for chr in table_name if chr.isalnum() or chr == "_")
|
|
|
|
|
|
"""Global mysql handles"""
|
|
db = None
|
|
cur = None
|
|
|
|
|
|
def loadSession(dbconf):
|
|
global db
|
|
if db:
|
|
db.close()
|
|
db = MySQLdb.connect(
|
|
read_default_file=dbconf, cursorclass=MySQLdb.cursors.DictCursor
|
|
)
|
|
return db.cursor()
|
|
|
|
|
|
def closeSession():
|
|
if cur:
|
|
cur.close()
|
|
global db
|
|
db.close()
|
|
db = None
|
|
|
|
|
|
"""Populate variant results for overview data"""
|
|
|
|
|
|
def getVariants(cur, table):
|
|
restbl = table.getDetails().getDBName()
|
|
cur.execute(
|
|
"""SELECT sum((t.time2 - t.time1 + 1) * width) AS total, resulttype,variant, v.id as variant_id, benchmark, details FROM variant v JOIN trace t ON v.id = t.variant_id JOIN fspgroup g ON g.variant_id = t.variant_id AND g.instr2 = t.instr2 AND g.data_address = t.data_address JOIN %s r ON r.pilot_id = g.pilot_id JOIN fsppilot p ON r.pilot_id = p.id GROUP BY v.id, resulttype, details"""
|
|
% (restbl)
|
|
) # % is used here, as a tablename must not be quoted
|
|
res = cur.fetchall()
|
|
rdic = {}
|
|
# Build dict with variant id as key
|
|
for r in res:
|
|
# if variant entry already exists:
|
|
variant = table.getVariant(int(r["variant_id"]))
|
|
if not variant: # if variant did not exist yet, create it:
|
|
variant_details = detaildealer.getVariant(restbl, r["variant"])
|
|
benchmark_details = detaildealer.getBenchmark(
|
|
restbl, r["variant"], r["benchmark"]
|
|
)
|
|
table_details = detaildealer.getTable(restbl)
|
|
variant = data.Variant(
|
|
int(r["variant_id"]),
|
|
r["variant"],
|
|
table_details,
|
|
benchmark_details,
|
|
variant_details,
|
|
)
|
|
variant.addResulttype(r["resulttype"], r["total"])
|
|
table.addVariant(variant)
|
|
|
|
|
|
"""Get overview data for index page"""
|
|
|
|
|
|
def reloadOverview():
|
|
overview = data.Overview()
|
|
detaildealer.reload(opts.details)
|
|
cur = loadSession(sqlconfig)
|
|
cur.execute("show tables like 'result_%'")
|
|
result_tables = cur.fetchall()
|
|
results = {}
|
|
for rdic in result_tables:
|
|
# r is the tablename, -> result_FOOBAR
|
|
for key, tablename in rdic.items():
|
|
table = data.ResultTable(tablename, detaildealer)
|
|
getVariants(cur, table)
|
|
overview.add(table)
|
|
# Check if objdump table exists
|
|
cur.execute("SHOW TABLES like 'objdump'")
|
|
objdump_exists = len(cur.fetchall()) == 1
|
|
closeSession()
|
|
return overview, objdump_exists
|
|
|
|
|
|
"""Load overview data at server startup"""
|
|
print("Loading overview data from database. This may take a while ...")
|
|
overview_data, objdump_exists = reloadOverview()
|
|
print("done.")
|
|
|
|
|
|
## Get overview data for views.index()
|
|
def getOverview():
|
|
return overview_data
|
|
|
|
|
|
def objdumpExists():
|
|
return objdump_exists
|
|
|
|
|
|
"""Get Results for one variant id"""
|
|
|
|
|
|
def getVariantResult(table, variantid):
|
|
cur = loadSession(sqlconfig)
|
|
restbl = scrub(table)
|
|
|
|
stmt = (
|
|
"SELECT resulttype, count(*) as total from %s r join fsppilot on r.pilot_id=fsppilot.id join variant on fsppilot.variant_id=variant.id"
|
|
% (restbl)
|
|
)
|
|
where = " WHERE variant.id = %s group by resulttype ORDER BY resulttype "
|
|
stmt = stmt + where
|
|
cur.execute(stmt, variantid)
|
|
res = cur.fetchall()
|
|
closeSession()
|
|
return res
|
|
|
|
|
|
"""Show objdump together with according injection result types."""
|
|
|
|
|
|
def getCode(result_table, variant_id, resultlabel=None):
|
|
result_table = scrub(result_table)
|
|
filt = ""
|
|
if not variant_id or not result_table:
|
|
return None
|
|
variant = overview_data.getVariantById(variant_id)
|
|
mapper = variant.getMapper()
|
|
if resultlabel:
|
|
dbnames = mapper.getDBNames(resultlabel)
|
|
if dbnames:
|
|
filt = " and ( "
|
|
for dbn in dbnames[:-1]:
|
|
filt += "resulttype = '" + dbn + "' OR "
|
|
filt += "resulttype = '" + dbnames[-1] + "' ) "
|
|
else:
|
|
filt = " and resulttype = '" + resultlabel + "' "
|
|
|
|
# I especially like this one:
|
|
select = "SELECT instr_address, opcode, disassemble, comment, sum(t.time2 - t.time1 + 1) as totals, GROUP_CONCAT(DISTINCT resulttype SEPARATOR ', ') as results FROM variant v "
|
|
join = (
|
|
" JOIN trace t ON v.id = t.variant_id JOIN fspgroup g ON g.variant_id = t.variant_id AND g.instr2 = t.instr2 AND g.data_address = t.data_address JOIN %s r ON r.pilot_id = g.pilot_id JOIN fsppilot p ON r.pilot_id = p.id JOIN objdump ON objdump.variant_id = v.id AND objdump.instr_address = injection_instr_absolute "
|
|
% (scrub(result_table))
|
|
)
|
|
where = "WHERE v.id = %s "
|
|
group = "GROUP BY injection_instr_absolute ORDER BY totals DESC "
|
|
|
|
cur = loadSession(sqlconfig)
|
|
stmt = select + join + where + filt + group
|
|
cur.execute(stmt, (variant_id))
|
|
dump = cur.fetchall()
|
|
|
|
closeSession()
|
|
resulttypes = variant.getResultLabels()
|
|
return dump, resulttypes
|
|
|
|
|
|
def getCodeExcerpt(variant_id, instr_addr):
|
|
code = {}
|
|
limit = 8
|
|
cur = loadSession(sqlconfig)
|
|
cur.execute(
|
|
"""(SELECT instr_address, opcode, disassemble, comment FROM objdump \
|
|
WHERE instr_address < %s AND variant_id = %s \
|
|
ORDER BY instr_address DESC LIMIT %s) \
|
|
ORDER BY instr_address ASC""",
|
|
(instr_addr, variant_id, limit),
|
|
)
|
|
below = cur.fetchall()
|
|
code["below"] = below
|
|
cur.execute(
|
|
"""SELECT instr_address, opcode, disassemble, comment FROM objdump \
|
|
WHERE instr_address >= %s AND variant_id = %s \
|
|
ORDER BY instr_address ASC LIMIT %s""",
|
|
(instr_addr, variant_id, limit + 1),
|
|
)
|
|
upper = cur.fetchall()
|
|
code["upper"] = upper
|
|
closeSession()
|
|
return code
|
|
|
|
|
|
def getResultsbyInstruction(result_table, variant_id, instr_addr, resultlabel=None):
|
|
restypefilter = None
|
|
if resultlabel:
|
|
variant = overview_data.getVariantById(variant_id)
|
|
mapper = variant.getMapper()
|
|
if resultlabel:
|
|
dbnames = mapper.getDBNames(resultlabel)
|
|
if dbnames:
|
|
restypefilter = " and ( "
|
|
for dbn in dbnames[:-1]:
|
|
restypefilter += "resulttype = '" + dbn + "' OR "
|
|
restypefilter += "resulttype = '" + dbnames[-1] + "' ) "
|
|
|
|
select = (
|
|
"SELECT bitoffset as 'Bit Offset', hex(injection_instr_absolute) as 'Instruction Address', hex(original_value) as 'Original Value', hex(data_address) as 'Data Address', resulttype as 'Result Type', details as 'Details' from %s "
|
|
% scrub(result_table)
|
|
)
|
|
join = "JOIN fsppilot ON pilot_id = fsppilot.id "
|
|
where = "WHERE variant_id = %s and injection_instr_absolute = %s "
|
|
order = "ORDER BY data_address, bitoffset"
|
|
|
|
cur = loadSession(sqlconfig)
|
|
if not restypefilter:
|
|
stmt = select + join + where + order
|
|
cur.execute(stmt, (variant_id, instr_addr))
|
|
else:
|
|
stmt = select + join + where + restypefilter + order
|
|
cur.execute(stmt, (variant_id, instr_addr))
|
|
|
|
res = cur.fetchall()
|
|
closeSession()
|
|
return res
|
|
|
|
|
|
def showDBstatus():
|
|
res = "TODO"
|
|
return res
|