Like everyone else who has published an Android app with in-app billing, I have followed the instructions from AIDL to Google Play Library migration guide and the rest of the integration documentation in order to implement the latest version of the Billing library into my app. All works well so far.
My app is a typical freemium app, where you pay to unlock a few extra features. However, it's not a very large one. There's no back-end server to verify purchases, and honestly there's no need for one. Nevertheless, I do value my app and the purchases made in it, so I have taken certain actions to prevent fraud.
One such action is concealing and obfuscating the app's code, so that decompiling it and cracking it becomes annoying enough for someone to consider paying the very low price for its premium features, instead of cracking it. I think I have succeeded in preventing that so far.
Before publishing my app with the new Billing library, I decompiled it and looked at the decompiled code. I can't describe how disappointing my implementation of the new library looks from a security point of view.
The previous version of the library used Intent and Bundle with String and int, where the new one uses Purchase and SkuDetails. Even though the method names are obfuscated by ProGuard, these two classes aren't. So, it's extremely easy to just search for "Purchase" in all files, and you'll soon find the onPurchasesUpdated, onQueryPurchasesResponse and onSkuDetailsResponse looking something like:
public void M(com.android.billingclient.api.g paramg, List<Purchase> paramList)
{
...
}
public void N(com.android.billingclient.api.g paramg, List<Purchase> paramList)
{
...
}
public void O(com.android.billingclient.api.g paramg, List<SkuDetails> paramList)
{
...
}
I think it's now very obvious for a cracker to follow the logic of the Purchase and SkuDetails objects, especially since we are required to somehow keep them in memory so that we launchBillingFlow including a SkuDetails in the BillingFlowParams.
So, the question is:
How could I better obfuscate the Purchase and SkuDetails classes in my decompiled code? Should I replace them with my own classes? Should I inherit from them? Should I re-create the SkuDetails class? Should I not worry whatsoever? How have you handled this?
One could wonder if decompiling an app is the first choice for a hacker. A rooted device could have a mock Play store app installed, that immediately returns that the user has payed to any app with IAPs. No knowledge of your app is needed to get the premium features.
In my opinion spending some time setting up a backend to check if it's a legitimate in app purchase, is worth more. Hosting the backend could be cheap - or even free - if you use fi. Firebase functions. The Play store sends to your backend it made an actual purchase and the backend reports to the app that it succeeded.