Exemplo n.º 1
0
def main(conversion_type, input_pyc, output_pyc):
    """Convert Python bytecode from one version to another.

    INPUT_PYC contains the input bytecode path name
    OUTPUT_PYC  contians the output bytecode path name if supplied
    The --conversion type option specifies what conversion to do.

    Note: there are a very limited set of conversions currently supported.
    Help out and write more!"""

    shortname = osp.basename(input_pyc)
    if shortname.endswith('.pyc'):
        shortname = shortname[:-4]
    src_version = conversion_to_version(conversion_type, is_dest=False)
    dest_version = conversion_to_version(conversion_type, is_dest=True)
    if output_pyc is None:
        output_pyc = "%s-%s.pyc" % (shortname, dest_version)

    if conversion_type in UPWARD_COMPATABLE:
        copy_magic_into_pyc(input_pyc, output_pyc, src_version, dest_version)
        return
    temp_asm = NamedTemporaryFile('w', suffix='.pyasm', prefix=shortname, delete=False)
    (filename, co, version,
     timestamp, magic_int) = disassemble_file(input_pyc, temp_asm, asm_format=True)
    temp_asm.close()
    assert version == float(src_version), (
        "Need Python %s bytecode; got bytecode for version %s" %
        (src_version, version))
    asm = asm_file(temp_asm.name)
    new_asm = transform_asm(asm, conversion_type, src_version, dest_version)
    os.unlink(temp_asm.name)
    write_pycfile(output_pyc, new_asm)
Exemplo n.º 2
0
    def check_for_password_file(self):
        self.potential_keys = []
        if hasattr(self, "archive_path"):
            dir_of_pyz = self.archive_path.parent
        else:
            dir_of_pyz = Path.cwd()

        key_file = dir_of_pyz / "pyimod00_crypto_key.pyc"
        if key_file.exists():
            self.encrypted = True
            logger.debug(
                f"[+] Found ZlibArchive encryption key file at path {key_file}"
            )
            crypto_key_filename: str  # full path of
            try:
                (
                    crypto_key_filename,
                    crypto_key_co,
                    crypto_key_python_version,
                    crypto_key_compilation_timestamp,
                    crypto_key_magic_int,
                    crypto_key_is_pypy,
                    crypto_key_source_size,
                    crypto_key_sip_hash,
                ) = disassemble_file(str(key_file),
                                     outstream=open(os.devnull, "w"))
            except Exception as e:
                logger.warning(
                    f"[!] Could not disassemble file {key_file}. Received error: {e}"
                )
            else:
                self.compilation_time = datetime.fromtimestamp(
                    crypto_key_compilation_timestamp)
                for const_string in crypto_key_co.co_consts:
                    if const_string and len(const_string) == 16:
                        self.potential_keys.append(const_string)
            # If we couldn't decompile the file to see the consts, lets just search the raw bytes of the file
            # for the password
            if not self.potential_keys:
                with key_file.open("rb") as file_ptr:
                    file_strings = utils.parse_for_strings(file_ptr.read())
                s: str
                for s in file_strings:
                    if len(s) >= 16 and "pyimod00_crypto_key" not in s:
                        while len(s) >= 16:
                            self.potential_keys.append(s[0:16])
                            s = s[1:]

            logger.info(
                f"[*] Found these potential PyInstaller PYZ Archive encryption keys: {self.potential_keys}"
            )

            if not self.potential_keys:
                logger.error(
                    f"[*] Encryption key file detected, however no password was able to be retrieved."
                )
