tools/tool/Tool.cpp (153 lines of code) (raw):

/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ #include <boost/algorithm/string.hpp> #include <boost/filesystem.hpp> #include <iostream> #include "DexLoader.h" #include "DexUtil.h" #include "JarLoader.h" #include "JsonWrapper.h" #include "ReachableClasses.h" #include "Tool.h" namespace fs = boost::filesystem; namespace { void load_store_dexen(DexStore& store, const DexMetadata& store_metadata, bool verbose, bool balloon, bool throw_on_balloon_error, int support_dex_version = 35) { for (const auto& file_path : store_metadata.get_files()) { if (verbose) { std::cout << "Loading " << file_path << std::endl; } DexClasses classes = load_classes_from_dex(DexLocation::make_location("", file_path), balloon, throw_on_balloon_error, support_dex_version); store.add_classes(std::move(classes)); } } DexMetadata parse_store_metadata(const fs::path& metadata_path) { DexMetadata metadata; std::ifstream file(metadata_path.string(), std::ios::in); std::string line; while (std::getline(file, line)) { std::vector<std::string> tokens; boost::split(tokens, line, boost::is_any_of(" ")); if (tokens.size() > 1) { if (tokens[0] == ".id") { metadata.set_id(tokens[1]); } else if (tokens[0] == ".requires") { metadata.get_dependencies().emplace_back(tokens[1]); } } } return metadata; } std::vector<std::string> find_store_dexen(const fs::path& store_dir_path) { std::vector<std::string> dexen; auto end = fs::directory_iterator(); for (fs::directory_iterator it(store_dir_path); it != end; ++it) { auto file = it->path(); if (fs::is_regular_file(file) && !file.extension().compare(std::string(".dex"))) { dexen.emplace_back(file.string()); } } return dexen; } std::vector<DexMetadata> find_stores(const std::string& apk_dir_str, const std::string& dexen_dir_str) { fs::path apk_dir_path(apk_dir_str); fs::path dexen_dir_path(dexen_dir_str); auto end = fs::directory_iterator(); std::vector<DexMetadata> metadatas; for (fs::directory_iterator it(dexen_dir_path); it != end; ++it) { // Look for metadata.txt for this store in the apk dir auto metadata_path = apk_dir_path; metadata_path += fs::path::preferred_separator; metadata_path += "assets"; metadata_path += fs::path::preferred_separator; metadata_path += it->path().filename().string(); metadata_path += fs::path::preferred_separator; metadata_path += "metadata.txt"; if (fs::is_regular_file(metadata_path) && fs::exists(metadata_path)) { // Build metadata for store auto metadata = parse_store_metadata(metadata_path); metadata.set_files(find_store_dexen(it->path())); metadatas.emplace_back(metadata); } } return metadatas; } } // namespace void Tool::add_standard_options(po::options_description& options) const { options.add_options()( "jars,j", po::value<std::string>()->value_name("foo.jar,bar.jar,...")->required(), "delimited list of system jars")( "apkdir,a", po::value<std::string>() ->value_name("/tmp/redex_extracted_apk") ->required(), "path of an apk dir obtained from redex.py -u")("dexendir,d", po::value<std::string>() ->value_name( "/tmp/" "redex_dexen") ->required(), "path of a dexen dir " "obtained from redex.py " "-u"); } DexStoresVector Tool::init(const std::string& system_jar_paths, const std::string& apk_dir_str, const std::string& dexen_dir_str, bool balloon, bool throw_on_balloon_error, int support_dex_version) { if (!fs::is_directory(fs::path(apk_dir_str))) { throw std::invalid_argument("'" + apk_dir_str + "' is not a directory"); } if (!fs::is_directory(fs::path(dexen_dir_str))) { throw std::invalid_argument("'" + dexen_dir_str + "' is not a directory"); } // Load jars if (!system_jar_paths.empty()) { auto delim = boost::is_any_of(":,"); std::vector<std::string> system_jars; boost::split(system_jars, system_jar_paths, delim); for (const auto& system_jar : system_jars) { if (m_verbose) { std::cout << "Loading " << system_jar << std::endl; } if (!load_jar_file(DexLocation::make_location("", system_jar))) { throw std::runtime_error("Could not load system jar file '" + system_jar + "'"); } } } // Load dexen DexStore root_store("dex"); DexStoresVector stores; // Load root dexen load_root_dexen(root_store, dexen_dir_str, balloon, throw_on_balloon_error, m_verbose, support_dex_version); stores.emplace_back(std::move(root_store)); // Load module dexen for (const auto& metadata : find_stores(apk_dir_str, dexen_dir_str)) { DexStore store(metadata); load_store_dexen(store, metadata, m_verbose, balloon, throw_on_balloon_error, support_dex_version); stores.emplace_back(std::move(store)); } // Initialize reachable classes if (m_verbose) { std::cout << "Initializing reachable classes" << std::endl; } Scope scope = build_class_scope(stores); JsonWrapper config; init_reachable_classes(scope, ReachableClassesConfig(config)); return stores; }