Android Tutorial Protect your Android application with the Licensing library

The licensing library allows you to use Android market licensing service to verify that the user is allowed to access your application.

Your applications sends a request to the local market application. The market application contacts the market server and returns the result. The result is cached based on the market rules.

It is recommended to go over Google's documentation related to the licensing method: Application Licensing | Android Developers

Configuring the licensing library is simple. You should first have a publisher account in the market.
The license key is available in Google Play developer console under Development tools - Services & APIs.

The licensing library and service will not prevent a dedicated hacker from hacking your application. It will however make it more difficult.

The first step is to initialize a LicenseChecker object:
B4X:
Sub Activity_Create(FirstTime As Boolean)
   Dim lc As LicenseChecker
   Dim p As PhoneId
   lc.Initialize("lc", p.GetDeviceId, publicKey, "kljdflkf".GetBytes("UTF8"))
   lc.SetVariableAndValue("test_1", "some secret value")
   lc.CheckAccess
End Sub
The result of the licensing check is cached locally. The cache is encrypted with AES algorithm. In order to avoid users from tampering with the cache and copying the cache to different devices, the device id is used together with the package name as the password.

Note that the same user will be able to download your application to other devices running with the same user account.

PhoneId (from the Phone library) requires the READ_STATE permission. The protection will still work if you pass an arbitrary string. It will be weaker however.
The Salt parameter should be an array of bytes with some random values (the values should be the same on each run).

Edit: It is recommended to use the alternative id method as described here: http://www.b4x.com/forum/basic4andr...oid-device-unique-id-alternative-phoneid.html

The next step is to call lc.CheckAccess. This in turn calls the market application or the local cache and checks whether the user is allowed to access the program.
One of the following events will be raised when the result arrives: Allow, DontAllow or Error (ErrorCode As String).
It is up to you to handle the event subs as required.

LicenseChecker.SetVariableAndValue
A simple way to hack an application is to "jump over" the checking code. For example a hacker might remove the call to CheckAccess and instead call your Allow event sub.
In order to make it a bit more complicated you can call LicenseChecker.SetVariableAndValue.
For example:
B4X:
lc.SetVariableAndValue("test_1", "some secret value")
The above code will set the value of a process global string value in the main activity named test1 to "some secret value" if the check was successful. You should not use or test the value of test1 in the Allow event sub as it will be too obvious. Instead you should use it later in your program.
You can be creative and pass the name of the variable or the value by using BytesToString or some other way.
As this variable is accessed in a dynamic way it will fail when the code is obfuscated. Therefore you need to include an underscore in the variable name to prevent it from being obfuscated. For example: test_1.
Note that SetVariableAndValue method will fail when running in rapid debug mode as the variable is part of the "debugger engine".

A more complete example:
B4X:
Sub Process_Globals
   Dim publicKey As String
   publicKey = "MIIBIjANBgkqhAADSFEFEFkiG9w0BfW/cGhTbtIs6QIDAQAB..."
   Dim test_1 As String
End Sub
Sub Globals

End Sub
Sub Activity_Create(FirstTime As Boolean)
   Dim lc As LicenseChecker
   Dim p As PhoneId
   lc.Initialize("lc", p.GetDeviceId, publicKey, "kljdflkf".GetBytes("UTF8"))
   lc.SetVariableAndValue("test1", "some secret value")
   lc.CheckAccess
End Sub
Sub lc_Allow
   Log("Allow")
End Sub
Sub lc_DontAllow
   Log("DontAllow")
   ToastMessageShow("Closing application.", True)
   Activity.Finish
End Sub
Sub lc_Error (ErrorCode As String)
   Log("error: " & ErrorCode)
   ToastMessageShow("Closing application.", True)
   Activity.Finish
End Sub
Sub Activity_Pause(UserClosed As Boolean)
 
End Sub
Sub Activity_Resume

End Sub

The library is available here: http://www.b4x.com/forum/additional-libraries-official-updates/11430-licensing-library.html
 
Last edited:

timo

Active Member
Licensed User
Longtime User
So, post #45 wasn't out of arg... :D


Erel,
...
The user purchases the app and installs it.
The user runs the app, presumably allowing the license cache file to properly set itself.
They then quickly back up the app with a 3rd party backup program.
They then cancel the purchase before the 15 minutes are up.
They can then restore the app from the backup - potentially including the license cache file...
Highwinder

Right or wrong, at the moment there isn't a better solution on the Market. If we want some sort of protection we must play with that one... and hope in correct buyers. This solution have pro and cons., but all developpers are on the same boat...
 

Highwinder

Active Member
Licensed User
Longtime User
The cache file expires after a certain time set by the market server. So this method will not work.

Excellent, this is good to know. I'm sure others are curious about this too.

Thanks for the clarification. :)

- Highwinder
 

nad

Active Member
Licensed User
Longtime User
Hello,

I have been working with the licensing library for some time already and everything works perfectly and now with the ofuscation is even better.

However i got a couple of questions from users asking regarding the need to use the READ_STATE permission.

From Erel's comments
"...
Note that the same user will be able to download your application to other devices running with the same user account.

PhoneId (from the Phone library) requires the READ_STATE permission. The protection will still work if you pass an arbitrary string. It will be weaker however.
The Salt parameter should be an array of bytes with some random values (the values should be the same on each run).
..."

I fear some people might be scared of the READ_STATE permission.
Is there any way to circumvent this? What would be the risk factor? people moving the apk between some mobiles with the same google account and then cracking the license?

Has any of you tried other method?

Thanks a lot for your comments
 

nad

