From 9923c591c11a01b512e76424b0e9dc9807acfb0b Mon Sep 17 00:00:00 2001 From: root Date: Sat, 1 Sep 2018 20:48:09 +0000 Subject: [PATCH] add entry point for reducer --- bin/deepstate/reducer.py | 137 +++++++++++++++++++++++++++++++++++++++ bin/setup.py.in | 1 + 2 files changed, 138 insertions(+) create mode 100644 bin/deepstate/reducer.py diff --git a/bin/deepstate/reducer.py b/bin/deepstate/reducer.py new file mode 100644 index 0000000..ad02d11 --- /dev/null +++ b/bin/deepstate/reducer.py @@ -0,0 +1,137 @@ +import sys +import subprocess +import os +import shutil + +def main(): + if "--help" in sys.argv: + print "usage: deepstate-reduce binary input-test output-test [string] [--which test]" + print + print "Reduces input-test by trying to delete OneOf blocks and lower byte values." + print + print "Writes reduced test to output-test." + print + print "Optional string gives an reduction criteria (searched for in test output)." + print "If no string is provided, looks for Failure or Crash." + print + print "--which test allows control over which DeepState test is executed, if none" + print "is provided, defaults to last test defined." + sys.exit(0) + + args = sys.argv + + try: + which = args.index("--which") + whichTest = args[which+1] + args = args[:which] + args[which + 2:] + except: + whichTest = None + + deepstate = args[1] + test = args[2] + out = args[3] + if len(args) > 4: + checkString = args[4] + else: + checkString = None + + def runCandidate(candidate): + with open(".reducer.out", 'w') as outf: + cmd = [deepstate + " --input_test_file " + + candidate + " --verbose_reads"] + if whichTest is not None: + cmd += ["--input_which_test", whichTest] + subprocess.call(cmd, shell=True, stdout=outf, stderr=outf) + result = [] + with open(".reducer.out", 'r') as inf: + for line in inf: + result.append(line) + return result + + def checks(result): + for line in result: + if checkString: + if checkString in line: + return True + else: + if "ERROR: Failed:" in line: + return True + if "ERROR: Crashed" in line: + return True + return False + + def structure(result): + OneOfs = [] + currentOneOf = [] + for line in result: + if "STARTING OneOf CALL" in line: + currentOneOf.append(-1) + elif "Reading byte at" in line: + lastRead = int(line.split()[-1]) + if currentOneOf[-1] == -1: + currentOneOf[-1] = lastRead + elif "FINISHED OneOf CALL" in line: + OneOfs.append((currentOneOf[-1], lastRead)) + currentOneOf = currentOneOf[:-1] + return (OneOfs, lastRead) + + initial = runCandidate(test) + if not checks(initial): + print "STARTING TEST DOES NOT SATISFY REDUCTION CRITERIA" + return 1 + + with open(test, 'rb') as test: + currentTest = bytearray(test.read()) + + print "ORIGINAL TEST HAS", len(currentTest), "BYTES" + + s = structure(initial) + print "LAST BYTE READ IS", s[1] + + if s[1] < len(currentTest): + print "SHRINKING TO IGNORE UNREAD BYTES" + currentTest = currentTest[:s[1]+1] + + changed = True + while changed: + changed = False + cuts = s[0] + for c in cuts: + newTest = currentTest[:c[0]] + currentTest[c[1]+1:] + with open(".candidate.test", 'wb') as outf: + outf.write(newTest) + r = runCandidate(".candidate.test") + if checks(r): + print "ONEOF REMOVAL REDUCED TEST TO", len(newTest), "BYTES" + s = structure(r) + changed = True + currentTest = newTest + break + for b in range(0, len(currentTest)): + for v in range(0, currentTest[b]): + newTest = bytearray(currentTest) + newTest[b] = v + with open(".candidate.test", 'wb') as outf: + outf.write(newTest) + r = runCandidate(".candidate.test") + if checks(r): + print "BYTE REDUCTION: BYTE", b, "FROM", currentTest[b], "TO", v + s = structure(r) + changed = True + currentTest = newTest + break + if not changed: + print "NO REDUCTIONS FOUND" + + if (s[1] + 1) > len(currentTest): + print "PADDING TEST WITH", (s[1] + 1) - len(currentTest), "ZEROS" + padding = bytearray('\x00' * ((s[1] + 1) - len(currentTest))) + currentTest = currentTest + padding + + with open(out, 'wb') as outf: + outf.write(currentTest) + + return 0 + +if "__main__" == __name__: + exit(main()) diff --git a/bin/setup.py.in b/bin/setup.py.in index b926ffa..dfb965e 100644 --- a/bin/setup.py.in +++ b/bin/setup.py.in @@ -36,5 +36,6 @@ setuptools.setup( 'deepstate = deepstate.main_manticore:main', 'deepstate-angr = deepstate.main_angr:main', 'deepstate-manticore = deepstate.main_manticore:main', + 'deepstate-reduce = deepstate.reducer:main', ] })