From 08456da845fa4f38c6db2b80ee8ac35b51264402 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Tue, 14 Feb 2023 22:10:17 +0100 Subject: [PATCH] Fixed #1972 AS3 Renaming invalid identifiers - various fixes Fixed #1972 AS3 imports taken only from packages, not package internal --- CHANGELOG.md | 2 + .../src/com/jpexs/decompiler/flash/SWF.java | 20 ++- .../com/jpexs/decompiler/flash/abc/ABC.java | 151 ++++++++++++------ .../flash/abc/avm2/AVM2Deobfuscation.java | 4 +- .../exporters/script/DependencyParser.java | 2 +- 5 files changed, 124 insertions(+), 55 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b8c160d3f..e2fb3e662 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ All notable changes to this project will be documented in this file. - [#1970] AS2 Renaming invalid identifiers for direct strings (no constant indices) - [#1970] AS2 Renaming invalid identifiers IndexOutOfBounds on invalid constant index (obfuscated code, etc.) - [#1972] AS3 Renaming invalid identifiers - '#' character +- [#1972] AS3 Renaming invalid identifiers - various fixes +- [#1972] AS3 imports taken only from packages, not package internal - Unresponsive status bar and its icon ## [18.3.5] - 2023-02-12 diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java index 7fcb3c974..adba388f6 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java @@ -2690,9 +2690,23 @@ public final class SWF implements SWFContainerItem, Timelined, Openable { } public int deobfuscateAS3Identifiers(RenameType renameType) { + + Map> stringUsageTypesMap = new HashMap<>(); + Map> stringUsagesMap = new HashMap<>(); + informListeners("deobfuscate", "Getting usages..."); for (Tag tag : getTags()) { - if (tag instanceof ABCContainerTag) { - ((ABCContainerTag) tag).getABC().deobfuscateIdentifiers(deobfuscated, renameType, true); + if (tag instanceof ABCContainerTag) { + Map stringUsageTypes = new HashMap<>(); + Set stringUsages = ((ABCContainerTag)tag).getABC().getStringUsages(); + ((ABCContainerTag)tag).getABC().getStringUsageTypes(stringUsageTypes); + stringUsageTypesMap.put(tag, stringUsageTypes); + stringUsagesMap.put(tag, stringUsages); + } + } + + for (Tag tag : getTags()) { + if (tag instanceof ABCContainerTag) { + ((ABCContainerTag) tag).getABC().deobfuscateIdentifiers(stringUsageTypesMap.get(tag),stringUsagesMap.get(tag), deobfuscated, renameType, true); ((ABCContainerTag) tag).getABC().constants.clearCachedMultinames(); ((ABCContainerTag) tag).getABC().constants.clearCachedDottedChains(); tag.setModified(true); @@ -2700,7 +2714,7 @@ public final class SWF implements SWFContainerItem, Timelined, Openable { } for (Tag tag : getTags()) { if (tag instanceof ABCContainerTag) { - ((ABCContainerTag) tag).getABC().deobfuscateIdentifiers(deobfuscated, renameType, false); + ((ABCContainerTag) tag).getABC().deobfuscateIdentifiers(stringUsageTypesMap.get(tag),stringUsagesMap.get(tag), deobfuscated, renameType, false); ((ABCContainerTag) tag).getABC().constants.clearCachedMultinames(); ((ABCContainerTag) tag).getABC().constants.clearCachedDottedChains(); tag.setModified(true); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ABC.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ABC.java index 0463b6dfd..3289790a8 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ABC.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ABC.java @@ -122,13 +122,13 @@ public class ABC implements Openable { /* Map from multiname index of namespace value to namespace name**/ private Map namespaceMap; - + private String file; - + private String fileTitle; - + private OpenableList openableList; - + private boolean isOpenable = false; public ABC(ABCContainerTag tag) { @@ -147,7 +147,7 @@ public class ABC implements Openable { public SWF getSwf() { return parentTag.getSwf(); } - + public List getAbcTags() { Openable openable = getOpenable(); if (openable instanceof SWF) { @@ -259,6 +259,7 @@ public class ABC implements Openable { public int removeTraps() throws InterruptedException { return removeTraps(null); } + public int removeTraps(DeobfuscationListener listener) throws InterruptedException { int rem = 0; for (int s = 0; s < script_info.size(); s++) { @@ -289,10 +290,41 @@ public class ABC implements Openable { } return ret; } - + + public void getTraitStringUsages(Set ret, Traits traits) { + for (Trait t:traits.traits) { + if (t instanceof TraitClass) { + int ci = ((TraitClass)t).class_info; + getTraitStringUsages(ret, instance_info.get(ci).instance_traits); + getTraitStringUsages(ret, class_info.get(ci).static_traits); + } + if (t instanceof TraitSlotConst) { + TraitSlotConst tsc = (TraitSlotConst)t; + if (tsc.value_kind == ValueKind.CONSTANT_Utf8) { + ret.add(tsc.value_index); + } + } + } + } + public Set getStringUsages() { Set ret = new HashSet<>(); + + for (ScriptInfo si:script_info) { + getTraitStringUsages(ret, si.traits); + } + + for (MethodInfo mi: method_info) { + if((mi.flags & MethodInfo.FLAG_HAS_OPTIONAL) == MethodInfo.FLAG_HAS_OPTIONAL) { + for (ValueKind vk : mi.optional) { + if (vk.value_kind == ValueKind.CONSTANT_Utf8) { + ret.add(vk.value_index); + } + } + } + } for (MethodBody body : bodies) { + getTraitStringUsages(ret, body.traits); for (AVM2Instruction ins : body.getCode().code) { for (int i = 0; i < ins.definition.operands.length; i++) { if (ins.definition.operands[i] == AVM2Code.DAT_STRING_INDEX) { @@ -308,7 +340,11 @@ public class ABC implements Openable { if (ret.containsKey(strIndex)) { if (!"name".equals(usageType)) { if (!ret.get(strIndex).equals(usageType)) { - ret.put(strIndex, "name"); + if ("class".equals(usageType) || ret.get(strIndex).equals("class")) { + ret.put(strIndex, "class"); + } else { + ret.put(strIndex, "name"); + } } } } else { @@ -316,14 +352,14 @@ public class ABC implements Openable { } } - private void getStringUsageTypes(Map ret, Traits traits, boolean classesOnly) { + private void getStringUsageTypes(Map ret, Traits traits) { for (Trait t : traits.traits) { int strIndex = constants.getMultiname(t.name_index).name_index; String usageType = ""; if (t instanceof TraitClass) { TraitClass tc = (TraitClass) t; - getStringUsageTypes(ret, class_info.get(tc.class_info).static_traits, classesOnly); - getStringUsageTypes(ret, instance_info.get(tc.class_info).instance_traits, classesOnly); + getStringUsageTypes(ret, class_info.get(tc.class_info).static_traits); + getStringUsageTypes(ret, instance_info.get(tc.class_info).instance_traits); if (instance_info.get(tc.class_info).name_index != 0) { setStringUsageType(ret, constants.getMultiname(instance_info.get(tc.class_info).name_index).name_index, "class"); @@ -331,6 +367,9 @@ public class ABC implements Openable { if (instance_info.get(tc.class_info).super_index != 0) { setStringUsageType(ret, constants.getMultiname(instance_info.get(tc.class_info).super_index).name_index, "class"); } + for (int iface : instance_info.get(tc.class_info).interfaces) { + setStringUsageType(ret, constants.getMultiname(iface).name_index, "class"); + } usageType = "class"; } @@ -339,14 +378,14 @@ public class ABC implements Openable { usageType = "method"; MethodBody body = findBody(tm.method_info); if (body != null) { - getStringUsageTypes(ret, body.traits, classesOnly); + getStringUsageTypes(ret, body.traits); } } if (t instanceof TraitFunction) { TraitFunction tf = (TraitFunction) t; MethodBody body = findBody(tf.method_info); if (body != null) { - getStringUsageTypes(ret, body.traits, classesOnly); + getStringUsageTypes(ret, body.traits); } usageType = "function"; } @@ -359,15 +398,13 @@ public class ABC implements Openable { usageType = "const"; } } - if (usageType.equals("class") || (!classesOnly)) { - setStringUsageType(ret, strIndex, usageType); - } + setStringUsageType(ret, strIndex, usageType); } } - public void getStringUsageTypes(Map ret, boolean classesOnly) { + public void getStringUsageTypes(Map ret) { for (ScriptInfo script : script_info) { - getStringUsageTypes(ret, script.traits, classesOnly); + getStringUsageTypes(ret, script.traits); } } @@ -386,32 +423,40 @@ public class ABC implements Openable { } } - public void deobfuscateIdentifiers(HashMap namesMap, RenameType renameType, boolean classesOnly) { - Set stringUsages = getStringUsages(); + public void deobfuscateIdentifiers(Map stringUsageTypes, Set stringUsages, HashMap namesMap, RenameType renameType, boolean doClasses) { Set namespaceUsages = getNsStringUsages(); - Map stringUsageTypes = new HashMap<>(); - informListeners("deobfuscate", "Getting usage types..."); - getStringUsageTypes(stringUsageTypes, classesOnly); AVM2Deobfuscation deobfuscation = getDeobfuscation(); - for (int i = 0; i < instance_info.size(); i++) { - informListeners("deobfuscate", "class " + i + "/" + instance_info.size()); - InstanceInfo insti = instance_info.get(i); - if (insti.name_index != 0) { - constants.getMultiname(insti.name_index).name_index = deobfuscation.deobfuscateName(stringUsageTypes, stringUsages, namespaceUsages, namesMap, constants.getMultiname(insti.name_index).name_index, true, renameType); - if (constants.getMultiname(insti.name_index).namespace_index != 0) { - constants.getNamespace(constants.getMultiname(insti.name_index).namespace_index).name_index - = deobfuscation.deobfuscatePackageName(stringUsageTypes, stringUsages, namesMap, constants.getNamespace(constants.getMultiname(insti.name_index).namespace_index).name_index, renameType); + + if (doClasses) { + for (int i = 0; i < instance_info.size(); i++) { + informListeners("deobfuscate", "class " + i + "/" + instance_info.size()); + InstanceInfo insti = instance_info.get(i); + if (insti.name_index != 0) { + constants.getMultiname(insti.name_index).name_index = deobfuscation.deobfuscateName(stringUsageTypes, stringUsages, namespaceUsages, namesMap, constants.getMultiname(insti.name_index).name_index, true, renameType); + if (constants.getMultiname(insti.name_index).namespace_index != 0) { + constants.getNamespace(constants.getMultiname(insti.name_index).namespace_index).name_index + = deobfuscation.deobfuscatePackageName(stringUsageTypes, stringUsages, namesMap, constants.getNamespace(constants.getMultiname(insti.name_index).namespace_index).name_index, renameType); + } + } + if (insti.super_index != 0) { + constants.getMultiname(insti.super_index).name_index = deobfuscation.deobfuscateName(stringUsageTypes, stringUsages, namespaceUsages, namesMap, constants.getMultiname(insti.super_index).name_index, true, renameType); + } + for (int iface : insti.interfaces) { + constants.getMultiname(iface).name_index = deobfuscation.deobfuscateName(stringUsageTypes, stringUsages, namespaceUsages, namesMap, constants.getMultiname(iface).name_index, true, renameType); } } - if (insti.super_index != 0) { - constants.getMultiname(insti.super_index).name_index = deobfuscation.deobfuscateName(stringUsageTypes, stringUsages, namespaceUsages, namesMap, constants.getMultiname(insti.super_index).name_index, true, renameType); - } - } - if (classesOnly) { + } else { return; } + for (int i = 1; i < constants.getMultinameCount(); i++) { informListeners("deobfuscate", "name " + i + "/" + constants.getMultinameCount()); + + Multiname m = constants.getMultiname(i); + int strIndex = m.name_index; + if (m.kind == Multiname.MULTINAME && strIndex > 0 && "*".equals(constants.getString(strIndex))) { + continue; + } constants.getMultiname(i).name_index = deobfuscation.deobfuscateName(stringUsageTypes, stringUsages, namespaceUsages, namesMap, constants.getMultiname(i).name_index, false, renameType); } for (int i = 1; i < constants.getNamespaceCount(); i++) { @@ -436,7 +481,12 @@ public class ABC implements Openable { String fullname = constants.getString(strIndex); String pkg = ""; String name = fullname; - if (fullname.contains(".")) { + boolean hasFourDots = false; + if (fullname.contains("::")) { + pkg = fullname.substring(0, fullname.lastIndexOf("::")); + name = fullname.substring(fullname.lastIndexOf("::") + 2); + hasFourDots = true; + } else if (fullname.contains(".")) { pkg = fullname.substring(0, fullname.lastIndexOf('.')); name = fullname.substring(fullname.lastIndexOf('.') + 1); } @@ -450,7 +500,7 @@ public class ABC implements Openable { name = constants.getString(nameStrIndex); String fullChanged = ""; if (!pkg.isEmpty()) { - fullChanged = pkg + "."; + fullChanged = pkg + (hasFourDots ? "::" : "."); } fullChanged += name; strIndex = constants.getStringId(fullChanged, true); @@ -507,6 +557,7 @@ public class ABC implements Openable { public ABC(ABCInputStream ais, SWF swf, ABCContainerTag tag) throws IOException { this(ais, swf, tag, null, null); } + public ABC(ABCInputStream ais, SWF swf, ABCContainerTag tag, String file, String fileTitle) throws IOException { this.parentTag = tag; this.file = file; @@ -514,7 +565,7 @@ public class ABC implements Openable { if (file != null || fileTitle != null) { isOpenable = true; } - + try { read(ais, swf); } catch (IOException ie) { @@ -526,7 +577,7 @@ public class ABC implements Openable { SWFDecompilerPlugin.fireAbcParsed(this, swf); } - + private void read(ABCInputStream ais, SWF swf) throws IOException { int minor_version = ais.readU16("minor_version"); int major_version = ais.readU16("major_version"); @@ -1039,7 +1090,7 @@ public class ABC implements Openable { return abcMethodIndexing; } - + public void resetMethodIndexing() { abcMethodIndexing = null; } @@ -2168,8 +2219,8 @@ public class ABC implements Openable { @Override public String getFile() { return file; - } - + } + @Override public String getFileTitle() { if (fileTitle != null) { @@ -2185,7 +2236,7 @@ public class ABC implements Openable { } return new File(file).getName(); } - + @Override public String getShortPathTitle() { if (openableList != null) { @@ -2210,12 +2261,12 @@ public class ABC implements Openable { } return getFileTitle(); } - + @Override public boolean isModified() { return getSwf().isModified(); //?? } - + @Override public void setOpenableList(OpenableList openableList) { this.openableList = openableList; @@ -2235,21 +2286,21 @@ public class ABC implements Openable { @Override public void saveTo(OutputStream os) throws IOException { saveToStream(os); - } - + } + @Override public void setFile(String file) { this.file = file; fileTitle = null; - } - + } + @Override public void clearModified() { getSwf().clearModified(); List allAbcs = new ArrayList<>(); allAbcs.add(this); List packs = getScriptPacks(null, allAbcs); - for(ScriptPack pack : packs) { + for (ScriptPack pack : packs) { if (pack.isModified()) { pack.clearModified(); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Deobfuscation.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Deobfuscation.java index 266bb534f..c9700485f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Deobfuscation.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Deobfuscation.java @@ -198,8 +198,10 @@ public class AVM2Deobfuscation { newname = DottedChain.parseNoSuffix(str); if (stringUsages.contains(strIndex) || namespaceUsages.contains(strIndex)) { // this name is already referenced as String + String usageType = stringUsageTypes.get(strIndex); strIndex = constants.addString(s); // add new index - } + stringUsageTypes.put(strIndex, usageType); + } constants.setString(strIndex, newname.toRawString()); if (!namesMap.containsKey(sChain)) { namesMap.put(sChain, DottedChain.parseNoSuffix(constants.getString(strIndex))); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/script/DependencyParser.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/script/DependencyParser.java index c9e01b5df..d3803272b 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/script/DependencyParser.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/script/DependencyParser.java @@ -50,7 +50,7 @@ public class DependencyParser { if (parseUsagesFromNS(ignoredCustom, abc, dependencies, uses, namespace_index, ignorePackage, name)) { return; - } else if ((ns.kind != Namespace.KIND_PACKAGE) && (ns.kind != Namespace.KIND_PACKAGE_INTERNAL)) { + } else if (ns.kind != Namespace.KIND_PACKAGE) { // && (ns.kind != Namespace.KIND_PACKAGE_INTERNAL)) { return; } newimport = newimport.addWithSuffix(name);