Java – why doesn’t Proguard confuse method bodies?

I'm using Proguard to confuse my Jar program Everything is normal, but Proguard does not confuse local variables in the method body Here is an example:

raw:

Confusion:

Variable names highlighted in yellow should be confused, but they are not How can I obfuscate them (rename them a, B, C, etc.)

This is my Proguard configuration: http://pastebin.com/sb3DMRcC (the above method is not from one of the excluded classes)

Solution

Because it can't The names of method parameters and local variables are not stored at compile time The name you see is generated by your decompiler

For compiled code, there are two ways to store data locally (that is, in methods):

>On operand stack > in local variable

The operand stack is actually just a stack For stack operators, see table 7.2.1 in the Java VM specification You can pop up the value (pop up), copy the top value (DUP), swap the first two values (SWAP) and slightly change the behavior (Pop2, dup_x1, dup_x2, dup2, dup2_x1, dup2_x2) And in most cases, if not all instructions that generate a return value will discard the value on the stack

The important part of this problem is how to reference the content on the stack, which is similar to any other stack: relative to the top position and according to the instructions used There is no number or name specified, it's just anything current

Now, for the so-called "local variables":

Treat them as ArrayLists rather than variables in Java Because that's how you access them: by index For variables 0 to 3, there are special instructions (i.e. single byte) because they are often used. All other variables can only be accessed through double byte instructions, and the second byte is the index Refer again to table 7.2, "loads" and "stores" The first five entries in the two tables are wide (double byte) storage / load instructions for each data type (please note that for a single value, Boolean, char, byte and short are converted to int, leaving only int, float and object as single slot values and long and double as double slot values. The next 20 instructions are instructions to directly access registers 0 to 3, and the last 8 instructions are used to access array indexes (note that the internal array, byte, char and short are not converted to int and do not waste space, which is why there are three instructions (not four, because byte and char have the same size))

The maximum stack size and the number of local variables are limited and must be given in the title of the code attribute of each method, such as section 4.7 3 (max_stack and max_locals)

However, the interesting thing about local variables is that they are also method parameters, which means that the number of local variables will never be less than the number of method parameters Note that when calculating the value of Java VM, variables of type long and double will be treated as two values, so two "slots" are required Also note that for non - static methods, parameter 0 will be for this, which requires another "slot"

Having said that, let's take a 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 a parameter myargs In addition, we have two constants "42" and 42.0d, and many external references:

> java. Lang. string [] – class > java Lang.numberformatexception – class > java Lang.string – class > java lang.Integer. ParseInt – method > java lang.System. Out – Fields > java io. PrintStream. Println – method

There are also some exports: Test and main, and the default constructor generated by the compiler for us

All constants, references, and exports are exported to constant pool – local variables and parameter names are not

Compile and disassemble classes (using javap - C test) to generate:

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
}

In addition to the default constructor, we can step through our main methods Notice how to use astore_ 1 and aload_ 1 access mystring and use iStore_ 2 and Iload_ 2 access Myint and use dstore_ 3 and dload_ 3. Visit mydouble Myargs will not be accessed anywhere, so there is no bytecode to handle it, but at the beginning of the method, the reference to the string array will be in the local variable 1 and will soon be overwritten by the reference "42"

If you pass the - V flag, javap will also display the constant pool, but it doesn't really add any value to the output, because all the relevant information in the constant pool will be displayed in the comment

But now, let's look at what the decompiler produces!

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 exported to the constant pool is preserved, and jd-gui just selects some names for local variables, while Procyon optimizes them completely The name of the parameter – paramarrayofstring vs array (compared with the original myargs) – is a good example, but in order to indicate that there is no "correct" name, the decompiler only needs to rely on some modes of selecting the name

I don't know where the "real" names in the decompiled code come from, but I'm pretty sure they're not included in the jar file Is the functionality of the IDE possible?

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>