Ejemplo n.º 1
0
def run_debug_injector(args):
    extracted_apk_dir = make_temp_dir(".extracted_apk", False)
    dex_dir = make_temp_dir(".dexen", False)

    with ZipManager(
            args.input_apk, extracted_apk_dir, args.output_apk), UnpackManager(
                args.input_apk, extracted_apk_dir,
                dex_dir) as store_files, LibraryManager(extracted_apk_dir):
        dexen = move_dexen_to_directories(dex_dir,
                                          dex_glob(dex_dir)) + store_files
        try:
            subprocess.check_output(
                [args.bin_path, "-o", dex_dir, "--dex-files"] + dexen,
                stderr=subprocess.STDOUT,
            )
        except subprocess.CalledProcessError as e:
            sys.stderr.write("Error while running inject debug binary:\n")
            sys.stderr.write(e.output.decode("utf-8"))
            exit(1)

    if (args.keystore is not None and args.keyalias is not None
            and args.keypass is not None):
        sign_apk(args.keystore, args.keypass, args.keyalias, args.output_apk)
Ejemplo n.º 2
0
def prepare_redex(args):
    logging.debug("Preparing...")
    debug_mode = args.unpack_only or args.debug

    if args.android_sdk_path:
        add_android_sdk_path(args.android_sdk_path)

    # avoid accidentally mixing up file formats since we now support
    # both apk files and Android bundle files
    file_ext = get_file_ext(args.input_apk)
    if not args.unpack_only:
        assert file_ext == get_file_ext(
            args.out), ('Input file extension ("' + file_ext +
                        '") should be the same as output file extension ("' +
                        get_file_ext(args.out) + '")')

    extracted_apk_dir = None
    dex_dir = None
    if args.unpack_only and args.unpack_dest:
        if args.unpack_dest[0] == ".":
            # Use APK's name
            unpack_dir_basename = os.path.splitext(args.input_apk)[0]
        else:
            unpack_dir_basename = args.unpack_dest[0]
        extracted_apk_dir = unpack_dir_basename + ".redex_extracted_apk"
        dex_dir = unpack_dir_basename + ".redex_dexen"
        try:
            os.makedirs(extracted_apk_dir)
            os.makedirs(dex_dir)
            extracted_apk_dir = os.path.abspath(extracted_apk_dir)
            dex_dir = os.path.abspath(dex_dir)
        except OSError as e:
            if e.errno == errno.EEXIST:
                print("Error: destination directory already exists!")
                print("APK: " + extracted_apk_dir)
                print("DEX: " + dex_dir)
                sys.exit(1)
            raise e

    config = args.config
    binary = args.redex_binary
    logging.debug("Using config %s",
                  config if config is not None else "(default)")
    logging.debug("Using binary %s",
                  binary if binary is not None else "(default)")

    if args.unpack_only or config is None:
        config_dict = {}
    else:
        with open(config) as config_file:
            try:
                lines = config_file.readlines()
                config_dict = json.loads(remove_comments(lines))
            except ValueError:
                raise ValueError("Invalid JSON in ReDex config file: %s" %
                                 config_file.name)

    # stop_pass_idx >= 0 means need stop before a pass and dump intermediate result
    stop_pass_idx = -1
    if args.stop_pass:
        passes_list = config_dict.get("redex", {}).get("passes", [])
        stop_pass_idx = get_stop_pass_idx(passes_list, args.stop_pass)
        if not args.output_ir or isfile(args.output_ir):
            print("Error: output_ir should be a directory")
            sys.exit(1)
        try:
            os.makedirs(args.output_ir)
        except OSError as e:
            if e.errno != errno.EEXIST:
                raise e

    logging.debug("Unpacking...")
    unpack_start_time = timer()
    if not extracted_apk_dir:
        extracted_apk_dir = make_temp_dir(".redex_extracted_apk", debug_mode)

    directory = make_temp_dir(".redex_unaligned", False)
    unaligned_apk_path = join(directory, "redex-unaligned." + file_ext)
    zip_manager = ZipManager(args.input_apk, extracted_apk_dir,
                             unaligned_apk_path)
    zip_manager.__enter__()

    if not dex_dir:
        dex_dir = make_temp_dir(".redex_dexen", debug_mode)

    is_bundle = isfile(join(extracted_apk_dir, "BundleConfig.pb"))
    unpack_manager = UnpackManager(
        args.input_apk,
        extracted_apk_dir,
        dex_dir,
        have_locators=config_dict.get("emit_locator_strings"),
        debug_mode=debug_mode,
        fast_repackage=args.dev,
        reset_timestamps=args.reset_zip_timestamps or args.dev,
        is_bundle=is_bundle,
    )
    store_files = unpack_manager.__enter__()

    lib_manager = LibraryManager(extracted_apk_dir, is_bundle=is_bundle)
    lib_manager.__enter__()

    if args.unpack_only:
        print("APK: " + extracted_apk_dir)
        print("DEX: " + dex_dir)
        sys.exit()

    # Unpack profiles, if they exist.
    _handle_profiles(args, debug_mode)

    logging.debug("Moving contents to expected structure...")
    # Move each dex to a separate temporary directory to be operated by
    # redex.
    dexen = move_dexen_to_directories(dex_dir, dex_glob(dex_dir))
    for store in sorted(store_files):
        dexen.append(store)
    logging.debug(
        "Unpacking APK finished in {:.2f} seconds".format(timer() -
                                                          unpack_start_time))

    if args.side_effect_summaries is not None:
        args.passthru_json.append(
            'ObjectSensitiveDcePass.side_effect_summaries="%s"' %
            args.side_effect_summaries)

    if args.escape_summaries is not None:
        args.passthru_json.append(
            'ObjectSensitiveDcePass.escape_summaries="%s"' %
            args.escape_summaries)

    for key_value_str in args.passthru_json:
        key_value = key_value_str.split("=", 1)
        if len(key_value) != 2:
            logging.debug(
                "Json Pass through %s is not valid. Split len: %s",
                key_value_str,
                len(key_value),
            )
            continue
        key = key_value[0]
        value = key_value[1]
        prev_value = config_dict.get(key, "(No previous value)")
        logging.debug(
            "Got Override %s = %s from %s. Previous %s",
            key,
            value,
            key_value_str,
            prev_value,
        )
        config_dict[key] = json.loads(value)

    # Scan for framework files. If not found, warn and add them if available.
    _check_android_sdk_api(args)
    # Check for shrinker heuristics.
    _check_shrinker_heuristics(args)

    # Scan for SDK jar. If not found, warn and add if available.
    _check_android_sdk(args)

    logging.debug("Running redex-all on %d dex files ", len(dexen))
    if args.lldb:
        debugger = "lldb"
    elif args.gdb:
        debugger = "gdb"
    else:
        debugger = None

    return State(
        args=args,
        config_dict=config_dict,
        debugger=debugger,
        dex_dir=dex_dir,
        dexen=dexen,
        extracted_apk_dir=extracted_apk_dir,
        stop_pass_idx=stop_pass_idx,
        lib_manager=lib_manager,
        unpack_manager=unpack_manager,
        zip_manager=zip_manager,
    )