From ea56b5680fb4f37100d997072c00bfe810ce8d4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Thu, 24 Jul 2025 23:47:25 +0200 Subject: [PATCH] Fixed: #1295, #116 AS3 dynamic construction via MultinameL --- CHANGELOG.md | 4 +- .../construction/ConstructPropIns.java | 3 +- .../abc/avm2/model/ConstructAVM2Item.java | 46 ++++++++++-- .../abc/avm2/model/ConstructPropAVM2Item.java | 34 ++++++++- .../decompiler/flash/abc/types/Multiname.java | 2 +- .../exporters/script/DependencyParser.java | 25 +++++++ .../as3decompile/ActionScript3ClassTest.java | 21 ++++++ .../as3_assembled-0/as3_assembled-0.main.abc | Bin 10225 -> 10450 bytes .../as3_assembled-0.main.asasm | 1 + .../TestConstructDynamically.class.asasm | 70 ++++++++++++++++++ .../TestConstructDynamically.script.asasm | 29 ++++++++ .../as3_assembled/bin/as3_assembled.swf | Bin 5905 -> 6015 bytes 12 files changed, 226 insertions(+), 9 deletions(-) create mode 100644 libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/tests/TestConstructDynamically.class.asasm create mode 100644 libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/tests/TestConstructDynamically.script.asasm diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d258fc33..1f4d1a8b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,7 @@ All notable changes to this project will be documented in this file. - [#2493] Incorrect placement of §§push instructions - AS3 direct editation/highlighter §§pop in class traits - AS direct editation/highlighter §§pop and §§dup can have getmember or call +- [#1295], [#116] AS3 dynamic construction via MultinameL ### Changed - Icon of "Deobfuscation options" menu from pile of pills to medkit @@ -3937,6 +3938,8 @@ Major version of SWF to XML export changed to 2. [#2483]: https://www.free-decompiler.com/flash/issues/2483 [#2486]: https://www.free-decompiler.com/flash/issues/2486 [#2493]: https://www.free-decompiler.com/flash/issues/2493 +[#1295]: https://www.free-decompiler.com/flash/issues/1295 +[#116]: https://www.free-decompiler.com/flash/issues/116 [#2476]: https://www.free-decompiler.com/flash/issues/2476 [#2404]: https://www.free-decompiler.com/flash/issues/2404 [#1418]: https://www.free-decompiler.com/flash/issues/1418 @@ -4178,7 +4181,6 @@ Major version of SWF to XML export changed to 2. [#2099]: https://www.free-decompiler.com/flash/issues/2099 [#2090]: https://www.free-decompiler.com/flash/issues/2090 [#2079]: https://www.free-decompiler.com/flash/issues/2079 -[#116]: https://www.free-decompiler.com/flash/issues/116 [#2097]: https://www.free-decompiler.com/flash/issues/2097 [#2098]: https://www.free-decompiler.com/flash/issues/2098 [#2093]: https://www.free-decompiler.com/flash/issues/2093 diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/construction/ConstructPropIns.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/construction/ConstructPropIns.java index 2b0c1f7e2..18b293243 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/construction/ConstructPropIns.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/construction/ConstructPropIns.java @@ -30,6 +30,7 @@ import com.jpexs.decompiler.flash.abc.avm2.model.FullMultinameAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.RegExpAvm2Item; import com.jpexs.decompiler.flash.abc.avm2.model.StringAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.XMLAVM2Item; +import com.jpexs.decompiler.flash.abc.types.Multiname; import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.TranslateStack; import com.jpexs.helpers.Reference; @@ -108,7 +109,7 @@ public class ConstructPropIns extends InstructionDefinition { if (obj instanceof FindPropertyAVM2Item) { multiname.property = false; //can be type - } + } stack.push(new ConstructPropAVM2Item(ins, localData.lineStartInstruction, obj, multiname, args, type.getVal(), isStatic.getVal())); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/ConstructAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/ConstructAVM2Item.java index c6738cb81..55db0972d 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/ConstructAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/ConstructAVM2Item.java @@ -16,11 +16,14 @@ */ package com.jpexs.decompiler.flash.abc.avm2.model; +import com.jpexs.decompiler.flash.abc.types.Multiname; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; +import com.jpexs.decompiler.graph.DottedChain; import com.jpexs.decompiler.graph.GraphSourceItem; import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.GraphTargetVisitorInterface; import com.jpexs.decompiler.graph.model.LocalData; +import com.jpexs.helpers.Helper; import java.util.List; import java.util.Objects; @@ -75,12 +78,45 @@ public class ConstructAVM2Item extends AVM2Item { || (object instanceof CallStaticAVM2Item) || (object instanceof CallSuperAVM2Item); - if (object.getPrecedence() > getPrecedence() || objectIsCall) { - writer.append("("); + boolean isGetDefinition = false; + if (object instanceof GetPropertyAVM2Item) { + GetPropertyAVM2Item getProperty = (GetPropertyAVM2Item) object; + if (getProperty.propertyName instanceof FullMultinameAVM2Item) { + FullMultinameAVM2Item fm = (FullMultinameAVM2Item) getProperty.propertyName; + if (fm.multinameIndex > 0) { + Multiname m = localData.abc.constants.getMultiname(fm.multinameIndex); + if (m.kind == Multiname.MULTINAMEL) { + if (m.getNamespaceSet(localData.abc.constants).namespaces.length == 1) { + isGetDefinition = true; + writer.append("("); + if (localData.fullyQualifiedNames.contains(DottedChain.parseNoSuffix("flash.utils.getDefinitionByName"))) { + writer.append("flash.utils.getDefinitionByName"); + } else { + writer.append("getDefinitionByName"); + } + writer.append("("); + String nname = m.getSingleNamespace(localData.abc.constants).getName(localData.abc.constants).toRawString(); + if (!nname.isEmpty()) { + writer.append("\""); + writer.append(Helper.escapeActionScriptString(nname)); + writer.append("\"+\".\"+"); + } + fm.name.appendTo(writer, localData); + writer.append("))"); + } + } + } + } } - object.toString(writer, localData); - if (object.getPrecedence() > getPrecedence() || objectIsCall) { - writer.append(")"); + + if (!isGetDefinition) { + if (object.getPrecedence() > getPrecedence() || objectIsCall) { + writer.append("("); + } + object.toString(writer, localData); + if (object.getPrecedence() > getPrecedence() || objectIsCall) { + writer.append(")"); + } } writer.spaceBeforeCallParenthesis(args.size()); if (object instanceof InitVectorAVM2Item) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/ConstructPropAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/ConstructPropAVM2Item.java index 85e793db4..0aa69d86f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/ConstructPropAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/ConstructPropAVM2Item.java @@ -16,11 +16,14 @@ */ package com.jpexs.decompiler.flash.abc.avm2.model; +import com.jpexs.decompiler.flash.abc.types.Multiname; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; +import com.jpexs.decompiler.graph.DottedChain; import com.jpexs.decompiler.graph.GraphSourceItem; import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.GraphTargetVisitorInterface; import com.jpexs.decompiler.graph.model.LocalData; +import com.jpexs.helpers.Helper; import java.util.List; import java.util.Objects; @@ -86,7 +89,36 @@ public class ConstructPropAVM2Item extends AVM2Item { @Override public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) throws InterruptedException { writer.append("new "); - formatProperty(writer, object, propertyName, localData, isStatic, false); + boolean isGetDefinition = false; + if (propertyName instanceof FullMultinameAVM2Item) { + FullMultinameAVM2Item fm = (FullMultinameAVM2Item) propertyName; + if (fm.multinameIndex > 0) { + Multiname m = localData.abc.constants.getMultiname(fm.multinameIndex); + if (m.kind == Multiname.MULTINAMEL) { + if (m.getNamespaceSet(localData.abc.constants).namespaces.length == 1) { + isGetDefinition = true; + writer.append("("); + if (localData.fullyQualifiedNames.contains(DottedChain.parseNoSuffix("flash.utils.getDefinitionByName"))) { + writer.append("flash.utils.getDefinitionByName"); + } else { + writer.append("getDefinitionByName"); + } + writer.append("("); + String nname = m.getSingleNamespace(localData.abc.constants).getName(localData.abc.constants).toRawString(); + if (!nname.isEmpty()) { + writer.append("\""); + writer.append(Helper.escapeActionScriptString(nname)); + writer.append("\"+\".\"+"); + } + fm.name.appendTo(writer, localData); + writer.append("))"); + } + } + } + } + if (!isGetDefinition) { + formatProperty(writer, object, propertyName, localData, isStatic, false); + } writer.spaceBeforeCallParenthesis(args.size()); writer.append("("); for (int a = 0; a < args.size(); a++) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/Multiname.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/Multiname.java index c553be4d5..5b38cb60c 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/Multiname.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/Multiname.java @@ -989,7 +989,7 @@ public class Multiname { * @return True if this MULTINAME kind with only one namespace */ public boolean isMULTINAMEwithOneNs(AVM2ConstantPool pool) { - return kind == MULTINAME && pool.getNamespaceSet(namespace_set_index).namespaces.length == 1; + return (kind == MULTINAME || kind == MULTINAMEL || kind == MULTINAMELA) && pool.getNamespaceSet(namespace_set_index).namespaces.length == 1; } /** 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 d4bfb026c..f9678b4fc 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 @@ -21,10 +21,13 @@ import com.jpexs.decompiler.flash.abc.avm2.AVM2Code; import com.jpexs.decompiler.flash.abc.avm2.AVM2Deobfuscation; import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction; import com.jpexs.decompiler.flash.abc.avm2.instructions.alchemy.AlchemyTypeIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.construction.ConstructIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.construction.ConstructPropIns; import com.jpexs.decompiler.flash.abc.avm2.instructions.construction.NewClassIns; import com.jpexs.decompiler.flash.abc.avm2.instructions.construction.NewFunctionIns; import com.jpexs.decompiler.flash.abc.avm2.instructions.other.GetLexIns; import com.jpexs.decompiler.flash.abc.avm2.instructions.other.GetOuterScopeIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other.GetPropertyIns; import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushScopeIns; import com.jpexs.decompiler.flash.abc.avm2.model.InitVectorAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.parser.script.AbcIndexing; @@ -196,6 +199,7 @@ public class DependencyParser { } } boolean wasNewClass = false; + AVM2Instruction prevIns = null; for (int i = 0; i < body.getCode().code.size(); i++) { AVM2Instruction ins = body.getCode().code.get(i); @@ -245,6 +249,26 @@ public class DependencyParser { } } } + if (ins.definition instanceof ConstructPropIns) { + Multiname m = abc.constants.getMultiname(ins.operands[0]); + if (m != null) { + if (m.kind == Multiname.MULTINAMEL) { + Dependency dep = new Dependency(DottedChain.parseNoSuffix("flash.utils.getDefinitionByName"), DependencyType.NAMESPACE); + dependencies.add(dep); + } + } + } + + //TODO: what if there's jump between getproperty and construct? + if (ins.definition instanceof ConstructIns && prevIns != null && prevIns.definition instanceof GetPropertyIns) { + Multiname m = abc.constants.getMultiname(prevIns.operands[0]); + if (m != null) { + if (m.kind == Multiname.MULTINAMEL) { + Dependency dep = new Dependency(DottedChain.parseNoSuffix("flash.utils.getDefinitionByName"), DependencyType.NAMESPACE); + dependencies.add(dep); + } + } + } if (classIndex > -1 && ins.definition instanceof GetOuterScopeIns) { if (ins.operands[0] > 0) { //first is global DottedChain type = abc.instance_info.get(classIndex).getName(abc.constants).getNameWithNamespace(abc.constants, true); @@ -282,6 +306,7 @@ public class DependencyParser { numberContextRef.setVal(ins.operands[k]); } } + prevIns = ins; } } } diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3ClassTest.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3ClassTest.java index 743e18a40..2d009a5cd 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3ClassTest.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3ClassTest.java @@ -748,4 +748,25 @@ public class ActionScript3ClassTest extends ActionScript3DecompileTestBase { + "}\n" ); } + + @Test + public void testConstructDynamically() { + decompileScriptPack("assembled", "tests.TestConstructDynamically", "package tests\n" + + "{\n" + + "import flash.display.*;\n" + + "import flash.utils.getDefinitionByName;\n" + + "public class TestConstructDynamically\n" + + "{\n" + + "public function TestConstructDynamically()\n" + + "{\n" + + "super();\n" + + "}\n" + + "public function test() : void\n" + + "{\n" + + "var _loc1_:* = new (getDefinitionByName(\"flash.display\"+\".\"+\"Sprite\"))();\n" + + "_loc1_ = new (getDefinitionByName(\"Object\"))();\n" + + "}\n" + + "}\n" + + "}"); + } } diff --git a/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/as3_assembled-0.main.abc b/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/as3_assembled-0.main.abc index f5ec7afc1f4cd7287067daebcc7ffc4ef2c0b953..b6b6498f05da2efba73b21bb172a132ca51deee8 100644 GIT binary patch delta 3661 zcmZ`*XK+(j7Cz_dJzZT{vL)Lpmh|K%+gOsZFwLRb##qJ_Q4BnaK(euU228UF5Q78PZ!wR?5ccw)!nL3-J|YP z_pA4)i_|hTpayLZp-qT+A4Bis=)H*EC(!#kdf!K{%e%t2)UWxyexKjPRY!Nq|7Z07 z1^wS*Knr*SzQB15lm(Ut0)gOUL?^Qm)q;hAVwbz9#65ROi)vYxTCqq!aM+C4hy|5} zWk)ediA9~a_E0;&a)@G>VmZYM zij@?rC{|PC|8^#nDHIRzroyTbY@r@M^?ZPA0SPAPoMS?$oswOY5K0zOvY3(;)Ul9S z9n|?AQs-j2F2#BX3sE+TgncT^#)9$Sq+kuiI6YhRtCxu-W z)@@-MU)U_*z4|H(bfce7mKL_LrnsFI0>P!Cq(+zztf(N+D#H4~E@45KuuV`XVNp3@ zeNZf6Ni|`c!7HJ!p0Gg(NEnO~wjII}mIn#zfhqw5~b&8)is2a|&U5VUC1z6NC*xn}qWMgk_;a!sIl<_CuG1 z3!4br14|@K#R$U43d`CSw7rCgu&#yJUKRk?v_dy3WrSs5wPfmzgzbiP60V<0*gn`O zVP*nh+n`s%O{Ijbhs_cial&@MRtdM&61D|)NVsznVZ$&a;qY|A?t#4$?yDgy*#I1n z_+SNLei)H(6e|fUgJUQM$I(NW7w$6$_oJ7vG(2PuPGTKlTj8`hIDE^3T>qgEY)F@aiv~8#)D$Zrnv-JU7Szs6!4z*uSqxEuiKuFQh|&awU(sVLM~UO>s+r=w8cUniPT#V>m^ju*|qJ-S6R!rbYrZ(i0*UBv*bhxXX2M+c+5*6TNV z)YJ+~6ScX&A0HQLrFpfN%;W>Qq8a6UyKkD7OeG;H82&utHIs2rS2d%WU-LCI&5wVC zJ!*8+emypbsSPAEKeZ8(fJ1Hq#F2R?VpA75)j89fI8n*kKi{iahHblXY09 zni1s#{+hnI3z;ekQeE9%dw;^PHJ8qT4hh$gleA!YzAvwnZ=| zNQPUS;p--26m_N<5sqau-7@;T89jo!T{A*_QQ2-Y`o0-Gih6-&Oyu8`)pRW%3dY6V zm5MU}5U4^Z3vlpOGG2V*mc0FViSUZ>r6+F1owr2kDf!axnR3TacW6cfpA~3|Jc}tr zO`Oj#UO7||3Kh~|b?O8n1Ue7(d!>Tb;l@GDvjJNWOkO6OHG{s8L5nlX*DaC71)wqpHlH*>8M3(Mf9+n)G~W~juq zKpwF;;NO@BEa%GN&+}d3#>p>8hIYHyb$NVT#%tovR&kwGjg!T%($f4AKQfCwhHKUPVuZZCY|5rr-w{w4GX!fi+V^&gJzqs^=<&`DTD%Rt$ z?2yfNr);*nz+!`JetDmoYNt^5X~tB(tFnIirf519>q~fZM7sHU zwmE%Q#Gbt?38YyznY)14VIZIUq?vr0w^hZOwsowA(M=+)zb&FZ(_@Wg+j^{#zh`?y zwZVMCyJo@})B~Ck=a;JDmBpz7OtN%=c&dH|r6x!+*Aj7|{k!>(RjZwEnt5kY4{Am& zUs~OOU-84$A^eg*QQe8x_;=MyoFAH;bEt-}F~|6bWD_UD)J znMviSYnm~gpNz~7Zx>I9?7fHbls8PudDO$2QNzEF)S;Uf)r4_ApI8&>C`?hj9=KF5e!SZI!m#8`yq<=itUyjji~Pv$~x!pU+c?v#7QEcXcN6`E1WyKC!3xx=+n z6NM=i)2gVTqDuv+bzc?TM-@9zO@RmQ2s~v9Jj%bVZ8TFGr+UR&)cAi3h<5Dy?0@o4 z-N}F2%zupUt=rOn#l(-JUac8*VwvaU-<+R2nD{Sbwy?z50`Y?e=aDFi>K{wQ9qA=; iN7oX#8OQYEIQB1YgPVeI;ZB81rs_r1Bbwn8Gyefra>{uC delta 3422 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