Migrating from ProGuard or DexGuard to DashO

DashO 10 is now available, with support for R8. Migration to DashO is now easier than ever!

Over the past year, we have seen an influx of developers looking to replace existing ProGuard and DexGuard implementations with DashO. While the three products are conceptually similar, we have found that there are important differences between the products, and those differences can lead to unexpected migration issues. This article summarizes many of the tips and techniques our support team has been refining, to shorten your learning curve and simplify your migration.

This article:

  • Provides a logical mapping of features between the three products.
  • Recommends specific patterns to:
    • Simplify and shorten your migration.
    • Improve the strength and effectiveness of your application protection.
    • Optimize and automate ongoing app protection to reduce the cost and complexity of maintaining protection.

Similarities and differences

At first glance, the three products offer a common set of features. All three:

  • Process compiled Java bytecode, producing new bytecode that has been obfuscated and modified in other ways.
  • Offer multiple ways to run from build scripts and to use project-specific config files.
  • Share similar configuration concepts including inputs, support libraries, entry points (-keep rules in ProGuard), exclusions, and detailed settings to fine-tune behavior.
  • Include incremental obfuscation and stack trace de-obfuscation.

However, there are important differences within these common feature categories.

Platform support: DexGuard is Android-only, while ProGuard and DashO both work on many types of Java applications (including Android). Developers cannot select DexGuard for non-Android applications.

Feature support: DashO and DexGuard offer a significantly broader collection of protection controls than does ProGuard. Users migrating from ProGuard will have new protection controls to evaluate, activate, and configure.

Development patterns: Many DexGuard features are API-based, and as such, require app code changes or additions. DashO is able to inject the corresponding features post-compile, without additional app development. (Note that DashO can also inject custom code, to support app-specific behavior.)

Configuration complexity: DashO includes a sophisticated GUI that serves as the primary configuration interface. The GUI loads bytecode, shows class trees to help configure inclusions and exclusions, and has built-in rules to prevent “illegal” configurations.

DashO’s GUI also includes a Project Wizard that automates much of the work of configuring a new project.

ProGuard and DexGuard only support text-based configuration. The available GUIs are little more than structured text editors, and do not include a Project Wizard. Developers have to rely on copying examples and manually entering names, which is error prone.

Pre-built Android SDK integration: ProGuard is built into the Android SDK, and some of the initial ProGuard configuration is automatic, for Android. DashO and DexGuard are independent tools that must be integrated into the build process.

Gradle integration assumptions

ProGuard’s Gradle docs (i.e. those published by GuardSquare) recommend integrating ProGuard into an Android build via a custom Gradle task. This it not a common Gradle integration pattern. (It is more typical of build systems like Ant.)

Android’s ProGuard docs (i.e. those published by Google) say “just turn it on”. This is feasible because ProGuard is distributed as part of Google’s Android Gradle plugin, and ProGuard is configured to work like a typical Gradle plugin.

Either approach can work, but “the Gradle way” is to integrate as a plugin. This article assumes that you have followed the Android instructions accordingly.

DashO can also be integrated either way, but it is optimized to be used as a plugin, and that’s the approach this article describes.

DashO and DashO Gradle Plugin versions

This article is based on DashO v8.5.0 and DashO Gradle Plugin v3.1.0. Please use those versions, or newer. Note that upgrading to DashO Gradle Plugin v3.1 might require upgrading the Android Gradle plugin version to v3.1.

In general, you should use the latest available version of DashO and of DashO Gradle Plugin. We continuously optimize and extend both components to improve protection, integration, and ease of use.

Migrating an Android application

This article focuses on migrating an Android application, but the ideas presented here are applicable to migrating Android libraries or non-Android (e.g. desktop) applications, too.

We’ll start by focusing on ProGuard. Most of the details are the same for DexGuard; we’ll cover DexGuard-specific issues later.

Migrating from ProGuard

To integrate ProGuard into an Android app, the usual approach is to:

  1. Update build.gradle per the documentation.
  2. Build, and troubleshoot any build issues (e.g. configure custom -keep rules, etc.).
  3. Run the app and troubleshoot any run-time issues (and re-configure ProGuard and re-build and re-run).
  4. Configure your build process to preserve the ProGuard map file so you can deobfuscate stack traces in the future.
  5. Continue to fine-tune the configuration, as needed.

DashO’s process is different because it has a New Project Wizard that can identify and auto-configure many parts of DashO, specifically for your app. It will also integrate DashO into your Gradle build for you.

DashO integrates into Android’s Gradle plugin in place of ProGuard. This approach simplifies the build integration by e.g. ensuring that up-to-date checking works correctly. Therefore, the first step of integrating DashO is to remove the ProGuard configuration.

