generate progress SVGs

This commit is contained in:
itsmattkc
2023-06-27 15:59:44 -07:00
parent 24ec7023bd
commit b080766321
5 changed files with 137 additions and 3 deletions

View File

@@ -1,6 +1,7 @@
#!/usr/bin/env python3
import argparse
import base64
from capstone import *
import difflib
import struct
@@ -15,9 +16,12 @@ parser.add_argument('original', metavar='original-binary', help='The original bi
parser.add_argument('recompiled', metavar='recompiled-binary', help='The recompiled binary')
parser.add_argument('pdb', metavar='recompiled-pdb', help='The PDB of the recompiled binary')
parser.add_argument('decomp_dir', metavar='decomp-dir', help='The decompiled source tree')
parser.add_argument('--total', '-T', metavar='total-func-count', help='Total number of expected functions (improves total accuracy statistic)')
parser.add_argument('--verbose', '-v', metavar='offset', help='Print assembly diff for specific function (original file\'s offset)')
parser.add_argument('--html', '-H', metavar='output-file', help='Generate searchable HTML summary of status and diffs')
parser.add_argument('--no-color', '-n', action='store_true', help='Do not color the output')
parser.add_argument('--svg', '-S', metavar='output-svg', help='Generate SVG graphic of progress')
parser.add_argument('--svg-icon', metavar='svg-icon', help='Icon to use in SVG (PNG)')
args = parser.parse_args()
@@ -50,6 +54,8 @@ source = args.decomp_dir
if not os.path.isdir(source):
parser.error('Source directory does not exist')
svg = args.svg
# Declare a class that can automatically convert virtual executable addresses
# to file addresses
class Bin:
@@ -365,7 +371,8 @@ for subdir, dirs, files in os.walk(source):
# If html, record the diffs to an HTML file
if html:
htmlinsert.append('{address: "%s", name: "%s", matching: %s, diff: "%s"}' % (hex(addr), recinfo.name, str(ratio), '\\n'.join(udiff).replace('"', '\\"').replace('\n', '\\n')))
escaped = '\\n'.join(udiff).replace('"', '\\"').replace('\n', '\\n').replace('<', '&lt;').replace('>', '&gt;')
htmlinsert.append('{address: "%s", name: "%s", matching: %s, diff: "%s"}' % (hex(addr), recinfo.name, str(ratio), escape))
except UnicodeDecodeError:
break
@@ -389,6 +396,49 @@ def gen_html(html, data):
htmlfile.write(templatedata)
htmlfile.close()
def gen_svg(svg, name, icon, implemented_funcs, total_funcs, raw_accuracy):
templatefile = open(get_file_in_script_dir('template.svg'), 'r')
if not templatefile:
print('Failed to find SVG template file, can\'t generate SVG summary')
return
templatedata = templatefile.read()
templatefile.close()
# Replace icon
if args.svg_icon:
iconfile = open(args.svg_icon, 'rb')
templatedata = templatedata.replace('{icon}', base64.b64encode(iconfile.read()).decode('utf-8'), 1)
iconfile.close()
# Replace name
templatedata = templatedata.replace('{name}', name, 1)
# Replace implemented statistic
templatedata = templatedata.replace('{implemented}', '%.2f%% (%i/%i)' % (implemented_funcs / total_funcs * 100, implemented_funcs, total_funcs), 1)
# Replace accuracy statistic
templatedata = templatedata.replace('{accuracy}', '%.2f%%' % (raw_accuracy / implemented_funcs * 100), 1)
# Generate progress bar width
total_statistic = raw_accuracy / total_funcs
percenttemplate = '{progbar'
percentstart = templatedata.index(percenttemplate)
percentend = templatedata.index('}', percentstart)
progwidth = float(templatedata[percentstart + len(percenttemplate) + 1:percentend]) * total_statistic
templatedata = templatedata[0:percentstart] + str(progwidth) + templatedata[percentend + 1:]
# Replace percentage statistic
templatedata = templatedata.replace('{percent}', '%.2f%%' % (total_statistic * 100), 1)
svgfile = open(svg, 'w')
if not svgfile:
print('Failed to write to SVG file %s' % svg)
return
svgfile.write(templatedata)
svgfile.close()
if html:
gen_html(html, htmlinsert)
@@ -396,5 +446,13 @@ if verbose:
if not found_verbose_target:
print('Failed to find the function with address %s' % hex(verbose))
else:
implemented_funcs = function_count
if args.total:
function_count = int(args.total)
if function_count > 0:
print('\nTotal accuracy %.2f%% across %i functions' % (total_accuracy / function_count * 100, function_count))
if svg:
gen_svg(svg, os.path.basename(original), args.svg_icon, implemented_funcs, function_count, total_accuracy)