防止 ProGuard 评估数学表达式并删除 Android 中未使用的指令
Preventing ProGuard from evaluating mathematical expressions and removing unused instructions in Android
我正在学习如何在 Android 中使用 ProGuard,在反编译调试 APK(使用 ProGuard 使用构建)后我注意到 ProGuard 删除了未使用的指令并计算数学表达式,例如:
如果我在使用 ProGuard 之前使用这行代码:
Integer JunkCode6666 = new Integer(Integer.MIN_VALUE+Integer.MAX_VALUE+1);
使用ProGuard后变成这样:
num = new Integer(0);
我想知道有没有办法保持原来的方式,这是为了混淆目的。如果有办法阻止 ProGuard 删除未使用的指令。谢谢。
我刚刚通过编译这个 class without proguard
进行了检查
public class Foo {
final Integer bar = new Integer(Integer.MIN_VALUE+Integer.MAX_VALUE+1);
}
编译构造函数是
public <init>()V
L0
LINENUMBER 1 L0
ALOAD 0
INVOKESPECIAL java/lang/Object.<init> ()V
L1
LINENUMBER 3 L1
ALOAD 0
NEW java/lang/Integer
DUP
ICONST_0 // <--- evaluated expression result
INVOKESPECIAL java/lang/Integer.<init> (I)V
PUTFIELD Foo.bar : Ljava/lang/Integer;
RETURN
L2
LOCALVARIABLE this LFoo; L0 L2 0
MAXSTACK = 4
MAXLOCALS = 1
所以它不是混淆器,而是 Java 编译器,这是因为 Integer
的构造函数中的值是 constant expression 并且在优化编译时间。
例如,您可以检查编译 class
的其他版本
public class Foo {
final Integer bar = new Integer(getA()+getB()+1);
private int getA(){
return Integer.MIN_VALUE;
}
private int getB(){
return Integer.MAX_VALUE;
}
}
将导致不同的构造函数
public <init>()V
L0
LINENUMBER 1 L0
ALOAD 0
INVOKESPECIAL java/lang/Object.<init> ()V
L1
LINENUMBER 3 L1
ALOAD 0
NEW java/lang/Integer
DUP
ALOAD 0
INVOKESPECIAL Foo.getA ()I
ALOAD 0
INVOKESPECIAL Foo.getB ()I
IADD
ICONST_1
IADD
INVOKESPECIAL java/lang/Integer.<init> (I)V
PUTFIELD Foo.bar : Ljava/lang/Integer;
RETURN
L2
LOCALVARIABLE this LFoo; L0 L2 0
MAXSTACK = 5
MAXLOCALS = 1
如您所见,在第二个版本中,实际上执行了 2 个加法,因为值是从方法调用中获得的,因此不再是常量。
我正在学习如何在 Android 中使用 ProGuard,在反编译调试 APK(使用 ProGuard 使用构建)后我注意到 ProGuard 删除了未使用的指令并计算数学表达式,例如: 如果我在使用 ProGuard 之前使用这行代码:
Integer JunkCode6666 = new Integer(Integer.MIN_VALUE+Integer.MAX_VALUE+1);
使用ProGuard后变成这样:
num = new Integer(0);
我想知道有没有办法保持原来的方式,这是为了混淆目的。如果有办法阻止 ProGuard 删除未使用的指令。谢谢。
我刚刚通过编译这个 class without proguard
进行了检查public class Foo {
final Integer bar = new Integer(Integer.MIN_VALUE+Integer.MAX_VALUE+1);
}
编译构造函数是
public <init>()V
L0
LINENUMBER 1 L0
ALOAD 0
INVOKESPECIAL java/lang/Object.<init> ()V
L1
LINENUMBER 3 L1
ALOAD 0
NEW java/lang/Integer
DUP
ICONST_0 // <--- evaluated expression result
INVOKESPECIAL java/lang/Integer.<init> (I)V
PUTFIELD Foo.bar : Ljava/lang/Integer;
RETURN
L2
LOCALVARIABLE this LFoo; L0 L2 0
MAXSTACK = 4
MAXLOCALS = 1
所以它不是混淆器,而是 Java 编译器,这是因为 Integer
的构造函数中的值是 constant expression 并且在优化编译时间。
例如,您可以检查编译 class
的其他版本public class Foo {
final Integer bar = new Integer(getA()+getB()+1);
private int getA(){
return Integer.MIN_VALUE;
}
private int getB(){
return Integer.MAX_VALUE;
}
}
将导致不同的构造函数
public <init>()V
L0
LINENUMBER 1 L0
ALOAD 0
INVOKESPECIAL java/lang/Object.<init> ()V
L1
LINENUMBER 3 L1
ALOAD 0
NEW java/lang/Integer
DUP
ALOAD 0
INVOKESPECIAL Foo.getA ()I
ALOAD 0
INVOKESPECIAL Foo.getB ()I
IADD
ICONST_1
IADD
INVOKESPECIAL java/lang/Integer.<init> (I)V
PUTFIELD Foo.bar : Ljava/lang/Integer;
RETURN
L2
LOCALVARIABLE this LFoo; L0 L2 0
MAXSTACK = 5
MAXLOCALS = 1
如您所见,在第二个版本中,实际上执行了 2 个加法,因为值是从方法调用中获得的,因此不再是常量。