def _handle_with_file(**options): # Need an absolute path for the target in order to simplify # symlink creation. target_path = options['target'] target_path = os.path.realpath(target_path) # Check that the target actually exists if not os.path.isfile(target_path): raise CommandError('Target %s does not exist' % target_path) arch, proj_config_class = get_arch(target_path) if arch: options['target'] = target_path options['target_files'] = [target_path] options['target_arch'] = arch # The module list is a list of tuples where the first element is # the module name and the second element is True if the module is # a kernel module options['modules'] = [(os.path.basename(target_path), False)] options['processes'] = [] if not isinstance(proj_config_class, WindowsDLLProjectConfiguration): options['processes'].append(os.path.basename(target_path)) call_command(Project(proj_config_class), **options) elif target_path.endswith('.inf'): _handle_inf(target_path, **options) else: raise CommandError('%s is not a valid target for S2E analysis' % target_path)
def _handle_empty_project(**options): if not options['no_target']: raise CommandError( 'No target binary specified. Use the --no-target option to create an empty project.' ) if not options['image']: raise CommandError( 'An empty project requires a VM image. Use the -i option to specify the image.' ) if not options['name']: raise CommandError( 'Project name missing. Use the -n option to specify one.') if options['type'] not in _get_configs(): raise CommandError( 'The project type is invalid. Please use %s for the --type option.' % _get_configs()) options['target'] = None options['target_files'] = [] options['target_arch'] = None # The module list is a list of tuples where the first element is # the module name and the second element is True if the module is # a kernel module options['modules'] = [] options['processes'] = [] call_command(Project(PROJECT_CONFIGS[options['type']]), **options)
def _gen_win_driver_project(target_path, file_paths, **options): first_sys_file = None for f in file_paths: if f.endswith('.sys'): first_sys_file = f # TODO: prompt the user to select the right driver if not first_sys_file: raise CommandError( 'Could not find any *.sys file in the INF file. ' 'Make sure the INF file is valid and belongs to a Windows driver.') # Pick the architecture of the first sys file arch, _ = get_arch(first_sys_file) if arch is None: raise CommandError('Could not determine architecture for %s' % first_sys_file) options['target'] = target_path options['target_arch'] = arch # All the files to download into the guest. options['target_files'] = list(set([target_path] + file_paths)) # TODO: support multiple kernel drivers options['modules'] = [(os.path.basename(first_sys_file), True)] options['processes'] = [] call_command(Project(WindowsDriverProjectConfiguration), **options)
def _create(self, config, force=False): project_dir = config['project_dir'] # Check if the project directory already exists _check_project_dir(project_dir, force) # Create the project directory os.mkdir(project_dir) if config['use_seeds'] and not os.path.isdir(config['seeds_dir']): os.mkdir(config['seeds_dir']) # Create symlinks to the target files (if they exist) if config['target_files']: self._symlink_project_files(project_dir, *config['target_files']) # Create a symlink to the guest tools directory self._symlink_guest_tools(project_dir, config['image']) # Create a symlink to guestfs (if it exists) if config['guestfs_path']: self._symlink_guestfs(project_dir, config['guestfs_path']) # Render the templates self._create_launch_script(project_dir, config) self._create_lua_config(project_dir, config) self._create_bootstrap(project_dir, config) # Save the project configuration as JSON _save_json_description(project_dir, config) # Generate recipes for PoV generation if config['use_recipes']: os.makedirs(config['recipes_dir']) call_command(RecipeCommand(), [], project=os.path.basename(project_dir)) # Display relevant messages to the user display_marker_warning = config['target_path'] and \ config['warn_input_file'] and \ not (config['use_symb_input_file'] or config['sym_args']) if display_marker_warning: logger.warning('You did not specify the input file marker @@. ' 'This marker is automatically substituted by a ' 'file with symbolic content. You will have to ' 'manually edit the bootstrap file in order to run ' 'the program on multiple paths.\n\n' 'Example: %s @@\n\n' 'You can also make arguments symbolic using the ' '``S2E_SYM_ARGS`` environment variable in the ' 'bootstrap file', config['target_path']) if config['use_seeds'] and not config['use_symb_input_file'] and config['warn_seeds']: logger.warning('Seed files have been enabled, however you did not ' 'specify an input file marker (i.e. \'@@\') to be ' 'substituted with a seed file. This means that ' 'seed files will be fetched but never used. Is ' 'this intentional?')
def _handle_inf(target_path, **options): logger.info( 'Detected Windows INF file, attempting to create device driver project...' ) driver = Driver(target_path) driver.analyze() driver_files = driver.get_files() if not driver_files: raise CommandError('Driver has no files') base_dir = os.path.dirname(target_path) logger.info(' Driver files:') file_paths = [] first_sys_file = None for f in driver_files: full_path = os.path.join(base_dir, f) if not os.path.exists(full_path): if full_path.endswith('.cat'): logger.warn('Catalog file %s is missing', full_path) continue else: raise CommandError('%s does not exist' % full_path) logger.info(' %s', full_path) file_paths.append(full_path) if full_path.endswith('.sys'): first_sys_file = full_path # Pick the architecture of the first sys file # TODO: prompt the user to select the right driver if not first_sys_file: raise CommandError('Could not find any *.sys file') arch, _ = get_arch(first_sys_file) if arch is None: raise CommandError('Could not determine architecture for %s' % first_sys_file) options['target'] = target_path options['target_arch'] = arch # All the files to download into the guest. options['target_files'] = [target_path] + file_paths # TODO: support multiple kernel drivers options['modules'] = [(os.path.basename(first_sys_file), True)] options['processes'] = [] call_command(Project(WindowsDriverProjectConfiguration), **options)
def _handle_test(self, test_root, test, test_config, img_templates): ts_dir = self.source_path('testsuite') if os.path.exists(os.path.join(test_root, 'Makefile')): _build_test(self._config, self.source_path('s2e'), test_root) blacklisted_images = set(test_config.get('blacklisted-images', [])) target_images = set(test_config.get('target-images', [])) for target_name in test_config['targets']: target_path = os.path.join(test_root, target_name) target = Target.from_file(target_path) project = target.initialize_project() images = project.get_usable_images(target, img_templates) for image_name in images: if image_name in blacklisted_images: logger.warn( '%s is blacklisted, skipping tests for that image', image_name) continue if target_images and image_name not in target_images: logger.debug('%s is not in target-images, skipping', image_name) continue options = { 'image': image_name, 'name': 'testsuite_%s_%s_%s' % (test, os.path.basename(target_name), image_name), 'target': target, 'target_args': test_config.get('target_arguments', []), 'force': True } options.update(test_config.get('options', [])) call_command(project, *[], **options) scripts = test_config.get('scripts', {}) run_tests_template = scripts.get('run_tests', 'run-tests.tpl') self._generate_run_tests(ts_dir, test, run_tests_template, options) _call_post_project_gen_script( test_root, test_config, self.projects_path(options['name']))
def _handle_empty_project(proj_class, *args, **options): if not options['no_target']: raise CommandError('No target binary specified. Use the -m option to ' 'create an empty project') if not options['image']: raise CommandError('An empty project requires a VM image. Use the -i ' 'option to specify the image') if not options['name']: raise CommandError('An empty project requires a name. Use the -n ' 'option to specify one') # If the project class wasn't explicitly overridden programmatically, get # one of the default project classes from the command line if not proj_class: project_types = PROJECT_TYPES.keys() if options['type'] not in project_types: raise CommandError('An empty project requires a type. Use the -t ' 'option and specify one from %s' % project_types) proj_class = PROJECT_TYPES[options['type']] target = Target.empty(proj_class) options['target'] = target return call_command(target.initialize_project(), *args, **options)
def handle(self, *args, **options): command = options.pop('command', ()) if command == 'basic_block': # Select the disassembler backend disassembler = options.pop('disassembler', ()) if disassembler == 'ida': from .code_coverage.ida_basic_block import IDABasicBlockCoverage return call_command(IDABasicBlockCoverage(), args, **options) elif disassembler == 'r2': from .code_coverage.r2_basic_block import R2BasicBlockCoverage return call_command(R2BasicBlockCoverage(), args, **options) elif command == 'lcov': return call_command(LineCoverage(), args, **options)
def _handle_generic_target(target_path, **options): arch, proj_config_class = get_arch(target_path) if not arch: raise CommandError('%s is not a valid target for S2E analysis' % target_path) options['target'] = target_path options['target_files'] = [target_path] options['target_arch'] = arch # The module list is a list of tuples where the first element is # the module name and the second element is True if the module is # a kernel module options['modules'] = [(os.path.basename(target_path), False)] options['processes'] = [] if not isinstance(proj_config_class, WindowsDLLProjectConfiguration): options['processes'].append(os.path.basename(target_path)) call_command(Project(proj_config_class), **options)
def handle(self, *args, **options): command = options.pop('command', ()) if command == 'basic_block': # Select the disassembler backend disassembler = options.pop('disassembler', ()) if disassembler == 'ida': call_command(IDABasicBlockCoverage(), args, **options) elif disassembler == 'r2': call_command(R2BasicBlockCoverage(), args, **options) elif disassembler == 'binaryninja': call_command(BinaryNinjaBasicBlockCoverage(), args, **options) elif command == 'lcov': call_command(LineCoverage(), args, **options) else: raise CommandError('Invalid command %s' % command)
def _gen_project(self, ts_dir, test_config, test_root, test, target, target_path, image_name, project, arg_idx): name = _get_test_project_name(test, target_path, image_name) name = f'{name}_{arg_idx}' options = { 'image': image_name, 'name': name, 'target': target, 'force': True, 'project_path': self.projects_path(name), 'testsuite_root': ts_dir } options.update(test_config.get('options', [])) if not validate_arguments(options): raise CommandError('Please check test case arguments') call_command(project, *[], **options) scripts = test_config.get('scripts', {}) run_tests_template = scripts.get('run_tests', 'run-tests.tpl') self._generate_run_tests(ts_dir, test, run_tests_template, options) _call_post_project_gen_script(test_root, test_config, options)
def handle(self, *args, **options): command = options.pop('command', ()) if command == 'generate': call_command(TestsuiteGenerator(), *args, **options) elif command == 'run': call_command(TestsuiteRunner(), *args, **options) elif command == 'list': call_command(TestsuiteLister(), *args, **options) else: raise CommandError('Invalid command %s' % command)
def handle(self, *args, **options): # Need an absolute path for the target in order to simplify # symlink creation. target_path = options['target'][0] target_path = os.path.realpath(target_path) # Check that the target actually exists if not os.path.isfile(target_path): raise CommandError('Target %s does not exist' % target_path) default_magic = Magic() magic_checks = [ (Magic(magic_file=CGC_MAGIC), CGC_REGEX, CGCProjectConfiguration, 'i386'), (default_magic, ELF32_REGEX, LinuxProjectConfiguration, 'i386'), (default_magic, ELF64_REGEX, LinuxProjectConfiguration, 'x86_64'), (default_magic, DLL32_REGEX, WindowsDLLProjectConfiguration, 'i386'), (default_magic, DLL64_REGEX, WindowsDLLProjectConfiguration, 'x86_64'), (default_magic, PE32_REGEX, WindowsProjectConfiguration, 'i386'), (default_magic, PE64_REGEX, WindowsProjectConfiguration, 'x86_64'), (default_magic, MSDOS_REGEX, WindowsProjectConfiguration, 'i386') ] # Check the target program against the valid file types for magic_check, regex, proj_config_class, arch in magic_checks: magic = magic_check.from_file(target_path) matches = regex.match(magic) # If we find a match, create that project. The user instructions # are returned if matches: options['target'] = target_path options['target_arch'] = arch return call_command(Project(proj_config_class), **options) # Otherwise no valid file type was found raise CommandError('%s is not a valid target for S2E analysis' % target_path)
def _handle_with_file(target_path, proj_class, *args, **options): target = Target.from_file(target_path, proj_class) options['target'] = target return call_command(target.initialize_project(), *args, **options)
def _handle_with_file(target_path, target_args, proj_class, *args, **options): target, proj_class = target_from_file(target_path, target_args, proj_class) options['target'] = target return call_command(proj_class(), *args, **options)
def _create(self, config, force=False): project_dir = config['project_dir'] target = config['target'] # Check if the project directory already exists _check_project_dir(project_dir, force) # Create the project directory os.makedirs(project_dir) if config['use_seeds'] and not os.path.isdir(config['seeds_dir']): os.mkdir(config['seeds_dir']) # Create symlinks to the target files (if they exist) if target.files: self._symlink_project_files(project_dir, *target.files) target.args.generate_symbolic_files(project_dir, config['use_seeds']) # Create symlinks to symbolic files if target.args.symbolic_files: self._symlink_project_files(project_dir, *target.args.symbolic_files) # Create a symlink to the guest tools directory self._symlink_guest_tools(project_dir, config['image']) # Create a symlink to guestfs (if it exists) if config['guestfs_paths']: self._symlink_guestfs(project_dir, config['guestfs_paths']) # Render the templates self._create_launch_script(project_dir, config) self._create_lua_config(project_dir, config) self._create_bootstrap(project_dir, config) # Even though the AbstractProject will save the project description, we # need it to be able to generate recipes below self._save_json_description(project_dir, config) # Generate recipes for PoV generation if config['use_recipes']: os.makedirs(config['recipes_dir']) call_command(RecipeCommand(), [], project=project_dir) # Display relevant messages to the user display_marker_warning = config['target'].path and \ config['warn_input_file'] and \ not config['single_path'] and \ not (config['target'].args.symbolic_files or config['sym_args']) if display_marker_warning: logger.warning( 'You did not specify any symbolic input. ' 'Symbolic execution requires symbolic inputs. You will have to ' 'manually edit the bootstrap file in order to run ' 'the program on multiple paths.\n\n' 'Example: %s @@\n\n' 'You can also make arguments symbolic using the ' '``S2E_SYM_ARGS`` environment variable in the ' 'bootstrap file', config['target'].path) seed_files_count = len(config['target'].args.blank_seed_files) if config['use_seeds'] and config['warn_seeds']: if not seed_files_count: logger.warning( 'Seed files have been enabled, however you did not ' 'specify an input file marker (i.e. \'@@\') to be ' 'substituted with a seed file. This means that ' 'seed files will be fetched but never used. Is ' 'this intentional?') if seed_files_count > 1: raise CommandError( 'You specified multiple symbolic inputs with @@. You may only have one ' 'when seeds are enabled.') return project_dir