[android-developers] Re: Obfuscating code
Unless your server provides something like downloadable content or functionality for your app I don't think you need to go through the trouble of implementing the license verification through your server. Doing it within your app is just fine, because either way a cracker can still look for these license check code portions and change them. Doing it just within your app is less work of course, so I'd go for that.
Regarding the LVL there are a few very important things to know about. Google never intended it to be taken verbatim as a drop-in solution for protecting your app. A lot of developers did that. And their apps can be easily cracked. The problem is that a cracker also knows the original LVL code.
You probably already know that the LVL needs to be customized for each app and definitely should not be used as an all-in-one solution library you just reference from your app project.
So basically you should copy the files into your app project and change the heck out of it so it's not recognizable anymore. Also all logging lines must be removed. Why they are there in the first place is a bit beyond me.
Anyway, the one big problem of the LVL is that its entry point interface ILicensingService apparently cannot be obfuscated. Proguard's documentation even says:
If you're using Google's optional License Verification Library, you can obfuscate its code along with your own code. You do have to preserve its
ILicensingServiceinterface for the library to work:-keep public interface com.android.vending.licensing.ILicensingService
That advice is absolutely misleading and basically opens a big door into identifying and cracking your app's LVL self-check. If the interface name "ILicensingService" is literally to find in your obfuscated Java code you have basically the entry point for cracking the app right there. With Java decompiler it's just another click away to find the response code check.
The Google session talk mentions that you should obfuscate the whole LVL, including ILicensingService. However, when I tried to do exactly that, it simply did not work. The name was always kept as if there is a hard-coded rule inside Proguard that makes the obfuscation of that identifier impossible. So I simply renamed ILicensingService. And it still works. I tested it extensively.
About using the NDK for self-integrity checks: it's actually pretty similar to using reflection in Java. First of all you also have the same problem here with string literals that basically give away what you're trying to do (class and method names). You need to obfuscate them.
One unobfuscated NDK example of getting the package name:
void Java_com_example_JniTestClass_checkPackageName(JNIEnv* env, jclass clazz, jobject context) {
jclass ctxClass = (*env)->GetObjectClass(env, context);
jmethodID getPackageNameMethodID = (*env)->GetMethodID(env, ctxClass, "getPackageName", "()Ljava/lang/String;");
jstring packageName = (*env)->CallObjectMethod(env, context, getPackageName);
}
Each JNI method is basically the native counterpart of a Java method declaration. The Java original might look like as follows:
public class JniTestClass {
public static native void checkPackageName(Context context);
}
I'm going to dissect the NDK code a bit:
jclass ctxClass = (*env)->GetObjectClass(env, context);
This gives you the class object of the context object. This is necessary for retrieving the class method "getPackageName" in the second line:
jmethodID getPackageNameMethodID = (*env)->GetMethodID(env, ctxClass, "getPackageName", "()Ljava/lang/String;");
This gives you a class method handle. This is necessary for calling that method in the following line. The last argument looks a bit cryptic. It's Java convention for expressing the method signature in a string notation. You can find more information about these signature strings on this page.
jstring packageName = (*env)->CallObjectMethod(env, context, getPackageName);
This gives you the actual package name as a Java string object. It's not a C-string yet. With another JNI function call you can convert it into a C-string. You need to make yourself familiar with JNI. It looks awkward but it isn't that bad in the end.
Reading the package info works pretty similar. You always need a "jclass" object then you can use that for retrieving a method or field member and then you can use JNI for calling that method or for reading the value of a field.
A few more words of advice. You should also obfuscate these native method names. You cannot do that with Proguard because that would break the link between your Java code and the native library. After all there must be a way for JNI to find these native methods and Proguard's obfuscation is random. You should apply non-sensical method names as Proguard would do:
public native void x(Context c);
Of course that makes it harder for you to maintain your code. However, you can make your native code a bit more readable by using #define:
#define jni_get_package_name Java_com_example_MyClass_x
void jni_get_package_name(JNIEnv* env, jclass clazz, jobject context) {
...
}
On Friday, March 1, 2013 10:41:08 AM UTC-6, dashman wrote:
Thank you for some excellent suggestions.--
I've watched that google i/o a few times.
i problem is actually doing it. e.g. just looking at the NDK and wish they
had a sample to read the package info etc.
offloading app logic to server is a great idea - but my app is designed to
work while off-line - so that will not help me.
i think my thinking is:
- doing some checks in native code
- also including some critical app functions in navtive code (thanks for that suggestion)
- check license with my server (if online) - and make it a requirement that it
needs to pass the test within a set # of days (e.g. 30).
the problem now is that - all the user has to do is uninstall the app and re-install it
and then they can use the app for another fixed amount of days.
--
You received this message because you are subscribed to the Google
Groups "Android Developers" group.
To post to this group, send email to android-developers@googlegroups.com
To unsubscribe from this group, send email to
android-developers+unsubscribe@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/android-developers?hl=en
---
You received this message because you are subscribed to the Google Groups "Android Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to android-developers+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

0 Comments:
Post a Comment
Subscribe to Post Comments [Atom]
<< Home