Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 78a8d373 authored by felkachang's avatar felkachang Committed by Felka Chang
Browse files

Dump the deobfuscate data using Protocol buffers

Using Google Protocol buffers to dump the obfuscating mapping
information of being used to deobfuscate items.
* shortened file path -> original file path
* resource id -> original resource name

This patch add a new option --save-obfuscating-map to deprecate
--resource-path-shortening-map. The option
--resource-path-shortening-map is kept until no one to use it.

Bug: 246489170
Bug: 228192695
     b/228192695#comment2
Test: make WITH_TIDY=1 aapt2
Test: atest aapt2_test

Change-Id: I29733c4dbae9f6dd2f0e9b2c87b0d2046662fc59
parent b4de8520
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -161,6 +161,15 @@ class Optimizer {
                                          << "failed shortening resource paths");
        return 1;
      }

      if (options_.obfuscation_map_path &&
          !obfuscator.WriteObfuscationMap(options_.obfuscation_map_path.value())) {
        context_->GetDiagnostics()->Error(android::DiagMessage()
                                          << "failed to write the obfuscation map to file");
        return 1;
      }

      // TODO(b/246489170): keep the old option and format until transform to the new one
      if (options_.shortened_paths_map_path
          && !WriteShortenedPathsMap(options_.table_flattener_options.shortened_path_map,
                                      options_.shortened_paths_map_path.value())) {
@@ -292,6 +301,7 @@ class Optimizer {
                                        ArchiveEntry::kAlign, writer);
  }

  // TODO(b/246489170): keep the old option and format until transform to the new one
  bool WriteShortenedPathsMap(const std::map<std::string, std::string> &path_map,
                               const std::string &file_path) {
    std::stringstream ss;
+10 −2
Original line number Diff line number Diff line
@@ -58,6 +58,7 @@ struct OptimizeOptions {
  bool shorten_resource_paths = false;

  // Path to the output map of original resource paths to shortened paths.
  // TODO(b/246489170): keep the old option and format until transform to the new one
  std::optional<std::string> shortened_paths_map_path;

  // Whether sparse encoding should be used for O+ resources.
@@ -65,6 +66,9 @@ struct OptimizeOptions {

  // Whether sparse encoding should be used for all resources.
  bool force_sparse_encoding = false;

  // Path to the output map of original resource paths/names to obfuscated paths/names.
  std::optional<std::string> obfuscation_map_path;
};

class OptimizeCommand : public Command {
@@ -120,9 +124,13 @@ class OptimizeCommand : public Command {
    AddOptionalSwitch("--shorten-resource-paths",
        "Shortens the paths of resources inside the APK.",
        &options_.shorten_resource_paths);
    // TODO(b/246489170): keep the old option and format until transform to the new one
    AddOptionalFlag("--resource-path-shortening-map",
        "Path to output the map of old resource paths to shortened paths.",
                    "[Deprecated]Path to output the map of old resource paths to shortened paths.",
                    &options_.shortened_paths_map_path);
    AddOptionalFlag("--save-obfuscation-map",
                    "Path to output the map of original paths/names to obfuscated paths/names.",
                    &options_.obfuscation_map_path);
    AddOptionalSwitch(
        "--deduplicate-entry-values",
        "Whether to deduplicate pairs of resource entry and value for simple resources.\n"
+24 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

#include "optimize/Obfuscator.h"

#include <fstream>
#include <map>
#include <set>
#include <string>
@@ -192,6 +193,29 @@ bool Obfuscator::Consume(IAaptContext* context, ResourceTable* table) {
  return true;
}

bool Obfuscator::WriteObfuscationMap(const std::string& file_path) const {
  pb::ResourceMappings resourceMappings;
  for (const auto& [id, name] : options_.id_resource_map) {
    auto* collapsedNameMapping = resourceMappings.mutable_collapsed_names()->add_resource_names();
    collapsedNameMapping->set_id(id);
    collapsedNameMapping->set_name(name);
  }

  for (const auto& [original_path, shortened_path] : options_.shortened_path_map) {
    auto* resource_path = resourceMappings.mutable_shortened_paths()->add_resource_paths();
    resource_path->set_original_path(original_path);
    resource_path->set_shortened_path(shortened_path);
  }

  {  // RAII style, output the pb content to file and close fout in destructor
    std::ofstream fout(file_path, std::ios::out | std::ios::trunc | std::ios::binary);
    if (!fout.is_open()) {
      return false;
    }
    return resourceMappings.SerializeToOstream(&fout);
  }
}

/**
 * Tell the optimizer whether it's needed to dump information for de-obfuscating.
 *
+3 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
#include <set>
#include <string>

#include "ResourceMetadata.pb.h"
#include "ResourceTable.h"
#include "android-base/function_ref.h"
#include "android-base/macros.h"
@@ -38,6 +39,8 @@ class Obfuscator : public IResourceTableConsumer {

  bool Consume(IAaptContext* context, ResourceTable* table) override;

  bool WriteObfuscationMap(const std::string& file_path) const;

  bool IsEnabled() const;

  enum class Result { Obfuscated, Keep_ExemptionList, Keep_Overlayable };
+60 −0
Original line number Diff line number Diff line
@@ -21,10 +21,14 @@
#include <string>

#include "ResourceTable.h"
#include "android-base/file.h"
#include "test/Test.h"

using ::aapt::test::GetValue;
using ::testing::AnyOf;
using ::testing::Eq;
using ::testing::HasSubstr;
using ::testing::IsTrue;
using ::testing::Not;
using ::testing::NotNull;

@@ -236,4 +240,60 @@ TEST(ObfuscatorTest, IsEnabledWithShortenPathAndCollapseStringPoolOption) {
  ASSERT_THAT(obfuscatorWithCollapseStringPoolOption.IsEnabled(), Eq(true));
}

static std::unique_ptr<ResourceTable> getProtocolBufferTableUnderTest() {
  std::string original_xml_path = "res/drawable/xmlfile.xml";
  std::string original_png_path = "res/drawable/pngfile.png";

  return test::ResourceTableBuilder()
      .AddFileReference("com.app.test:drawable/xmlfile", original_xml_path)
      .AddFileReference("com.app.test:drawable/pngfile", original_png_path)
      .AddValue("com.app.test:color/mycolor", aapt::ResourceId(0x7f020000),
                aapt::util::make_unique<aapt::BinaryPrimitive>(
                    uint8_t(android::Res_value::TYPE_INT_COLOR_ARGB8), 0xffaabbcc))
      .AddString("com.app.test:string/mystring", ResourceId(0x7f030000), "hello world")
      .Build();
}

TEST(ObfuscatorTest, WriteObfuscationMapInProtocolBufferFormat) {
  OptimizeOptions options{.shorten_resource_paths = true};
  options.table_flattener_options.collapse_key_stringpool = true;
  Obfuscator obfuscator(options);
  ASSERT_TRUE(obfuscator.Consume(test::ContextBuilder().Build().get(),
                                 getProtocolBufferTableUnderTest().get()));

  obfuscator.WriteObfuscationMap("obfuscated_map.pb");

  std::string pbOut;
  android::base::ReadFileToString("obfuscated_map.pb", &pbOut, false /* follow_symlinks */);
  EXPECT_THAT(pbOut, HasSubstr("drawable/xmlfile.xml"));
  EXPECT_THAT(pbOut, HasSubstr("drawable/pngfile.png"));
  EXPECT_THAT(pbOut, HasSubstr("mycolor"));
  EXPECT_THAT(pbOut, HasSubstr("mystring"));
  pb::ResourceMappings resourceMappings;
  EXPECT_THAT(resourceMappings.ParseFromString(pbOut), IsTrue());
  EXPECT_THAT(resourceMappings.collapsed_names().resource_names_size(), Eq(2));
  auto& resource_names = resourceMappings.collapsed_names().resource_names();
  EXPECT_THAT(resource_names.at(0).name(), AnyOf(Eq("mycolor"), Eq("mystring")));
  EXPECT_THAT(resource_names.at(1).name(), AnyOf(Eq("mycolor"), Eq("mystring")));
  auto& shortened_paths = resourceMappings.shortened_paths();
  EXPECT_THAT(shortened_paths.resource_paths_size(), Eq(2));
  EXPECT_THAT(shortened_paths.resource_paths(0).original_path(),
              AnyOf(Eq("res/drawable/pngfile.png"), Eq("res/drawable/xmlfile.xml")));
  EXPECT_THAT(shortened_paths.resource_paths(1).original_path(),
              AnyOf(Eq("res/drawable/pngfile.png"), Eq("res/drawable/xmlfile.xml")));
}

TEST(ObfuscatorTest, WriteObfuscatingMapWithNonEnabledOption) {
  OptimizeOptions options;
  Obfuscator obfuscator(options);
  ASSERT_TRUE(obfuscator.Consume(test::ContextBuilder().Build().get(),
                                 getProtocolBufferTableUnderTest().get()));

  obfuscator.WriteObfuscationMap("obfuscated_map.pb");

  std::string pbOut;
  android::base::ReadFileToString("obfuscated_map.pb", &pbOut, false /* follow_symlinks */);
  ASSERT_THAT(pbOut, Eq(""));
}

}  // namespace aapt