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:

johnaaronrose

Active Member
Licensed User
Longtime User
You should only test the value of test_1 in (or after) lc_Allow.

I have done that with the same result. It's very awkward for me to check the log as B4A will not connect properly (either by wireless or bluetooth) to it so that I can see my phone's log on my PC. So I compile & run in order to generate the .apk on my PC. I then connect my PC & phone by USB cable, copy the .apk to the phone's sdcard, disconnect the USB cable, and install the app using the Easy Installer app (from Google Play). However, I'm able to view the log (after running my app) by using the Catlog app (from Google Play). The results are interesting:
CheckLicense sub is called,
neither lc_Allow, lc_DontAllow or lc_Error is called,
other Activity_Create code is executed,
'No hacking allowed' is logged,
Window Manager error: main has leaked window... PhoneWindow$DecorView...

Code extracts:
B4X:
Sub Process_Globals
'These global variables will be declared once when the application starts.
 'These variables can be accessed from all modules.
  Private publicKey As String
  publicKey = "MIIBIjA...
  Private test_1 As String
  test_1 = ""
  Private secret As String
  secret = "abcd"

Sub Activity_Create(FirstTime As Boolean)
  Dim ph As Phone
  Log("PhoneModel="&ph.Model)
  If ph.Model = "sdk" Then
    'emulator -> jump to Allow
    AllowEmulator
  Else
    'check license
    CheckLicense
  End If

Sub AllowEmulator
  Log("Allow Emulator")
   test_1 = secret
End Sub

Sub CheckLicense
   Log("CheckLicense")
  Dim lc As LicenseChecker
  Dim pi As PhoneId
  lc.Initialize("lc", pi.GetDeviceId, publicKey, "malach".GetBytes("UTF8"))
  lc.SetVariableAndValue("test_1", secret)
  Log("test_1="&test_1)
   ToastMessageShow("test_1="&test_1, True)
   Log("lc.CheckAccess")
   lc.CheckAccess
End Sub

Sub lc_Allow
  Log("Allow")
   Log("test_1="&test_1)
   ToastMessageShow("test_1="&test_1, True)
   If test_1 <> secret Then
      Log("No hacking allowed")
      Log("test_1="&test_1)
     ToastMessageShow("No hacking allowed: Closing application.", True)
     Activity.Finish
   End If
End Sub

Sub lc_DontAllow
  Log("DontAllow")
  ToastMessageShow("License check fails: Closing application.", True)
  Activity.Finish
End Sub

Sub lc_Error (ErrorCode As String)
  Log("License Check Error: " & ErrorCode)
  ToastMessageShow("License check error: Closing application.", True)
  Activity.Finish
End Sub

PS I have looked at the thread referred to in message #70 on this thread. The messages posted after #1 have confused the solution: should the code in #13 on that thread be used rather than the code in #1 or....?
 
Last edited:

johnaaronrose

Active Member
Licensed User
Longtime User
Apologies

Why don't you use USB debugging?

If the "no hacking message" was logged then lc_Allow was called.

