diff --git a/jadx-core/src/main/java/jadx/core/deobf/Deobfuscator.java b/jadx-core/src/main/java/jadx/core/deobf/Deobfuscator.java index 859341f95..e555b05de 100644 --- a/jadx-core/src/main/java/jadx/core/deobf/Deobfuscator.java +++ b/jadx-core/src/main/java/jadx/core/deobf/Deobfuscator.java @@ -483,21 +483,7 @@ public class Deobfuscator { if (name.length() > maxLength) { return "x" + Integer.toHexString(name.hashCode()); } - if (!NameMapper.isAllCharsPrintable(name)) { - return removeInvalidChars(name); - } - return name; - } - - private String removeInvalidChars(String name) { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < name.length(); i++) { - int ch = name.charAt(i); - if (NameMapper.isPrintableChar(ch)) { - sb.append((char) ch); - } - } - return sb.toString(); + return NameMapper.removeInvalidCharsMiddle(name); } private void dumpClassAlias(ClassNode cls) { diff --git a/jadx-core/src/main/java/jadx/core/deobf/NameMapper.java b/jadx-core/src/main/java/jadx/core/deobf/NameMapper.java index 4e8e75686..9262f051f 100644 --- a/jadx-core/src/main/java/jadx/core/deobf/NameMapper.java +++ b/jadx-core/src/main/java/jadx/core/deobf/NameMapper.java @@ -91,6 +91,14 @@ public class NameMapper { && isAllCharsPrintable(str); } + public static boolean isValidIdentifierStart(int codePoint) { + return Character.isJavaIdentifierStart(codePoint); + } + + public static boolean isValidIdentifierPart(int codePoint) { + return Character.isJavaIdentifierPart(codePoint); + } + public static boolean isPrintableChar(int c) { return 32 <= c && c <= 126; } @@ -105,6 +113,49 @@ public class NameMapper { return true; } + /** + * Return modified string with removed: + *
+ * Note: this 'middle' method must be used with prefixed string: + *
+ */ + public static String removeInvalidCharsMiddle(String name) { + if (isValidIdentifier(name) && isAllCharsPrintable(name)) { + return name; + } + int len = name.length(); + StringBuilder sb = new StringBuilder(len); + for (int i = 0; i < len; i++) { + int codePoint = name.codePointAt(i); + if (isPrintableChar(codePoint) && isValidIdentifierPart(codePoint)) { + sb.append((char) codePoint); + } + } + return sb.toString(); + } + + /** + * Return string with removed invalid chars, see {@link #removeInvalidCharsMiddle} + *
+ * Prepend prefix if first char is not valid as java identifier start char.
+ */
+ public static String removeInvalidChars(String name, String prefix) {
+ String result = removeInvalidCharsMiddle(name);
+ if (!result.isEmpty()) {
+ int codePoint = result.codePointAt(0);
+ if (!isValidIdentifierStart(codePoint)) {
+ return prefix + result;
+ }
+ }
+ return result;
+ }
+
private NameMapper() {
}
}
diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/RenameVisitor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/RenameVisitor.java
index 802e27942..c3cf80bbe 100644
--- a/jadx-core/src/main/java/jadx/core/dex/visitors/RenameVisitor.java
+++ b/jadx-core/src/main/java/jadx/core/dex/visitors/RenameVisitor.java
@@ -72,14 +72,9 @@ public class RenameVisitor extends AbstractVisitor {
ClassInfo classInfo = cls.getClassInfo();
ClassInfo alias = classInfo.getAlias();
String clsName = alias.getShortName();
- String newShortName = null;
- char firstChar = clsName.charAt(0);
- if (Character.isDigit(firstChar)) {
- newShortName = Consts.ANONYMOUS_CLASS_PREFIX + clsName;
- } else if (firstChar == '$') {
- newShortName = "C" + clsName;
- }
- if (newShortName != null) {
+
+ String newShortName = fixClsShortName(clsName);
+ if (!newShortName.equals(clsName)) {
classInfo.rename(cls.root(), alias.makeFullClsName(newShortName, true));
}
if (alias.getPackage().isEmpty()) {
@@ -89,6 +84,17 @@ public class RenameVisitor extends AbstractVisitor {
}
}
+ private String fixClsShortName(String clsName) {
+ char firstChar = clsName.charAt(0);
+ if (Character.isDigit(firstChar)) {
+ return Consts.ANONYMOUS_CLASS_PREFIX + NameMapper.removeInvalidCharsMiddle(clsName);
+ }
+ if (firstChar == '$') {
+ return 'C' + NameMapper.removeInvalidCharsMiddle(clsName);
+ }
+ return NameMapper.removeInvalidChars(clsName, "C");
+ }
+
private void checkFields(ClassNode cls) {
Set