def setUp(self): core = config.get_group("core") core.seed = 61 core.mprocessing = core.mprocessing.single dirname = os.path.dirname(__file__) self.m = Manticore(os.path.join(dirname, "binaries", "basic_linux_amd64"), policy="random")
class StateHooks(unittest.TestCase): def setUp(self): core = config.get_group("core") core.seed = 61 core.mprocessing = core.mprocessing.single dirname = os.path.dirname(__file__) self.m = Manticore(os.path.join(dirname, "binaries", "basic_linux_amd64"), policy="random") def test_state_hooks(self): @self.m.hook(0x400610, after=True) def process_hook(state: State) -> None: # We can't remove because the globally applied hooks are stored in # the Manticore class, not State self.assertFalse(state.remove_hook(0x400610, process_hook, after=True)) # We can remove this one because it was applied specifically to this # State (or its parent) self.assertTrue(state.remove_hook(None, do_nothing, after=True)) state.add_hook(None, do_nothing, after=False) state.add_hook(None, do_nothing, after=True) state.add_hook(0x400647, fin, after=True) state.add_hook(0x400647, fin, after=False) for state in self.m.ready_states: self.m.add_hook(None, do_nothing, after=True, state=state) f = io.StringIO() with redirect_stdout(f): self.m.run() self.assertIn("Reached fin callback", f.getvalue())
def setUp(self): dirname = os.path.dirname(__file__) self.concrete_instance = Manticore(os.path.join(dirname, "binaries", "rusticorn")) self.concrete_instance.register_plugin(ResumeUnicornPlugin()) self.concrete_instance.add_hook(self.MAIN, callback=self.hook_main) self.concrete_instance.add_hook(self.PRE_LOOP, callback=self.hook_pre_loop) self.concrete_instance.add_hook(self.DONE, callback=self.hook_ret_good) self.concrete_instance.add_hook(self.FAIL, callback=self.hook_ret_fail)
def verify(argv): logger.debug(f'Verifying program "{argv}"') # Address and stack_size are from linux.py # TODO(yan): Refactor these constants into a reachable value in platform qemu.start("arm", argv, va_size=stack_top, stack_size=stack_size) gdb.start("arm", argv) m = Manticore(argv[0], argv[1:]) m.verbosity = 2 init_logging() logger.setLevel(logging.DEBUG) @m.hook(None) def on_instruction(state): """ Handle all the hooks for each instruction executed. Ordered as: pre_qemu * qemu exec * post_qemu // svc synchronization happens here (mmap specifically) pre_mcore * mcore exec * post_mcore // all memory written in a mcore syscall gets moved to qemu here """ global initialized, last_instruction # Initialize our state to QEMU's if not initialized: initialize(state) initialized = True if last_instruction: post_mcore(state, last_instruction) # Kernel helpers are inline in QEMU; do nothing if (state.cpu.PC >> 16) == 0xFFFF: return pre_qemu(state) last_mnemonic = [x.strip() for x in gdb.getInstruction().split(":") ][1].split("\t")[0] gdb.stepi() post_qemu(state, last_mnemonic) last_instruction = state.cpu.instruction pre_mcore(state) m.run()
def test(): from manticore.native import Manticore from manticore.core.smtlib import operators if __name__ == "__main__": m = Manticore("./angrme") else: m = Manticore("./test_hxp2018_angrme/angrme") m.context["solved"] = False max_length = 40 # maximum flag length (rough guess-timate) m.verbosity(1) @m.hook(0x555555555187) def inject_symbolic_input(state): # skip expensive call to fgets state.cpu.RIP = 0x5555555551A0 # manually inject symbolic variable in place of input with m.locked_context() as context: solution = state.new_symbolic_buffer(max_length) # constrain flag format state.constrain(solution[0] == ord("h")) state.constrain(solution[1] == ord("x")) state.constrain(solution[2] == ord("p")) state.constrain(solution[3] == ord("{")) # constrain characters to be printable ASCII or null byte for i in range(max_length): state.constrain( operators.OR( solution[i] == 0, operators.AND(ord(" ") <= solution[i], solution[i] <= ord("}")), ) ) address = state.cpu.RSP + 0x30 context["input_address"] = address print("[+] input address: " + hex(state.cpu.RSP + 0x30)) state.cpu.write_bytes(address, solution) @m.hook(0x555555556390) def abandon(state): print("[-] abandoning path") state.abandon() @m.hook(0x555555556370) def success(state): with m.locked_context() as context: print("[+] found success path") address = context["input_address"] flag = "".join(map(chr, state.solve_buffer(address, max_length))) print("[+] flag: " + flag) with m.locked_context() as context: if "hxp{4nd_n0w_f0r_s0m3_r3al_ch4ll3ng3}" in flag: context["solved"] = True m.kill() m.run() assert m.context["solved"]
def setUp(self): dirname = os.path.dirname(__file__) self.m = Manticore(os.path.join(dirname, 'binaries', 'arguments_linux_amd64'), argv=['argv', 'mc', 'argface']) self.concrete_instance = Manticore(os.path.join( dirname, 'binaries', 'arguments_linux_amd64'), argv=['argv', 'mc', 'argface']) self.concrete_instance.register_plugin(ConcretePlugin()) '''
def main(): parser = argparse.ArgumentParser(description="Follow a concrete trace") parser.add_argument("-f", "--explore_from", help="Value of PC from which to explore symbolically", type=str) parser.add_argument( "-t", "--explore_to", type=str, default=sys.maxsize, help= "Value of PC until which to explore symbolically. (Probably don't want this set)", ) parser.add_argument("--verbose", "-v", action="count", default=0, help="Increase verbosity") parser.add_argument( "cmd", type=str, nargs="+", help= 'Program and arguments. Use "--" to separate script arguments from target arguments', ) args = parser.parse_args(sys.argv[1:]) range = None if args.explore_from: range = (args.explore_from, args.explore_to) # Create a concrete Manticore and record it m1 = Manticore.linux(args.cmd[0], args.cmd[1:]) t = ExtendedTracer() r = TraceReceiver(t) m1.verbosity(args.verbose) m1.register_plugin(t) m1.register_plugin(r) m1.run(procs=1) time.sleep(3) # Create a symbolic Manticore and follow last trace symbolic_args = ["+" * len(arg) for arg in args.cmd[1:]] m2 = Manticore.linux(args.cmd[0], symbolic_args) f = Follower(r.trace) if range: f.add_symbolic_range(*range) m2.verbosity(args.verbose) m2.register_plugin(f) m2.run()
def setUp(self): core = config.get_group("core") core.seed = 61 core.mprocessing = core.mprocessing.single dirname = os.path.dirname(__file__) self.m = Manticore( os.path.join(dirname, "binaries", "basic_state_merging"), policy="random" ) self.plugin = self.StateCounter() self.m.register_plugin(Merger()) self.m.register_plugin(self.plugin)
def setUp(self): dirname = os.path.dirname(__file__) self.m = Manticore( os.path.join(dirname, "binaries", "arguments_linux_amd64"), argv=["argv", "mc", "argface"], ) self.concrete_instance = Manticore( os.path.join(dirname, "binaries", "arguments_linux_amd64"), argv=["argv", "mc", "argface"], ) self.concrete_instance.register_plugin(ConcretePlugin()) """
def benchmark(program): print(f"[*] Benchmarking program \"{program}\"") m = Manticore(program) m.run(should_profile=True) results = m._executor.dump_stats() if results is None: print(f"[*] Failed to collect stats for program {program}") return display(results) return results
def test_introspect_daemon(self): self.history = [] m = Manticore(ms_file, stdin_size=17) m.register_daemon(self.introspect_loop) m.run() sleep(1) # Leave time for the callback to fire after we've finished self.assertGreater(len(self.history), 0) progression = [] for hist in self.history: hist = hist.values() progression.append(( sum(1 if (st.state_list == StateLists.ready) else 0 for st in hist), sum(1 if (st.state_list == StateLists.busy) else 0 for st in hist), sum(1 if (st.state_list == StateLists.terminated) else 0 for st in hist), )) self.assertEqual(progression[-1][0], 0) # Once finished, we have no ready states self.assertEqual(progression[-1][1], 0) # Once finished, we have no busy states # Once finished, we have only terminated states. self.assertGreater(progression[-1][2], 0) f = io.StringIO() with contextlib.redirect_stdout(f): m.pretty_print_states() self.assertIn("Terminated States: {}".format(progression[-1][2]), f.getvalue())
def symbolic_run_get_cons(trace): """ Execute a symbolic run that follows a concrete run; return constraints generated and the stdin data produced """ # mem: has no concurrency support. Manticore should be 'Single' process m2 = Manticore.linux(prog, workspace_url="mem:") f = Follower(trace) set_verbosity(VERBOSITY) m2.register_plugin(f) def on_term_testcase(mm, state, err): with m2.locked_context() as ctx: readdata = [] for name, fd, data in state.platform.syscall_trace: if name in ("_receive", "_read") and fd == 0: readdata.append(data) ctx["readdata"] = readdata ctx["constraints"] = list(state.constraints.constraints) m2.subscribe("will_terminate_state", on_term_testcase) m2.run() constraints = m2.context["constraints"] datas = m2.context["readdata"] return constraints, datas
def test_thumb_mode_entrypoint(self): # thumb_mode_entrypoint is a binary with only one instruction # 0x1000: add.w r0, r1, r2 # which is a Thumb instruction, so the entrypoint is set to 0x1001 m = Manticore.linux( os.path.join(os.path.dirname(__file__), "binaries", "thumb_mode_entrypoint")) m.context["success"] = False @m.init def init(m, ready_states): for state in ready_states: state.platform.current.regfile.write("R0", 0) state.platform.current.regfile.write("R1", 0x1234) state.platform.current.regfile.write("R2", 0x5678) @m.hook(0x1001) def pre(state): # If the wrong PC value was used by the loader (0x1001 instead of 0x1000), # the wrong instruction bytes will have been fetched from memory state.abandon() @m.hook(0x1004) def post(state): # If the wrong execution mode was set by the loader, the wrong instruction # will have been executed, so the register value will be incorrect with m.locked_context() as ctx: ctx["success"] = state.cpu.regfile.read("R0") == 0x68AC state.abandon() m.run() self.assertTrue(m.context["success"])
def symbolic_run_get_cons(trace): ''' Execute a symbolic run that follows a concrete run; return constraints generated and the stdin data produced ''' m2 = Manticore.linux(prog, workspace_url='mem:') f = Follower(trace) m2.verbosity(VERBOSITY) m2.register_plugin(f) def on_term_testcase(mcore, state, stateid, err): with m2.locked_context() as ctx: readdata = [] for name, fd, data in state.platform.syscall_trace: if name in ('_receive', '_read') and fd == 0: readdata.append(data) ctx['readdata'] = readdata ctx['constraints'] = list(state.constraints.constraints) m2.subscribe('will_terminate_state', on_term_testcase) m2.run() constraints = m2.context['constraints'] datas = m2.context['readdata'] return constraints, datas
def test_thumb_mode_entrypoint(self): # thumb_mode_entrypoint is a binary with only one instruction # 0x1000: add.w r0, r1, r2 # which is a Thumb instruction, so the entrypoint is set to 0x1001 m = Manticore.linux( os.path.join(os.path.dirname(__file__), 'binaries', 'thumb_mode_entrypoint')) m.success = False @m.init def init(state): state.cpu.regfile.write('R0', 0) state.cpu.regfile.write('R1', 0x1234) state.cpu.regfile.write('R2', 0x5678) @m.hook(0x1001) def pre(state): # If the wrong PC value was used by the loader (0x1001 instead of 0x1000), # the wrong instruction bytes will have been fetched from memory state.abandon() @m.hook(0x1004) def post(state): # If the wrong execution mode was set by the loader, the wrong instruction # will have been executed, so the register value will be incorrect m.success = state.cpu.regfile.read('R0') == 0x68ac state.abandon() m.run() self.assertTrue(m.success)
def profile(program, sort="cumulative"): print(f'[*] Profiling program "{program}"') m = Manticore(program) m.run(should_profile=True) stats = m.get_profiling_stats() print(f"[*] Loaded profiling data.") if stats is None: print(f"[*] Failed to collect stats for program {program}") return stats.sort_stats(sort) stats.print_stats()
def test_integration_basic_stdin(self): import struct dirname = os.path.dirname(__file__) self.m = Manticore( os.path.join(dirname, 'binaries', 'basic_linux_amd64')) self.m.run() workspace = self.m._output.store.uri with open(os.path.join(workspace, 'test_00000000.stdin'), 'rb') as f: a = struct.unpack('<I', f.read())[0] with open(os.path.join(workspace, 'test_00000001.stdin'), 'rb') as f: b = struct.unpack('<I', f.read())[0] if a > 0x41: self.assertTrue(a > 0x41) self.assertTrue(b <= 0x41) else: self.assertTrue(a <= 0x41) self.assertTrue(b > 0x41)
def concrete_run_get_trace(inp): m1 = Manticore.linux(prog, concrete_start=inp, workspace_url='mem:') t = ExtendedTracer() r = TraceReceiver(t) m1.verbosity(VERBOSITY) m1.register_plugin(t) m1.register_plugin(r) m1.run(procs=1) return r.trace
def test_integration_basic_stdin(self): import struct dirname = os.path.dirname(__file__) self.m = Manticore( os.path.join(dirname, "binaries", "basic_linux_amd64")) self.m.run() self.m.finalize() workspace = self.m._output.store.uri with open(os.path.join(workspace, "test_00000000.stdin"), "rb") as f: a = struct.unpack("<I", f.read())[0] with open(os.path.join(workspace, "test_00000001.stdin"), "rb") as f: b = struct.unpack("<I", f.read())[0] if a > 0x41: self.assertTrue(a > 0x41) self.assertTrue(b <= 0x41) else: self.assertTrue(a <= 0x41) self.assertTrue(b > 0x41)
def executeDirected(program, pathsObject, args=[]): workplace_url = "/tmp/mcore_tmp" m = Manticore(program, argv=args, workspace_url=workplace_url, pure_symbolic=False) consts = config.get_group("core") consts.__setattr__("procs", 1) #Store variables in global context to ensure that we can communicate them to the callback function with m.locked_context() as context: context['paths'] = pathsObject context['targets'] = dict() #Register hook to have each executed instruction's RIP logged m.add_hook(None, log_rip) m.register_plugin(DirectedExtractorPlugin()) #Output the set of paths for i in pathsObject.paths: l = [hex(j) for j in i.path] logger.debug(",".join(l)) #Execute the directed symbolic execution m.run() #Obtain the dictionary of control flow edges from Manticore with m.locked_context() as context: targets = context['targets'] #Output results logger.debug("--Results Sorted by Pathlen--") sortedPaths = sorted(pathsObject.paths, key=lambda x: x.pathLen, reverse=False) for i in range(pathsObject.pathsLen): pathID = sortedPaths[i].pathID if pathID in targets.keys(): logger.debug("Path " + str(pathID) + "[len=" + str(sortedPaths[i].pathLen) + "] ending with " + hex( pathsObject.lastAddresses[pathID]) + " has the following successors " + ",".join([str(i) for i in targets[pathID]])) else: logger.debug("Path " + str(pathID) + "[len=" + str(sortedPaths[i].pathLen) + "]" + " is infeasible") return targets
def test_daemon(self): self.fired = False m = Manticore(ms_file, stdin_size=17) m.register_daemon(self.daemon) m.run() self.assertTrue(self.fired)
def test(): from manticore.native import Manticore m = Manticore("test_ais3_crackme/ais3_crackme", ["a" * 30]) buffer_addr = 0 num_bytes = 24 with m.locked_context() as w: w[1] = False @m.hook(0x4005CD) def hook(state): print("fake 2 args EDI=2") state.cpu.EDI = 0x2 @m.hook(0x4005F3) def hook(state): print("retreive buffer from rax") global buffer_addr # print state.cpu.read_int(state.cpu.RAX), 'yoo' # assert 0 solution = state.new_symbolic_buffer(num_bytes) state.constrain(solution[0] == ord("a")) state.constrain(solution[1] == ord("i")) state.constrain(solution[2] == ord("s")) state.constrain(solution[3] == ord("3")) state.constrain(solution[4] == ord("{")) buffer_addr = state.cpu.read_int(state.cpu.RAX) with m.locked_context() as w: w[1] = buffer_addr print("buffer addr : %08x " % (buffer_addr)) state.cpu.write_bytes(buffer_addr, solution) @m.hook(0x40060E) def hook(state): state.abandon() print("failure path") @m.hook(0x400602) def hook(state): print("win path: attemping to solve") with m.locked_context() as w: buffer_addr = w[1] res = "".join(map(chr, state.solve_buffer(buffer_addr, num_bytes))) print("flag: %s" % res) if res == "ais3{I_tak3_g00d_n0t3s}": with m.locked_context() as w: w[1] = True m.kill() m.verbosity = 1 m.run() with m.locked_context() as w: assert w[1]
def symbolic_run(prog, params, trace, pc_crash): print "Starting symbolic execution" trace_set = set(trace) m = Manticore(prog, params) # The hook will be applied only to the instruction @pc_crash @m.hook(pc_crash) def crash_analysis(state): # Add the constraint on eax state.constrain(state.cpu.EAX == 0x0804887c) # 0x0804887c = @call_me # Retrieve the arguments corresponding to argv[1] argv_1 = next((i for i in state.input_symbols if i.name == 'ARGV1_1'), None) if argv_1: # Ask the value of argv_1 to the solver val_argv_1 = state.solve_one(argv_1) # Pretty print of the solution print "The solution is:" print "\\x" + "\\x".join("{:02x}".format(ord(c)) for c in val_argv_1) state.abandon() trace_set = set(trace) # convert the list to a set # None: The hook will be applied to all the instructions @m.hook(None) def follow_trace(state): if 'visited' not in state.context: state.context['visited'] = set() state.context['visited'].add(state.cpu.PC) # We stop to explore the current path if it doesn't follow the targeted path if not state.context['visited'] <= trace_set: print "State diverge at 0x%x" % state.cpu.PC state.abandon() m.run()
def concrete_run_get_trace(inp): consts = config.get_group("core") consts.mprocessing = consts.mprocessing.single m1 = Manticore.linux(prog, concrete_start=inp, workspace_url="mem:") t = ExtendedTracer() # r = TraceReceiver(t) set_verbosity(VERBOSITY) m1.register_plugin(t) # m1.register_plugin(r) m1.run() for st in m1.all_states: return t.get_trace(st)
def test_symbolic_argv_envp(self): dirname = os.path.dirname(__file__) self.m = Manticore.linux(os.path.join(dirname, 'binaries', 'arguments_linux_amd64'), argv=['+'], envp={'TEST': '+'}) for state in self.m.all_states: ptr = state.cpu.read_int(state.cpu.RSP + (8 * 2)) # get argv[1] mem = state.cpu.read_bytes(ptr, 2) self.assertTrue(issymbolic(mem[0])) self.assertEqual(mem[1], b'\0') ptr = state.cpu.read_int(state.cpu.RSP + (8 * 4)) # get envp[0] mem = state.cpu.read_bytes(ptr, 7) self.assertEqual(b''.join(mem[:5]), b'TEST=') self.assertEqual(mem[6], b'\0') self.assertTrue(issymbolic(mem[5]))
def profile(program, sort="cumulative"): print(f'[*] Profiling program "{program}"') m = Manticore(program) profiler = Profiler() m.register_plugin(profiler) m.run() m.finalize() stats = profiler.get_profiling_data() print(f"[*] Loaded profiling data.") if stats is None: print(f"[*] Failed to collect stats for program {program}") return stats.sort_stats(sort) stats.print_stats()
def test_custom_introspector(self): self.history = [] m = Manticore(ms_file, introspection_plugin_type=MyIntrospector, stdin_size=17) m.register_daemon(self.introspect_loop) m.run() self.assertGreater(len(self.history), 0) self.assertTrue( any( getattr(st, "i_am_custom", False) for st in self.history[-1].values()))
def test_symbolic(self): # Create src and dst strings # This binary is compiled using gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0 # with flags: -g -static -fno-builtin BIN_PATH = os.path.join(os.path.dirname(__file__), "binaries/str_model_tests", "sym_strncpy_test") tmp_dir = tempfile.TemporaryDirectory(prefix="mcore_test_sym_") m = Manticore(BIN_PATH, stdin_size=10, workspace_url=str(tmp_dir.name)) addr_of_strncpy = 0x0400490 @m.hook(addr_of_strncpy) def strncpy_model(state): state.invoke_model(strncpy) m.run() m.finalize() # Approximate regexes for expected testcase output # Example Match above each regex # Manticore varies the hex output slightly per run expected = [ # STDIN: b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' r"STDIN: b\'\\x00(\\x([0-9a-f]{2})){9}\'", # STDIN: b'\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff' r"STDIN: b\'(\\x((?!(00))([0-9a-f]{2}))){1}\\x00(\\x([0-9a-f]{2})){8}\'", # STDIN: b'\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff' r"STDIN: b\'(\\x((?!(00))([0-9a-f]{2}))){2}\\x00(\\x([0-9a-f]{2})){7}\'", # STDIN: b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' r"STDIN: b\'(\\x((?!(00))([0-9a-f]{2}))){10}\'", ] inputs = f"{str(m.workspace)}/test_*.input" # Make a list of the generated input states stdins = [] for inpt in glob(inputs): with open(inpt) as f: stdins.append(f.read()) # Check the number of input states matches the number of regexes self.assertEqual(len(stdins), len(expected)) # Assert that every regex has a matching input for e in expected: match = False for s in stdins: if re.fullmatch(e, s) == None: match = True break self.assertTrue(match)
def test_symbolic_argv_envp(self) -> None: dirname = os.path.dirname(__file__) self.m = Manticore.linux( os.path.join(dirname, "binaries", "arguments_linux_amd64"), argv=["+"], envp={"TEST": "+"}, ) for state in self.m.all_states: ptr = state.cpu.read_int(state.cpu.RSP + (8 * 2)) # get argv[1] mem = state.cpu.read_bytes(ptr, 2) self.assertTrue(issymbolic(mem[0])) self.assertEqual(mem[1], b"\0") ptr = state.cpu.read_int(state.cpu.RSP + (8 * 4)) # get envp[0] mem = state.cpu.read_bytes(ptr, 7) self.assertEqual(b"".join(mem[:5]), b"TEST=") self.assertEqual(mem[6], b"\0") self.assertTrue(issymbolic(mem[5]))
def test(): from manticore.native import Manticore if __name__ == "__main__": import sys prog = sys.argv[1] params = sys.argv[2:] else: prog = "test_exploit_generation_example/bof" params = ["AAAAAAAAAAAAAAAAAAAAAAA"] m = Manticore(prog, params) m.verbosity(2) # 'trace' will contain the executed instructions m.context["trace"] = [] # None: The hook will be applied to all the instructions @m.hook(None) def record_trace(state): pc = state.cpu.PC ins = state.cpu.instruction # Store the instruction with m.locked_context() as c: c["trace"] += [pc] # We manipulate directly capstone instruction c["last_ins"] = "%s %s" % (ins.mnemonic, ins.op_str) # print(state.cpu) # print(state.mem) m.run() # Print number of instructions recorded and the last executed print("%d instructions are recorded" % len(m.context["trace"])) print("Last instruction executed:") print("0x%x: %s" % (m.context["trace"][-1], m.context["last_ins"])) assert m.context["last_ins"] == "call eax"