I don't use USB debugging because when I connect my phone to my PC using a USB cable, B4A compile & run does not find the phone and states that no device is available. When I 'Turn on USB Storage' on the phone, I can see (on my PC) the phone's sdcard contents but B4A compile & run does not find the phone as before. Therefore, the USB connection does work but the problem is either the phone (probably Cyanogen Mod 7.2 - I've tried Googling & the Modaco Forum but with no success) or B4A: I don't know how to determine which is the problem.

Forgive my error in saying that lc_Allow was not called. It was called. But the problem is that test_1 is set to "".
 

johnaaronrose

Active Member
Licensed User
Longtime User
Log messages

Are you sure that you are reading the correct log message and not the one before lc.checkAccess ?

I think that what's confusing me is that I didn't realise till just now that Log messages are not being displayed by the CatLog app on my phone. Thus, the only message that I'm seeing in addition to PackageManager & WindowsManager ones is the one produced by a ToastMessage command in lc_Allow. I think that what's happening is that the lc.Initialize command is executed and then the lc_Allow sub is being invoked without executing the rest of the CheckLicense sub. Because if that were not so, the SetVariableAndValue command would cause test_1 to be set.

I'll check this out tomorrow by inserting more ToastMessageShow commands in the code: not able to do it this evening due to prior commitment.
 

johnaaronrose

Active Member
Licensed User
Longtime User
I think that what's confusing me is that I didn't realise till just now that Log messages are not being displayed by the CatLog app on my phone. Thus, the only message that I'm seeing in addition to PackageManager & WindowsManager ones is the one produced by a ToastMessage command in lc_Allow. I think that what's happening is that the lc.Initialize command is executed and then the lc_Allow sub is being invoked without executing the rest of the CheckLicense sub. Because if that were not so, the SetVariableAndValue command would cause test_1 to be set.

I'll check this out tomorrow by inserting more ToastMessageShow commands in the code: not able to do it this evening due to prior commitment.

It's now working OK. What I did was to: kill my app (and all others running) using Advanced Task Killer app, use Easy Uninstaller app to uninstall my app, use Easy Installer app to install my app. I had Log, MsgBox & ToastMessageShow for various displays so that I couldn't miss them as the app executed. The app went through CheckLicense & lc_Allow and showed test_1 as my expected value i.e. all as expected. I'm baffled as to the problem's cause: all I can think of is that Easy Uninstaller app didn't fully clear out the app or that Google Play website is flaky. I have a question about Google Play: is the procedure for 'Publish' a new version to 'Unpublish' the old version before publishing the new version? I'll start a new thread if you think that I should, Erel.
 

MrKim

Well-Known Member
Licensed User
Longtime User
No. The result is cached locally.


What do you mean with routing list?

Cached for how long? I am having a devil of a time testing my app. Changing the "Licensed Test Response" in the Developer Console is giving me results that I can only describe as erratic. Sometimes the app will respond immediately, sometimes wrong, sometimes after 5 or 10 minutes.

And I am basically at this point just using your sample code from the Licensing Library. Clearing user data and reinstalling the app sometimes responds, sometimes not.

Will having the app on more than one device with the same account (phone and emulator) have an effect?

Kim
 
Last edited:

MrKim

Well-Known Member
Licensed User
Longtime User
Where are the extras?

I don't see any way to get at the Server Response Extras VT, GT, GR, UT. Am I missing something?
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
Apparently some elements or files that come with my app are not automatically overwritten when B4A is put back to normal release mode (without obfuscation).
If you have an explanation for this that would be very much appreciated.
I never encountered such an issue. If you are able to reproduce it then please start a new thread in the bugs forum.
 

Armoured

Member
Licensed User
Longtime User
Hi Erel,
With this library we must modify the manifest of the application?
If the answer is "Yes" how?

Thanks
 

johnaaronrose

Active Member
Licensed User
Longtime User
Phone & tablet

My app is free. However, I'm using Erel's code as in post #1: so it's difficult for someone else to copy my app's code. I'm not using the enhancement described in thread Android Device Unique ID - Alternative to PhoneId: mainly because I don't understand it. My app downloads & works OK on both my phone & my tablet. On my phone (using Gingerbread), I can move the app to an SD card & it works OK. On my tablet (using Ice Cream Sandwich), if I move the app to to an SD card, it fails with 'some secret value' not matching. Can anybody explain why?
 

johnaaronrose

Active Member
Licensed User
Longtime User
Now works from SD card on tablet!

Now works from SD card on tablet!

Code extracts for checking value:

B4X:
Public secret As String
   secret = "abcd"

B4X:
Sub Activity_Create(FirstTime As Boolean)
   Dim ph As Phone
  Log("PhoneModel="&ph.Model)
   If ph.Model = "sdk" Then
    'emulator -> jump to Allow
    AllowEmulator
  Else
    'check license
    CheckLicense
  End If

B4X:
Sub AllowEmulator
  Log("Allow Emulator")
   test_1 = secret
End Sub

Sub CheckLicense
   Log("CheckLicense")
   Dim lc As LicenseChecker
  Dim pi As PhoneId
  lc.Initialize("lc", pi.GetDeviceId, publicKey, "abcdef".GetBytes("UTF8"))
  lc.SetVariableAndValue("test_1", secret)
  Log("test_1="&test_1)
   Log("lc.CheckAccess")
   lc.CheckAccess
End Sub

Sub lc_Allow
  Log("Allow")
   If test_1 <> secret Then
      Log("No hacking allowed")
      Log("test_1="&test_1)
      Msgbox("No hacking allowed.", "Closing application")   
      ExitApplication
   End If
End Sub

Sub lc_DontAllow
  Log("DontAllow")
   Msgbox("License check fails.", "Closing application")
  Activity.Finish
End Sub

Sub lc_Error (ErrorCode As String)
  Log("License Check Error: " & ErrorCode)
   Msgbox("License check error.", "Closing application")
  Activity.Finish
End Sub
 
Top