Active Member
Licensed User
Longtime User
Thanks a lot Erel. I will continue using the phone id and just add some comments on the android market description about licensing needing it.

Cheers,
 

Brad

Active Member
Licensed User
Longtime User
What's the downside in adding the license check to another sub? It's critical that nothing screws up when a user launches my app. I would prefer to add it to say when the user moves to the settings screen.
 

Brad

Active Member
Licensed User
Longtime User
I moved to another sub and it seems to be working. I used a Boolean to check just once.
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
Hello,

I have been working with the licensing library for some time already and everything works perfectly and now with the ofuscation is even better.

However i got a couple of questions from users asking regarding the need to use the READ_STATE permission.

From Erel's comments
"...
Note that the same user will be able to download your application to other devices running with the same user account.

PhoneId (from the Phone library) requires the READ_STATE permission. The protection will still work if you pass an arbitrary string. It will be weaker however.
The Salt parameter should be an array of bytes with some random values (the values should be the same on each run).
..."

I fear some people might be scared of the READ_STATE permission.
Is there any way to circumvent this? What would be the risk factor? people moving the apk between some mobiles with the same google account and then cracking the license?

Has any of you tried other method?

You should use the alternative id method: Android Device Unique ID - Alternative to PhoneId
 

bluedude

Well-Known Member
Licensed User
Longtime User
Works

Tested it all today and it works. However, you need to upload an APK to the market for this to work.

Cheers,
 

nad

Active Member
Licensed User
Longtime User
Sad
Today one of my apps appeared on google cracked.

In latest versions of this crack software they even remove Google ads from apps just with a long click on the apk.

Wondering what can be done if even google licensing fails. Nothing to do with b4a, it's a google problem and ofc mine if i have understood it right.

Anyone knows if some more steps can be done to make things a bit harder?


"....
XXXXXXXXXX is one of the most used creations of xXXXXXXX. It has now been updated to version XXXXX with many fixes an a lot of upgrades and improvements added. You can break Android Market License of a number of apps using this app. XXXXXXXX does not guarantee 100% working of the app.
..."

My only hope is that to crack it they need to have root and superuser and execute that software against apk individually, i mean every person would need to do that themselves. Not many android users know how to do that or so i hope.

I will be adding many setVariableandValue and many checks from now on. Increase the maximum possible the character length for keys. Also load house ads (programmed i mean) when (with my own images and links) i notice that admob or other ad providers are pointing to 127.0.0.1 on the host file due the high number of roms that edit the host file to avoid ads.

Erel, can i check two times one lc.initialize with getDeviceId from the GetDeviceId sub and the other from p.getdeviceid being p (phoneid) for another lc2.initialize?

Or instead using a getDeviceId (from sub) AND p.getDeviceId (from phoneid). so you have a mixture of the two ids in the lc.initialize (just wondering)


Another question erel, what happens with old users who have purchased the software if i change dramatically the licensing code. Do they get a new cached file first time they initialize?

And the last one,

When I am ofuscating the code, if i declare the dim test1 as string and later

lc.setvariable("test1", ...

it fails so i need to check the ofuscated variables and write there the ofuscated name

lc.setvariable("vvv"

Would using dim test_1 as string decrease security?

Thanks!
 
Last edited:

Erel

B4X founder
Staff member
Licensed User
Longtime User
You cannot check twice with different keys. You can however create a key from both keys (append one to another).

You should use a variable such as v_v with SetVariableAndValue. As this variable is accessed with reflection it should not be obfuscated.

Another question erel, what happens with old users who have purchased the software if i change dramatically the licensing code. Do they get a new cached file first time they initialize?
It should work properly.
 
D

Deleted member 103

Guest
Hi Erel,

Something like:
Code:

Dim p As Phone
If p.Model = "sdk" Then
'emulator -> jump to Allow
lc_Allow
Else
'check license
End If

When I try this code with me then it does not work!
I am testing with 2 emulators and my HTC-Desire.

Variable p.Model in Emulator:
1) GALAXY-Tab: p.Model = GALAXY-Tab
2) Motorola_DroidX: p.Model = generic

Variable p.Model in HTC-Desire: p.Model = HTC Desire

Variable p.Manufacturer in Emulator:
1) GALAXY-Tab: p.Manufacturer = unknown
2) Motorola_DroidX: p.Manufacturer = unknown

Variable p.Manufacturer in HTC-Desire: p.Manufacturer = HTC


With which variable should I check it?
Is there a better way can be uniquely identified with an emulator?

Thank you very much
Filippo
 
D

Deleted member 103

Guest
"sdk" works with the standard emulator. Other builds can return other values. I'm not familiar with another more reliable way to test this.
All right, that means i can this Test use only in debug mode.
 

magarcan

Active Member
Licensed User
Longtime User
I'm using this code:
B4X:
Sub Activity_Create(FirstTime As Boolean)
   'Licencia
   Dim lc As LicenseChecker
    Dim p As PhoneId
    lc.Initialize("lc", p.GetDeviceId, publicKey, "kljdflkf".GetBytes("UTF8"))
    lc.SetVariableAndValue("test1", "some secret value")
    lc.CheckAccess
...
End Sub
App run without problem in emulator but in my device (Galaxy Nexus with Android 4.1) y get this error:
"An error has occurred in sub: main_activity_create (java line: 234) java.lang.RuntimeException: java.lang.NoSuchFieldException: _test1
Continue?"

Any idea? :sign0148:
 

magarcan

Active Member
Licensed User
Longtime User
I've tried it in debug mode and release (without ofuscation) and hapens the same...
 
Top