From 0a4dc74c61eaf3c8d1caec3d36d49f3b653742f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Sat, 3 Apr 2021 19:25:57 +0200 Subject: [PATCH] =?UTF-8?q?Fixed:=20AS=20decompilation=20-=20=C2=A7=C2=A7p?= =?UTF-8?q?ush=20before=20loop?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 1 + .../flash/abc/avm2/graph/AVM2Graph.java | 18 +++- .../action/model/FunctionActionItem.java | 3 +- .../src/com/jpexs/decompiler/graph/Graph.java | 22 ++-- .../ActionScript3AssembledDecompileTest.java | 16 +++ .../as3_assembled-0/as3_assembled-0.main.abc | Bin 6744 -> 7021 bytes .../as3_assembled-0.main.asasm | 1 + .../tests/TestPushWhile.class.asasm | 99 ++++++++++++++++++ .../tests/TestPushWhile.script.asasm | 29 +++++ .../as3_assembled/bin/as3_assembled.swf | Bin 4084 -> 4250 bytes 10 files changed, 176 insertions(+), 13 deletions(-) create mode 100644 libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/tests/TestPushWhile.class.asasm create mode 100644 libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/tests/TestPushWhile.script.asasm diff --git a/CHANGELOG.md b/CHANGELOG.md index 4df8d40b3..045558141 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ All notable changes to this project will be documented in this file. - Rename invalid identifiers renames identifiers with a dollar sign - [#1676] Messages on movie tags when Flash Player ActiveX not available - [#1677] DefineFont2/3 - missing codeTableOffset if numGlyphs is zero and font has layout +- AS decompilation - §§push before loop ## [14.3.1] - 2021-03-25 ### Fixed diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java index 606c3b5f5..aeef14a0f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java @@ -1611,7 +1611,7 @@ public class AVM2Graph extends Graph { } @Override - protected GraphTargetItem checkLoop(List output, LoopItem loopItem, BaseLocalData localData, List loops, List throwStates) { + protected GraphTargetItem checkLoop(List output, LoopItem loopItem, BaseLocalData localData, List loops, List throwStates, TranslateStack stack) { AVM2LocalData aLocalData = (AVM2LocalData) localData; if (loopItem instanceof WhileItem) { WhileItem w = (WhileItem) loopItem; @@ -1620,6 +1620,22 @@ public class AVM2Graph extends Graph { HasNextAVM2Item hn = (HasNextAVM2Item) w.expression.get(w.expression.size() - 1); if (hn.obj != null) { if (hn.obj.getNotCoerced().getThroughRegister().getNotCoerced() instanceof FilteredCheckAVM2Item) { + + //All items are moved from stack to output before entering while, + // this code block moves them back to stack + int pushnum = 0; + for (int i = output.size() - 2 /*last is loop*/; i >= 0; i--) { + if (output.get(i) instanceof PushItem) { + pushnum++; + } else { + break; + } + } + int rem = output.size() - 1 - pushnum; + for (int i = output.size() - 1 - pushnum; i <= output.size() - 2; i++) { + stack.push(((PushItem) output.remove(rem)).value); + } + //---------- end moving back to stack if (w.commands.size() >= 3) { int pos = 0; Set localRegsToKill = new HashSet<>(); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/FunctionActionItem.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/FunctionActionItem.java index 95a4c9de8..ec9c4b1fe 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/FunctionActionItem.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/FunctionActionItem.java @@ -35,6 +35,7 @@ import com.jpexs.decompiler.graph.GraphSourceItemPos; import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.GraphTargetVisitorInterface; import com.jpexs.decompiler.graph.SourceGenerator; +import com.jpexs.decompiler.graph.model.BranchStackResistant; import com.jpexs.decompiler.graph.model.LocalData; import com.jpexs.helpers.Helper; import java.util.ArrayList; @@ -48,7 +49,7 @@ import java.util.Set; * * @author JPEXS */ -public class FunctionActionItem extends ActionItem { +public class FunctionActionItem extends ActionItem implements BranchStackResistant { public List actions; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java index a7f6c86c5..f02f992df 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java @@ -1350,7 +1350,7 @@ public class Graph { return printGraph(foundGotos, partCodes, partCodePos, visited, localData, stack, allParts, parent, part, stopPart, stopPartKind, loops, throwStates, null, staticOperation, path, 0); } - protected GraphTargetItem checkLoop(List output, LoopItem loopItem, BaseLocalData localData, List loops, List throwStates) { + protected GraphTargetItem checkLoop(List output, LoopItem loopItem, BaseLocalData localData, List loops, List throwStates, TranslateStack stack) { return loopItem; } @@ -1901,6 +1901,9 @@ public class Graph { } } + if (isLoop) { + makeAllCommands(ret, stack); + } if (debugPrintGraph) { System.err.println("loopsize:" + loops.size()); } @@ -2675,7 +2678,7 @@ public class Graph { } currentLoop.phase = 2; - GraphTargetItem replaced = checkLoop(ret, li, localData, loops, throwStates); + GraphTargetItem replaced = checkLoop(ret, li, localData, loops, throwStates, sPreLoop); if (replaced != li) { int index = ret.indexOf(li); ret.remove(index); @@ -2951,21 +2954,18 @@ public class Graph { clen--; } } - while (stack.size() > 0) { - GraphTargetItem p = stack.pop(); + for (int i = stack.size() - 1; i >= 0; i--) { + GraphTargetItem p = stack.get(i); if (p instanceof BranchStackResistant) { continue; } + stack.remove(i); if (!(p instanceof PopItem)) { - if (p instanceof FunctionActionItem) { + if (isExit) { + //ASC2 leaves some function calls unpopped on stack before returning from a method commands.add(clen, p); } else { - if (isExit) { - //ASC2 leaves some function calls unpopped on stack before returning from a method - commands.add(clen, p); - } else { - commands.add(clen, new PushItem(p)); - } + commands.add(clen, new PushItem(p)); } } } diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3AssembledDecompileTest.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3AssembledDecompileTest.java index b464e472b..e95a32d4a 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3AssembledDecompileTest.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3AssembledDecompileTest.java @@ -131,6 +131,22 @@ public class ActionScript3AssembledDecompileTest extends ActionScript3DecompileT false); } + @Test + public void testPushWhile() { + decompileMethod("assembled", "testPushWhile", "var _loc3_:int = 5;\r\n" + + "§§push(obfuscated[\"xxx\"] = new [\"ByteArray\"]());\r\n" + + "§§push(50);\r\n" + + "while(§§dup(§§pop()))\r\n" + + "{\r\n" + + "§§dup(§§pop())[§§dup(§§dup(§§pop())).length] = 41 ^ 111;\r\n" + + "§§dup(§§pop())[§§dup(§§dup(§§pop())).length] = 9 ^ 84;\r\n" + + "§§push(§§pop() - 1);\r\n" + + "}\r\n" + + "§§pop();\r\n" + + "§§pop();\r\n", + false); + } + @Test public void testSetSlotDup() { decompileMethod("assembled", "testSetSlotDup", "var _loc5_:int = 5;\r\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 782886fa7251894f56b320ed7fa01ff84565e9ac..7a52bbf8efc5543a798b77bbaf06c7b8b6b6d135 100644 GIT binary patch delta 2492 zcmai!Nl=@~6@cICf9b!4kbWf420x1tix$L>z<_sQV}w^RHn!yjtOdzp25gUkF`mUR zo_!{n*y&28DwiBG$t2El@gY@nNX4fdQc1~^^^#nta+s7;xuq&0-9M$O%qdbm^{4k< zzt`{e^5?NH$C(K!AZdV~J~F8*8;owdIw{lXXO-`by>I zjrAJeAopGD=)LvI)SWxUdr$sJevR&?>Pm5~mfBcfURmS6P&v^gsuK{5p`| zNk1DR?G{ZfP!^~70!2!3nBoX+8m79JHot?kd4!ISvg3q#RCa~1kC3o&y}gqfL)7&# zQrAPI_FE$3C5nR-3lxhK*D0nbzCrQ+48^yF@k1e_6u&8k$4Hyr6WcmV^%GQ|qizp% zpQa<{=;(PmhE!9jMyWPHo8Lvc_XDJAo~kiE>*~c0zU;cu-jD1Nk}4>1Xnat~fq`x} zPrAo=#@+pYL~|*FyHk}EPq_CAcas;~>ehaO$^jvVgd7%fM97qoW8r3-d4S-41f`XT z)2pM3K!b!G2A9O9Ho^{qN1``C*dg#q^oIyL0s)D^cEXNAL}GgfVaK3TVwaDw{jf)3 zZ5G)g){Z zE=j+9H(@hyRpPZi!cM_;iG>JZQ&5(;#J}Af?~-9kh-6BHDWhoO6r4ltB3yw*C_$M2 zwYh(*T?M@xJ5-=i^r>JBVps*1M866y8@p6!8pBQ%+>_{4q4^;8s^H0BR0Z!e_NZXa zVv7nbr?FoJ-yH5y!GA%urj=II4L}VT5DlE;aT!e&+7_@|g+LMeR0viuqAC!o@@>z= zxew820Mv5>V7dVo#tVC^WA*AlZk%KR6ooLCw{9;?G}IGPtrA3|w{BOUKrNG6I&VRAQ2uSwGqf9$R3_as($ zo0&=0hVs4fcMsg=03wR08109VCTXI4nuUoZt9&Z`!Neky$ zz_c!$x}}pT%GpNgRm)SW*1_+z^ulB;_3VQxltE7}PBikz~_ zf7y}@4sGz_kgyFlY;Q>0Ew1>c^}7;F{EY9eDKkBAGQE^c85k|m8Zu)zi8E-l>R`PDE*2y#ebjL;x(Gqp$0T07uBjuXRv&cX8CtIt+VbL|? zg0g0cxNH%VY5rS(Cnouq{-6`|T_@<(yvM5ba(`Z_I2}6>vwDv?U0|I0kEqu?3Sj>B^T9kj$N6wRh!9IWR)^OKz&sqRbaQ<%k`p%MKG%rz=}$4T^J-fz|R z@TbA=v{_3TD8~PxJ?~H6UNjO#6N+KOQbSr{gUr@XPstRqN(I4<|Y_jymvT6~b{x6*V%3S~e delta 2205 zcmZvdX>41^5rAj*9s8D|$VXCqq$oXG2X*ie`9z&QBvUdi$|n^|vT50pN$N0t=J1)r zmJ+8&&e~ZN0n+?yF7!uH)c;x(Xo3FgA3128{A>CvMS;S~-vWiZOO_}K^by1T-puUG z&g^pekI`?24HHrzp3fh$pX%!I^2KZL@RP@n?js_9hunJ9}!@(+xm$;ePUl4gUVrjTZ{#UJnm_1cT>`5$GI z=0Tz=hE*H9hqaJ=Hc3{rew44)#^4^e%F>c?r5hc+Fi z=>lzc=I9_&O{E&8S}%3qN1FKoQgxB4{ruOiZvKsHJ^UV$3MetTakU4PBVeH0%|CYM z_^;f~{}Iil^wph}0sb@h2>;ftZjKXF_6XT0WWSIJAqRv^g_{RhGY}j_P+AD{f{rQz z4H32vToRjtgzW*3M6X5IUhqo{gbCXZmc&qmut|tWY-=Oz0PK>u+fUdSbV=-PC7Wyl zdL{P-2pfmE#KbPbrXVFTZ4;J-jKm?Y=roK<9P1+N5bTw>ubZ$Ln3Q;+gRp}zE%Bg_ zuu+(inC~HM7LG_f+DTXrPDm`Y6NGssn;k*zHX=-AiFQXE_ybe0fT~H@2%MIF#odHW z!&!;vqJ-t)yu=dk^2F`^S=7!Wk_j=lgrb8}a1ymsummd*=9fLan-LZC4s26_M$xZ= z(T}Yvup|ala5=b3g{EP&RdA1^SB2*N*rkFei`^=CbJ(GRIg36Oe8;dy1^*m&st{OI z+jB|_>IR?&42TB(a!1dgsX}lWcdKBPF{(mHoDJlbclhLe^cw)%gtlxCgMfK$4{KlV<9M!qbJ zpl~&Wt0E)3BwdSq$2(@l6Xm!txf`aN(sZ6rnCtp=i6#DpnaYfDzsvBZyk@X z>W{yyXoWpWh8n)_o;?#0S{e~<$Z40j;oBE-3J&CjE!?o(lC~wjd$O&hQx?PR%-}(AG(!zNbFs%!xj)v3A(y3CUcD0S` z{+?K}qRk|6>sUO#>e`rjP;qTcJ}6AfWB_ptELwMcOxtZo6vpCxJ}+iv>hm z)HDyc7sQXZUei_Sb%sYSz za8`9;PRJRU)WwiTGwJ9Q#7$5SyeR{pDthc{7ym^|A{C!OjIHBxY$G;v5Z<_o%Obqg znPD04v9kp6Cviu#R2ULm33f&n00FWxpegFzLK*Q~(Q8+``DCzvu_)4-3-yJLN^Zv5 zqQ@lvv#y_%{9T>1lK))iy^{Y>=V{5mtaF+FHu#&toY086^7Y|JeK;nDj#+?Qqr$s# zJ>{ZlS3CIUR;M+;?U+o25$nGv3)>d0^gZQ&v4Xk(s5k$s7Jc-{x|cBiRjq2J#lMNvtQP%twTFKg8c&^>!q|?FnMIMlgljv& z4uMQ11U; z+v!bSSuql2W2Y~9l{dBK^lQ>{g)g?IIzS1Nxc_bGc~Q)!lqPlE71ZGZMiQ{G&+wWM5ykFK-(}^s*xQ ko<}`Bq*J9JZ?8Fddp!q=2Ia=tc)iw;)5VZojf#^04cCc`jQ{`u diff --git a/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/as3_assembled-0.main.asasm b/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/as3_assembled-0.main.asasm index bd01e338c..489896ae4 100644 --- a/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/as3_assembled-0.main.asasm +++ b/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/as3_assembled-0.main.asasm @@ -28,5 +28,6 @@ program #include "tests/TestDecrementPrecedence.script.asasm" #include "tests/TestSwitchGoto.script.asasm" #include "tests/TestTryWhile.script.asasm" + #include "tests/TestPushWhile.script.asasm" ; place to add next end ; program diff --git a/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/tests/TestPushWhile.class.asasm b/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/tests/TestPushWhile.class.asasm new file mode 100644 index 000000000..8977cc6ab --- /dev/null +++ b/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/tests/TestPushWhile.class.asasm @@ -0,0 +1,99 @@ +class + refid "tests:TestPushWhile" + instance QName(PackageNamespace("tests"), "TestPushWhile") + extends QName(PackageNamespace(""), "Object") + flag SEALED + flag PROTECTEDNS + protectedns ProtectedNamespace("tests:TestPushWhile") + iinit + refid "tests:TestPushWhile/instance/init" + body + maxstack 1 + localcount 1 + initscopedepth 4 + maxscopedepth 5 + code + getlocal0 + pushscope + + getlocal0 + constructsuper 0 + + returnvoid + end ; code + end ; body + end ; method + trait method QName(PackageNamespace(""), "run") + method + refid "tests:TestPushWhile/instance/run" + returns QName(PackageNamespace(""), "void") + body + maxstack 2 + localcount 4 + initscopedepth 4 + maxscopedepth 5 + code + getlocal0 + pushscope + pushbyte 5 + setlocal 3 + + pushstring "ByteArray" + dup + findpropstrict MultinameL([PackageNamespace("flash.utils","1")]) + swap + constructprop MultinameL([PackageNamespace("flash.utils","1")]), 0 + dup + getlex QName(PackageNamespace("","2"),"obfuscated") + swap + pushstring "xxx" + swap + setproperty MultinameL([PackageNamespace("","2")]) + pushint 50 + ofs0016: + label + dup + iffalse ofs0039 + decrement_i + swap + dup + dup + getproperty QName(PackageNamespace("","2"),"length") + pushbyte 41 + pushbyte 111 + bitxor + setproperty MultinameL([PackageNamespace("","2")]) + dup + dup + getproperty QName(PackageNamespace("","2"),"length") + pushbyte 9 + pushbyte 84 + bitxor + setproperty MultinameL([PackageNamespace("","2")]) + swap + jump ofs0016 + ofs0039: + pop + pop + returnvoid + end ; code + end ; body + end ; method + end ; trait + end ; instance + cinit + refid "tests:TestPushWhile/class/init" + body + maxstack 1 + localcount 1 + initscopedepth 3 + maxscopedepth 4 + code + getlocal0 + pushscope + + returnvoid + end ; code + end ; body + end ; method +end ; class diff --git a/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/tests/TestPushWhile.script.asasm b/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/tests/TestPushWhile.script.asasm new file mode 100644 index 000000000..57fea0452 --- /dev/null +++ b/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/tests/TestPushWhile.script.asasm @@ -0,0 +1,29 @@ +script + sinit + refid "tests:TestPushWhile/init" + body + maxstack 2 + localcount 1 + initscopedepth 1 + maxscopedepth 3 + code + getlocal0 + pushscope + + findpropstrict Multiname("TestPushWhile", [PackageNamespace("tests")]) + getlex QName(PackageNamespace(""), "Object") + pushscope + + getlex Multiname("Object", [PrivateNamespace(null, "tests:TestPushWhile"), PackageNamespace(""), PackageNamespace("tests"), PackageInternalNs("tests"), Namespace("http://adobe.com/AS3/2006/builtin")]) + newclass "tests:TestPushWhile" + popscope + initproperty QName(PackageNamespace("tests"), "TestPushWhile") + + returnvoid + end ; code + end ; body + end ; method + trait class QName(PackageNamespace("tests"), "TestPushWhile") + #include "TestPushWhile.class.asasm" + end ; trait +end ; script diff --git a/libsrc/ffdec_lib/testdata/as3_assembled/bin/as3_assembled.swf b/libsrc/ffdec_lib/testdata/as3_assembled/bin/as3_assembled.swf index 51679b492d05626e3430821dd934e3ee53552ecf..6fdb3d7a9f72b16a5eac7e23a0e790f125fd1c45 100644 GIT binary patch literal 4250 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