mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-07-11 15:58:48 +00:00
common deobfuscated name generation in as3 and as2 deobfuscation
This commit is contained in:
@@ -38,7 +38,7 @@ import java.util.regex.Pattern;
|
||||
*/
|
||||
public class IdentifiersDeobfuscation {
|
||||
|
||||
private final Random rnd = new Random();
|
||||
private static final Random rnd = new Random();
|
||||
|
||||
private final int DEFAULT_FOO_SIZE = 10;
|
||||
|
||||
@@ -88,6 +88,14 @@ public class IdentifiersDeobfuscation {
|
||||
"void", "while", "with"
|
||||
};
|
||||
|
||||
// TODO, why do we have 2 different list? Moved from AVM2Deobfuscation
|
||||
public static final String[] reservedWordsAS3_2 = {
|
||||
"as", "break", "case", "catch", "class", "const", "continue", "default", "delete", "do", "each", "else",
|
||||
"extends", "false", "finally", "for", "function", "get", "if", "implements", "import", "in", "instanceof",
|
||||
"interface", "internal", "is", "native", "new", "null", "override", "package", "private", "protected", "public",
|
||||
"return", "set", "super", "switch", "this", "throw", "true", "try", "typeof", "use", "var", /*"void",*/ "while",
|
||||
"with", "dynamic", "default", "final", "in", "static"};
|
||||
|
||||
//syntactic keywords - can be used as identifiers, but that have special meaning in certain contexts
|
||||
public static final String[] syntacticKeywordsAS3 = {"each", "get", "set", "namespace", "include", "dynamic", "final", "native", "override", "static"};
|
||||
|
||||
@@ -105,44 +113,38 @@ public class IdentifiersDeobfuscation {
|
||||
return false;
|
||||
}
|
||||
|
||||
private String fooString(boolean as3, HashMap<DottedChain, DottedChain> deobfuscated, String orig, boolean firstUppercase, int rndSize) {
|
||||
boolean exists;
|
||||
String ret;
|
||||
loopfoo:
|
||||
do {
|
||||
exists = false;
|
||||
int len = 3 + rnd.nextInt(rndSize - 3);
|
||||
StringBuilder sb = new StringBuilder(len);
|
||||
for (int i = 0; i < len; i++) {
|
||||
char c;
|
||||
if ((i % 2) == 0) {
|
||||
c = FOO_CHARACTERS.charAt(rnd.nextInt(FOO_CHARACTERS.length()));
|
||||
} else {
|
||||
c = FOO_JOIN_CHARACTERS.charAt(rnd.nextInt(FOO_JOIN_CHARACTERS.length()));
|
||||
}
|
||||
if (i == 0 && firstUppercase) {
|
||||
c = Character.toUpperCase(c);
|
||||
}
|
||||
sb.append(c);
|
||||
// TODO: Why do we need this method???
|
||||
public static boolean isReservedWord2(String s) {
|
||||
if (s == null) {
|
||||
return false;
|
||||
}
|
||||
String[] reservedWords = reservedWordsAS3_2;
|
||||
s = s.trim();
|
||||
for (String rw : reservedWords) {
|
||||
if (rw.equals(s)) {
|
||||
return true;
|
||||
}
|
||||
ret = sb.toString();
|
||||
if (allVariableNamesStr.contains(ret)) {
|
||||
exists = true;
|
||||
rndSize += 1;
|
||||
continue loopfoo;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static String fooString(boolean firstUppercase, int rndSize) {
|
||||
int len = 3 + rnd.nextInt(rndSize - 3);
|
||||
StringBuilder sb = new StringBuilder(len);
|
||||
for (int i = 0; i < len; i++) {
|
||||
char c;
|
||||
if ((i % 2) == 0) {
|
||||
c = FOO_CHARACTERS.charAt(rnd.nextInt(FOO_CHARACTERS.length()));
|
||||
} else {
|
||||
c = FOO_JOIN_CHARACTERS.charAt(rnd.nextInt(FOO_JOIN_CHARACTERS.length()));
|
||||
}
|
||||
if (isReservedWord(ret, as3)) {
|
||||
exists = true;
|
||||
rndSize += 1;
|
||||
continue;
|
||||
if (i == 0 && firstUppercase) {
|
||||
c = Character.toUpperCase(c);
|
||||
}
|
||||
if (deobfuscated.containsValue(DottedChain.parse(ret))) {
|
||||
exists = true;
|
||||
rndSize += 1;
|
||||
continue;
|
||||
}
|
||||
} while (exists);
|
||||
return ret;
|
||||
sb.append(c);
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public void deobfuscateInstanceNames(boolean as3, HashMap<DottedChain, DottedChain> namesMap, RenameType renameType, List<Tag> tags, Map<DottedChain, DottedChain> selected) {
|
||||
@@ -266,25 +268,27 @@ public class IdentifiersDeobfuscation {
|
||||
if (namesMap.containsKey(sChain)) {
|
||||
return namesMap.get(sChain).toRawString();
|
||||
} else {
|
||||
Integer cnt = typeCounts.get(usageType);
|
||||
if (cnt == null) {
|
||||
cnt = 0;
|
||||
}
|
||||
|
||||
String ret = null;
|
||||
if (renameType == RenameType.TYPENUMBER) {
|
||||
boolean found;
|
||||
int rndSize = DEFAULT_FOO_SIZE;
|
||||
do {
|
||||
found = false;
|
||||
if (renameType == RenameType.TYPENUMBER) {
|
||||
ret = Helper.getNextId(usageType, typeCounts, true);
|
||||
if (allVariableNamesStr.contains(ret)) {
|
||||
found = true;
|
||||
}
|
||||
} else if (renameType == RenameType.RANDOMWORD) {
|
||||
ret = fooString(firstUppercase, rndSize);
|
||||
if (allVariableNamesStr.contains(ret)
|
||||
|| isReservedWord(ret, as3)
|
||||
|| namesMap.containsValue(DottedChain.parse(ret))) {
|
||||
found = true;
|
||||
rndSize++;
|
||||
}
|
||||
}
|
||||
} while (found);
|
||||
|
||||
boolean found;
|
||||
do {
|
||||
found = false;
|
||||
cnt++;
|
||||
ret = usageType + "_" + cnt;
|
||||
found = allVariableNamesStr.contains(ret);
|
||||
} while (found);
|
||||
typeCounts.put(usageType, cnt);
|
||||
} else if (renameType == RenameType.RANDOMWORD) {
|
||||
ret = fooString(as3, namesMap, s, firstUppercase, DEFAULT_FOO_SIZE);
|
||||
}
|
||||
namesMap.put(DottedChain.parse(s), DottedChain.parse(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -16,14 +16,15 @@
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.abc.avm2;
|
||||
|
||||
import com.jpexs.decompiler.flash.IdentifiersDeobfuscation;
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.abc.RenameType;
|
||||
import com.jpexs.decompiler.graph.DottedChain;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@@ -33,27 +34,14 @@ import java.util.regex.Pattern;
|
||||
*/
|
||||
public class AVM2Deobfuscation {
|
||||
|
||||
private static final Random rnd = new Random();
|
||||
|
||||
private static final int DEFAULT_FOO_SIZE = 10;
|
||||
|
||||
public static final String[] reservedWords = {
|
||||
"as", "break", "case", "catch", "class", "const", "continue", "default", "delete", "do", "each", "else",
|
||||
"extends", "false", "finally", "for", "function", "get", "if", "implements", "import", "in", "instanceof",
|
||||
"interface", "internal", "is", "native", "new", "null", "override", "package", "private", "protected", "public",
|
||||
"return", "set", "super", "switch", "this", "throw", "true", "try", "typeof", "use", "var", /*"void",*/ "while",
|
||||
"with", "dynamic", "default", "final", "in", "static"};
|
||||
|
||||
public static final String VALID_FIRST_CHARACTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_";
|
||||
|
||||
public static final String VALID_NEXT_CHARACTERS = VALID_FIRST_CHARACTERS + "0123456789";
|
||||
|
||||
public static final String VALID_NS_CHARACTERS = ".:$";
|
||||
|
||||
public static final String FOO_CHARACTERS = "bcdfghjklmnpqrstvwz";
|
||||
|
||||
public static final String FOO_JOIN_CHARACTERS = "aeiouy";
|
||||
|
||||
private final SWF swf;
|
||||
|
||||
private final AVM2ConstantPool constants;
|
||||
@@ -69,18 +57,9 @@ public class AVM2Deobfuscation {
|
||||
this.constants = constants;
|
||||
}
|
||||
|
||||
private static boolean isReserved(String s) {
|
||||
for (String rw : reservedWords) {
|
||||
if (rw.equals(s.trim())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isValidNSPart(String s) {
|
||||
boolean isValid = true;
|
||||
if (isReserved(s)) {
|
||||
if (IdentifiersDeobfuscation.isReservedWord2(s)) {
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
@@ -114,62 +93,29 @@ public class AVM2Deobfuscation {
|
||||
return null;
|
||||
}
|
||||
|
||||
private String fooString(HashMap<DottedChain, DottedChain> deobfuscated, String orig, boolean firstUppercase, int rndSize, String usageType, RenameType renameType) {
|
||||
boolean exists;
|
||||
String ret;
|
||||
int pos = 0;
|
||||
|
||||
private String fooString(HashMap<DottedChain, DottedChain> deobfuscated, String orig, boolean firstUppercase, String usageType, RenameType renameType) {
|
||||
if (usageType == null) {
|
||||
usageType = "name";
|
||||
}
|
||||
if (usageTypesCount.containsKey(usageType)) {
|
||||
pos = usageTypesCount.get(usageType);
|
||||
}
|
||||
|
||||
loopfoo:
|
||||
String ret = null;
|
||||
boolean found;
|
||||
int rndSize = DEFAULT_FOO_SIZE;
|
||||
|
||||
do {
|
||||
exists = false;
|
||||
ret = "";
|
||||
found = false;
|
||||
if (renameType == RenameType.TYPENUMBER) {
|
||||
pos++;
|
||||
ret = usageType + "_" + pos;
|
||||
ret = Helper.getNextId(usageType, usageTypesCount, true);
|
||||
} else if (renameType == RenameType.RANDOMWORD) {
|
||||
int len = 3 + rnd.nextInt(rndSize - 3);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < len; i++) {
|
||||
char c;
|
||||
if ((i % 2) == 0) {
|
||||
c = FOO_CHARACTERS.charAt(rnd.nextInt(FOO_CHARACTERS.length()));
|
||||
} else {
|
||||
c = FOO_JOIN_CHARACTERS.charAt(rnd.nextInt(FOO_JOIN_CHARACTERS.length()));
|
||||
}
|
||||
if (i == 0 && firstUppercase) {
|
||||
c = Character.toUpperCase(c);
|
||||
}
|
||||
sb.append(c);
|
||||
}
|
||||
|
||||
ret = sb.toString();
|
||||
ret = IdentifiersDeobfuscation.fooString(firstUppercase, rndSize);
|
||||
}
|
||||
if (swf.as3StringConstantExists(ret)) {
|
||||
exists = true;
|
||||
rndSize += 1;
|
||||
continue loopfoo;
|
||||
|
||||
if (swf.as3StringConstantExists(ret)
|
||||
|| IdentifiersDeobfuscation.isReservedWord2(ret)
|
||||
|| deobfuscated.containsValue(DottedChain.parse(ret))) {
|
||||
found = true;
|
||||
rndSize++;
|
||||
}
|
||||
if (isReserved(ret)) {
|
||||
exists = true;
|
||||
rndSize += 1;
|
||||
continue;
|
||||
}
|
||||
if (deobfuscated.containsValue(DottedChain.parse(ret))) {
|
||||
exists = true;
|
||||
rndSize += 1;
|
||||
continue;
|
||||
}
|
||||
} while (exists);
|
||||
usageTypesCount.put(usageType, pos);
|
||||
} while (found);
|
||||
deobfuscated.put(DottedChain.parse(orig), DottedChain.parse(ret));
|
||||
return ret;
|
||||
}
|
||||
@@ -194,7 +140,7 @@ public class AVM2Deobfuscation {
|
||||
for (int p = 0; p < sChain.size(); p++) {
|
||||
String part = sChain.get(p);
|
||||
if (!isValidNSPart(part)) {
|
||||
ret.add(fooString(namesMap, part, false, DEFAULT_FOO_SIZE, "package", renameType));
|
||||
ret.add(fooString(namesMap, part, false, "package", renameType));
|
||||
} else {
|
||||
ret.add(part);
|
||||
}
|
||||
@@ -218,7 +164,7 @@ public class AVM2Deobfuscation {
|
||||
}
|
||||
String s = constants.getString(strIndex);
|
||||
boolean isValid = true;
|
||||
if (isReserved(s)) {
|
||||
if (IdentifiersDeobfuscation.isReservedWord2(s)) {
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
@@ -244,7 +190,7 @@ public class AVM2Deobfuscation {
|
||||
if (namesMap.containsKey(sChain)) {
|
||||
newname = namesMap.get(sChain);
|
||||
} else {
|
||||
String str = fooString(namesMap, constants.getString(strIndex), firstUppercase, DEFAULT_FOO_SIZE, stringUsageTypes.get(strIndex), renameType);
|
||||
String str = fooString(namesMap, constants.getString(strIndex), firstUppercase, stringUsageTypes.get(strIndex), renameType);
|
||||
newname = DottedChain.parse(str);
|
||||
}
|
||||
if (stringUsages.contains(strIndex) || namespaceUsages.contains(strIndex)) { // this name is already referenced as String
|
||||
|
||||
@@ -1365,4 +1365,24 @@ public class Helper {
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
public static String getNextId(String str, Map<String, Integer> lastIds) {
|
||||
return getNextId(str, lastIds, false);
|
||||
}
|
||||
|
||||
public static String getNextId(String str, Map<String, Integer> lastIds, boolean addFirst) {
|
||||
Integer a = lastIds.get(str);
|
||||
if (a == null) {
|
||||
lastIds.put(str, 1);
|
||||
if (addFirst) {
|
||||
str += "_1";
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
a++;
|
||||
lastIds.put(str, a);
|
||||
return str + "_" + a;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user