| benf.org : other : cfr : Illegal identifiers - (For obfuscation or otherwise). |
Note that this is a fairly similar issue to renaming duplicate identifiers
One possible attempt at obfuscation (again, as with renaming duplicate identifiers, this is such a simple transformation it's probably not worth the name 'obfuscation'....) is to hack the const pool of a class to give members / methods names which are not valid identifiers.
It's more complex than you might think! Java is very friendly to non-ascii languages, and allows unicode identifiers, so as to facilitate development in non-english languages.
Because of this, it's not as simple as writing a small regex to determine if an identifier is valid - I encourage you to look at java.lang.CharacterData, java.lang.CharacterData00, java.lang.CharacterData01 etc if you don't believe me!
Instead, we make use of Character.isJavaIdentifierStart & Character.isJavaIdentifierPart - please see Java Language Spec 3.8 for details.
Here, I've used a hex editor to alter the constant pool so that I have both members and methods with spaces in their names. If we decompile this as is, it produces illegal java.
/*
* Decompiled with CFR 0_93.
*/
package org.benf.cfr.tests;
import java.io.PrintStream;
/*
* Illegal identifiers - consider using --renameillegalidents true
*/
public class NameTest22 {
public float f d;
public int f e;
public NameTest22(int n) {
this.f d = n + 3;
this.f e = n + 4;
}
public void tes a() {
System.out.println(this.f d);
}
public void tes b() {
System.out.println(this.f e);
}
}
I've left enough information to disambiguate identifiers, but of course, I could have renamed them entirely to spaces as well!
CFR (as of 0_93) will check if a class is using illegal identifiers in its own fields/methods, and remind you to use --renameillegalidents true
package org.benf.cfr.tests;
import java.io.PrintStream;
public class NameTest22 {
public float cfr_renamed_0;
public int cfr_renamed_1;
public NameTest22(int n) {
this.cfr_renamed_0 = n + 3;
this.cfr_renamed_1 = n + 4;
}
public void cfr_renamed_2() {
System.out.println(this.cfr_renamed_0);
}
public void cfr_renamed_3() {
System.out.println(this.cfr_renamed_1);
}
}
Please note: CFR will not automatically enable this flag.
We need to make sure that the name chosen to replace these idents is used everywhere the same illegal ident is used - it's of no use if CFR chooses replacements for a client class in one pass, and different ones for the implementation in another. So this is only going to be of value if you are decompiling a definition and usage in the same pass
| Last updated 01/2015 |