diff --git a/CHANGELOG.md b/CHANGELOG.md index 087f8bbc1..6d65366f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ All notable changes to this project will be documented in this file. - [#1670] Parent component/window of dialogs not properly set - AS decompilation - Gotos handling vs and/or - AS decompilation - certain combinations of ifs and switch +- AS3 jump deobfuscator - fix for try..catch clauses ## [14.3.1] - 2021-03-25 ### Fixed diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorJumps.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorJumps.java index 310292683..12ea068d7 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorJumps.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorJumps.java @@ -31,9 +31,8 @@ import java.util.Map; /** * - * AVM2 Deobfuscator removing single assigned local registers. + * AVM2 Deobfuscator replacing jumps/ifs targeting other jumps. * - * Example: var a = true; var b = false; ... if(a){ ...ok }else{ not executed } * * @author JPEXS */ @@ -57,22 +56,36 @@ public class AVM2DeobfuscatorJumps extends SWFDecompilerAdapter { for (int i = 0; i < code.code.size(); i++) { AVM2Instruction ins = code.code.get(i); if (ins.definition instanceof JumpIns) { + long srcAddr = ins.getAddress(); long targetAddr = ins.getTargetAddress(); - { - //We do not want exception start to be redirected somewhere else - if (exceptionStarts.contains(i)) { - continue; - } - for (int r : refs.get(i)) { - if (r >= 0) { //Not Exception start/end - AVM2Instruction srcIns = code.code.get(r); - if ((srcIns.definition instanceof JumpIns) || ((srcIns.definition instanceof IfTypeIns) && (r != i - 1))) { - int oldop = srcIns.operands[0]; - srcIns.operands[0] = (int) (targetAddr - (srcIns.getAddress() + srcIns.getBytesLength())); - if (srcIns.operands[0] != oldop) { - found = true; - } + //source and target must be in the same try..catch block + boolean exceptionMismatch = false; + for (int e = 0; e < body.exceptions.length; e++) { + boolean sourceMatch = srcAddr >= body.exceptions[e].start && srcAddr < body.exceptions[e].end; + boolean targetMatch = targetAddr >= body.exceptions[e].start && targetAddr < body.exceptions[e].end; + if (sourceMatch != targetMatch) { + exceptionMismatch = true; + break; + } + } + if (!exceptionMismatch) { + continue; + } + + //We do not want exception start to be redirected somewhere else + if (exceptionStarts.contains(i)) { + continue; + } + for (int r : refs.get(i)) { + if (r >= 0) { //Not Exception start/end + AVM2Instruction srcIns = code.code.get(r); + + if ((srcIns.definition instanceof JumpIns) || ((srcIns.definition instanceof IfTypeIns) && (r != i - 1))) { + int oldop = srcIns.operands[0]; + srcIns.operands[0] = (int) (targetAddr - (srcIns.getAddress() + srcIns.getBytesLength())); + if (srcIns.operands[0] != oldop) { + found = true; } } } 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 b02623e6f..b464e472b 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 @@ -333,6 +333,29 @@ public class ActionScript3AssembledDecompileTest extends ActionScript3DecompileT false); } + @Test + public void testTryWhile() { + decompileMethod("assembled", "testTryWhile", "try\r\n" + + "{\r\n" + + "var c:String = \"aa\";\r\n" + + "while(c)\r\n" + + "{\r\n" + + "if(b)\r\n" + + "{\r\n" + + "break;\r\n" + + "}\r\n" + + "c = c.Object;\r\n" + + "}\r\n" + + "}\r\n" + + "catch(e:Error)\r\n" + + "{\r\n" + + "browserMode = false;\r\n" + + "return;\r\n" + + "}\r\n" + + "trace(\"finish\");\r\n", + false); + } + @Test public void testUnnamedException() { decompileMethod("assembled", "testUnnamedException", "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 930971d3a..782886fa7 100644 Binary files a/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/as3_assembled-0.main.abc and b/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/as3_assembled-0.main.abc differ 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 3d6b3666a..bd01e338c 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 @@ -27,5 +27,6 @@ program #include "tests/TestSlots.init/inline_method.method.asasm" #include "tests/TestDecrementPrecedence.script.asasm" #include "tests/TestSwitchGoto.script.asasm" + #include "tests/TestTryWhile.script.asasm" ; place to add next end ; program diff --git a/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/tests/TestTryWhile.class.asasm b/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/tests/TestTryWhile.class.asasm new file mode 100644 index 000000000..07153452e --- /dev/null +++ b/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/tests/TestTryWhile.class.asasm @@ -0,0 +1,123 @@ +class + refid "tests:TestTryWhile" + instance QName(PackageNamespace("tests"), "TestTryWhile") + extends QName(PackageNamespace(""), "Object") + flag SEALED + flag PROTECTEDNS + protectedns ProtectedNamespace("tests:TestTryWhile") + iinit + refid "tests:TestTryWhile/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:TestTryWhile/instance/run" + returns QName(PackageNamespace(""), "void") + body + maxstack 2 + localcount 4 + initscopedepth 4 + maxscopedepth 5 + trait slot QName(PackageInternalNs(""),"a") + slotid 1 + type QName(PackageNamespace(""),"String") + end ; trait + trait slot QName(PackageInternalNs(""),"b") + slotid 2 + type QName(PackageNamespace(""),"String") + end ; trait + trait slot QName(PackageInternalNs(""),"c") + slotid 3 + type QName(PackageNamespace(""),"String") + end ; trait + + code + getlocal0 + pushscope + newactivation + dup + setlocal1 + pushscope +ofs0006: + getscopeobject 1 + pushstring "aa" + setslot 3 + jump ofs0030 +ofs0011: + label + getscopeobject 1 + getslot 2 + iffalse ofs0022 + jump ofs0038 +; jump ofs0022 +ofs0022: + getscopeobject 1 + getscopeobject 1 + getslot 3 + getproperty QName(PackageNamespace("x"),"Object") + setslot 3 +ofs0030: + getscopeobject 1 + getslot 3 + iftrue ofs0011 +ofs0038: + jump ofs0054 +ofs003c: + getlocal0 + pushscope + getlocal1 + pushscope + newcatch 0 + dup + setlocal2 + dup + pushscope + swap + setslot 1 + findproperty QName(PrivateNamespace("*","242"),"browserMode") + pushfalse + initproperty QName(PrivateNamespace("*","242"),"browserMode") + returnvoid + popscope + kill 2 +ofs0054: + findpropstrict QName(PackageNamespace(""),"trace") + pushstring "finish" + callpropvoid QName(PackageNamespace(""),"trace"), 1 + returnvoid + end ; code + try from ofs0006 to ofs0038 target ofs003c type QName(PackageNamespace(""),"Error") name QName(PackageNamespace(""),"e") end + end ; body + end ; method + end ; trait + end ; instance + cinit + refid "tests:TestTryWhile/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/TestTryWhile.script.asasm b/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/tests/TestTryWhile.script.asasm new file mode 100644 index 000000000..fac51602e --- /dev/null +++ b/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/tests/TestTryWhile.script.asasm @@ -0,0 +1,29 @@ +script + sinit + refid "tests:TestTryWhile/init" + body + maxstack 2 + localcount 1 + initscopedepth 1 + maxscopedepth 3 + code + getlocal0 + pushscope + + findpropstrict Multiname("TestTryWhile", [PackageNamespace("tests")]) + getlex QName(PackageNamespace(""), "Object") + pushscope + + getlex Multiname("Object", [PrivateNamespace(null, "tests:TestTryWhile"), PackageNamespace(""), PackageNamespace("tests"), PackageInternalNs("tests"), Namespace("http://adobe.com/AS3/2006/builtin")]) + newclass "tests:TestTryWhile" + popscope + initproperty QName(PackageNamespace("tests"), "TestTryWhile") + + returnvoid + end ; code + end ; body + end ; method + trait class QName(PackageNamespace("tests"), "TestTryWhile") + #include "TestTryWhile.class.asasm" + end ; trait +end ; script