I'm using progurad to get rid of some logging:
-assumenosideeffects class android.util.Log {
public static int d(...);
public static int v(...);
}
I don't want anything else to happen to any classes. In particular I don't want any obfuscation, since this is a library. The clients of the library will apply obfuscation themselfs.
Is there a way to tell proguard to do "nothing" except the -assumenosideeffects rule please?
This option is applied in the optimization step, so you could disable shrinking and obfuscation. You still need to provide -keep options, e.g. ProGuard manual > Examples > A typical library.
Related
I use Kotlin and I have many internal classes.
I want to obfuscate and shrink everything apart from all public classes.
Proguard rules:
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-verbose
-optimizationpasses 5
-overloadaggressively
-repackageclasses ''
-allowaccessmodification
-keep public class * {
public <methods>;
public <fields>;
}
Unfortunately the -keep public class * behaves defensively and keeps all names, also for the internal classes.
Your rules are way too broad.
Single "-keep" with nested rules is more broad, compared to combination of "-keepmembers" and "-keepclasseswithmembers" rules
Full "-keep" rule means "do not change bytecode of that method, ever"
Classes, referenced by kept classes and methods, can not be removed, renamed or repackaged
This line in your rules keeps all your classes and interfaces:
-keep public class * {
I mean ALL of them. Whether they have public members or not.
Use -keepclasseswithmembers instead!
Because of these lines
{
public <methods>;
public <fields>;
}
all your public methods will be left untouched, which means that repackaging and renaming methods, referenced from your public methods can not be carried out!
If you want at least some repackaging to be done, make sure to allow optimization (because repackaging is performed as part of optimization step):
-keepmembers,allowoptimization public class * {
public <methods>;
public <fields>;
}
In addition to repackaging, this will also allow for some inlining (which in turn assists in removing classes, that supply inlined methods).
Also with Android apps you are much better off repackaging into your primary package (the application package, or package with biggest number of your immovable classes in it) instead of empty package (''). This is because some "exported" classes (Activities, Views, Services, other stuff, referenced from xml files) can not be moved outside of their package by Proguard, — aapt dynamically generates special rules to prevent that. The part of optimization process, that changes access modes from public to protected/private, becomes more efficient the more classes can be placed together in single package.
I want to obfuscate and shrink everything apart from all public classes.
Bad idea. You really should try to obfuscate as much as possible, especially public classes. If you restrict obfuscation, repackaging is also restricted! It would rename them!!
Aim for the most specific rules possible.
If you want to prevent shrinking:
-keep,allowoptimization,allowobfuscation public class com.example.Example
If you want to prevent renaming, but allow stripping unused classes:
-keep,allowoptimization,allowshrinking public class com.example.*
In general, avoid wildcard rules (bare *) and -keep rules: prefer rules for specific classes and -keepmembers/-keepclasseswithmembers
The correct approaches for obfuscating applications and libraries are completely different, but they have something in common — you should not care about public methods/classes; just obfuscate/shrink/repackage as much as possible until any more would break it.
For applications you should just obfuscate/repackage as much as possible. If you don't know, which packages are safe to obfuscate, start from opting known safe packages into obfuscation.
For libraries — do not apply Proguard to library itself (unless you are trying to achieve security by obscurity). Use the feature of aar format — consumer proguard files — that allows to supply rule "segments", which should be followed during final app obfuscation.
I'm in a situation where the implementation of a library we are using is newer than the implementation one of our dependencies was coded against. E.g. Dependency uses MyLibrary-1.0 and we're using MyLibrary-2.0.
In the newer implementation a deprecated method has been removed, which causes run-time errors for us.
I'm trying to use AOP (Spring-AOP to be specific) to intercept calls made to the missing method, and proxy them into an existing method... but I can't seem to get the Aspect right.
It feels like Java is raising the 'java.lang.NoSuchMethodError' exception before my Aspect has an opportunity to intercept. Is there some trick I'm missing, or is this just not feasible (e.g. the method must exist in order to aspect it)?
#Before("execution(* com.mylibrary.SomeClass.*(..))")
Fails with java.lang.NoSuchMethodError
#Around("target(com.mylibrary.SomeClass) && execution(* missingMethod(..))")
Fails with java.lang.NoSuchMethodError
Assuming that your are talking about a 3rd party library which is independent of Spring, you cannot use Spring AOP with its proxy-based "AOP lite" approach which only works for public, non-static methods of Spring components. Please use the more powerful AspectJ instead. The Spring manual explains how to integrate full AspectJ with load-time weaving (LTW) into Spring applications. If your application is not based on Spring so far and you just wanted to use the framework because of Spring AOP, you can skip the whole Spring stuff altogether and use plain AspectJ.
The feature you want to use is an inter-type declaration (ITD), more specifically AspectJ's ability to declare methods for existing classes. Here is some sample code:
3rd party library:
package org.library;
public class Utility {
public String toHex(int number) {
return Integer.toHexString(number);
}
// Let us assume that this method was removed from the new library version
/*
#Deprecated
public String toOct(int number) {
return Integer.toOctalString(number);
}
*/
}
Let us assume that the method I commented out was just removed from the latest version your own project depends on, but you know how to re-implement it.
Project dependency depending on old version of 3rd party library:
package com.dependency;
import org.library.Utility;
public class MyDependency {
public void doSomethingWith(int number) {
System.out.println(number + " in octal = " + new Utility().toOct(number));
}
}
Because the previously deprecated method Utility.toOct does not exist anymore in the version used by your own project, you will get NoSuchMethodError during runtime when calling MyDependency.doSomethingWith.
Your own application:
package de.scrum_master.app;
import org.library.Utility;
import com.dependency.MyDependency;
public class Application {
public static void main(String[] args) {
System.out.println("3333 in hexadecimal = " + new Utility().toHex(3333));
new MyDependency().doSomethingWith(987);
}
}
As you can see, the application also uses the same library, but a different method which still exists in the current version. Unfortunately, it also uses the dependency which relies on the existence of the removed method. So how should we repair this?
Aspect using ITD:
AspectJ to the rescue! We just add the missing method to the 3rd party library.
package de.scrum_master.aspect;
import org.library.Utility;
public aspect DeprecatedMethodProvider {
public String Utility.toOct(int number) {
return Integer.toOctalString(number);
}
}
If you compile this project with the AspectJ compiler Ajc, it just works. In your real life scenario, compile the aspect into its own aspect library, put the weaving agent aspectjweaver.jar on the JVM command line in order to activate LTW and enjoy how it weaves the method into the library class via byte code instrumentation during class-loading.
Log output:
3333 in hexadecimal = d05
987 in octal = 1733
Et voilà! Enjoy. :-)
When the JVM load a class, it resolves all dependencies in a "linker" phase : external classes, properties and method. You can't pass this phase in your case, because methods are missing.
There are two modes on (Spring-)AOP: Proxy, and weaving.
Proxy create... a proxy around a class: the targeted class must exist and be loaded
Weaving can happen before a class is loaded: when a classloader load a class, an array of byte[] is passed to the weaver, which can manipulate the class bytecode before the class is really reified. This type of aop can work in your case. However, it will not be an easy task.
Will DexGuard help me to obfuscate my broadcastReceiver ? I have important algorithm in one of my broadcast Receivers and i need a way to obfuscate it, but DexGuard needs purchase a license ? Proguards free, any suggestions ? and i can't find a link to download redex by facebook so i assume its still in development. So my question is which one of them will obfuscate my broadcastReceiver.
my proguard file has content like this:
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
**-keep public class * extends android.content.BroadcastReceiver**
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class com.android.vending.licensing.ILicensingService
notice it says to keep broadcastReceiver, how can i hide my data ? I'd have to try and move all my logic to another class but broadcastreceiver gets garbage collected aggressively. So not a option.
You are right the default ProGuard and DexGuard config excludes classes that extend BroadcastReceiver so just move to another class. It would be better OO design to have your logic in separate class - makes it more testable for one. Certainly DexGuard will offer stronger protection than ProGuard given it has specific protection functionality Class encryption and API hiding sound as if they would be useful. Note there are other commercial obfuscators for Android.
For increased security one option would be to store/run the algorithm in native code given it's more difficult to reverse engineer.
But actually as you say important algorithm I wonder if it should be in the app at all. Storing and running the algorithm in a controlled server environment and having a secure API would be better IMO - of course there's no 100% security as your server could get hacked but this would likely be better than having a copy of the algorithm in every .apk downloaded.
In IntelliJ when code is not used anywhere it will be "grayed out." Is there any way to see if a set of classes aren't used anywhere?
I have this set of classes with references to each other so IntelliJ is counting this set of classes as being used. In this case I know the code is useless but it would be nice to have the ability to automatically detect this sort of thing. The logic to do this isn't amazingly difficult... Does anyone know if this is possible in IntelliJ?
This "greyed out" mark simply reflects declaration usages in other source code files or framework configuration files. Declaration usage search cannot detect orphan clusters of classes as these classes are formally referenced.
There is a technique, that may help here: define some root set of entry points (main() methods, web.xml declarations, etc) and trace all the references, effectively building a graph of used classes/methods. Once graph is completed, you can treat unvisited classes as dead code. Pretty similar to what Java garbage collector does during young gen collection. It is quite difficult and resource consuming for on-the-fly code analysis, so Intellij has it implemented as a separate inspection one can run manually.
To demonstrate it let's create a fresh project containing the following code:
public class Main {
public static void main(String[] args) {
System.out.println(new Used());
}
}
class Used {}
class ObviouslyUnused {}
class TrickyUnused1 {
TrickyUnused1() {
System.out.println(new TrickyUnused2());
}
}
class TrickyUnused2 {
TrickyUnused2() {
System.out.println(new TrickyUnused1());
}
}
In the editor we can see, that only ObvoiuslyUnused is greyed out. Let's run an "Unused declaration" inspection:
and here we go, inspections shows, that our unused self-referenced class cluster is not reachable:
You should be aware, though, that there are always means of referencing code in implicit ways: reflection, native calls, runtime code generation, SPI implementations, references from framework configuration files, etc. So no static anlisys tool can be 100% accurate when detecting dead code.
I have a library that is about to be obfuscated using ProGuard. "Library mode" is almost applicable for my use case, i.e. it is almost fine to keep all public and protected classes and class members.
However due to Java's visibility requirements some members cannot be made package private or private and thus they are public classes although they should not be in the library. I would like to have them obfuscated to make it more clearly that these classes do not belong to the public api, as well as to get better obfuscation and smaller library jars.
Is there a way to exclude some items from a proguard "keep" rule without specifying each of these items by name (using the '!').
Ideally I would like to annotate these classes and members with a tagging annotation, but as far as I understand Proguard can only be told to keep items with certain annotations.
You can only keep items indeed. If you want to exclude certain class members, you have to do so by listing or annotating the class members that you do want to keep. When specifying a class name, you can provide a list, optionally with "!" to exclude names. When specifying a class member name and type, that is not possible. Still, in both cases, you can use wildcards. If you pick special names for your internal classes, this might work:
-keep public class * {
public protected *** !myInternalField*;
public protected *** !myInternalMethod*(...);
}