From 2390b1840c5a8ff5ddd54b5bf83af63711117e2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Sun, 28 Nov 2021 19:54:29 +0100 Subject: [PATCH] Fixed AS1/2 switch with nontrivial expressions - secondpass for all strictequals --- .../jpexs/decompiler/flash/action/Action.java | 35 ++++++++--- .../decompiler/flash/action/ActionGraph.java | 59 ++++++++++++++----- .../flash/action/swf3/ActionWaitForFrame.java | 8 +++ .../action/swf4/ActionWaitForFrame2.java | 7 +++ 4 files changed, 84 insertions(+), 25 deletions(-) diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/Action.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/Action.java index 34ef2bb57..acc0d596f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/Action.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/Action.java @@ -86,6 +86,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -930,9 +931,15 @@ public abstract class Action implements GraphSourceItem { * @throws java.lang.InterruptedException */ public static List actionsToTree(boolean insideDoInitAction, boolean insideFunction, HashMap regNames, HashMap variables, HashMap functions, List actions, int version, int staticOperation, String path) throws InterruptedException { + HashMap variablesBackup = new LinkedHashMap<>(variables); + HashMap functionsBackup = new LinkedHashMap<>(functions); try { return ActionGraph.translateViaGraph(null, insideDoInitAction, insideFunction, regNames, variables, functions, actions, version, staticOperation, path); } catch (SecondPassException spe) { + variables.clear(); + variables.putAll(variablesBackup); + functions.clear(); + functions.putAll(functionsBackup); return ActionGraph.translateViaGraph(spe.getData(), insideDoInitAction, insideFunction, regNames, variables, functions, actions, version, staticOperation, path); } } @@ -982,6 +989,18 @@ public abstract class Action implements GraphSourceItem { this.ignored = ignored; } + private static HashMap prepareVariables(GraphSourceItemContainer cnt, HashMap variables) { + HashMap variables2 = Helper.deepCopy(variables); + if (cnt instanceof ActionDefineFunction || cnt instanceof ActionDefineFunction2) { + for (int r = 0; r < 256; r++) { + if (variables2.containsKey("__register" + r)) { + variables2.remove("__register" + r); + } + } + } + return variables2; + } + public static List actionsPartToTree(SecondPassData secondPassData, boolean insideDoInitAction, Reference fi, HashMap registerNames, HashMap variables, HashMap functions, TranslateStack stack, List actions, int start, int end, int version, int staticOperation, String path) throws InterruptedException, GraphPartChangeException { if (start < actions.size() && (end > 0) && (start > 0)) { logger.log(Level.FINE, "Entering {0}-{1}{2}", new Object[]{start, end, actions.size() > 0 ? (" (" + actions.get(start).toString() + " - " + actions.get(end == actions.size() ? end - 1 : end) + ")") : ""}); @@ -1033,14 +1052,7 @@ public abstract class Action implements GraphSourceItem { long endAddr = action.getAddress() + cnt.getHeaderSize(); String cntName = cnt.getName(); List> outs = new ArrayList<>(); - HashMap variables2 = Helper.deepCopy(variables); - if (cnt instanceof ActionDefineFunction || cnt instanceof ActionDefineFunction2) { - for (int r = 0; r < 256; r++) { - if (variables2.containsKey("__register" + r)) { - variables2.remove("__register" + r); - } - } - } + HashMap variables2 = prepareVariables(cnt, variables); for (long size : cnt.getContainerSizes()) { if (size == 0) { outs.add(new ArrayList<>()); @@ -1056,7 +1068,12 @@ public abstract class Action implements GraphSourceItem { } } } - out = ActionGraph.translateViaGraph(secondPassData, insideDoInitAction, true, regNames, variables2, functions, actions.subList(adr2ip(actions, endAddr), adr2ip(actions, endAddr + size)), version, staticOperation, path + (cntName == null ? "" : "/" + cntName)); + try { + out = ActionGraph.translateViaGraph(null, insideDoInitAction, true, regNames, variables2, functions, actions.subList(adr2ip(actions, endAddr), adr2ip(actions, endAddr + size)), version, staticOperation, path + (cntName == null ? "" : "/" + cntName)); + } catch (SecondPassException spe) { + variables2 = prepareVariables(cnt, variables); + out = ActionGraph.translateViaGraph(spe.getData(), insideDoInitAction, true, regNames, variables2, functions, actions.subList(adr2ip(actions, endAddr), adr2ip(actions, endAddr + size)), version, staticOperation, path + (cntName == null ? "" : "/" + cntName)); + } } catch (OutOfMemoryError | TranslateException | StackOverflowError ex) { logger.log(Level.SEVERE, "Decompilation error in: " + path, ex); if (ex instanceof OutOfMemoryError) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraph.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraph.java index 4d3157ce8..5ed1f343f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraph.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraph.java @@ -398,6 +398,15 @@ public class ActionGraph extends Graph { } } + private GraphPart findPart(int ip, Set allParts) { + for (GraphPart p : allParts) { + if (p.containsIP(ip)) { + return p; + } + } + return null; + } + @Override protected List check(List currentRet, List foundGotos, Map> partCodes, Map partCodePos, Set visited, GraphSource code, BaseLocalData localData, Set allParts, TranslateStack stack, GraphPart parent, GraphPart part, List stopPart, List stopPartKind, List loops, List throwStates, List output, Loop currentLoop, int staticOperation, String path) throws InterruptedException { if (!output.isEmpty()) { @@ -445,29 +454,31 @@ public class ActionGraph extends Graph { if (secondPassData != null) { for (int si = 0; si < secondPassData.switchParts.size(); si++) { if (secondPassData.switchParts.get(si).get(0).equals(part)) { - part = secondPassData.switchParts.get(si).get(secondPassData.switchParts.get(si).size() - 1); + //we need to use findpart as parts have changed between first and second pass + part = findPart(secondPassData.switchParts.get(si).get(secondPassData.switchParts.get(si).size() - 1).start, allParts); caseBodyParts.clear(); - caseBodyParts.addAll(secondPassData.switchOnFalseParts.get(si)); + for (GraphPart p : secondPassData.switchOnFalseParts.get(si)) { + caseBodyParts.add(findPart(p.start, allParts)); + } caseValuesMap.clear(); caseValuesMap.addAll(secondPassData.switchCaseExpressions.get(si)); secondSwitchFound = true; } } } - int cnt = 1; - if (!secondSwitchFound) { + if (false) { //always do secondPass try { - while (part.nextParts.size() > 1 - && part.nextParts.get(1).getHeight() > 1 - && code.get(part.nextParts.get(1).end >= code.size() ? code.size() - 1 : part.nextParts.get(1).end) instanceof ActionIf - && ((top = translatePartGetStack(localData, part.nextParts.get(1), stack, staticOperation)) instanceof StrictEqActionItem)) { - cnt++; - part = part.nextParts.get(1); - caseBodyParts.add(part.nextParts.get(0)); + while (part.nextParts.size() > 1 + && part.nextParts.get(1).getHeight() > 1 + && code.get(part.nextParts.get(1).end >= code.size() ? code.size() - 1 : part.nextParts.get(1).end) instanceof ActionIf + && ((top = translatePartGetStack(localData, part.nextParts.get(1), stack, staticOperation)) instanceof StrictEqActionItem)) { + cnt++; + part = part.nextParts.get(1); + caseBodyParts.add(part.nextParts.get(0)); - set = (StrictEqActionItem) top; - caseValuesMap.add(set.rightSide); + set = (StrictEqActionItem) top; + caseValuesMap.add(set.rightSide); } } catch (GraphPartChangeException gce) { //ignore @@ -555,9 +566,16 @@ public class ActionGraph extends Graph { List switchExpressions = new ArrayList<>(); List switchOnFalseParts = new ArrayList<>(); BinaryOpItem sneq = (BinaryOpItem) ii.expression; - if (sneq.leftSide instanceof StoreRegisterActionItem) { - StoreRegisterActionItem sr = (StoreRegisterActionItem) sneq.leftSide; - int regId = sr.register.number; + if ((sneq.leftSide instanceof StoreRegisterActionItem) || (sneq.leftSide instanceof GetVariableActionItem)) { + + int regId = -1; + GetVariableActionItem svar = null; + if (sneq.leftSide instanceof StoreRegisterActionItem) { + StoreRegisterActionItem sr = (StoreRegisterActionItem) sneq.leftSide; + regId = sr.register.number; + } else { + svar = (GetVariableActionItem) sneq.leftSide; + } switchParts.add(ii.decisionPart); switchExpressions.add(sneq.rightSide); @@ -586,6 +604,15 @@ public class ActionGraph extends Graph { } else { break; } + } else if (svar != null && sneq.leftSide instanceof GetVariableActionItem) { + if (sneq.leftSide.valueEquals(svar)) { + switchParts.add(ii2.decisionPart); + switchOnFalseParts.add(ii2.onTruePart); + switchExpressions.add(sneq.rightSide); + walkNext.add(isNeq ? ii2.onFalse : ii2.onTrue); + } else { + break; + } } else { break; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf3/ActionWaitForFrame.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf3/ActionWaitForFrame.java index bf1b94ee4..f99e4b0bc 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf3/ActionWaitForFrame.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf3/ActionWaitForFrame.java @@ -39,6 +39,7 @@ import com.jpexs.decompiler.graph.TranslateStack; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Set; @@ -106,9 +107,16 @@ public class ActionWaitForFrame extends Action implements ActionStore { public void translate(SecondPassData secondPassData, boolean insideDoInitAction, GraphSourceItem lineStartAction, TranslateStack stack, List output, HashMap regNames, HashMap variables, HashMap functions, int staticOperation, String path) throws InterruptedException { GraphTargetItem frameTi = new DirectValueActionItem(null, null, 0, (Long) ((long) frame), new ArrayList<>()); List body; + HashMap variablesBackup = new LinkedHashMap<>(variables); + HashMap functionsBackup = new LinkedHashMap<>(functions); + try { body = ActionGraph.translateViaGraph(null, insideDoInitAction, true, regNames, variables, functions, skipped, SWF.DEFAULT_VERSION, staticOperation, path); } catch (SecondPassException spe) { + variables.clear(); + variables.putAll(variablesBackup); + functions.clear(); + functions.putAll(functionsBackup); body = ActionGraph.translateViaGraph(spe.getData(), insideDoInitAction, true, regNames, variables, functions, skipped, SWF.DEFAULT_VERSION, staticOperation, path); } output.add(new IfFrameLoadedActionItem(frameTi, body, this, lineStartAction)); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf4/ActionWaitForFrame2.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf4/ActionWaitForFrame2.java index aa6f16046..311cc8d6a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf4/ActionWaitForFrame2.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf4/ActionWaitForFrame2.java @@ -38,6 +38,7 @@ import com.jpexs.decompiler.graph.TranslateStack; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Set; @@ -151,9 +152,15 @@ public class ActionWaitForFrame2 extends Action implements ActionStore { public void translate(SecondPassData secondPassData, boolean insideDoInitAction, GraphSourceItem lineStartAction, TranslateStack stack, List output, HashMap regNames, HashMap variables, HashMap functions, int staticOperation, String path) throws InterruptedException { GraphTargetItem frame = stack.pop(); List body; + HashMap variablesBackup = new LinkedHashMap<>(variables); + HashMap functionsBackup = new LinkedHashMap<>(functions); try { body = ActionGraph.translateViaGraph(null, insideDoInitAction, true, regNames, variables, functions, skipped, SWF.DEFAULT_VERSION, staticOperation, path); } catch (SecondPassException spe) { + variables.clear(); + variables.putAll(variablesBackup); + functions.clear(); + functions.putAll(functionsBackup); body = ActionGraph.translateViaGraph(spe.getData(), insideDoInitAction, true, regNames, variables, functions, skipped, SWF.DEFAULT_VERSION, staticOperation, path); } output.add(new IfFrameLoadedActionItem(frame, body, this, lineStartAction));