Exemplo n.º 3
0
def main(asm, show_bytes, header, files):
    """Disassembles a Python bytecode file.

    We handle bytecode for virtually every release of Python and some releases of PyPy.
    The version of Python in the bytecode doesn't have to be the same version as
    the Python interpreter used to run this program. For example, you can disassemble Python 3.6.1
    bytecode from Python 2.7.13 and vice versa.
    """
    Usage_short = """usage:
   %s [--asm] -i FILE...
   %s --version
Type -h for for full help.""" % (program, program)

    if not (2.5 <= PYTHON_VERSION <= 3.7):
        sys.stderr(
            print("This works on Python version 2.5..3.7; have %s" %
                  PYTHON_VERSION))

    if not len(files):
        sys.stderr.write("No file(s) given..\n")
        print(Usage_short, file=sys.stderr)
        sys.exit(1)

    for path in files:
        # Some sanity checks
        if not osp.exists(path):
            sys.stderr.write("File name: '%s' doesn't exist\n" % path)
            continue
        elif not osp.isfile(path):
            sys.stderr.write("File name: '%s' isn't a file\n" % path)
            continue
        elif osp.getsize(path) < 50:
            sys.stderr.write(
                "File name: '%s (%d bytes)' is too short to be a valid pyc file\n"
                % (path, osp.getsize(path)))
            continue

        disassemble_file(path, sys.stdout, asm, header, show_bytes)
    return
Exemplo n.º 4
0
def main(asm, show_bytes, header, files):
    """Disassembles a Python bytecode file.

    We handle bytecode for virtually every release of Python and some releases of PyPy.
    The version of Python in the bytecode doesn't have to be the same version as
    the Python interpreter used to run this program. For example, you can disassemble Python 3.6.9
    bytecode from Python 2.7.15 and vice versa.
    """
    if not (2.7 <= PYTHON_VERSION <= 3.9):
        if 2.4 <= PYTHON_VERSION <= 2.6:
            sys.stderr.write(
                "This code works on 2.7..3.8. code that works for %s can be found in the python-2.4 branch\n"
                % PYTHON_VERSION
            )
            sys.exit(1)
        sys.stderr.write(
            "This works on Python version 2.7..3.8; have %s.\n" % PYTHON_VERSION
        )
        sys.exit(2)

    for path in files:
        # Some sanity checks
        if not osp.exists(path):
            sys.stderr.write("File name: '%s' doesn't exist\n" % path)
            continue
        elif not osp.isfile(path):
            sys.stderr.write("File name: '%s' isn't a file\n" % path)
            continue
        elif osp.getsize(path) < 50:
            sys.stderr.write(
                "File name: '%s (%d bytes)' is too short to be a valid pyc file\n"
                % (path, osp.getsize(path))
            )
            continue

        disassemble_file(path, sys.stdout, asm, header, show_bytes)
    return
Exemplo n.º 5
0
def main(asm, show_bytes, header, files):
    """Disassembles a Python bytecode file.

    We handle bytecode for virtually every release of Python and some releases of PyPy.
    The version of Python in the bytecode doesn't have to be the same version as
    the Python interpreter used to run this program. For example, you can disassemble Python 3.6.1
    bytecode from Python 2.7.13 and vice versa.
    """
    Usage_short = """usage:
   %s [--asm] -i FILE...
   %s --version
Type -h for for full help.""" % (program, program)


    if not (2.5 <= PYTHON_VERSION <= 3.8):
        sys.stderr(print("This works on Python version 2.5..3.8; have %s" % PYTHON_VERSION))

    if not len(files):
        sys.stderr.write("No file(s) given..\n")
        print(Usage_short, file=sys.stderr)
        sys.exit(1)

    for path in files:
        # Some sanity checks
        if not osp.exists(path):
            sys.stderr.write("File name: '%s' doesn't exist\n" % path)
            continue
        elif not osp.isfile(path):
            sys.stderr.write("File name: '%s' isn't a file\n" % path)
            continue
        elif osp.getsize(path) < 50:
            sys.stderr.write("File name: '%s (%d bytes)' is too short to be a valid pyc file\n" % (path, osp.getsize(path)))
            continue

        disassemble_file(path, sys.stdout, asm, header, show_bytes)
    return
