Fixed #116 AS3 Cyclic typenames protection

This commit is contained in:
Jindra Petřík
2023-10-07 17:36:15 +02:00
parent 7d1f4db775
commit 1c29ada719
5 changed files with 78 additions and 26 deletions

View File

@@ -729,6 +729,7 @@ public class ABC implements Openable {
}
ais.endDumpLevel();
}
constants.checkCyclicTypeNames();
ais.endDumpLevel(); // cpool_info

View File

@@ -867,4 +867,10 @@ public class AVM2ConstantPool implements Cloneable {
}
}
public void checkCyclicTypeNames() {
for (int i = 0; i < constant_multiname.size(); i++) {
Multiname.checkTypeNameCyclic(this, i);
}
}
}

View File

@@ -99,11 +99,11 @@ public class InstanceInfo {
CharacterTag ct = abc.getSwf().getCharacterByClass(className);
if (ct != null) {
if (ct instanceof DefineBinaryDataTag) {
writer.appendNoHilight("[Embed(source=\"" + ASSETS_DIR + ct.getCharacterExportFileName() + ".bin\", mimeType=\"application/octet-stream\")]").newLine();
writer.appendNoHilight("[Embed(source=\"" + ASSETS_DIR + Helper.makeFileName(ct.getCharacterExportFileName()) + ".bin\", mimeType=\"application/octet-stream\")]").newLine();
}
if (ct instanceof ImageTag) {
ImageTag it = (ImageTag) ct;
writer.appendNoHilight("[Embed(source=\"" + ASSETS_DIR + ct.getCharacterExportFileName() + ((ImageTag) ct).getImageFormat().getExtension() + "\")]").newLine();
writer.appendNoHilight("[Embed(source=\"" + ASSETS_DIR + Helper.makeFileName(ct.getCharacterExportFileName()) + ((ImageTag) ct).getImageFormat().getExtension() + "\")]").newLine();
}
if (ct instanceof DefineSpriteTag) {
writer.appendNoHilight("[Embed(source=\"" + ASSETS_DIR + "assets.swf\", symbol=\"" + Helper.escapeActionScriptString(className) + "\")]").newLine();
@@ -111,7 +111,7 @@ public class InstanceInfo {
if (ct instanceof DefineSoundTag) {
//should be mp3, otherwise it won't work. Should we convert this?
DefineSoundTag st = (DefineSoundTag) ct;
writer.appendNoHilight("[Embed(source=\"" + ASSETS_DIR + ct.getCharacterExportFileName() + "." + (st.getSoundFormat().formatId == SoundFormat.FORMAT_MP3 ? "mp3" : "wav") + "\")]").newLine();
writer.appendNoHilight("[Embed(source=\"" + ASSETS_DIR + Helper.makeFileName(ct.getCharacterExportFileName()) + "." + (st.getSoundFormat().formatId == SoundFormat.FORMAT_MP3 ? "mp3" : "wav") + "\")]").newLine();
}
if (ct instanceof FontTag) {
FontTag ft = (FontTag) ct;
@@ -125,7 +125,7 @@ public class InstanceInfo {
}
}
writer.appendNoHilight("[Embed(source=\"" + ASSETS_DIR + ct.getCharacterExportFileName() + ".ttf\",").newLine();
writer.appendNoHilight("[Embed(source=\"" + ASSETS_DIR + Helper.makeFileName(ct.getCharacterExportFileName()) + ".ttf\",").newLine();
writer.appendNoHilight("fontName=\"" + Helper.escapeActionScriptString(ft.getFontNameIntag()) + "\",").newLine();
writer.appendNoHilight("fontFamily=\"" + Helper.escapeActionScriptString(ft.getFontName())+ "\",").newLine();
writer.appendNoHilight("mimeType=\"application/x-font\",").newLine();
@@ -174,7 +174,7 @@ public class InstanceInfo {
if (ct instanceof DefineFont4Tag) {
DefineFont4Tag ft4 = (DefineFont4Tag)ct;
writer.appendNoHilight("[Embed(source=\"" + ASSETS_DIR + ct.getCharacterExportFileName() + ".cff\",").newLine();
writer.appendNoHilight("[Embed(source=\"" + ASSETS_DIR + Helper.makeFileName(ct.getCharacterExportFileName()) + ".cff\",").newLine();
writer.appendNoHilight("fontName=\"" + Helper.escapeActionScriptString(ft4.fontName) + "\",").newLine();
writer.appendNoHilight("mimeType=\"application/x-font\",").newLine();
writer.appendNoHilight("fontWeight=\"" + (ft4.fontFlagsBold ? "bold" : "normal") + "\",").newLine();

View File

@@ -80,6 +80,9 @@ public class Multiname {
@Internal
private boolean displayNamespace = false;
@Internal
private boolean cyclic = false;
public String getNamespaceSuffix() {
if (displayNamespace) {
return "#" + namespace_index;
@@ -157,6 +160,39 @@ public class Multiname {
return new Multiname(TYPENAME, 0, 0, 0, qname_index, params);
}
public static void checkTypeNameCyclic(AVM2ConstantPool constants, int name_index) {
Set<Integer> visited = new HashSet<>();
if (name_index >= constants.getMultinameCount()) {
return;
}
Multiname m = constants.getMultiname(name_index);
if (m != null) {
m.cyclic = checkCyclicTypeNameSub(constants, name_index, visited);
}
}
private static boolean checkCyclicTypeNameSub(AVM2ConstantPool constants, int name_index, Set<Integer> visited) {
if (name_index >= constants.getMultinameCount()) {
return false;
}
Multiname m = constants.getMultiname(name_index);
if (m != null && m.kind == Multiname.TYPENAME) {
if (visited.contains(name_index)) {
return true;
}
visited.add(name_index);
if (checkCyclicTypeNameSub(constants, m.qname_index, visited)) {
return true;
}
for (int p : m.params) {
if (checkCyclicTypeNameSub(constants, p, visited)) {
return true;
}
}
}
return false;
}
public boolean isAttribute() {
if (kind == QNAMEA) {
return true;
@@ -272,16 +308,15 @@ public class Multiname {
String versionAdd = "";
if (name != null && name.length() > 0) {
char lastChar = name.charAt(name.length() - 1);
if (lastChar >= Namespace.MIN_API_MARK && lastChar <= Namespace.MAX_API_MARK) {
name = name.substring(0, name.length() - 1);
versionAdd = String.format("\\u%04x", (int) lastChar);
}
}
return constants.getNamespace(index).getKindStr() + "(" + (name == null ? "null" : "\"" +
Helper.escapePCodeString(name) + versionAdd
return constants.getNamespace(index).getKindStr() + "(" + (name == null ? "null" : "\""
+ Helper.escapePCodeString(name) + versionAdd
+ "\"") + (sub > 0 ? ",\"" + sub + "\"" : "") + ")";
}
@@ -331,6 +366,9 @@ public class Multiname {
case MULTINAMELA:
return getKindStr() + "(" + namespaceSetToString(constants, namespace_set_index) + ")";
case TYPENAME:
if (cyclic) {
return "CyclicTypeName";
}
String tret = getKindStr() + "(";
tret += multinameToString(constants, qname_index, fullyQualifiedNames);
tret += "<";
@@ -350,8 +388,8 @@ public class Multiname {
}
private String typeNameToStr(AVM2ConstantPool constants, List<DottedChain> fullyQualifiedNames, boolean dontDeobfuscate, boolean withSuffix) {
if (constants.getMultiname(qname_index).name_index == name_index) {
return "ambiguousTypeName";
if (cyclic) {
return "§§cyclic_typename()";
}
StringBuilder typeNameStr = new StringBuilder();
typeNameStr.append(constants.getMultiname(qname_index).getName(constants, fullyQualifiedNames, dontDeobfuscate, withSuffix));
@@ -389,7 +427,7 @@ public class Multiname {
if (nskind == Namespace.KIND_NAMESPACE || nskind == Namespace.KIND_PACKAGE_INTERNAL) {
DottedChain dc = abc.findCustomNsOfMultiname(this);
String nsname = dc != null ? dc.getLast() : null;
if (nsname != null && !"AS3".equals(nsname)) {
String identifier = dontDeobfuscate ? nsname : IdentifiersDeobfuscation.printIdentifier(true, nsname);
if (identifier != null && !identifier.isEmpty()) {
@@ -432,9 +470,9 @@ public class Multiname {
if (cached != null) {
return cached;
}
DottedChain nsName = getSimpleNamespaceName(constants);
if (nsName == null) {
if (nsName == null) {
Namespace ns = getNamespace(constants);
if (ns == null) {
NamespaceSet nss = getNamespaceSet(constants);
@@ -453,7 +491,7 @@ public class Multiname {
if (nsName != null) {
ret = nsName.add(name, withSuffix ? getNamespaceSuffix() : "");
} else {
ret = new DottedChain(new String[]{name}, new String[]{withSuffix ? getNamespaceSuffix() : ""});
ret = new DottedChain(new String[]{name}, new String[]{withSuffix ? getNamespaceSuffix() : ""});
}
constants.cacheMultinameWithNamespace(this, ret);
return ret;
@@ -466,19 +504,20 @@ public class Multiname {
return constants.getNamespace(namespace_index);
}
}
/**
* Gets simple namespace name as dottedchain. Ignores swf api versioning.
*
* @param constants
* @return
* @return
*/
public DottedChain getSimpleNamespaceName(AVM2ConstantPool constants) {
public DottedChain getSimpleNamespaceName(AVM2ConstantPool constants) {
if (hasOwnNamespace()) {
if (namespace_index == 0 || namespace_index == -1) {
return DottedChain.EMPTY;
}
return getNamespace(constants).getName(constants);
}
}
if (hasOwnNamespaceSet()) {
NamespaceSet nss = getNamespaceSet(constants);
if (nss == null) {
@@ -488,11 +527,12 @@ public class Multiname {
}
return null;
}
/**
* Gets simplpe namespace kind. Ignores swf api versioning.
*
* @param constants
* @return
* @return
*/
public int getSimpleNamespaceKind(AVM2ConstantPool constants) {
if (hasOwnNamespace()) {
@@ -500,7 +540,7 @@ public class Multiname {
return 0;
}
return getNamespace(constants).kind;
}
}
if (hasOwnNamespaceSet()) {
NamespaceSet nss = getNamespaceSet(constants);
if (nss == null) {
@@ -510,7 +550,7 @@ public class Multiname {
}
return 0;
}
public List<Integer> getApiVersions(AVM2ConstantPool constants) {
if (hasOwnNamespace()) {
return new ArrayList<>();
@@ -520,7 +560,7 @@ public class Multiname {
}
return new ArrayList<>();
}
public boolean isApiVersioned(AVM2ConstantPool constants) {
if (hasOwnNamespace()) {
return false;
@@ -656,4 +696,8 @@ public class Multiname {
return true;
}
public boolean isCyclic() {
return cyclic;
}
}