Introduction
PreEmptive Protection - DashO is an application hardening and obfuscation tool for Java, Android, and Kotlin applications. DashO works in several ways to protect your library or app. First, it obfuscates the compiled code, altering it so that it is more difficult to analyze using static techniques. Second, it injects code to detect and respond to tampering and debugging attempts, making it hard to analyze dynamically. Third, it provides a means to detect tampering, debugging, or Android rooting and to respond to these events via standard or custom responses.
Why Protect?
Obfuscation is a means of risk mitigation. In the modern world, there are many risks to software, including:
- Various kinds of theft (of trade secrets or other intellectual property)
- Loss of revenue (through piracy)
- Exposure or loss of data (including personally identifiable information)
- Defacement and brand-dilution (through piracy)
The applicability or severity of any particular risk to your product or domain may vary, but no product is free from all risks.
Modern software is seldom isolated – it typically acts as a single component in a larger interconnected system. Defense in depth requires protection at each layer of a system. DashO's hardening can be a significant component of a secure strategy. This may include elimination of potential attack vectors entirely through tamper detection. This could also include reducing attack surface area though unused code removal. Additionally, in the United States there may be legal protections afforded to your software by demonstrating an intent to protect trade secrets with obfuscation.
Why DashO?
We take pride in the fact that we keep DashO up-to-date with the latest features of the Java Language, the JVM specification, and frequent updates to the Android development landscape.
DashO is a mature product that has been developed over the course of two decades. It has weathered the storm of Java projects in the field, and the vast majority of the snags in using the technology have already been encountered and fixed, or otherwise resolved (e.g. support for Spring Framework, Dynamic Class Loading, etc.).
How it works
You create a project configuration using our graphical user interface ("GUI"), optionally using our step-by-step wizard. DashO then applies that configuration to your app in a post-compile build step, in the case of Java, or within the Gradle build, in the case of Android. This means that your application can be protected entirely without making code changes.
The DashO build can be run directly from within the GUI, or can be integrated into your continuous-integration build using the command-line interface ("CLI"), Gradle, or Ant.
Once obfuscation is complete, several files are produced that can be reviewed or preserved for future reference:
- A report of what obfuscation was applied
- A report about what renamings were applied
- A renaming map describing the mapping from old name to new
- A string encryption map describing how strings were encrypted
Getting Started
If you have not already purchased DashO and just want to try it out, you can register and download an evaluation. Once you have downloaded the evaluation, you should receive an email with a time-limited serial number that will let you run the product.
Once installed, you can create a project using the step-by-step Wizard, or use the User Interface to create a project from scratch. You can also use our Sample Applications as a guide.
When you're ready, please contact us to get more information about sales and support.
Features
All of DashO's features can be configured through the GUI. Additionally, check-related features may also be configured through use of code annotations, if that is more convenient for your development approach. Finally, if needed, the configuration .dox
files may be adjusted by hand.
Obfuscation
Obfuscation in DashO is comprised of three techniques: renaming, control-flow, and string encryption. Additionally, minor code updates may take advantage of incremental obfuscation.
Renaming Obfuscation
DashO Renaming Obfuscation can rename classes, methods, fields, annotations, and package hierarchies. Source code is intended to be read by two audiences: computers and humans. Much of what is only useful to the human audience is preserved in the compiled bytecode, including method names, etc. Renaming strips all of this information from the bytecode – replacing semantic names with otherwise meaningless unique names (e.g. a
, b
, etc.).
In Java, a method call foo(bar)
could refer to two different overloads of foo
, e.g. foo(int)
or foo(String)
. Resolution based on the type of bar
happens at compile-time. The JVM treats two methods in a class with the same name but different parameter lists as unrelated. DashO takes advantage of this, providing a feature named Overload-Induction™, to rename methods to the same name so long as they have distinct parameter lists. The result is that the would-be reverse-engineer cannot even take advantage of method overloading as a hint to understand the code.
Once deployed, if your renaming-obfuscated app encounters exceptions, any emitted stack trace will use the renamed package, class, and method names. DashO will let you decode the stack trace using the renaming map file preserved from the build. This can be done in the DashO GUI, or it can be done using DashO Lucidator, a stand-alone command-line application.
Control-Flow Obfuscation
DashO Control-Flow Obfuscation alters the code to make it harder to understand without changing its function. One of the goals of this is to remove patterns that decompilers look for when trying to reconstruct the source code. DashO can optionally add try-catch blocks and split existing blocks. Both of these add additional control flow to further confuse decompilers.
String Encryption Obfuscation
String literals in source code are preserved in the constant pool in compiled .class
files. DashO String Encryption Obfuscation replaces these with encrypted values that are decrypted in the running application as they are used. The default encryption in DashO is balanced in terms of security and run-time efficiency, but you may optionally provide your own custom encryption algorithms.
Incremental Obfuscation
If your app is built as a collection of jars, each jar could be obfuscated independently as a library, leaving the public interface of each unrenamed. However, since you want to rename all internal methods, you will want to obfuscate the all of the jars in a single DashO build. Now suppose you need to update just one of those dependencies. Rerunning the DashO build could choose all different names, and references in the dependent jars might no longer be valid.
DashO provides Incremental Obfuscation as an option. The renaming map and string encryption map from a prior build are passed to DashO to be reused. This way the same encryption algorithms are used, and new names are only chosen for newly added identifiers. Thus, in our example, the modified dependency could be recompiled, obfuscated with incremental obfuscation, and then updated independently of the other jars.
Runtime Checks
Checks allow your executing code to respond to conditions detected in the execution environment. You can configure how to respond, using a canned response or provide your own custom action. Canned responses include setting a flag, terminating the application, terminating with a random exception, and hanging indefinitely.
Runtime checks provide means to obscure the code site where the check is happening. A separate Response object is available for most Checks. The Checks and Responses can work in tandem. They can be injected into different methods, or even different classes. Thus the place in the app that takes action based on the Check can be unrelated to the place where it determines that it should do so. A probability percentage can also be specified to reduce the reproducibility of the Response's behavior.
These features can be used in combination, so an app could be "aware" that it has been tampered with, but not immediately reveal that fact to a would-be attacker. Place a check in one or two places early in execution, and then sprinkle responses throughout various features, each with some probability of terminating the app.
Checks and Responses can be configured either by adding annotations to your source code, or by configuring them in the GUI.
Debug Checks
DashO Debugging Check lets your code detect and respond to being actively debugged in a debugger.
With Java and Android, an app must be started with debugging enabled in order to debug it. DashO Debug Enabled Check allows your code to respond to being started with debugging enabled, even if a debugger has not attached to the running process.
Root Check
DashO Root Check lets your code detect and respond when it is being run on a rooted Android device.
Shelf Life Check
DashO Shelf Life Check verifies that a particular instance of the app has not expired. Relative or absolute expiration date can be specified explicitly at build time, or it can be based on a token. This token can be provided to the check as a resource in a jar or through arbitrary means via your custom code. Shelf Life Check can also be configured to provide a warning period prior to expiration. A command-line utility, tokengenerator
, is available for generating Shelf Life Tokens.
Tamper Check
DashO Tamper Check works in tandem with jar signing to verify that the running code has not been tampered with since you built it. Similarly for Android, Tamper Check works in tandem with APK signing.
Removal
DashO Removal removes unused classes and members. As methods are parsed, referenced classes, methods, and fields are marked as used. Anything not marked as used is a candidate for removal. Specifying entry points allows DashO to accurately determine what is unused. For libraries, Removal can be configured to only remove unused members or classes that are not public. Removal also strips debug information and non-essential attributes from .class
files.
DashO Method Call Removal removes method calls from code. This can be very useful for calls that may be appropriate in development, may not be desirable for production, for which it would be impractical to remove by hand. A prime example of this is Android logging removal.
Optimization
DashO Optimization speeds up your code and reduces resulting binary size, by performing algebraic identity, strength reduction, and other peephole optimizations.
PreMark
DashO PreMark lets you watermark your app. Watermarking is used to unobtrusively embed data into an application without impacting its runtime behavior. There are two different ways to apply this technique.
In the first approach, the watermark is configured in the GUI and applied in the DashO build. This watermark could contain information such as a copyright. Being applied during the DashO build, there would, ostensibly, be only a single watermark for all distributed copies of that version of the app.
In the second approach, the watermark is applied in an automatable post-build process using our stand-alone command-line utility. This watermark could contain a serial number or other identifier. The intention being that each distributed copy of the app would have a unique identifier. In doing so, DashO watermarks can be used to track unauthorized copies of software back to their source.