To migrate from ProGuard to DashO, use this process:

  1. Remove the ProGuard configuration
    • Typically, this means removing any minifyEnabled statements (DashO will put new ones in) and any proguardFiles (or proguardFile) statements.
    • Some projects might also have ProGuard-specific paths in the repositories or dependencies sections; if so, remove them.
    • If you have any custom build steps to preserve the map file, comment those out. (You might want this code when you need to start preserving the DashO map file.)
    • You might want to remove any ProGuard-specific config files (e.g. proguard-rules.pro) from source control.
  2. Build the app for release
    • This build will be unobfuscated, because ProGuard has been removed.
  3. Run the New Project Wizard
    • Run DashO and the New Project Wizard will appear (unless disabled). The Wizard can also be started from the menu or the toolbar.
    • Click through and choose “Android” and “Gradle” at the appropriate places.
    • When it asks for a project directory, use the directory where your main app is built. That might be the root of your project or it might be a subdirectory if you have a multi-project build (i.e. with a settings.gradle).
    • DashO will analyze your project and prompt you to configure your inputs, libraries, entry points, and whether you want to make a flavor-specific build. (It will attempt to auto-discover most of these things.)
      • On the Add Jars page of the Wizard, you should see one Input in the list, corresponding to the build output directory of your project (e.g. build/intermediates/classes/<flavor>/<type>). If the Wizard also found additional .jar files (e.g. from your project’s libs/ directory), please Remove those, to make the initial configuration simpler. (DashO will still find them and use them, if they are needed, even if we remove them now.)
    • Finish working through the Wizard, and click Finish.
    • DashO will generate a custom config and automatically integrate itself into your Gradle build, according to your choices.
  4. Fine-tune the configuration
    • If you are building an Android application (vs. a standalone library), set Unused Classes and Unused Members to Remove, if they aren’t already set that way. (A future version of DashO will make these values the default, for Android applications.)
    • If you use Crashlytics, edit the dasho.gradle file (that the Wizard created for you, in your app directory) and add transformName = 'proguard' to the dashOConfig closure. (The DashO Wizard will configure DashO to generate a ProGuard-compatible map file, which Crashlytics will automatically pick up and use, but the Crashlytics Gradle plugin will generate an error if minifyEnabled is true but it can’t find a build task named “proguard”. This change works around that error.)
  5. Build
    • Build your release configuration, from Gradle.
    • Troubleshoot any build issues. See the Troubleshooting notes below, if needed.
  6. Run the app
    • Troubleshoot any run-time issues (and re-configure DashO and re-build and re-run).
    • If you had any custom ProGuard configuration rules (e.g. -keep), it might help to review those rules and migrate them to your DashO config. See the table below for details.
  7. Preserve the DashO map file(s)
    • This is specific to your environment; you should configure your build to save the map file so you can deobfuscate stack traces in the future. If you were doing this before with ProGuard or DexGuard, the same process should work for DashO.

You can see an example of how the Wizard will modify your Gradle build in the obfuscated branch of our DashO-GameOfLife sample on GitHub. Specifically, the Wizard will:

When integrating into a highly-customized build, the Wizard might error while trying to update build.gradle. In such cases, the Wizard will still configure as much as it can, but check the list above to see if anything is missing. You can also refer to our troubleshooting section below for further resources.

Advanced protection

At this point, DashO is integrated and the app has an higher level of protection than it had with ProGuard. Notably, DashO has Control Flow and String Encryption and they are enabled by default.

From here, there are two primary ways you can further improve the level of protection.

First, convert some or all of your libraries to be inputs so they will be obfuscated as well.

For Android Gradle projects, the Inputs are managed by Gradle (and are passed to DashO via the ${gradleInputs} property), so input configuration is done on the Gradle side via the includeAsInputs array in the dashOConfig closure in dasho.gradle. (There are also some shorthand ways to specify libraries, for Android.)

By default, the Wizard configures your primary application as the only input. Your in-house libraries, and any third-party libraries, will be configured as support libraries. (i.e. the includeAsInputs array will be unspecified, or empty.)

This makes it easier to get started, and you should keep this configuration until you have your build working. Then, to improve protection, convert your libraries over to be inputs (i.e. list them in the includeAsInputs array), so they are obfuscated as well.

Second, start using DashO’s advanced features, most notably, Checks. Checks are code that DashO injects into your app, during the build, that detect certain conditions (e.g. whether the app has been tampered) and can either call custom code that you specify, or automatically perform certain actions (e.g. throw a random exception). Checks can also call custom code that you develop, to respond in application-specific ways.

Checks provide run-time security to better protect your app against tampering, unauthorized inspection, and reverse engineering. These controls extend app security beyond the app itself, to the data that flows through the app as it runs. Checks are a powerful way to prevent, detect, and defend against counterfeiting, malware insertion, data theft, piracy, vulnerability analysis, and more.

As of this writing, DashO includes four Checks for Android:

  • Root – Is the application running on a rooted device?
  • Tamper – Has the application been tampered with?
  • Debug – Is the application being debugged and/or does it allow debugging?
  • Shelf Life – Has this application expired (or will it expire soon)?

To integrate Checks, use the Injection section of the user interface, and/or see the documentation for help.

Troubleshooting

There are a few common situations that might come up during or after the initial Wizard integration, and a few frequently-used techniques that can help sort them out.

