Tamper Check and Response
PreEmptive Protection™ DashO™ for Android & Java can inject checks into applications to detect if they have been tampered with. Tamper checking requires that your application be signed either by DashO or by another process following processing by DashO. The Tamper Checks and Responses are configured via the Checks - Tamper or by adding code annotations.
Tamper Check
To detect tampering place a TamperCheck on one or more methods in your application. DashO adds code that performs a runtime check that verifies the code has been signed by a particular certificate. This Check can be configured as described in the Overview, but may also require signing information.
An application can contain multiple uses of TamperCheck
with various configurations.
Using more than one Check or mixing the Responses will hamper attackers.
private static boolean tamperFlag;
@TamperCheck(action="@tamperFlag")
public static void main(final String[] args){
}
@TamperCheck(response=ResponseType.Hang)
private int computeResult(){
}
Interaction with Signing
The Tamper Check is performed by verifying at runtime that the code has been signed by a particular certificate. If DashO is used to sign the resulting jars, then no further configuration is required. If the jars are signed by another process, after they have been obfuscated using DashO, you need to tell DashO about the signing information with additional attributes of the TamperCheck. This allows DashO to retrieve the key information required to perform the runtime tamper checking. The information specified is similar to what is found on the Output Signing page.
@TamperCheck(action="@tamperFlag", storepass="${master.psw}",
storetype="JKS", alias="ProdKey")
public static void main(final String[] args){
}
When you use the user interface to enter a password for storepass
value and it does not contain property references DashO will store the password in an encrypted form.
Notes:
If your application uses a custom class loader, make sure it loads the signing certificates.
For Example: In an OSGI (Eclipse Equinox) based application, you must configureosgi.signedcontent.support
. It needs to allow at leastcertificate
and you cannot setosgi.support.class.certificate
tofalse
.
If your application utilizes code generation, make sure it works properly with signed jars before adding Tamper Detection. You may need to sign the jars which generate the code with the same certificate.
For Example: In a Spring-based application, you would need to signspring-core-4.0.1.RELEASE.jar
(or a similar jar).
The Tamper Check for Android requires access to the application's context; it expects agetApplicationContext()
method to exist on the class where it is being injected. Classes extendingandroid.context.Context
, likeandroid.app.Activity
,android.app.Application
,android.app.Service
, etc. will inheritgetApplicationContext()
, and require no additional changes. Otherwise, you will need to add agetApplicationContext()
method and make sure it returns a properContext
.
Tamper Checks will only work properly on libraries if they are not merged into an application, or if the application is signed by the same certificate used by the Tamper Check. For example, an Android library (AAR) that has Tamper Checks will behave as though it was tampered when it is merged into an Android application (APK), unless the application is signed with the certificate used by the Tamper Check.
If you are using key rotation and your application requires Android Pie (or later), use the last alias in the rotation. Otherwise, you need to provide the first alias in the rotation.
Tamper Response
The TamperResponse annotation interacts with the TamperCheck. This Response can be configured as described in the Overview.
private static boolean tamperFlag;
@TamperCheck(action="@tamperFlag")
public static void main(final String[] args){
}
@TamperResponse(source="@tamperFlag", response=ResponseType.Exit, probability=0.05f)
private int computeResult(){
}
@TamperResponse(source="@tamperFlag", response=ResponseType.Error, probability=0.1f)
private FileInputStream readInput(){
}
Google Play App Signing
If you have opted into Google Play App Signing, then Google will manage the final signing of Android apps that are served in the Google Play Store, which requires careful configuration when you are using Tamper Checks.
If you elect to use this service, you will have two signing keys: an upload key with which you sign your app or app bundle before submitting it to Google, and an app signing key with which Google signs your APKs for distribution in the Google Play Store. When using Tamper Check with Google Play App Signing, it is important to configure the Tamper Check to verify that the app signing key has been used to sign the app, rather than the upload key.
You can do this by downloading the app signing certificate from the Google Play Console, importing the certificate into a keystore as a trusted certificate, and configuring your Tamper Check to use that certificate.
Note:
If you have configured your Tamper Check in this manner, then it will behave as though it has been tampered if you try to run it when it is signed with the upload certificate.