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.basic4ppc.com/forum/basi...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.basic4ppc.com/forum/additional-libraries-official-updates/11430-licensing-library.html
 
Last edited:

Wembly

Member
Licensed User
Hi - I seem to be having a issue with the new B4A version 3 beta 2 and the use of this library.

Using the following code:

B4X:
Sub Process_Globals
   
    Dim publicKey As String
    publicKey = "MIIBIjANBgkqhki...."
    Dim test_1 As String
...

    If CheckConnection = True Then
   
        lc.Initialize("lc", GetDeviceId, publicKey, "kljdflkf".GetBytes("UTF8"))
        lc.SetVariableAndValue("test_1", "test value")
        lc.CheckAccess
       
        If test_1 <> "test value" Then Activity.finish
    End If

I now get the following error in debug:

unexpected error.
Error occurred on line: 110 (main)
mainafterFirstLayout (java line: 98)
java.lang.RuntimeException: java.lang.NoSuchFieldException: _test_1
at com.android.vending.licensing.ServerManagedPolicy.allowAccess(SourceFile:275)
at com.android.vending.licensing.LicenseChecker.checkAccess(SourceFile:133)
at anywheresoftware.b4a.objects.LicenseCheckerWrapper.CheckAccess(SourceFile:60)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at anywheresoftware.b4a.shell.Shell.runVoidMethod(Shell.java:487)
at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:210)
at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:170)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:93)
at uk.co.androidapps4u.ProExpMgr.main.afterFirstLayout(main.java:98)

Please can anyone advise as why this is happening?

Thanks.
 

Wembly

Member
Licensed User
Thanks Erel.

One other oddity I've noticed and can't explain is when the app is first installed and executed it immediately closes without error but when run the app second time or any time there after it runs fine.

I have tracked down the closure to the license check but not sure why it always closes on first run after install - any ideas?

The code example ns my previous post is lifted from my app.

I have now released the app to Google Play and same behaviour is happening when installed from there too.

Cheers
 

Wembly

Member
Licensed User
Below is lifted straight out of my app - the DontAllow event is consistently called on the first run after installation, subsequent launch of app fine.

B4X:
Sub Process_Globals
 
    Dim publicKey As String
    publicKey = "MIIBIjANBgkqhki...."
    Dim test_1 As String


Sub Activity_Create(FirstTime As Boolean)
    'Do not forget to load the layout file created with the visual designer. For example:
    'Activity.LoadLayout("Layout1")
   
    Dim lc As LicenseChecker
    Dim p As PhoneId
   
    ' License checking
   
    If CheckConnection = True Then
   
        lc.Initialize("lc", GetDeviceId, publicKey, "kljdflkf".GetBytes("UTF8"))
        lc.SetVariableAndValue("test_1", "string")
        lc.CheckAccess
       
        If test_1 <> "string" Then Activity.finish
    End If

    Activity.LoadLayout("main")
 

PFlores81

Active Member
Licensed User
After implementing this, I then launch my application, and it closes immediately displaying an error in the toast. It never logs the error though. kind of irritating.

Edit: It seems to error when Obfuscating the code. Not sure why, however if I do a standard build, it works just fine.
 
Last edited:

LucaMs

Expert
Licensed User
Erel, sorry, but i don't understand.

In the first post you wrote:
-----------------------------------------------
"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.
-----------------------------------------------

I did not understand because, probably, I wish that Google would create a key based on the name of my package + the user account + the device ID.

What is it about: the device id is used together with the package name as the password?

P.S. Hmm maybe I understood: it is a pw to access that cache?

Since the method of Google does not prevent a user to install the app on various devices, don't you think that we should create our own system, with a unique key as I wrote above (and a request from the user for this key)?
 
Last edited:

Hariono Sutanto

New Member
Licensed User
Hi..I need some helps here...
already try and follow from first post , read entire thread...already publish the apps and still not succeed...

Did i miss something?

By the way , here is my code..

B4X:
Sub Process_Globals
    Dim Genuine_1 As String
    Dim PublicKey As String ="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAphmpftmOOKJdyNbQdfc45CuhH9mfUSQdJ5I1auWrFVKnGyzTBwENUNwvtu4WNVj3uQqDohlInkwZITkPHqt+pZYRvsn3VYyUF2vGr92w1GzVVM0pMbFinoFLzlr8+bOTWBcXcmUxDfGZ8GcV/3oJ1/3w97W+BizKngzQ9Fw4T068teiFmf8/5IF/XjANeR0qWeJ98doe7i4dtJD+Qa7kZC8aJxxb9jxjkDTCnFASMKofnCa/t90YlkH/cluswYi0DM1KWB5xuKUF8JegVzVP23I0u9m25Ocp4V1c0PcnRL0FxNbTOayA/9nYK7rbD5BpsT1RpBQSiVB4mrW2GihGjQIDAQAB"
End Sub

Sub Globals
    'These global variables will be redeclared each time the activity is created.
    'These variables can only be accessed from this module.
End Sub

Sub Activity_Create(FirstTime As Boolean)
    Dim LC As LicenseChecker
    Dim p As PhoneId
    LC.Initialize("lc",p.GetDeviceId,PublicKey,"mkios2014salt".GetBytes("UTF8"))
    LC.SetVariableAndValue("Genuine_1", "some secret value")
    LC.CheckAccess
    Activity.LoadLayout("frmMain")
End Sub

Sub Activity_Resume
End Sub

Sub Activity_Pause (UserClosed As Boolean)
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

What I've got when run this code is always going to lc_DontAllow
Any help appreciate ..
 
Last edited:

Hariono Sutanto

New Member
Licensed User
Today re-run that code and everything works fine...
also try to playing with license test response and the result is very nice.

License Test Response
LICENSED > Code is going to lc_Allow
NOT_LICENSED > Code is going to lc_DontAllow


Maybe need a few days to make it works communicate between our devices with play store server.
 

Shadow&Max

Active Member
Licensed User
Need to know if I install this into my app, will it mess things up if I upload the app to Amazon as well???
 
Top