Is there a way to detect (during runtime) if your application is ProGuarded? My goal here is to set a boolean value based on whether the application is ProGuarded or not.
I think it'd be easier if you set a boolean on build variants/flavors that you run ProGuard on.
For example: if you run ProGuard on Release and Staging but not on Debug, set a boolean variable to true on release and staging, but false on debug. This may help
This is a bit of a workaround but there are a few avenues by which reflection will solve this.
One way would be for you to first determine a class that is obfuscated/minified in the case of proguard. So say you have a class com.package.Thing that when proguard is enabled gets minified to be called just com.package.a (or whatever, it doesn't matter). Then use reflection to see if the original class exists.
Something like this:
boolean isProguardEnabled() {
try{
return Class.forName("com.package.Thing") == null;
catch(ClassNotFoundException cnfe) {
return true;
}
}
Obviously this only works if you know of a class that will be changed when proguard is enabled.
Perhaps more generically, you could look for a class com.package.a and use that as a signal that proguard is enabled, assuming of course that you don't genuinely have a class by the name of a. By default proguard will just use the alphabet to come up with class names, but you can also specify in your proguard configuration your own list of class names to use (which presents another way to do this same trick, look for one of those class names that you've specified).
Related
We are building an Android application where we use Timber for Log-output. We have defined our own .e, .d, .v etc functions and use if (BuildConfig.DEBUG) to see if we should output the log. This takes care of the issue that we don't want to output Debug-logs in our releases but all the string literals used in our functions calls are still present in the compiled source code. We furthermore use ProGuard for obfuscation. To exemplify, in a class we can have:
somObj.normalFunction(variable)
Log.d("This secret class achieved its secret mission!");
In our release, this will not be seen in the app logs but if you reverse-engineer the APK you will see something like:
q.b(m)
z.a("This secret class achieved its secret mission!");
which can give a hint to the hackers about what class they are looking at.
So what we're looking for is to either be able to completely REMOVE all the Log function calls at compile time (using some pre-processing, annotation or something, but hopefully without having to add something before EVERY function call) OR to obfuscate all the String literal parameters to those function calls. So, two ideal solutions would be if the source, just before compilation, instead looks like:
q.b(m);
or
q.b(m);
z.a("jgasoisamgp23mmwaföfm,ak,ä")
Just by thinking I can see two bad ways to achieve this. Either we surround ALL calls to Log.d with if(BuildConfig.DEBUG) which will make the compiler remove them before compilation. But this is very tideous. OR, we make sure that every time you want to add a log-printout you need to do
Log.d(LogClass.getLog(1234))
and you then define ALL those logs inside LogClass and then remove them with if(BuildConfig.DEBUG) and return null in getLog if that's the case. But that makes it more tideous every time you want to add a log.
So finally, is there any GOOD solution to this?
DISCLAIMER: I work for PreEmptive, the company that makes PreEmptive Protection - DashO.
DashO is capable of removing calls to specific methods (e.g., Log methods). While this doesn't remove the instructions to load the string literal, just the call itself, DashO also offers String Encryption, which would offer some protection to those string literals.
As an example, I ran this class through DashO:
public class App {
public static void main(String[] args) {
Log.d("Secret message here");
}
}
After removing calls to Log.d with String Encryption on, the decompiled output looks like this:
public class App
{
public static void main(String[] paramArrayOfString)
{
a.replace("Bwpfpb7u|ih}z{?($0&", -12 - -61);
}
}
DashO offers other protections (e.g., Control Flow Obfuscation) that tend to break decompilers; I've turned those off for this demonstration.
What I would do is one or some of the following:
Use Timber (so you don't need to bother removing things or adding if statements). You simply do this once in your Application#onCreate(); if you are in DEBUG, then you plant a DebugTree that prints to the console. Else, you plant an "empty tree" that does nothing.
Simulate Timber but create your own "YourLogger" class and do the same (if you don't want to include a "third-party" library even though it's just one class). So you'd have YourLogger.v("tag", "string") and inside you'd do: if (debug) { Log.v(tag, string); } and so on and so forth for all other log types.
Use Proguard to strip the logging, and what not.
1 and 2 imply you go through your app and replace all Log. lines with either Timber. or YourLogger.
Option 3 wouldn't need that, since the code would be removed during obfuscation and the calls would do nothing, but this is mode complicated (and I haven't done it in years, don't even remember how it's done, probably easy to look it up).
I'd go for 1.
Update
Since apparently I don't know how to read, I think that in order to achieve this, your only bet is to have some sort of lookup mechanism for the actual text you want to emit/hide.
Strings.xml is the easiest, since it's included with Android and you can even localize the error messages (if that were needed, of course). Yes, there's a lookup time penalty, but I'd say unless you're iterating over thousands of items and logging different strings every time or something, the penalty wont' be noticeable (I don't have data for this, you'd have to benchmark).
Alternatively, instead of relying on resources, you could just use a file, read it, and load the strings in memory... a trade off; do you use more memory at the cost of simplicity and time to code the solution, or do you use the built-in mechanism and pay the CPU time?
TL;DR: with proguard enabled, when using reflection, my properties look private, non-nullable and without annotations, despite proguard config that should keep all these attributes.
I have some simple data classes with public properties to serve as data models in my Android app. Later, when doing generic [de]serialization of said classes, I filter the property list like this:
val properties = instance::class.memberProperties
.filter { it.visibility == KVisibility.PUBLIC } // && some other conditions, unrelated here
.filterIsInstance<KMutableProperty<*>>()
It works normally on my debug builds (I mean it selects the properties I want it to). But, when doing a release build, where proguard is active, the result is empty. To check why, I logged all the relevant stuff about the properties of one class -- turns out their visibility field reads PRIVATE (and all other attributes remain the same as on a debug build).
I already have a line in proguard config to keep all the models:
-keepclassmembers class * extends com.models.package.name.BaseModel { *; }
I tried this one before, with same result:
-keep class com.models.package.name.** { *; }
Why/how does proguard affect property visibility? Should I modify the config somehow? Or am I missing something else here?
UPDATE: It seems like visibility is not the only thing. prop.returnType.isMarkedNullable also doesn't work, it returns false for properties declared nullable. And annotations also seem to get lost, even though I asked proguard to keep them. Is there any way to work around this? It pretty much renders 2 weeks of my work useless...
Thanks to the suggestion from #yole in question comments, I've been able to make this work. Even though my classes were configured to be kept by ProGuard, it stripped the kotlin.Metadata annotations from them. These annotatons are where Kotlin stores all the attributes I was missing. The solution is to prevent ProGuard from deleting them, adding to configuration:
-keep class kotlin.Metadata { *; }
(on a side note: it's weird that it's not included in the default config, at least if you're using the kotlin.reflect.full package. Or at least it should be mentioned clearly somewhere in the docs...)
I have one Android open source library project in which I have been using a separate library for logging (Which is also developed by me).
The logging library is not that important, but it makes the development and debugging easier (Both for me and the user of the main library).
I am using gradle (and Jitpack) to use both the libraries. Now the Logging library is actually having few extra permissions in manifest (For writing logs to file, not necessary for the main library).
Now one of the user asked me to remove the extra permissions. And I don't know how can I do that without removing the logging library (or changing the functionality in the logging library itself).
I even realised that few people might not need the logging library at all, so is there a way I can make it optional, like if the user didn't include the Logging library in their build.gradle, it won't get imported which I can detect and not call the logging functions?
I know it sounds confusing, but I'd like to know how to decouple both the libraries. In fact please let me know if you know about any such example from any popular library too.
Yes you can probably do both with some clever tricks.
part 1. PERMISSIONS
About the manifest permissions. It's pretty simple, do not add the permission to the logging library and instead, check it on runtime. Like this:
if (context.checkPermission(
Manifest.permission.WRITE_EXTERNAL_STORAGE,
android.os.Process.myPid(),
Process.myUid()) == PackageManager.PERMISSION_GRANTED) {
carry on with your write to disk operation ...
}
and then on your documentation you write that IF developers using the library wants to have a local logging, they have to declare WRITE_EXTERNAL_STORAGE on the manifest.
part 2. (not) IMPORTING THE LIB
All I'm gonna write here is by heart and 100% NOT tested. There might (will) be some errors that you'll have to shift around, but hopefully I'll pass a solid idea.
First on the NoobCameraFlash lib you'll define LumberJack in the build.gradle file with provided instead of compile. This will make the compiler known about the LumberJack so compilation can pass, but it won't include it on the actual build.
Then create in your NoobCameraFlash library a class that is a mirror of the library funcionalities. Which means the methods d(String, String), e(String, String) etc.
Then you in this mirror class you will something like the following to check if lumberjack is actually available.
private static boolean lumberJackAvailable = false;
private static boolean lumberJackTested = false;
private static boolean isLumberJackAvailable() {
if(lumberJackTested) return lumberJackAvailable;
lumberJackTested = true;
try {
if(Class.forName("") != null) {
lumberJackAvailable = true;
}
} catch(Throwable e){
// ClassNotFoundException, LinkageError, ExceptionInInitializerError
}
return lumberJackAvailable;
}
public static LumberJackMirror create() {
// could also be a singleton
if(isLumberJackAvailable() return new LumberJackMirror();
else return null;
}
then of course you have to check if(lumberJackMirror != null). So as you can see it's not the most straight forward way of doing things.
Another way that simplifies this a little bit is to create an interface in a different library, that both the mirror and the actual LumberJack implements and use the factory can return an empty implementation of the interface instead of having to null check all the time.
As well, include on the documentation, that if developers want to have the logging functionality they have to add it to the build.gradle. Something like compile 'your_groud_id:lumberjack:version'
edit
another common way of doing that is to make it explicit on the NoobCameraFlash initialisation code. Something like:
NoobCameraFlash.config()
.setLogger(new LumberJack());
so that forces developers to know about LumberJack instead of checking via Class. But that would mean you need some version of LumberJack that is not just static methods.
end_edit
But hopefully just the permission removal will be enough and you don't have to do this part.2 =]
happy coding.
I'm running into many problems with the Android Support Library's ViewPager widget. Due to lack of documentation and just incorrect behavior, I've been learning how things work based on the source.
Looking at the source, I see that the ViewPager, I see a constant defined as
private static final boolean DEBUG = false;
If I can set this to true, then I can enable all the debugging for the ViewPager class
However, I can't determine how to modify this value at runtime. Reflection didn't seem to have access to it.
Is the only way to change this flag is by recompiling the source?
1.remove the "final" property;
2.add a method allowed to modify the DEBUG value;
3.recompile the source.
For enabling debug, maybe you should extends this class firstly. Then use your customized class instead of ViewPager.
A final variable cannot be changed after it is assigned therefore you would need to recompile from source with DEBUG = true if you want to enable the built in debugging statements.
I am writing my first Android application and I am liberally using asserts() from junit.framework.Assert
I would like to find a way to ensure that the asserts are only compiled into the debug build, not in the release build.
I know how to query the android:debuggable attribute from the manifest so I could create a variable and accomplish this in the following fashon:
static final boolean mDebug = ...
if (mDebug)
Assert.assertNotNull(view);
Is there a better way to do this? i.e. I would prefer not to use an if() with each assert.
thanks
I think the Java language's assert keyword is likely what you want. Under the covers, the assert keyword essentially compiles into Dalvik byte code that does two things:
Checks whether the static variable assertionsDisabled (set in the class' static constructor via a call to java.lang.Class.desiredAssertionStatus()) is != 0 and if so, does nothing
If it is 0, then it checks the assertion expression and throws a java.lang.AssertionError if the expression resolves to false, effectively terminating your application.
The Dalvik runtime by default has assertions turned off, and therefore desiredAssertionStatus always returns 1 (or more precisely, some non-zero value). This is akin to running in "retail" mode. In order to turn on "debug" mode, you can run the following command against the emulator or the device:
adb shell setprop debug.assert 1
and this should do the trick (should work on the emulator or any rooted debugging-ready device).
Note however that the aforementioned Dalvik code that checks the value of assertionsDisabled and throws an AssertionError if the expression is false is always included in your byte code and liberal sprinkling of asserts in your code may lead to byte code bloat.
Please see this for a bit more detail: Can I use assert on Android devices?
If you're concerned about shipping code with the JUnit asserts in (or any other class path), you can use the ProGuard config option 'assumenosideeffects', which will strip out a class path on the assumption that removing it does nothing to the code.
Eg.
-assumenosideeffects class junit.framework.Assert {
*;
}
I have a common debug library I put all my testing methods in, and then use this option to strip it from my released apps.
This also removes the hard to spot problem of strings being manipulated that are never used in release code. For example if you write a debug log method, and in that method you check for debug mode before logging the string, you are still constructing the string, allocating memory, calling the method, but then opting to do nothing. Stripping the class out then removes the calls entirely, meaning as long as your string is constructed inside the method call, it goes away as well.
Make sure it is genuinely safe to just strip the lines out however, as it is done with no checking on ProGuard's part. Removing any void returning method will be fine, however if you are taking any return values from whatever you are removing, make sure you aren't using them for actual operational logic.
I mean if you were using a language feature, like assert(), the compiler should be able to strip that out. But this is an actual class and if a class is referenced by executable code it will be included or assumed included in the final product by the compiler.
However there is nothing stopping you from creating a script that removes all the references to the Assert class in all of your code base before compilation.
Another approach would be to make a test project that targets your application and within JUnit tests actually calls the Assert on the areas which you want to make sure work. I personally like this approach because it is a nice and clean separation of test and application.
If you are just worried about the having an if-statement everywhere, then just wrap Assert with your own class, DebuggableAssert which does that check before each call to Assert.X. It will be sort of less performant because of the method entry/exit and the conditionals but if you can maintain your code better then it might be worth it.