diff --git a/angrop/gadget_finder/__init__.py b/angrop/gadget_finder/__init__.py index a823101..6737c4a 100644 --- a/angrop/gadget_finder/__init__.py +++ b/angrop/gadget_finder/__init__.py @@ -120,6 +120,23 @@ def _initialize_gadget_analyzer(self): def analyze_gadget(self, addr): return self.gadget_analyzer.analyze_gadget(addr) + def analyze_gadget_list(self, addr_list, processes=4, show_progress=True): + gadgets = [] + + initargs = (self.gadget_analyzer,) + iterable = addr_list + if show_progress: + iterable = tqdm.tqdm(iterable=iterable, smoothing=0, total=len(addr_list), + desc="ROP", maxinterval=0.5, dynamic_ncols=True) + + with Pool(processes=processes, initializer=_set_global_gadget_analyzer, initargs=initargs) as pool: + it = pool.imap_unordered(run_worker, iterable, chunksize=1) + for gadget in it: + if gadget is not None: + gadgets.append(gadget) + + return sorted(gadgets, key=lambda x: x.addr) + def get_duplicates(self): """ return duplicates that have been seen at least twice diff --git a/angrop/rop.py b/angrop/rop.py index 4a4c756..9798afa 100644 --- a/angrop/rop.py +++ b/angrop/rop.py @@ -102,10 +102,26 @@ def analyze_gadget(self, addr): self._screen_gadgets() return g + def analyze_gadget_list(self, addr_list, processes=4, show_progress=True): + """ + Analyzes a list of addresses to identify ROP gadgets. + Saves rop gadgets in self.rop_gadgets + Saves syscall gadgets in self.syscall_gadgets + Saves stack pivots in self.stack_pivots + :param processes: number of processes to use + :param show_progress: whether or not to show progress bar + """ + + self._all_gadgets = self.gadget_finder.analyze_gadget_list( + addr_list, processes=processes, show_progress=show_progress) + self._screen_gadgets() + return self.rop_gadgets + def find_gadgets(self, processes=4, show_progress=True): """ Finds all the gadgets in the binary by calling analyze_gadget on every address near a ret. - Saves gadgets in self._gadgets + Saves rop gadgets in self.rop_gadgets + Saves syscall gadgets in self.syscall_gadgets Saves stack pivots in self.stack_pivots :param processes: number of processes to use """ @@ -117,7 +133,8 @@ def find_gadgets(self, processes=4, show_progress=True): def find_gadgets_single_threaded(self, show_progress=True): """ Finds all the gadgets in the binary by calling analyze_gadget on every address near a ret - Saves gadgets in self.gadgets + Saves rop gadgets in self.rop_gadgets + Saves syscall gadgets in self.syscall_gadgets Saves stack pivots in self.stack_pivots """ self._all_gadgets, self._duplicates = self.gadget_finder.find_gadgets_single_threaded( diff --git a/tests/test_find_gadgets.py b/tests/test_find_gadgets.py index 215e074..325f1dc 100644 --- a/tests/test_find_gadgets.py +++ b/tests/test_find_gadgets.py @@ -189,6 +189,19 @@ def test_gadget_timeout(): gadget = rop.analyze_gadget(0x4005d5) assert gadget +def local_multiprocess_analyze_gadget_list(): + # pylint: disable=pointless-string-statement + proj = angr.Project(os.path.join(tests_dir, "x86_64", "datadep_test"), auto_load_libs=False) + rop = proj.analyses.ROP() + """ + 0x4006d8, 0x400864 good gadgets + 0x4005d8 bad instruction + """ + gadgets = rop.analyze_gadget_list([0x4006d8, 0x4005d8, 0x400864]) + assert len(gadgets[1]) == 2 + assert gadgets[0].addr == 0x4006d8 + assert gadgets[1].addr == 0x400864 + def run_all(): functions = globals() all_functions = {x:y for x, y in functions.items() if x.startswith('test_')} @@ -196,6 +209,7 @@ def run_all(): if hasattr(all_functions[f], '__call__'): all_functions[f]() local_multiprocess_find_gadgets() + local_multiprocess_analyze_gadget_list() if __name__ == "__main__": logging.getLogger("angrop.rop").setLevel(logging.DEBUG)