Exemplo n.º 6
0
def do_tests(
    src_dir,
    patterns,
    target_dir,
    start_with=None,
    do_verify=False,
    max_files=800,
    do_compile=False,
    verbose=False,
):
    def visitor(files, dirname, names):
        files.extend([
            os.path.normpath(os.path.join(dirname, n)) for n in names
            for pat in patterns if fnmatch(n, pat)
        ])

    def file_matches(files, root, basenames, patterns):
        files.extend([
            os.path.normpath(os.path.join(root, n)) for n in basenames
            for pat in patterns if fnmatch(n, pat)
        ])

    files = []
    if do_compile:
        for root, dirs, basenames in os.walk(src_dir):
            file_matches(files, root, basenames, PY)
            for sfile in files:
                py_compile.compile(sfile)
                pass
            pass
        files = []
        pass

    cwd = os.getcwd()
    os.chdir(src_dir)
    if PYTHON3:
        for root, dirname, names in os.walk(os.curdir):
            files.extend([
                os.path.normpath(os.path.join(root, n)) for n in names
                for pat in patterns if fnmatch(n, pat)
            ])
            pass
        pass
    else:
        os.path.walk(os.curdir, visitor, files)
    files.sort()

    if start_with:
        try:
            start_with = files.index(start_with)
            files = files[start_with:]
            print(">>> starting with file", files[0])
        except ValueError:
            pass

    if len(files) > max_files:
        files = [file for file in files if not "site-packages" in file]
        files = [file for file in files if not "test" in file]
        if len(files) > max_files:
            files = files[:max_files]
            pass
    elif len(files) == 0:
        print("No files found\n")
        os.chdir(cwd)
        return

    output = open(os.devnull, "w")
    # output = sys.stdout
    start_time = time.time()
    print(time.ctime())
    for i, bc_file in enumerate(files):
        if verbose:
            print(os.path.join(src_dir, bc_file))
        if sys.version_info >= (3, 4, 0) and bc_file.endswith(".py"):
            check_bc_file = check_object_path(bc_file)
            if not osp.exists(check_bc_file):
                basename = osp.basename(bc_file)[0:-3]
                new_bc_file = tempfile.mkstemp(prefix=basename + "-",
                                               suffix=".pyc",
                                               text=False)[1]
                py_compile.compile(bc_file, cfile=new_bc_file, doraise=True)
                bc_file = new_bc_file

        bc_filename, co, version, ts, magic = main.disassemble_file(
            bc_file, output)
        if do_verify:
            file = co.co_filename
            verify_file(file, bc_filename)
        if i % 100 == 0 and i > 0:
            print("Processed %d files" % (i))
    print("Processed %d files, total" % (i + 1))
    print(time.ctime())
    elapsed_time = time.time() - start_time
    print("%g seconds" % elapsed_time)
    os.chdir(cwd)
Exemplo n.º 7
0
def do_tests(src_dir, obj_patterns, target_dir, opts):

    def file_matches(files, root, basenames, patterns):
        files.extend(
            [os.path.normpath(os.path.join(root, n))
                 for n in basenames
                    for pat in patterns
                        if fnmatch(n, pat)])

    files = []
    # Change directories so use relative rather than
    # absolute paths. This speeds up things, and allows
    # main() to write to a relative-path destination.
    cwd = os.getcwd()
    os.chdir(src_dir)

    if opts['do_compile']:
        compiled_version = opts['compiled_version']
        if compiled_version and PYTHON_VERSION != compiled_version:
            sys.stderr.write("Not compiling: desired Python version is %s "
                                 "but we are running %s\n" %
                                 (compiled_version, PYTHON_VERSION))
        else:
            for root, dirs, basenames in os.walk(src_dir):
                file_matches(files, root, basenames, PY)
                for sfile in files:
                    py_compile.compile(sfile)
                    pass
                pass
            files = []
            pass
        pass

    for root, dirs, basenames in os.walk('.'):
        # Turn root into a relative path
        dirname = root[2:]  # 2 = len('.') + 1
        file_matches(files, dirname, basenames, obj_patterns)

    if not files:
        sys.stderr.write("Didn't come up with any files to test! Try with --compile?\n")
        exit(1)

    os.chdir(cwd)
    files.sort()

    if opts['start_with']:
        try:
            start_with = files.index(opts['start_with'])
            files = files[start_with:]
            print('>>> starting with file', files[0])
        except ValueError:
            pass

    output = open(os.devnull,"w")
    # output = sys.stdout
    print(time.ctime())
    print('Source directory: ', src_dir)
    cwd = os.getcwd()
    os.chdir(src_dir)
    try:
          for infile in files:
                main.disassemble_file(infile, output)
                if opts['do_verify']:
                    pass
                    # print("Need to do something here to verify %s" % infile)
                    # msg = verify.verify_file(infile, outfile)

        # if failed_files != 0:
        #     exit(2)
        # elif failed_verify != 0:
        #     exit(3)

    except (KeyboardInterrupt, OSError):
        print()
        exit(1)
    os.chdir(cwd)
