Is proguard capable to obfuscate logger messages?
The simple answer is that ProGuard does not do this.
And relatedly, ProGuard will not obfuscate constant strings in your code either; see Does proguard work to obfuscate static string constants?.
The best things I can suggest are:
- Turn off logging in your release version.
- Log to Crashlytics so that the end users don't to get to see the log messages on their devices.
- Implement a custom
LogFormatter
that obfuscates the log messages on the fly. (It could do it for all log messages, or just for log messages that match particular patterns.) - If you are actually trying to obfuscate the log message strings embedded in your code, there are alternatives to ProGuard that will do that; see the Q&A link above for some leads.
Don't obfuscate hardcoded string in proguard
Are you sure that this is the problem, because ProGuard doesn´t obfuscate string like stated in their FAQ:
No. String encryption in program code has to be perfectly reversible by definition, so it only improves the obfuscation level. It increases the footprint of the code. However, by popular demand, ProGuard's closed-source sibling for Android, DexGuard, does provide string encryption, along with more protection techniques against static and dynamic analysis
Similiar question (but the guy wants strings to be obfuscated), author of proguard replied:
https://stackoverflow.com/a/12665420/1643188
proguard doesnt preserve string values
Issue resolved, I added the following to the proguard-rules file
-keepclassmembers class * {
static java.lang.String *;
}
That did the trick :-)
Why proguard does not obfuscate method body?
Why proguard does not obfuscate method body?
Because it can't.
The names of method arguments and local variables are simply not stored when compiling.
The names you're seeing are generated by your decompiler.
For compiled code, there are two ways to store data locally (i.e. within a method):
- On the operand stack
- In local variables
The operand stack is really just a stack.
See Table 7.2 from the Java VM Specification for stack operators.
You can pop values (pop
), duplicate the top value (dup
), swap the top two values (swap
) and the same with slightly altered behaviour (pop2
, dup_x1
, dup_x2
, dup2
, dup2_x1
, dup2_x2
).
And most, if not all instructions that produce a return value will drop said value onto the stack.
The important thing for this question is how things on the stack are referred to, which is like with any other stack:
Relative to the top position, and based on the instruction used.
There are no assigned numbers or names, it's just whatever's currently there.
Now, for the so-called "local variables":
Think of them more as an ArrayList
than variables in Java.
Because that's exactly how you access them: by index.
For the variables 0 to 3, there are special instructions (i.e. single byte) because they are used so often, all other variables can only be accessed via a two-byte instruction, where the second byte is the index.
See Table 7.2 again, "Loads" and "Stores".
The first five entries in both tables are the wide (two-byte) store/load instructions for each data type (note that, for single values, boolean
, char
, byte
and short
are all converted to int
, leaving only int
, float
and Object
as single-slot values and long
and double
as double-slot ones), the next twenty instructions are the instructions for direct access to registers 0 to 3, and the last eight instructions are to access array indices (note that inside arrays, boolean
, byte
, char
and short
are not converted to int
, to not waste space, which is why there are three more instructions (not four, since byte
and char
have the same size)).
Both the maximum stack size and the number of local variables are limited, and must be given in the header of the Code
attribute of each method, as defined in Section 4.7.3 (max_stack
and max_locals
).
The interesting thing about local variables, though, is that they double as method arguments, meaning that the number of local variables can never be lower than the number of method arguments.
Note that when counting values for the Java VM, variables of the type long
and double
are treated as two values, and need two "slots" accordingly.
Also note that for non-static methods, the argument 0 will be this
, which requires another "slot" for itself.
That being said, let's look at some code!
Example:
class Test
{
public static void main(String[] myArgs) throws NumberFormatException
{
String myString = "42";
int myInt = Integer.parseInt(myString);
double myDouble = (double)myInt * 42.0d;
System.out.println(myDouble);
}
}
Here we have three local variables myString
, myInt
and myDouble
, plus one argument myArgs
.
In addition, we have two constants "42"
and 42.0d
, and a lot of external references:
java.lang.String[]
- classjava.lang.NumberFormatException
- classjava.lang.String
- classjava.lang.Integer.parseInt
- methodjava.lang.System.out
- fieldjava.io.PrintStream.println
- method
And some exports: Test
and main
, plus the default constructor that the compiler will generate for us.
All constants, references and exports will be exported to the Constant Pool - the local variables and argument names will not.
Compiling and disassembling the class (using javap -c Test
) yields:
Compiled from "Test.java"
class Test {
Test();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]) throws java.lang.NumberFormatException;
Code:
0: ldc #2 // String 42
2: astore_1
3: aload_1
4: invokestatic #3 // Method java/lang/Integer.parseInt:(Ljava/lang/String;)I
7: istore_2
8: iload_2
9: i2d
10: ldc2_w #4 // double 42.0d
13: dmul
14: dstore_3
15: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
18: dload_3
19: invokevirtual #7 // Method java/io/PrintStream.println:(D)V
22: return
}
Besides the default constructor, we can see our main
method, step by step.
Note how myString
is accessed with astore_1
and aload_1
, myInt
with istore_2
and iload_2
, and myDouble
with dstore_3
and dload_3
.myArgs
isn't accessed anywhere, so there's no bytecode dealing with it either, but at the beginning of the method, a reference to the String array will be in local variable 1, which gets soon overwritten by a reference to "42"
.
javap
will also show you the Constant Pool if you pass it the -v
flag, but it doesn't really add any value to the output, since all relevant information from the Constant Pool is displayed in comments anyway.
But now, let's look at what the decompilers produce!
JD-GUI 0.3.5 (JD-Core 0.6.2):
import java.io.PrintStream;
class Test
{
public static void main(String[] paramArrayOfString)
throws NumberFormatException
{
String str = "42";
int i = Integer.parseInt(str);
double d = i * 42.0D;
System.out.println(d);
}
}
Procyon 0.5.28:
class Test
{
public static void main(final String[] array) throws NumberFormatException {
System.out.println(Integer.parseInt("42") * 42.0);
}
}
Note how everything that was exported to the Constant Pool persists, while JD-GUI simply picks some names for local variables, and Procyon optimizes them out entirely.
The name of the argument - paramArrayOfString
vs array
(vs the original myArgs
) - is a perfect example, though, to show that there is no "correct" name anymore, and the decompilers simply have to rely on some pattern of picking a name.
I don't know where the "true" names in your decompiled code are coming from, but I'm fairly certain that they're not contained in the jar file.
Feature of your IDE maybe?
Setting ProGuard to obfuscate local variables and arguments
You should remove or refine the option -keepattributes
. It implies keeping attributes with local variable names:
-keepattributes LocalVariableTable,LocalVariableTypeTable
You could at least exclude those
-keepattributes !LocalVariableTable,!LocalVariableTypeTable
Ideally, you'd only preserve the attributes that are strictly required.
See the ProGuard manual > Usage > -keepattributes
Related Topics
Caused By: Java.Lang.Classnotfoundexception: Didn't Find Class in Firebase Phone Authentication
When Onbindviewholder Is Called and How It Works
How to Remove Only Trailing Spaces of a String in Java and Keep Leading Spaces
Bitmap Getwidth Returns Wrong Value
Android Retrofit Design Patterns
Simple Program to Call R from Java Using Eclipse and Rserve
Translating Ruby Encryption Code to Java
Java or Python for Natural Language Processing
Spring Boot - Handle to Hibernate Sessionfactory
How to Exclude an Element from a Firestore Query
Android Drawable Speech Bubble
Google Signin API Exception 10
How to Parse or Split Url Address in Java
How to Highlight Multiple Words in Edittext
Java Object Analogue to R Data.Frame