Java 为什么proguard不混淆方法体?
我正在使用ProGuard混淆我的.jar程序。除了ProGuard不会混淆方法体中的局部变量之外,一切都正常工作。以下是一个例子: 未加工: 模糊化: 以黄色突出显示的变量名称应该是模糊的,但它们不是。我怎样才能混淆它们(使它们重命名为a、b、c等?) 这是我的ProGuard配置:(上面的方法不是来自一个排除的类) 为什么proguard不混淆方法体 因为它不能 编译时不会存储方法参数和局部变量的名称。Java 为什么proguard不混淆方法体?,java,variables,jvm,proguard,obfuscation,Java,Variables,Jvm,Proguard,Obfuscation,我正在使用ProGuard混淆我的.jar程序。除了ProGuard不会混淆方法体中的局部变量之外,一切都正常工作。以下是一个例子: 未加工: 模糊化: 以黄色突出显示的变量名称应该是模糊的,但它们不是。我怎样才能混淆它们(使它们重命名为a、b、c等?) 这是我的ProGuard配置:(上面的方法不是来自一个排除的类) 为什么proguard不混淆方法体 因为它不能 编译时不会存储方法参数和局部变量的名称。 您看到的名称是由反编译器生成的 对于编译后的代码,有两种方法在本地(即在方法内)存储
您看到的名称是由反编译器生成的 对于编译后的代码,有两种方法在本地(即在方法内)存储数据:
- 在操作数堆栈上
- 在局部变量中
请参阅Java VM规范中的堆栈运算符。
您可以弹出值(
pop
),复制最上面的值(dup
),交换最上面的两个值(swap
),以及稍微改变行为的值(pop2
,dup\ux1
,dup\ux2
,dup2\ux1
,dup2\ux2
)。大多数,如果不是所有产生返回值的指令,都会将该值放到堆栈上 对于这个问题,重要的是如何引用堆栈上的内容,这与任何其他堆栈一样:
相对于顶部位置,并基于使用的指令。
没有指定的数字或名称,只是当前存在的任何内容 现在,对于所谓的“局部变量”: 与Java中的变量相比,它们更像是一个
ArrayList
。因为这正是您访问它们的方式:通过索引。
对于变量0到3,有特殊指令(即单字节指令),因为它们经常使用,所有其他变量只能通过双字节指令访问,其中第二个字节是索引。
请再次参阅“加载”和“存储”。
两个表中的前五个条目是每种数据类型的宽(双字节)存储/加载指令(注意,对于单值,
布尔值
、字符
、字节
和短
都转换为int
,只剩下int
、浮点值
和对象
作为单槽值,而长
和双
作为双槽值),接下来的二十条指令是直接访问寄存器0到3的指令,最后八条指令是访问数组索引的指令(请注意,在数组内部,boolean
、byte
、char
和short
未转换为int
,以避免浪费空间,这就是为什么还有三条指令(不是四条,因为byte
和char
的大小相同))
最大堆栈大小和局部变量的数量都是有限的,必须在每个方法的code
属性的标题中给出,如(max\u stack
和max\u locals
中所定义)
然而,关于局部变量的有趣之处在于,它们兼作方法参数,这意味着局部变量的数量永远不能低于方法参数的数量。请注意,在计算Java VM的值时,
long
和double
类型的变量被视为两个值,并需要相应的两个“插槽”。还请注意,对于非静态方法,参数0将是this,它本身需要另一个“槽” 话虽如此,让我们看看一些代码 例如:
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);
}
}
这里我们有三个局部变量myString
,myInt
和myDouble
,加上一个参数myArgs
此外,我们还有两个常量
“42”
和42.0d
,以及许多外部引用:
-classjava.lang.String[]
-classjava.lang.NumberFormatException
-classjava.lang.String
-方法java.lang.Integer.parseInt
-字段java.lang.System.out
-方法java.io.PrintStream.println
Test
和main
,以及编译器将为我们生成的默认构造函数
所有常量、引用和导出都将导出到-本地变量和参数名称将不会
编译和反汇编类(使用javap-c Test
)会产生:
Procyon 0.5.28:
class Test
{
public static void main(final String[] array) throws NumberFormatException {
System.out.println(Integer.parseInt("42") * 42.0);
}
}
请注意,导出到常量池的所有内容都是如何持久的,而JD-GUI只是为局部变量选择一些名称,Procyon会对它们进行完全优化。参数的名称-
paramArrayOfString
vsarray
(vs原始的myArgs
)-是一个完美的例子,它表明不再有“正确”的名称,反编译器只需依靠某种模式来选择名称
我不知道反编译代码中的“真实”名称来自何处,但我相当确定它们不包含在jar文件中。IDE的功能可能?是“模糊化”代码还是真正的Java代码或已反编译的Java代码?我的理解是字节码文件根本不记录方法参数和局部变量的名称。(如果这是ProGuard发出的源代码,请尝试编译它。然后反编译.class文件…或使用javap查看它。)@StephenC这是反编译的Java代码。我对.jar文件进行了模糊处理(在编译.jar之后使用ProGuard),然后反编译了较早的模糊处理的.jar.jar文件(字节码)
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);
}
}
class Test
{
public static void main(final String[] array) throws NumberFormatException {
System.out.println(Integer.parseInt("42") * 42.0);
}
}