Android application developers lose billions of dollars every year due to illegal copying and distribution of their products. According to data App Annieup to 25% of all installations of mobile applications are from pirated versions, and in some regions (for example, in Southeast Asia) this figure reaches 60%. Protecting an application from copying is not just a matter of preserving revenue, but also a matter of brand reputation, security of user data and compliance with license agreements.
In this article we will look at 7 proven protection methodsfrom basic (code obfuscation) to advanced (server-based license validation), and also consider tools that will help automate the process. We will pay special attention practical nuances: how to bypass restrictions Google Play, why some methods only work on rooted devices, and how not to lose legitimate users, strengthening protection. If you are the owner of a startup, an indie developer or a representative of a large company, here you will find a solution to suit your needs.
1. Code obfuscation: the first barrier for hackers
Obfuscation is the process of converting source code into a hard-to-read form without changing its functionality. In the context of Android, it solves two problems: it complicates reverse engineering (APK decompilation) and hides the logic of the application, including licensing or authentication algorithms.
The most popular tool for obfuscation of Android applications is ProGuard. built in Android Studio. It removes unused code, renames classes and methods into meaningless sequences of characters (for example, a.b() instead of LicenseChecker.verify()). However, ProGuard has limitations:
- ๐น Does not encrypt string resources (they can be extracted from
resources.arsc). - ๐น Does not protect against dynamic analysis (for example, through Frida or Xposed).
- ๐น Requires manual configuration
proguard-rules.profor libraries (for example, Retrofit or Firebase).
For enhanced protection, use DexGuard (commercial version of ProGuard) or Obfuscator-LLVM โthey add string encryption, code integrity control and debugging protection. Example configuration for DexGuard:
-keep class com.example.license.** { *; }-renamesourcefileattribute SourceFile
-optimizationpasses 5
-dontshrink
โ ๏ธ Attention: Obfuscation does not protect against copying of an APK file from the user's device. It only complicates code modification. Additional methods are required for full protection.
2. APK integrity check: detecting changes
Pirates often modify APK files by removing checks. licenses or introducing advertising. To detect such changes, use checksums (hashes) or digital signatures. Working algorithm:
- When building the application, calculate the hash of the original APK (for example,
SHA-256). - Embed this hash into the application code (for example, in
AndroidManifest.xmlas metadata). - At each launch, compare the hash of the current APK with the reference one.
Example code in Kotlin for checking the hash:
fun verifyApkIntegrity(context: Context): Boolean {val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0)
val apkPath = packageInfo.applicationInfo.sourceDir
val expectedHash = "YOUR_EXPECTED_SHA256_HASH" // Hash of the original APK
val actualHash = File(apkPath).inputStream().use { input ->
MessageDigest.getInstance("SHA-256").digest(input.readBytes()).joinToString("") {
"%02x".format(it)
}
}
return actualHash == expectedHash
}
If the hashes do not match, the application can:
- ๐ Block the launch with a notification to the user.
- ๐ Send a report to the server (with IP and device data).
- ๐ Go to "demo mode" with limited functionality.
โ ๏ธ Attention: The APK hash will change after any update. Do not forget to update the reference value in the code with each release.
3. data-i="82">(LVL) is an official mechanism for checking the legality of installing an application. It works on the principle of a request to Google servers: the application sends
Google Play Licensing (LVL) is the official mechanism for verifying the legality of an application installation. It works on the principle of a request to Google servers: the application sends unique device identifier and receives a response about the license status (LICENSED, NOT_LICENSED or RETRY).
Advantages of LVL:
- ๐ Integration with Google infrastructure (no need to deploy your own server).
- ๐ฑ Support for offline mode (response caching for 1โ7 days).
- ๐ก๏ธ Protection against response substitution via certificates.
How to configure LVL:
- Add the library to
build.gradle:implementation 'com.google.android.vending:license:8.3.0' - Generate a license key in Google Play Console (
Settings โ Licensing and in-app purchases). - Implement a response handler:
class LicenseCheckerCallback : LicenseCheckerCallback {override fun allow() { / Allow access / }
override fun dontAllow() { / Block / }
override fun applicationError(errorCode: Int) { / Handle error / }
}
LVL restrictions:
- โ Does not work for applications distributed outside Google Play.
- โ Pirates can block requests to Google servers via
hostsor VPN. - โ Requires an Internet connection (albeit with caching).
Add dependency to build.gradle|
Generate a key in Google Play Console|
Implement LicenseCheckerCallback|
Test on an emulator with a fake response (RESPONSE_NORMAL)|
Configure offline mode processing-->
4. Server validation: maximum protection
The most reliable, but also the most complex method is checking the license on your server. Operating principle:
- The application sends unique device data (IMEI, Android ID, MAC address, etc.) to the server.
- The server checks whether this ID is associated with a legal purchase.
- Returns the access token that the application caches.
Advantages:
- ๐ Works for any distribution channels (including third-party stores).
- ๐ง Flexible logic (you can block devices suspected of piracy).
- ๐ Ability to collect statistics on illegal installations.
Architecture example:
| Component | Responsibility | Tools |
|---|---|---|
| Android application | Collecting device data, sending a request, processing a response | Retrofit, OkHttp |
| Backend | License verification, token generation, logging | Spring Boot, Node.js, Firebase Functions |
| Database | Storing a list of legal devices/purchases | PostgreSQL, MongoDB |
| Admin panel | Manual unlocking, analytics | AdminJS, custom solution |
Key points of implementation:
- ๐ Use JWT tokens with a short lifetime (1โ24 hours).
- ๐ Implement a mechanism for updating the token without re-validation.
- ๐ก๏ธ Encrypt traffic (HTTPS + certificate pinning).
โ ๏ธ Attention: Collection of unique device identifiers (IMEI, MAC) may conflict with privacy policy (for example GDPR in the EU Use anonymized hashes or request explicit consent). user.
How do they bypass server validation?
Pirates can:
1. Substitute the response server via a MITM attack (if certificate pinning is not used).
2. Emulate a server on a local device (for example, through Charles Proxy).
3. Change application logicso that it always considers the response valid (via APK patching).
To complicate such attacks, combine server-side validation with APK integrity checking and obfuscation.
5. Protection against debugging and reverse engineering
Even if the code is obfuscated, attackers can analyze the behavior of the application at runtime using debuggers (JDB, IDA Pro) or frameworks like Frida. To complicate their task:
- ๐ ๏ธ Disable debugging in the release build:
android:debuggable="false"in
AndroidManifest.xml. - ๐ Check for the presence of a debugger:
if (Debug.isDebuggerConnected() || Debug.waitingForDebugger()) {// Blocking or false data
} - ๐ Use Native Code (C/C++): Move critical checks (for example, licensing) to native-libraries (.so files). They are more difficult to decompile.
- ๐ซ Block tools like Frida:
if (checkFrida()) {throw SecurityException("Tampering detected")
}
For detection Frida you can check:
- Presence of processes (
frida-server). - Loaded libraries (
libfrida-gadget.so). - Open ports (27042โ27047).
Example code for checking Frida on Kotlin:
fun checkFrida(): Boolean {return try {
System.loadLibrary("frida-gadget") // Attempting to load the Frida library
true
} catch (e: UnsatisfiedLinkError) {
false
}
}
To protect native code, use LLVM Obfuscator or Ollvm. These tools convert binary files into equivalent but unreadable code, maintaining performance.
6. Linking to the device and hardware keys
One of the radical methods is binding the application to the unique characteristics of the device. complicates the transfer of a pirated copy to other gadgets. Implementation options:
- ๐ฑ IMEI/MEID: Unique device identifier (requires permission
READ_PHONE_STATE). - ๐ Android ID: Identifier reset only after resetting the device (
Settings.Secure.ANDROID_ID). - ๐พ Serial Number: Device serial number (
Build.SERIAL). - ๐ Hardware Fingerprint: Combination of several parameters (model, manufacturer, OS version, etc.).
Example of generating a hardware fingerprint:
fun getDeviceFingerprint(context: Context): String {val telephonyManager = context.getSystemService(TELEPHONY_SERVICE) as TelephonyManager
val androidId = Settings.Secure.getString(context.contentResolver, Settings.Secure.ANDROID_ID)
val serial = Build.SERIAL ?: "unknown"
val imei = if (Build.VERSION.SDK_INT >= 26) {
telephonyManager.imei ?: "unknown"
} else {
telephonyManager.deviceId ?: "unknown"
}
return "$androidId|$serial|$imei|${Build.MODEL}".hashCode().toString()
}
How to use binding:
- When you first start, send a fingerprint to the server and link it to your account the user.
- At subsequent launches, compare the current fingerprint with the saved one.
- If there is a mismatch, request re-authentication or block access.
โ ๏ธ Attention: Binding to a device may cause problems for legitimate users:
- After resetting the settings (factory reset), the Android ID will change.
- On some devices (for example, Xiaomi)
Build.SERIALreturnsunknown.- In Android 10+ access to IMEI is limited (requires permission
READ_PRIVILEGED_PHONE_STATE, which is not available to regular applications).We recommend combining several identifiers and providing the user with a way to restore access (for example, via email).
7. Alternative methods: from DRM to social protection
In addition to technical solutions, consider non-standard approachesthat will make life more difficult for pirates or make piracy less profitable:
- ๐ฎ DRM for content: If your application distributes media files (video, music), use Widevine or PlayReady to encrypt them. Even if the APK is copied, the content will remain protected.
- ๐ง Account linking: Require registration via email/social networks and link the license to the account, not the device.
- ๐ฐ Subscription model: Piracy is less profitable for applications with monthly payment (for example, Netflix or Spotify\)) than for one-time purchases.
- ๐ค Partnerships with manufacturers: Some brands (for example, Samsung or Huawei) offer built-in protection mechanisms for applications in their branded stores.
- ๐ข Social pressure: Show risk notifications to users of pirated versions (viruses, data theft) or offer a discount on the legal version.
Important fact: According to the study Digital TV Research, 38% of users of pirated applications are willing to switch to the legal version if they are offered a discount or bonus (for example, an additional month of subscription is free). This approach works better than complete blocking, especially for freemium applications.
A combination of technical and social methods gives the best result. For example, server validation + account linking + offering a discount for pirates can reduce illegal installations by 40โ60%.
FAQ: Frequently asked questions about protecting Android applications
โ You can Is it possible to protect an application 100% from copying?
No, absolute protection is not possible. exists. Any protection can be bypassed if the attacker is willing to spend enough time and resources. However, the combination of methods (obfuscation + server validation + device binding) makes hacking economically unprofitable for most pirates.
The goal of protection is not to make hacking impossible, but increase its cost. to a level exceeding the potential benefit. For example, if it takes 20 hours to hack your application, and sales bring in $1000 per month, most pirates will prefer to attack less protected targets.
โ How to protect an application if it is distributed outside of Google Play?
For applications distributed through APK, Amazon Appstore or third-party platforms:
- Use server validation (see section 4).
- Implement APK integrity check (section 2).
- For paid applications, use own licensing system (for example, through SMS or bank payments).
- Consider DRM protection for content (if applicable).
Example: Application Lucky Patcher (hacking tool) blocks work on devices with root access and checks the integrity of its APK. Similar mechanisms can be implemented in your application.
โ Does protection slow down the application?
Yes, some methods can affect performance:
- Obfuscation (ProGuard/DexGuard): Increases build time, but does not affect runtime.
- Integrity check APK: Adds ~100โ300 ms at startup (depending on APK size).
- Server validation: Requires a network request (latency depends on the server).
- Native code: Can speed up critical checks, but increases the size of the APK.
Optimization:
- Cache check results (for example, server response).
- Perform heavy checks in a background thread.
- Use
Lazyloading protected components.
โ What should I do if my application has already been hacked?
If a pirated version of your application has appeared on the network:
- Submit a removal request:
- For Google Play: via form
Copyright Infringementv Google Play Console. - For distribution sites: via DMCA Notice (templates are available on the sites GitHub or Chilling Effects).
- For Google Play: via form
- Change the scanning algorithm licenses.
- Add a new APK integrity check.
- Update server keys.
- Inform users: Release notes of the new update indicate that older versions are unsafe (for example, contain vulnerabilities).
- Analyze leaks: Use tools like MobSF or JADXto understand how the security was compromised.
Example of a DMCA request for a site:
To: abuse@example.comSubject: DMCA Takedown Request
I am the copyright owner of the Android application "[App Name]" (package: com.example.app). The following URL hosts an unauthorized copy of my work:
[Link to pirated version]
This letter is an official notification under the Digital Millennium Copyright Act (DMCA). I request the immediate removal of this content.
Contact me at: your@email.com
[Your name/company]
โ What tools automate protection?
List of tools to simplify protection:
| Category | Tool | Description | Cost |
|---|---|---|---|
| Obfuscation | DexGuard | Advanced obfuscation, string encryption, anti-debug protection | From $499/year |
| Integrity check | SafetyNet Attestation API | Checking the device for root access and modifications via Google | Free (limits) |
| Licensing | Google Play Licensing | Official license verification system for Google Play | Free |
| DRM | Widevine | Protection of media content (video, audio) | Paid license |
| Analysis vulnerabilities | MobSF | Security scanner for APK/IPA (detection of backdoors, leaks) | Free |
For small projects, a combination of ProGuard + Google Play Licensing + integrity checkis enough. For corporate solutions, consider DexGuard or custom backend.