First, don’t hesitate to take advantage of the fact that DashO users always have access to our world-class support team. We’d be happy to help you with any issues you have during your migration.

Second, make sure you are using the correct version of DashO, DashO Gradle Plugin, and Android Gradle Plugin.

Third, make sure your Inputs are configured correctly.

Check (in the DashO UI, on the Inputs page) that the only DashO input is ${gradleInput}. Remove any additional values, and (if desired) configure those inputs via includeAsInputs, per above.

If DashO is still reporting errors about missing classes or methods, you can try enabling Ignore Missing Classes and/or Ignore Missing Methods on the Input – Options screen.

Fourth, review the Entry Points to be sure they are correct. (Note that additional Entry Points may be shown on the Special Classes screen.) Entry Points are the places where your application is called by the operating system (i.e. Android), or by any code reflection. DashO needs to know about all entry points to ensure it doesn’t remove or rename things that are referenced by name at run-time.

Most entry points will be automatically discovered by the Wizard, but any that are missed will cause run-time issues. If you have any manually-configured -keep rules in your ProGuard configuration, they might need to be manually converted to entry points in DashO.

Fifth, if you have any ProGuard rules that use the implements or extends keywords to match a set of subclasses, you will need to configure each matched class individually in DashO. DashO does not (as of this writing) have a corresponding way to configure a group of related entry points all at once.

Sixth, try enabling verbose mode in the DashO Gradle plugin. You can also run gradle with -DSHOW_DASHO_CMD to see additional detail about how DashO Gradle Plugin calls DashO.

Finally, our Gradle plugin has detailed Troubleshooting documentation that can help with any Gradle-specific error messages you are seeing. (For general DashO build errors, please refer to the DashO User Guide.)

Migrating from DexGuard

Most of the guidance from the ProGuard migration process applies to migrating from DexGuard, but there are a few important additional details.

First, DexGuard’s Gradle configuration is typically more complex, so removing it typically requires more work:

  1. In most cases, you will need to remove lines from one or more gradle files (e.g. build.gradle):
    • flatDir repository reference to the DexGuard install directory.
    • classpath dependency reference to the DexGuard plugin.
    • An apply plugin: 'dexguard' line.
  2. DexGuard also typically takes over more parts of the build process, so verify that e.g. packaging and signing are working as expected after DexGuard is removed. (DashO can be configured to perform these steps as well, under different integration scenarios, but typically it isn’t necessary to do so.)

Second, some of DexGuard’s advanced features (e.g. custom encryption, or DexGuard’s versions of DashO’s Checks) depend on extra libraries that must be integrated into your project, and on extra code that you write into your application. Removing those libraries and that additional code requires additional work:

  1. You may want to remove those libraries from your source control.
  2. If you wrote code that calls into those libraries, that code will need to be removed.
  3. You might also have written code that was called by those libraries, which you might wish to remove, or to preserve for use by DashO.
    • Note, however, that DashO’s checks are injected, and can inject certain response behaviors (e.g. hang, crash, or close) automatically. If your response code is just e.g. throwing an exception, you might not need to preserve it, because you can configure DashO to inject the same behavior automatically.

Third, as with ProGuard, DexGuard does not include Control Flow obfuscation and does not turn String Encryption on by default. DashO includes both, and they are on by default (for Android).

Finally, as before, configure Checks in DashO. In this case, however, you might be able to reuse any custom response code that you wrote for DexGuard by configuring DashO to call it when Checks are triggered.

Mapping Common ProGuard and DexGuard features to DashO

The following table will help you map your ProGuard or DexGuard settings to DashO:

ProGuard optionCorresponding DashO feature
-adaptresourcefilecontentsDashO automatically identifies and updates resource file references as needed.
-dontoptimizeDisable optimization globally or for particular packages, classes, or methods.
-injarsFor Android projects, this is handled automatically but can be customized via includeAsInputs in the Gradle configuration. Non-Android projects configure Inputs in DashO.
-keepEntry Points, possibly configured as Android Special Classes for Android apps. The Wizard will usually find and configure these.
-keepattributesConfigure which attributes should be removed or preserved. The Wizard will usually configure these appropriately.
-keepclassmembersThis does not directly translate, but can be approximated. Configure a Renaming exclusion and uncheck Selects Class. You can also configure a Removal exclusion but that will preserve the class as well.
-keepnamesConfigure a Renaming exclusion.
-libraryjarsFor Android projects, this is handled automatically but can be customized via includeAsInputs in the Gradle configuration. Non-Android projects configure Inputs (as support libraries) in DashO.
-overloadaggressivelyThe Overload Induction option for Renaming is on by default.
-repackageclassesConfigure package flattening.
-verboseEnable verbose output.

Wrapping up

We are always interested in feedback from our users. If you have any feedback about this process (good or bad!), we’d love to hear it. Please reach out to our support team or sales team with your questions and comments.

And welcome to DashO!

DexGuard and GuardSquare are trademarks of GuardSquare NV.