Exemplo n.º 8
0
def do_tests(src_dir, patterns, target_dir, start_with=None,
                 do_verify=False, max_files=800, do_compile=False,
                 verbose=False):

    def visitor(files, dirname, names):
        files.extend(
            [os.path.normpath(os.path.join(dirname, n))
                 for n in names
                    for pat in patterns
                        if fnmatch(n, pat)])

    def file_matches(files, root, basenames, patterns):
        files.extend(
            [os.path.normpath(os.path.join(root, n))
                 for n in basenames
                    for pat in patterns
                        if fnmatch(n, pat)])

    files = []
    if do_compile:
        for root, dirs, basenames in os.walk(src_dir):
            file_matches(files, root, basenames, PY)
            for sfile in files:
                py_compile.compile(sfile)
                pass
            pass
        files = []
        pass

    cwd = os.getcwd()
    os.chdir(src_dir)
    if PYTHON3:
        for root, dirname, names in os.walk(os.curdir):
            files.extend(
                [os.path.normpath(os.path.join(root, n))
                     for n in names
                        for pat in patterns
                            if fnmatch(n, pat)])
            pass
        pass
    else:
        os.path.walk(os.curdir, visitor, files)
    files.sort()

    if start_with:
        try:
            start_with = files.index(start_with)
            files = files[start_with:]
            print('>>> starting with file', files[0])
        except ValueError:
            pass

    if len(files) > max_files:
        files = [file for file in files if not 'site-packages' in file]
        files = [file for file in files if not 'test' in file]
        if len(files) > max_files:
            files = files[:max_files]
            pass
    elif len(files) == 0:
        print("No files found\n")
        os.chdir(cwd)
        return

    output = open(os.devnull,"w")
    # output = sys.stdout
    start_time = time.time()
    print(time.ctime())
    for i, bc_file in enumerate(files):
        if verbose:
            print(os.path.join(src_dir, bc_file))
        if sys.version_info >= (3, 4, 0) and bc_file.endswith('.py'):
            check_bc_file = check_object_path(bc_file)
            if not osp.exists(check_bc_file):
                basename = osp.basename(bc_file)[0:-3]
                new_bc_file = tempfile.mkstemp(prefix=basename + '-',
                                           suffix='.pyc', text=False)[1]
                py_compile.compile(bc_file, cfile=new_bc_file, doraise=True)
                bc_file = new_bc_file

        bc_filename, co, version, ts, magic = main.disassemble_file(bc_file, output)
        if do_verify:
            file = co.co_filename
            verify_file(file, bc_filename)
        if i % 100 == 0 and i > 0:
            print("Processed %d files" % (i))
    print("Processed %d files, total" % (i+1))
    print(time.ctime())
    elapsed_time = time.time() - start_time
    print("%g seconds" % elapsed_time)
    os.chdir(cwd)
