Example #1
0
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)
Example #2
0
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)
Example #3
0
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)
Example #4
0
    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?')
Example #5
0
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)
Example #6
0
    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']))
Example #7
0
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)
Example #8
0
    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)
Example #9
0
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)
Example #10
0
    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)
Example #11
0
    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)
Example #12
0
    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)
Example #13
0
    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)
Example #14
0
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)
Example #15
0
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)
Example #16
0
    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