Loading tools/aapt2/cmd/Optimize.cpp +2 −2 Original line number Diff line number Diff line Loading @@ -154,8 +154,8 @@ class Optimizer { return 1; } if (options_.shorten_resource_paths) { Obfuscator obfuscator(options_.table_flattener_options.shortened_path_map); Obfuscator obfuscator(options_); if (obfuscator.IsEnabled()) { if (!obfuscator.Consume(context_, apk->GetResourceTable())) { context_->GetDiagnostics()->Error(android::DiagMessage() << "failed shortening resource paths"); Loading tools/aapt2/format/binary/TableFlattener.cpp +16 −17 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ #include "format/binary/ChunkWriter.h" #include "format/binary/ResEntryWriter.h" #include "format/binary/ResourceTypeExtensions.h" #include "optimize/Obfuscator.h" #include "trace/TraceBuffer.h" using namespace android; Loading Loading @@ -466,9 +467,6 @@ class PackageFlattener { // table. std::map<ConfigDescription, std::vector<FlatEntry>> config_to_entry_list_map; // hardcoded string uses characters which make it an invalid resource name const std::string obfuscated_resource_name = "0_resource_name_obfuscated"; for (const ResourceTableEntryView& entry : type.entries) { if (entry.staged_id) { aliases_.insert(std::make_pair( Loading @@ -477,30 +475,31 @@ class PackageFlattener { } uint32_t local_key_index; ResourceName resource_name({}, type.named_type, entry.name); if (!collapse_key_stringpool_ || name_collapse_exemptions_.find(resource_name) != name_collapse_exemptions_.end()) { auto onObfuscate = [this, &local_key_index, &entry](Obfuscator::Result obfuscatedResult, const ResourceName& resource_name) { if (obfuscatedResult == Obfuscator::Result::Keep_ExemptionList) { local_key_index = (uint32_t)key_pool_.MakeRef(entry.name).index(); } else { // resource isn't exempt from collapse, add it as obfuscated value if (entry.overlayable_item) { } else if (obfuscatedResult == Obfuscator::Result::Keep_Overlayable) { // if the resource name of the specific entry is obfuscated and this // entry is in the overlayable list, the overlay can't work on this // overlayable at runtime because the name has been obfuscated in // resources.arsc during flatten operation. const OverlayableItem& item = entry.overlayable_item.value(); context_->GetDiagnostics()->Warn(android::DiagMessage(item.overlayable->source) << "The resource name of overlayable entry " << resource_name.to_string() << "'" << " shouldn't be obfuscated in resources.arsc"); << "The resource name of overlayable entry '" << resource_name.to_string() << "' shouldn't be obfuscated in resources.arsc"); local_key_index = (uint32_t)key_pool_.MakeRef(entry.name).index(); } else { // TODO(b/228192695): output the entry.name and Resource id to make // de-obfuscated possible. local_key_index = (uint32_t)key_pool_.MakeRef(obfuscated_resource_name).index(); } local_key_index = (uint32_t)key_pool_.MakeRef(Obfuscator::kObfuscatedResourceName).index(); } }; Obfuscator::ObfuscateResourceName(collapse_key_stringpool_, name_collapse_exemptions_, type.named_type, entry, onObfuscate); // Group values by configuration. for (auto& config_value : entry.values) { config_to_entry_list_map[config_value->config].push_back( Loading tools/aapt2/format/binary/TableFlattener.h +13 −5 Original line number Diff line number Diff line Loading @@ -14,8 +14,13 @@ * limitations under the License. */ #ifndef AAPT_FORMAT_BINARY_TABLEFLATTENER_H #define AAPT_FORMAT_BINARY_TABLEFLATTENER_H #ifndef TOOLS_AAPT2_FORMAT_BINARY_TABLEFLATTENER_H_ #define TOOLS_AAPT2_FORMAT_BINARY_TABLEFLATTENER_H_ #include <map> #include <set> #include <string> #include <unordered_map> #include "Resource.h" #include "ResourceTable.h" Loading Loading @@ -71,6 +76,9 @@ struct TableFlattenerOptions { // // This applies only to simple entries (entry->flags & ResTable_entry::FLAG_COMPLEX == 0). bool deduplicate_entry_values = false; // Map from original resource ids to obfuscated names. std::unordered_map<uint32_t, std::string> id_resource_map; }; class TableFlattener : public IResourceTableConsumer { Loading @@ -82,12 +90,12 @@ class TableFlattener : public IResourceTableConsumer { bool Consume(IAaptContext* context, ResourceTable* table) override; private: DISALLOW_COPY_AND_ASSIGN(TableFlattener); TableFlattenerOptions options_; android::BigBuffer* buffer_; DISALLOW_COPY_AND_ASSIGN(TableFlattener); }; } // namespace aapt #endif /* AAPT_FORMAT_BINARY_TABLEFLATTENER_H */ #endif // TOOLS_AAPT2_FORMAT_BINARY_TABLEFLATTENER_H_ tools/aapt2/format/proto/ProtoSerialize.cpp +11 −10 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #include "ValueVisitor.h" #include "androidfw/BigBuffer.h" #include "optimize/Obfuscator.h" using android::ConfigDescription; Loading Loading @@ -366,21 +367,21 @@ void SerializeTableToPb(const ResourceTable& table, pb::ResourceTable* out_table } pb_type->set_name(type.named_type.to_string()); // hardcoded string uses characters which make it an invalid resource name static const char* obfuscated_resource_name = "0_resource_name_obfuscated"; for (const auto& entry : type.entries) { pb::Entry* pb_entry = pb_type->add_entry(); if (entry.id) { pb_entry->mutable_entry_id()->set_id(entry.id.value()); } ResourceName resource_name({}, type.named_type, entry.name); if (options.collapse_key_stringpool && options.name_collapse_exemptions.find(resource_name) == options.name_collapse_exemptions.end()) { pb_entry->set_name(obfuscated_resource_name); } else { pb_entry->set_name(entry.name); } auto onObfuscate = [pb_entry, &entry](Obfuscator::Result obfuscatedResult, const ResourceName& resource_name) { pb_entry->set_name(obfuscatedResult == Obfuscator::Result::Obfuscated ? Obfuscator::kObfuscatedResourceName : entry.name); }; Obfuscator::ObfuscateResourceName(options.collapse_key_stringpool, options.name_collapse_exemptions, type.named_type, entry, onObfuscate); // Write the Visibility struct. pb::Visibility* pb_visibility = pb_entry->mutable_visibility(); Loading tools/aapt2/optimize/Obfuscator.cpp +92 −3 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #include "optimize/Obfuscator.h" #include <map> #include <set> #include <string> #include <unordered_set> Loading @@ -32,7 +33,10 @@ static const char base64_chars[] = namespace aapt { Obfuscator::Obfuscator(std::map<std::string, std::string>& path_map_out) : path_map_(path_map_out) { Obfuscator::Obfuscator(OptimizeOptions& optimizeOptions) : options_(optimizeOptions.table_flattener_options), shorten_resource_paths_(optimizeOptions.shorten_resource_paths), collapse_key_stringpool_(optimizeOptions.table_flattener_options.collapse_key_stringpool) { } std::string ShortenFileName(android::StringPiece file_path, int output_length) { Loading Loading @@ -77,7 +81,8 @@ struct PathComparator { } }; bool Obfuscator::Consume(IAaptContext* context, ResourceTable* table) { static bool HandleShortenFilePaths(ResourceTable* table, std::map<std::string, std::string>& shortened_path_map) { // used to detect collisions std::unordered_set<std::string> shortened_paths; std::set<FileReference*, PathComparator> file_refs; Loading Loading @@ -109,10 +114,94 @@ bool Obfuscator::Consume(IAaptContext* context, ResourceTable* table) { shortened_path = GetShortenedPath(shortened_filename, extension, collision_count); } shortened_paths.insert(shortened_path); path_map_.insert({*file_ref->path, shortened_path}); shortened_path_map.insert({*file_ref->path, shortened_path}); file_ref->path = table->string_pool.MakeRef(shortened_path, file_ref->path.GetContext()); } return true; } void Obfuscator::ObfuscateResourceName( const bool collapse_key_stringpool, const std::set<ResourceName>& name_collapse_exemptions, const ResourceNamedType& type_name, const ResourceTableEntryView& entry, const android::base::function_ref<void(Result obfuscatedResult, const ResourceName&)> onObfuscate) { ResourceName resource_name({}, type_name, entry.name); if (!collapse_key_stringpool || name_collapse_exemptions.find(resource_name) != name_collapse_exemptions.end()) { onObfuscate(Result::Keep_ExemptionList, resource_name); } else { // resource isn't exempt from collapse, add it as obfuscated value if (entry.overlayable_item) { // if the resource name of the specific entry is obfuscated and this // entry is in the overlayable list, the overlay can't work on this // overlayable at runtime because the name has been obfuscated in // resources.arsc during flatten operation. onObfuscate(Result::Keep_Overlayable, resource_name); } else { onObfuscate(Result::Obfuscated, resource_name); } } } static bool HandleCollapseKeyStringPool( const ResourceTable* table, const bool collapse_key_string_pool, const std::set<ResourceName>& name_collapse_exemptions, std::unordered_map<uint32_t, std::string>& id_resource_map) { if (!collapse_key_string_pool) { return true; } int entryResId = 0; auto onObfuscate = [&entryResId, &id_resource_map](const Obfuscator::Result obfuscatedResult, const ResourceName& resource_name) { if (obfuscatedResult == Obfuscator::Result::Obfuscated) { id_resource_map.insert({entryResId, resource_name.entry}); } }; for (auto& package : table->packages) { for (auto& type : package->types) { for (auto& entry : type->entries) { if (!entry->id.has_value() || entry->name.empty()) { continue; } entryResId = entry->id->id; ResourceTableEntryView entry_view{ .name = entry->name, .id = entry->id ? entry->id.value().entry_id() : (std::optional<uint16_t>)std::nullopt, .visibility = entry->visibility, .allow_new = entry->allow_new, .overlayable_item = entry->overlayable_item, .staged_id = entry->staged_id}; Obfuscator::ObfuscateResourceName(collapse_key_string_pool, name_collapse_exemptions, type->named_type, entry_view, onObfuscate); } } } return true; } bool Obfuscator::Consume(IAaptContext* context, ResourceTable* table) { HandleCollapseKeyStringPool(table, options_.collapse_key_stringpool, options_.name_collapse_exemptions, options_.id_resource_map); if (shorten_resource_paths_) { return HandleShortenFilePaths(table, options_.shortened_path_map); } return true; } /** * Tell the optimizer whether it's needed to dump information for de-obfuscating. * * There are two conditions need to dump the information for de-obfuscating. * * the option of shortening file paths is enabled. * * the option of collapsing resource names is enabled. * @return true if the information needed for de-obfuscating, otherwise false */ bool Obfuscator::IsEnabled() const { return shorten_resource_paths_ || collapse_key_stringpool_; } } // namespace aapt Loading
tools/aapt2/cmd/Optimize.cpp +2 −2 Original line number Diff line number Diff line Loading @@ -154,8 +154,8 @@ class Optimizer { return 1; } if (options_.shorten_resource_paths) { Obfuscator obfuscator(options_.table_flattener_options.shortened_path_map); Obfuscator obfuscator(options_); if (obfuscator.IsEnabled()) { if (!obfuscator.Consume(context_, apk->GetResourceTable())) { context_->GetDiagnostics()->Error(android::DiagMessage() << "failed shortening resource paths"); Loading
tools/aapt2/format/binary/TableFlattener.cpp +16 −17 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ #include "format/binary/ChunkWriter.h" #include "format/binary/ResEntryWriter.h" #include "format/binary/ResourceTypeExtensions.h" #include "optimize/Obfuscator.h" #include "trace/TraceBuffer.h" using namespace android; Loading Loading @@ -466,9 +467,6 @@ class PackageFlattener { // table. std::map<ConfigDescription, std::vector<FlatEntry>> config_to_entry_list_map; // hardcoded string uses characters which make it an invalid resource name const std::string obfuscated_resource_name = "0_resource_name_obfuscated"; for (const ResourceTableEntryView& entry : type.entries) { if (entry.staged_id) { aliases_.insert(std::make_pair( Loading @@ -477,30 +475,31 @@ class PackageFlattener { } uint32_t local_key_index; ResourceName resource_name({}, type.named_type, entry.name); if (!collapse_key_stringpool_ || name_collapse_exemptions_.find(resource_name) != name_collapse_exemptions_.end()) { auto onObfuscate = [this, &local_key_index, &entry](Obfuscator::Result obfuscatedResult, const ResourceName& resource_name) { if (obfuscatedResult == Obfuscator::Result::Keep_ExemptionList) { local_key_index = (uint32_t)key_pool_.MakeRef(entry.name).index(); } else { // resource isn't exempt from collapse, add it as obfuscated value if (entry.overlayable_item) { } else if (obfuscatedResult == Obfuscator::Result::Keep_Overlayable) { // if the resource name of the specific entry is obfuscated and this // entry is in the overlayable list, the overlay can't work on this // overlayable at runtime because the name has been obfuscated in // resources.arsc during flatten operation. const OverlayableItem& item = entry.overlayable_item.value(); context_->GetDiagnostics()->Warn(android::DiagMessage(item.overlayable->source) << "The resource name of overlayable entry " << resource_name.to_string() << "'" << " shouldn't be obfuscated in resources.arsc"); << "The resource name of overlayable entry '" << resource_name.to_string() << "' shouldn't be obfuscated in resources.arsc"); local_key_index = (uint32_t)key_pool_.MakeRef(entry.name).index(); } else { // TODO(b/228192695): output the entry.name and Resource id to make // de-obfuscated possible. local_key_index = (uint32_t)key_pool_.MakeRef(obfuscated_resource_name).index(); } local_key_index = (uint32_t)key_pool_.MakeRef(Obfuscator::kObfuscatedResourceName).index(); } }; Obfuscator::ObfuscateResourceName(collapse_key_stringpool_, name_collapse_exemptions_, type.named_type, entry, onObfuscate); // Group values by configuration. for (auto& config_value : entry.values) { config_to_entry_list_map[config_value->config].push_back( Loading
tools/aapt2/format/binary/TableFlattener.h +13 −5 Original line number Diff line number Diff line Loading @@ -14,8 +14,13 @@ * limitations under the License. */ #ifndef AAPT_FORMAT_BINARY_TABLEFLATTENER_H #define AAPT_FORMAT_BINARY_TABLEFLATTENER_H #ifndef TOOLS_AAPT2_FORMAT_BINARY_TABLEFLATTENER_H_ #define TOOLS_AAPT2_FORMAT_BINARY_TABLEFLATTENER_H_ #include <map> #include <set> #include <string> #include <unordered_map> #include "Resource.h" #include "ResourceTable.h" Loading Loading @@ -71,6 +76,9 @@ struct TableFlattenerOptions { // // This applies only to simple entries (entry->flags & ResTable_entry::FLAG_COMPLEX == 0). bool deduplicate_entry_values = false; // Map from original resource ids to obfuscated names. std::unordered_map<uint32_t, std::string> id_resource_map; }; class TableFlattener : public IResourceTableConsumer { Loading @@ -82,12 +90,12 @@ class TableFlattener : public IResourceTableConsumer { bool Consume(IAaptContext* context, ResourceTable* table) override; private: DISALLOW_COPY_AND_ASSIGN(TableFlattener); TableFlattenerOptions options_; android::BigBuffer* buffer_; DISALLOW_COPY_AND_ASSIGN(TableFlattener); }; } // namespace aapt #endif /* AAPT_FORMAT_BINARY_TABLEFLATTENER_H */ #endif // TOOLS_AAPT2_FORMAT_BINARY_TABLEFLATTENER_H_
tools/aapt2/format/proto/ProtoSerialize.cpp +11 −10 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #include "ValueVisitor.h" #include "androidfw/BigBuffer.h" #include "optimize/Obfuscator.h" using android::ConfigDescription; Loading Loading @@ -366,21 +367,21 @@ void SerializeTableToPb(const ResourceTable& table, pb::ResourceTable* out_table } pb_type->set_name(type.named_type.to_string()); // hardcoded string uses characters which make it an invalid resource name static const char* obfuscated_resource_name = "0_resource_name_obfuscated"; for (const auto& entry : type.entries) { pb::Entry* pb_entry = pb_type->add_entry(); if (entry.id) { pb_entry->mutable_entry_id()->set_id(entry.id.value()); } ResourceName resource_name({}, type.named_type, entry.name); if (options.collapse_key_stringpool && options.name_collapse_exemptions.find(resource_name) == options.name_collapse_exemptions.end()) { pb_entry->set_name(obfuscated_resource_name); } else { pb_entry->set_name(entry.name); } auto onObfuscate = [pb_entry, &entry](Obfuscator::Result obfuscatedResult, const ResourceName& resource_name) { pb_entry->set_name(obfuscatedResult == Obfuscator::Result::Obfuscated ? Obfuscator::kObfuscatedResourceName : entry.name); }; Obfuscator::ObfuscateResourceName(options.collapse_key_stringpool, options.name_collapse_exemptions, type.named_type, entry, onObfuscate); // Write the Visibility struct. pb::Visibility* pb_visibility = pb_entry->mutable_visibility(); Loading
tools/aapt2/optimize/Obfuscator.cpp +92 −3 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #include "optimize/Obfuscator.h" #include <map> #include <set> #include <string> #include <unordered_set> Loading @@ -32,7 +33,10 @@ static const char base64_chars[] = namespace aapt { Obfuscator::Obfuscator(std::map<std::string, std::string>& path_map_out) : path_map_(path_map_out) { Obfuscator::Obfuscator(OptimizeOptions& optimizeOptions) : options_(optimizeOptions.table_flattener_options), shorten_resource_paths_(optimizeOptions.shorten_resource_paths), collapse_key_stringpool_(optimizeOptions.table_flattener_options.collapse_key_stringpool) { } std::string ShortenFileName(android::StringPiece file_path, int output_length) { Loading Loading @@ -77,7 +81,8 @@ struct PathComparator { } }; bool Obfuscator::Consume(IAaptContext* context, ResourceTable* table) { static bool HandleShortenFilePaths(ResourceTable* table, std::map<std::string, std::string>& shortened_path_map) { // used to detect collisions std::unordered_set<std::string> shortened_paths; std::set<FileReference*, PathComparator> file_refs; Loading Loading @@ -109,10 +114,94 @@ bool Obfuscator::Consume(IAaptContext* context, ResourceTable* table) { shortened_path = GetShortenedPath(shortened_filename, extension, collision_count); } shortened_paths.insert(shortened_path); path_map_.insert({*file_ref->path, shortened_path}); shortened_path_map.insert({*file_ref->path, shortened_path}); file_ref->path = table->string_pool.MakeRef(shortened_path, file_ref->path.GetContext()); } return true; } void Obfuscator::ObfuscateResourceName( const bool collapse_key_stringpool, const std::set<ResourceName>& name_collapse_exemptions, const ResourceNamedType& type_name, const ResourceTableEntryView& entry, const android::base::function_ref<void(Result obfuscatedResult, const ResourceName&)> onObfuscate) { ResourceName resource_name({}, type_name, entry.name); if (!collapse_key_stringpool || name_collapse_exemptions.find(resource_name) != name_collapse_exemptions.end()) { onObfuscate(Result::Keep_ExemptionList, resource_name); } else { // resource isn't exempt from collapse, add it as obfuscated value if (entry.overlayable_item) { // if the resource name of the specific entry is obfuscated and this // entry is in the overlayable list, the overlay can't work on this // overlayable at runtime because the name has been obfuscated in // resources.arsc during flatten operation. onObfuscate(Result::Keep_Overlayable, resource_name); } else { onObfuscate(Result::Obfuscated, resource_name); } } } static bool HandleCollapseKeyStringPool( const ResourceTable* table, const bool collapse_key_string_pool, const std::set<ResourceName>& name_collapse_exemptions, std::unordered_map<uint32_t, std::string>& id_resource_map) { if (!collapse_key_string_pool) { return true; } int entryResId = 0; auto onObfuscate = [&entryResId, &id_resource_map](const Obfuscator::Result obfuscatedResult, const ResourceName& resource_name) { if (obfuscatedResult == Obfuscator::Result::Obfuscated) { id_resource_map.insert({entryResId, resource_name.entry}); } }; for (auto& package : table->packages) { for (auto& type : package->types) { for (auto& entry : type->entries) { if (!entry->id.has_value() || entry->name.empty()) { continue; } entryResId = entry->id->id; ResourceTableEntryView entry_view{ .name = entry->name, .id = entry->id ? entry->id.value().entry_id() : (std::optional<uint16_t>)std::nullopt, .visibility = entry->visibility, .allow_new = entry->allow_new, .overlayable_item = entry->overlayable_item, .staged_id = entry->staged_id}; Obfuscator::ObfuscateResourceName(collapse_key_string_pool, name_collapse_exemptions, type->named_type, entry_view, onObfuscate); } } } return true; } bool Obfuscator::Consume(IAaptContext* context, ResourceTable* table) { HandleCollapseKeyStringPool(table, options_.collapse_key_stringpool, options_.name_collapse_exemptions, options_.id_resource_map); if (shorten_resource_paths_) { return HandleShortenFilePaths(table, options_.shortened_path_map); } return true; } /** * Tell the optimizer whether it's needed to dump information for de-obfuscating. * * There are two conditions need to dump the information for de-obfuscating. * * the option of shortening file paths is enabled. * * the option of collapsing resource names is enabled. * @return true if the information needed for de-obfuscating, otherwise false */ bool Obfuscator::IsEnabled() const { return shorten_resource_paths_ || collapse_key_stringpool_; } } // namespace aapt