Exemplo n.º 9
0
def do_tests(src_dir, obj_patterns, target_dir, opts):
    def file_matches(files, root, basenames, patterns):
        files.extend([
            os.path.normpath(os.path.join(root, n)) for n in basenames
            for pat in patterns if fnmatch(n, pat)
        ])

    files = []
    # Change directories so use relative rather than
    # absolute paths. This speeds up things, and allows
    # main() to write to a relative-path destination.
    cwd = os.getcwd()
    os.chdir(src_dir)

    if opts['do_compile']:
        compiled_version = opts['compiled_version']
        if compiled_version and PYTHON_VERSION != compiled_version:
            sys.stderr.write("Not compiling: desired Python version is %s "
                             "but we are running %s\n" %
                             (compiled_version, PYTHON_VERSION))
        else:
            for root, dirs, basenames in os.walk(src_dir):
                file_matches(files, root, basenames, PY)
                for sfile in files:
                    py_compile.compile(sfile)
                    pass
                pass
            files = []
            pass
        pass

    for root, dirs, basenames in os.walk('.'):
        # Turn root into a relative path
        dirname = root[2:]  # 2 = len('.') + 1
        file_matches(files, dirname, basenames, obj_patterns)

    if not files:
        sys.stderr.write(
            "Didn't come up with any files to test! Try with --compile?\n")
        exit(1)

    os.chdir(cwd)
    files.sort()

    if opts['start_with']:
        try:
            start_with = files.index(opts['start_with'])
            files = files[start_with:]
            print('>>> starting with file', files[0])
        except ValueError:
            pass

    output = open(os.devnull, "w")
    # output = sys.stdout
    print(time.ctime())
    print('Source directory: ', src_dir)
    cwd = os.getcwd()
    os.chdir(src_dir)
    try:
        for infile in files:
            main.disassemble_file(infile, output)
            if opts['do_verify']:
                pass
                # print("Need to do something here to verify %s" % infile)
                # msg = verify.verify_file(infile, outfile)

    # if failed_files != 0:
    #     exit(2)
    # elif failed_verify != 0:
    #     exit(3)

    except (KeyboardInterrupt, OSError):
        print()
        exit(1)
    os.chdir(cwd)
