Skip to content

Commit

Permalink
Set bundle config to deduplicate resource entries after obfuscation
Browse files Browse the repository at this point in the history
Summary:
This diff makes ObfuscateResourcesPass twiddle a BundleConfig.pb file option (if input is .aab file) to get more benefits out of what it does.

One of ObfuscateResourcesPass's tasks is to rename resource entries to "name removed" and thus, so it makes sense for this pass to turn on the bundle config option telling the final apk creation to look for identical (ResTable_entry, Res_value) since ObfuscateResourcesPass is largely responsible for making things identical.

Sidenote: this option only takes effect in recent versions of bundletool, as google/bundletool@8ab1a9f#diff-285d19cf023954460f3466b1efa792eea6b66cf787f52547c1cd5fe206811e0a finally implements this (Redex has been performing this functionality on .apk files for a while now).

Reviewed By: longinoa

Differential Revision: D42380391

fbshipit-source-id: cff5406eea32a9bcd5d461981564e3c505d9d273
  • Loading branch information
wsanville authored and facebook-github-bot committed Dec 18, 2023
1 parent 4c00d35 commit b309244
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 1 deletion.
13 changes: 12 additions & 1 deletion Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,16 @@ proto_res_header_out = $(addprefix protores/, $(notdir ${proto_res_in:.proto=.pb
proto_res_body_out = $(addprefix protores/, $(notdir ${proto_res_in:.proto=.pb.cc}))
BUILT_SOURCES = $(proto_res_header_out)

proto_cfg_in = \
proto/config.proto

protocfg/%.pb.cc protocfg/%.pb.h: proto/config.proto | mdir ; $(PROTOC) --proto_path=$(dir $^) --cpp_out=$(top_srcdir)/protocfg $^
mdir: ; mkdir -p $(top_srcdir)/protocfg

proto_cfg_header_out = $(addprefix protocfg/, $(notdir ${proto_cfg_in:.proto=.pb.h}))
proto_cfg_body_out = $(addprefix protocfg/, $(notdir ${proto_cfg_in:.proto=.pb.cc}))
BUILT_SOURCES += $(proto_cfg_header_out)

endif

#
Expand Down Expand Up @@ -335,7 +345,8 @@ libredex_la_LIBADD = \
if SET_PROTOBUF
libredex_la_SOURCES += \
protores/Resources.pb.cc \
protores/Configuration.pb.cc
protores/Configuration.pb.cc \
protocfg/config.pb.cc

libredex_la_LIBADD += \
$(LIBPROTOBUF_LIBS)
Expand Down
23 changes: 23 additions & 0 deletions libredex/BundleResources.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <google/protobuf/text_format.h>

#include "Debug.h"
#include "DetectBundle.h"
#include "DexUtil.h"
#include "ReadMaybeMapped.h"
#include "RedexMappedFile.h"
Expand Down Expand Up @@ -2300,6 +2301,28 @@ void BundleResources::obfuscate_xml_files(
}
}

void BundleResources::finalize_bundle_config(const ResourceConfig& config) {
if (!config.canonical_entry_types.empty() && has_bundle_config(m_directory)) {
std::string bundle_config_path =
(boost::filesystem::path(m_directory) / "BundleConfig.pb").string();
read_protobuf_file_contents(
bundle_config_path,
[&](google::protobuf::io::CodedInputStream& input, size_t size) {
android::bundle::BundleConfig bundle_config;
always_assert_log(bundle_config.ParseFromCodedStream(&input),
"BundleResource failed to read %s",
bundle_config_path.c_str());
auto pb_resource_optimizations =
bundle_config.mutable_optimizations()
->mutable_resource_optimizations();
pb_resource_optimizations->mutable_collapsed_resource_names()
->set_deduplicate_resource_entries(true);
std::ofstream out(bundle_config_path, std::ofstream::binary);
always_assert(bundle_config.SerializeToOstream(&out));
});
}
}

ResourcesPbFile::~ResourcesPbFile() {}

#endif // HAS_PROTOBUF
3 changes: 3 additions & 0 deletions libredex/BundleResources.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
#include <unordered_set>
#include <vector>

#include "GlobalConfig.h"
#include "androidfw/ResourceTypes.h"
#include "protocfg/config.pb.h"
#include "protores/Resources.pb.h"
#include <google/protobuf/repeated_field.h>

Expand Down Expand Up @@ -125,6 +127,7 @@ class BundleResources : public AndroidResources {
void obfuscate_xml_files(const std::unordered_set<std::string>& allowed_types,
const std::unordered_set<std::string>&
do_not_obfuscate_elements) override;
void finalize_bundle_config(const ResourceConfig& config) override;

protected:
std::vector<std::string> find_res_directories() override;
Expand Down
4 changes: 4 additions & 0 deletions libredex/RedexResources.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,10 @@ bool AndroidResources::can_obfuscate_xml_file(
return false;
}

void AndroidResources::finalize_bundle_config(const ResourceConfig& config) {
// Do nothing in super implementation, sub class will override if relevant.
}

void ResourceTableFile::finalize_resource_table(const ResourceConfig& config) {
// Intentionally left empty, proto resource table will not contain a relevant
// structure to clean up.
Expand Down
3 changes: 3 additions & 0 deletions libredex/RedexResources.h
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,9 @@ class AndroidResources {
const std::string& dirname);
// Classnames present in native libraries (lib/*/*.so)
std::unordered_set<std::string> get_native_classes();
// Sets up BundleConfig.pb file with relevant options for resource
// optimizations that need to executed by bundletool/aapt2.
virtual void finalize_bundle_config(const ResourceConfig& config);

const std::string& get_directory() { return m_directory; }

Expand Down
8 changes: 8 additions & 0 deletions opt/obfuscate_resources/ObfuscateResourcesPass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,14 @@ void ObfuscateResourcesPass::run_pass(DexStoresVector& stores,
m_keep_resource_name_prefixes, keep_resource_names_specific);
mgr.incr_metric("num_anonymized_resource_names", changed);
mgr.incr_metric("num_anonymized_resource_files", filepath_old_to_new.size());

// Obfuscation may create duplicate entry/value structures. Make sure to set
// relevant values in BundleConfig.pb to take advantage of that (if
// configured).
const auto& global_config = conf.get_global_config();
auto global_resources_config =
global_config.get_config_by_name<ResourceConfig>("resources");
resources->finalize_bundle_config(*global_resources_config);
}

static ObfuscateResourcesPass s_pass;
5 changes: 5 additions & 0 deletions test/instr/obfuscateresources.config
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@
],
"obfuscate_xml_attributes": false
},
"resources": {
"canonical_entry_types": [
"id"
]
},
"compute_xml_reachability": true,
"finalize_resource_table": true
}

0 comments on commit b309244

Please sign in to comment.