diff --git a/CHANGELOG.md b/CHANGELOG.md index 0baa6de7b..c09b74fc2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ All notable changes to this project will be documented in this file. - AS3 direct editation - interface method namespace - AS3 p-code docs - deldescendants, negate_p operands - AS3 p-code - IGNORE_REST method flag incorrectly shown as EXPLICIT +- [#1989] AS3 - Slow deobfuscation (AVM2DeobfuscatorSimpleOld) ### Changed - AS1/2/3 P-code - format Number values with EcmaScript toString function @@ -3001,6 +3002,7 @@ All notable changes to this project will be documented in this file. [#1981]: https://www.free-decompiler.com/flash/issues/1981 [#1982]: https://www.free-decompiler.com/flash/issues/1982 [#1986]: https://www.free-decompiler.com/flash/issues/1986 +[#1989]: https://www.free-decompiler.com/flash/issues/1989 [#1970]: https://www.free-decompiler.com/flash/issues/1970 [#1972]: https://www.free-decompiler.com/flash/issues/1972 [#1973]: https://www.free-decompiler.com/flash/issues/1973 diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java index 66e3063c3..0f89ffa3d 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java @@ -2798,10 +2798,16 @@ public class AVM2Code implements Cloneable { } public int removeDeadCode(MethodBody body) throws InterruptedException { + return removeDeadCode(body, new Reference<>(-1)); + } + + public int removeDeadCode(MethodBody body, Reference minChangedIpRef) throws InterruptedException { HashMap> refs = visitCode(body); int cnt = 0; + Integer minChangedIp = -1; for (int i = code.size() - 1; i >= 0; i--) { if (refs.get(i).isEmpty()) { + minChangedIp = i; code.get(i).setIgnored(true, 0); cnt++; } @@ -2814,6 +2820,9 @@ public class AVM2Code implements Cloneable { if (ins.definition instanceof JumpIns) { if (ins.operands[0] == 0) { ins.setIgnored(true, 0); + if (minChangedIp == -1 || minChangedIp > i) { + minChangedIp = i; + } cnt++; } } @@ -2821,6 +2830,8 @@ public class AVM2Code implements Cloneable { removeIgnored(body); + minChangedIpRef.setVal(minChangedIp); + return cnt; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorSimpleOld.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorSimpleOld.java index f2a951fa7..d7638f687 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorSimpleOld.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorSimpleOld.java @@ -101,6 +101,7 @@ import com.jpexs.decompiler.graph.TranslateException; import com.jpexs.decompiler.graph.TranslateStack; import com.jpexs.decompiler.graph.model.FalseItem; import com.jpexs.decompiler.graph.model.TrueItem; +import com.jpexs.helpers.Reference; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -176,16 +177,18 @@ public class AVM2DeobfuscatorSimpleOld extends AVM2DeobfuscatorZeroJumpsNullPush if (Thread.currentThread().isInterrupted()) { throw new InterruptedException(); } - + localData.scopeStack.clear(); localData.localRegs.clear(); localData.localRegAssignmentIps.clear(); localData.localRegs.clear(); initLocalRegs(localData, localReservedCount, body.max_regs); - - if (executeInstructions(importantOffsets, staticRegs, body, abc, code, localData, i, code.code.size() - 1, null, inlineIns, jumpTargets)) { - //startover because dead code was removed and current ip is thus invalid - i = -1; + Reference minChangedIpRef = new Reference<>(-1); + if (executeInstructions(importantOffsets, staticRegs, body, abc, code, localData, i, code.code.size() - 1, null, inlineIns, jumpTargets, minChangedIpRef)) { + int minChangedIp = minChangedIpRef.getVal(); + if (minChangedIp < i + 1) { + i = minChangedIp - 1; + } } } @@ -221,11 +224,13 @@ public class AVM2DeobfuscatorSimpleOld extends AVM2DeobfuscatorZeroJumpsNullPush } } - private boolean executeInstructions(Set importantOffsets, Map staticRegs, MethodBody body, ABC abc, AVM2Code code, AVM2LocalData localData, int idx, int endIdx, ExecutionResult result, List inlineIns, List jumpTargets) throws InterruptedException { + private boolean executeInstructions(Set importantOffsets, Map staticRegs, MethodBody body, ABC abc, AVM2Code code, AVM2LocalData localData, int idx, int endIdx, ExecutionResult result, List inlineIns, List jumpTargets, Reference minChangedIpRef) throws InterruptedException { List output = new ArrayList<>(); FixItemCounterTranslateStack stack = new FixItemCounterTranslateStack(""); int instructionsProcessed = 0; + + int minChangedIp = Integer.MAX_VALUE; endIdx = code.code.size() - 1; while (true) { @@ -270,9 +275,11 @@ public class AVM2DeobfuscatorSimpleOld extends AVM2DeobfuscatorZeroJumpsNullPush if (fins.definition instanceof NewFunctionIns) { int fidx = code.code.indexOf(fins); code.removeInstruction(fidx, body); + if (fidx < minChangedIp) minChangedIp = fidx; } int nidx = code.code.indexOf(ins); code.removeInstruction(nidx, body); + if (nidx < minChangedIp) minChangedIp = nidx; if (nins == null) { idx = code.code.size(); } else { @@ -295,6 +302,7 @@ public class AVM2DeobfuscatorSimpleOld extends AVM2DeobfuscatorZeroJumpsNullPush int regId = ((SetLocalTypeIns) def).getRegisterId(ins); staticRegs.put(regId, localData.localRegs.get(regId).getNotCoerced()); code.replaceInstruction(idx, new AVM2Instruction(0, DeobfuscatePopIns.getInstance(), null), body); + if (idx < minChangedIp) minChangedIp = idx; importantOffsets.clear(); importantOffsets.addAll(code.getImportantOffsets(body, false)); @@ -315,6 +323,7 @@ public class AVM2DeobfuscatorSimpleOld extends AVM2DeobfuscatorZeroJumpsNullPush } code.replaceInstruction(idx, pushins, body); + if (idx < minChangedIp) minChangedIp = idx; stack.push(staticRegs.get(regId)); ins = pushins; def = ins.definition; @@ -418,6 +427,7 @@ public class AVM2DeobfuscatorSimpleOld extends AVM2DeobfuscatorZeroJumpsNullPush boolean ifed = false; if (def instanceof PopIns) { code.replaceInstruction(idx, new AVM2Instruction(ins.getAddress(), DeobfuscatePopIns.getInstance(), null), body); + if (idx < minChangedIp) minChangedIp = idx; idx++; } else if (def instanceof JumpIns) { long address = ins.getTargetAddress(); @@ -449,6 +459,7 @@ public class AVM2DeobfuscatorSimpleOld extends AVM2DeobfuscatorZeroJumpsNullPush AVM2Instruction jumpIns = new AVM2Instruction(0, AVM2Instructions.Jump, new int[]{0}); //jumpIns.operands[0] = ins.operands[0] /*- ins.getBytes().length*/ + jumpIns.getBytes().length; code.replaceInstruction(idx, jumpIns, body); + if (idx < minChangedIp) minChangedIp = idx; jumpIns.operands[0] = (int) (tarIns.getAddress() - jumpIns.getAddress() - jumpIns.getBytesLength()); for (int s = 0; s < stackCount; s++) { code.insertInstruction(idx, new AVM2Instruction(ins.getAddress(), DeobfuscatePopIns.getInstance(), null), true, body); @@ -457,6 +468,7 @@ public class AVM2DeobfuscatorSimpleOld extends AVM2DeobfuscatorZeroJumpsNullPush idx = code.adr2pos(jumpIns.getTargetAddress()); } else { //System.err.println("replacing " + ins + " on " + idx + " with pop"); + if (idx < minChangedIp) minChangedIp = idx; code.replaceInstruction(idx, new AVM2Instruction(ins.getAddress(), DeobfuscatePopIns.getInstance(), null), body); for (int s = 1 /*first is replaced*/; s < stackCount; s++) { code.insertInstruction(idx, new AVM2Instruction(ins.getAddress(), DeobfuscatePopIns.getInstance(), null), true, body); @@ -465,13 +477,24 @@ public class AVM2DeobfuscatorSimpleOld extends AVM2DeobfuscatorZeroJumpsNullPush idx++; } - //this might be slow:-(, but makes importantOffsets relevant - code.removeDeadCode(body); - removeZeroJumps(code, body); + Reference minChangedIp2Ref = new Reference<>(-1); + //this might be slow:-(, but makes importantOffsets relevant + code.removeDeadCode(body, minChangedIp2Ref); + + if (minChangedIp2Ref.getVal() != -1 && minChangedIp2Ref.getVal() < minChangedIp) { + minChangedIp = minChangedIp2Ref.getVal(); + } + minChangedIp2Ref.setVal(-1); + removeZeroJumps(code, body, minChangedIp2Ref); + + if (minChangedIp2Ref.getVal() != -1 && minChangedIp2Ref.getVal() < minChangedIp) { + minChangedIp = minChangedIp2Ref.getVal(); + } importantOffsets.clear(); importantOffsets.addAll(code.getImportantOffsets(body, false)); + minChangedIpRef.setVal(minChangedIp); return true; //endIdx = code.code.size()-1; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorZeroJumpsNullPushes.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorZeroJumpsNullPushes.java index 5396fc938..67c5643eb 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorZeroJumpsNullPushes.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorZeroJumpsNullPushes.java @@ -37,6 +37,7 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushUndefinedIns; import com.jpexs.decompiler.flash.abc.types.MethodBody; import com.jpexs.decompiler.flash.abc.types.traits.Trait; import com.jpexs.decompiler.flash.helpers.SWFDecompilerAdapter; +import com.jpexs.helpers.Reference; import java.util.Set; /** @@ -45,8 +46,13 @@ import java.util.Set; */ public class AVM2DeobfuscatorZeroJumpsNullPushes extends SWFDecompilerAdapter { + protected boolean removeZeroJumps(AVM2Code code, MethodBody body) throws InterruptedException { + return removeZeroJumps(code, body, new Reference<>(-1)); + } + protected boolean removeZeroJumps(AVM2Code code, MethodBody body, Reference minChangedIpRef) throws InterruptedException { boolean result = false; + int minChangedIp = -1; for (int i = 0; i < code.code.size(); i++) { AVM2Instruction ins = code.code.get(i); if (ins.definition instanceof JumpIns) { @@ -55,12 +61,16 @@ public class AVM2DeobfuscatorZeroJumpsNullPushes extends SWFDecompilerAdapter { throw new InterruptedException(); } + if (minChangedIp == -1) { + minChangedIp = i; + } code.removeInstruction(i, body); i--; result = true; } } } + minChangedIpRef.setVal(minChangedIp); return result; }