Exemplo n.º 10
0
def test_get_jump_targets():
    my_dir = osp.dirname(osp.abspath(__file__))

    # Python 2.7 code
    code = bug708901.__code__

    # FIXME: Consider loading from a file like below to remove
    # dependence on running interpreter
    if PYTHON_VERSION == 2.7:
        # 19:           0 SETUP_LOOP               23 (to 26)
        #               3 LOAD_GLOBAL               0 (range)
        #               6 LOAD_CONST                1 (1)
        #
        # 20:           9 LOAD_CONST                2 (10)
        #              12 CALL_FUNCTION             2 (2 positional, 0 keyword pair)
        #              15 GET_ITER
        #         >>   16 FOR_ITER                  6 (to 25)
        #              19 STORE_FAST                0 (res)
        #
        # 21:          22 JUMP_ABSOLUTE            16 (to 16)
        #         >>   25 POP_BLOCK
        #         >>   26 LOAD_CONST                0 (None)
        #              29 RETURN_VALUE
        offset_map = opcode_27.get_jump_target_maps(code, opcode_27)

        expected = {
            3: [0],
            6: [3],
            9: [6],
            12: [9],
            15: [12],
            16: [15, 22],
            19: [16],
            22: [19],
            25: [16],
            26: [0, 25],
            29: [26]
        }
        assert expected == offset_map

        offsets = opcode_27.get_jump_targets(code, opcode_27)
        assert offsets == [26, 25, 16]

    test_pyc = my_dir + '/../test/bytecode_2.7/01_dead_code.pyc'
    (version, timestamp, magic_int, co, pypy,
     source_size) = load_module(test_pyc)
    code = co.co_consts[0]
    offsets = opcode_27.get_jump_targets(code, opcode_27)
    assert [10] == offsets

    # from xdis.main import disassemble_file
    # print('\n')
    # disassemble_file(test_pyc)

    #  2:           0 LOAD_FAST                 0 (a)
    #               3 POP_JUMP_IF_FALSE        10 (to 10)
    #
    #  3:           6 LOAD_CONST                1 (5)
    #               9 RETURN_VALUE
    #
    #  5:     >>   10 LOAD_CONST                2 (6)
    #              13 RETURN_VALUE
    #              14 LOAD_CONST                0 (None)
    #              17 RETURN_VALUE
    offset_map = opcode_27.get_jump_target_maps(code, opcode_27)
    # print(offset_map)
    expect = {3: [0], 6: [3], 9: [6], 10: [3], 13: [10], 17: [14]}
    assert expect == offset_map

    # Python 3.6 code wordcode
    # ------------------------
    test_pyc = my_dir + '/../test/bytecode_3.6/01_dead_code.pyc'
    (version, timestamp, magic_int, co, pypy,
     source_size) = load_module(test_pyc)
    code = co.co_consts[0]

    #  2:           0 LOAD_FAST                 0 (a)
    #               2 POP_JUMP_IF_FALSE         8 (to 8)
    #
    #  3:           4 LOAD_CONST                1 (5)
    #               6 RETURN_VALUE
    #
    #  5:           8 LOAD_CONST                2 (6)
    #              10 RETURN_VALUE
    #              12 LOAD_CONST                0 (None)
    #              14 RETURN_VALUE

    offsets = opcode_36.get_jump_targets(code, opcode_36)
    assert offsets == [8]

    from xdis.main import disassemble_file
    print('\n')
    disassemble_file(test_pyc)

    offset_map = opcode_36.get_jump_target_maps(code, opcode_36)
    expect = {2: [0], 4: [2], 6: [4], 8: [2], 10: [8], 14: [12]}
    assert expect == offset_map
Exemplo n.º 11
0
def test_get_jump_targets():
    my_dir = osp.dirname(osp.abspath(__file__))

    # Python 2.7 code
    code = bug708901.__code__

    # FIXME: Consider loading from a file like below to remove
    # dependence on running interpreter
    if PYTHON_VERSION == 2.7:
        # 19:           0 SETUP_LOOP               23 (to 26)
        #               3 LOAD_GLOBAL               0 (range)
        #               6 LOAD_CONST                1 (1)
        #
        # 20:           9 LOAD_CONST                2 (10)
        #              12 CALL_FUNCTION             2 (2 positional, 0 keyword pair)
        #              15 GET_ITER
        #         >>   16 FOR_ITER                  6 (to 25)
        #              19 STORE_FAST                0 (res)
        #
        # 21:          22 JUMP_ABSOLUTE            16 (to 16)
        #         >>   25 POP_BLOCK
        #         >>   26 LOAD_CONST                0 (None)
        #              29 RETURN_VALUE
        offset_map = opcode_27.get_jump_target_maps(code,  opcode_27)

        expected = { 3: [0], 6: [3], 9: [6], 12: [9], 15: [12],
                    16: [15, 22], 19: [16], 22: [19], 25: [16],
                    26: [0, 25], 29: [26]}
        assert expected == offset_map

        offsets = opcode_27.get_jump_targets(code,  opcode_27)
        assert offsets == [26, 25, 16]

    test_pyc = my_dir +'/../test/bytecode_2.7/01_dead_code.pyc'
    (version, timestamp, magic_int, co, pypy,
     source_size) = load_module(test_pyc)
    code = co.co_consts[0]
    offsets = opcode_27.get_jump_targets(code,  opcode_27)
    assert [10] == offsets

    # from xdis.main import disassemble_file
    # print('\n')
    # disassemble_file(test_pyc)

    #  2:           0 LOAD_FAST                 0 (a)
    #               3 POP_JUMP_IF_FALSE        10 (to 10)
    #
    #  3:           6 LOAD_CONST                1 (5)
    #               9 RETURN_VALUE
    #
    #  5:     >>   10 LOAD_CONST                2 (6)
    #              13 RETURN_VALUE
    #              14 LOAD_CONST                0 (None)
    #              17 RETURN_VALUE
    offset_map = opcode_27.get_jump_target_maps(code,  opcode_27)
    # print(offset_map)
    expect = {3: [0], 6: [3], 9: [6], 10: [3], 13: [10], 17: [14]}
    assert expect == offset_map

    # Python 3.6 code wordcode
    # ------------------------
    test_pyc = my_dir +'/../test/bytecode_3.6/01_dead_code.pyc'
    (version, timestamp, magic_int, co, pypy,
     source_size) = load_module(test_pyc)
    code = co.co_consts[0]

    #  2:           0 LOAD_FAST                 0 (a)
    #               2 POP_JUMP_IF_FALSE         8 (to 8)
    #
    #  3:           4 LOAD_CONST                1 (5)
    #               6 RETURN_VALUE
    #
    #  5:           8 LOAD_CONST                2 (6)
    #              10 RETURN_VALUE
    #              12 LOAD_CONST                0 (None)
    #              14 RETURN_VALUE

    offsets = opcode_36.get_jump_targets(code,  opcode_36)
    assert offsets == [8]

    from xdis.main import disassemble_file
    print('\n')
    disassemble_file(test_pyc)

    offset_map = opcode_36.get_jump_target_maps(code,  opcode_36)
    expect = {2: [0], 4: [2], 6: [4], 8: [2], 10: [8], 14: [12]}
    assert expect == offset_map
