def testFilter(self): scout = ApiScout() results = { 'test_1': [(0x0, ), (0x10, ), (0x14, ), (0x30, ), (0x40, ), (0x44, ), (0x48, )], 'test_2': [(0x0, ), (0x18, ), (0x1c, )], 'test_3': [(0x0, )], } # no arguments = no filtering filtered = scout.filter(results, 0, 0, 0) self.assertEqual(results, filtered) # filtering by range: filtered = scout.filter(results, 0x14, 0x34, 0) expected = { 'test_1': [(0x14, ), (0x30, )], 'test_2': [(0x18, ), (0x1c, )], 'test_3': [] } self.assertEqual(expected, filtered) # filtering by distance: filtered = scout.filter(results, 0, 0, 0x4) expected = { 'test_1': [(0x10, ), (0x14, ), (0x40, ), (0x44, ), (0x48, )], 'test_2': [(0x18, ), (0x1c, )], 'test_3': [] } self.assertEqual(expected, filtered)
def main(): parser = argparse.ArgumentParser( description= 'Demo: Use apiscout with a prepared api database (created using DatabaseBuilder.py) to crawl a dump for imports and render the results.' ) parser.add_argument( '-f', '--filter', type=int, default=0, help='Filter out APIs that do not have a neighbour within N bytes.') parser.add_argument( '-i', '--ignore_aslr', action='store_true', help= 'Do not apply the per-module ASLR offset potentially contained in a API DB file.' ) parser.add_argument('binary_path', type=str, default='', help='Path to the memory dump to crawl.') parser.add_argument( 'db_path', type=str, nargs='*', help= 'Path to the DB(s). If no argument is given, use all files found in "./dbs"' ) args = parser.parse_args() if args.binary_path: binary = "" if os.path.isfile(args.binary_path): with open(args.binary_path, "rb") as f_binary: binary = f_binary.read() if not args.db_path: args.db_path = get_all_db_files() scout = ApiScout() # override potential ASLR offsets that are stored in the API DB files. scout.ignoreAslrOffsets(args.ignore_aslr) # load DB file for db_path in args.db_path: scout.loadDbFile(db_path) print("Using '{}' to analyze '{}.".format(args.db_path, args.binary_path)) num_apis_loaded = scout.getNumApisLoaded() filter_info = " - neighbour filter: 0x%x" % args.filter if args.filter else "" print("Buffer size is {} bytes, {} APIs loaded{}.\n".format( len(binary), num_apis_loaded, filter_info)) results = scout.crawl(binary) filtered_results = scout.filter(results, 0, 0, args.filter) print(scout.render(filtered_results)) else: parser.print_help()
def main(): parser = argparse.ArgumentParser(description='Demo: Use apiscout with a prepared api database (created using DatabaseBuilder.py) to crawl a dump for imports and render the results.') parser.add_argument('-f', '--filter', type=int, default=0, help='Filter out APIs that do not have a neighbour within N bytes.') parser.add_argument('-i', '--ignore_aslr', action='store_true', help='Do not apply the per-module ASLR offset potentially contained in a API DB file.') parser.add_argument('-c', '--collection_file', type=str, default='', help='Optionally match the output against a WinApi1024 vector collection file.') parser.add_argument('-b', '--base_addr', type=str, default='', help='Set base address to given value (int or 0x-hex format).') parser.add_argument('-t', '--import_table_only', action='store_true', help='Do not crawl for API references but only parse the import table instead - assumes an unmapped PE file as input.') parser.add_argument('binary_path', type=str, default='', help='Path to the memory dump to crawl.') parser.add_argument('db_path', type=str, nargs='*', help='Path to the DB(s). If no argument is given, use all files found in "./dbs"') args = parser.parse_args() if args.binary_path: binary = "" if os.path.isfile(args.binary_path): with open(args.binary_path, "rb") as f_binary: binary = f_binary.read() scout = ApiScout() base_addr = get_base_addr(args) print("Using base adress 0x{:x} to infer reference counts.".format(base_addr)) scout.setBaseAddress(base_addr) # override potential ASLR offsets that are stored in the API DB files. scout.ignoreAslrOffsets(args.ignore_aslr) # load DB file db_paths = [] if args.db_path: db_paths = args.db_path elif not args.import_table_only: db_paths = get_all_db_files() for db_path in db_paths: scout.loadDbFile(db_path) # load WinApi1024 vector scout.loadWinApi1024(get_winapi1024_path()) # scout the binary results = {} if args.import_table_only: print("Parsing Import Table for\n {}.".format(args.binary_path)) results = scout.evaluateImportTable(binary, is_unmapped=True) else: print("Using \n {}\nto analyze\n {}.".format("\n ".join(db_paths), args.binary_path)) num_apis_loaded = scout.getNumApisLoaded() filter_info = " - neighbour filter: 0x%x" % args.filter if args.filter else "" print("Buffer size is {} bytes, {} APIs loaded{}.\n".format(len(binary), num_apis_loaded, filter_info)) results = scout.crawl(binary) filtered_results = scout.filter(results, 0, 0, args.filter) print(scout.render(filtered_results)) print(scout.renderVectorResults(filtered_results)) if args.collection_file: print(scout.renderResultsVsCollection(filtered_results, args.collection_file)) else: parser.print_help()
class ApiChooser(Choose): """ A simple chooser to be used as an embedded chooser """ def __init__(self, title, api_results, flags=0): Choose.__init__(self, title, [["#", 6], ["Offset", 14], ["API Address", 14], ["DLL", 20], ["API", 35]], embedded=True, width=140, height=20, flags=flags) self.row_count = 0 self.base_address = [ea for ea in idautils.Segments()][0] self.scout = ApiScout() self.scout.setBaseAddress(self.base_address) self.api_results = api_results self.all_items = self.populate(api_results) self.items = self.populate(api_results) self.icon = 4 self.selcount = 0 def filterDisplay(self, from_addr, to_addr, distance): filtered_items = self.scout.filter(self.api_results, from_addr, to_addr, distance) self.items = self.populate(filtered_items) def populate(self, api_results): api_rows = [] unified_results = set([]) for key in api_results: unified_results.update(api_results[key]) for index, entry in enumerate(sorted(unified_results)): dll_name = "{} ({}bit)".format(entry[2], entry[4]) api_rows.append(["%d" % (index + 1), "0x%x" % (self.base_address + entry[0]), "0x%x" % entry[1], dll_name, entry[3]]) self.row_count += 1 return api_rows def OnClose(self): pass def getItems(self, l): items = [] for index in l: items.append([int(self.items[index][1], 16), int(self.items[index][2], 16), self.items[index][3], str(self.items[index][4])]) return items def OnGetLine(self, n): return self.items[n] def OnGetSize(self): n = len(self.items) return n