Exemplo n.º 12
0
def do_tests(src_dir,
             patterns,
             target_dir,
             start_with=None,
             do_verify=False,
             max_files=800,
             do_compile=False,
             verbose=False):
    def visitor(files, dirname, names):
        files.extend([
            os.path.normpath(os.path.join(dirname, n)) for n in names
            for pat in patterns if fnmatch(n, pat)
        ])

    def file_matches(files, root, basenames, patterns):
        files.extend([
            os.path.normpath(os.path.join(root, n)) for n in basenames
            for pat in patterns if fnmatch(n, pat)
        ])

    files = []
    if do_compile:
        for root, dirs, basenames in os.walk(src_dir):
            file_matches(files, root, basenames, PY)
            for sfile in files:
                py_compile.compile(sfile)
                pass
            pass
        files = []
        pass

    cwd = os.getcwd()
    os.chdir(src_dir)
    if PYTHON3:
        for root, dirname, names in os.walk(os.curdir):
            files.extend([
                os.path.normpath(os.path.join(root, n)) for n in names
                for pat in patterns if fnmatch(n, pat)
            ])
            pass
        pass
    else:
        os.path.walk(os.curdir, visitor, files)
    files.sort()

    if start_with:
        try:
            start_with = files.index(start_with)
            files = files[start_with:]
            print('>>> starting with file', files[0])
        except ValueError:
            pass

    if len(files) > max_files:
        files = [file for file in files if not 'site-packages' in file]
        files = [file for file in files if not 'test' in file]
        if len(files) > max_files:
            files = files[:max_files]
            pass
    elif len(files) == 0:
        print("No files found\n")
        os.chdir(cwd)
        return

    output = open(os.devnull, "w")
    # output = sys.stdout
    start_time = time.time()
    print(time.ctime())
    for i, bc_file in enumerate(files):
        if verbose:
            print(os.path.join(src_dir, bc_file))
        bc_filename, co, version, ts, magic = main.disassemble_file(
            bc_file, output)
        if do_verify:
            file = co.co_filename
            verify_file(file, bc_filename)
        if i % 100 == 0 and i > 0:
            print("Processed %d files" % (i))
    print("Processed %d files, total" % (i + 1))
    print(time.ctime())
    elapsed_time = time.time() - start_time
    print("%g seconds" % elapsed_time)
    os.chdir(cwd)