diff --git a/CHANGELOG.md b/CHANGELOG.md index 971a72b5f..5ba42c409 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,8 @@ All notable changes to this project will be documented in this file. - Flash player preview not stripping scripts from DefineSprites - Not clearing selected depth after timelined change - [#2480] AS1/2 P-code decompilation of try..catch with empty catch body at the end of function +- [#2477] AS1/2 deobfuscation - and/or operators, jumps before function start, + jumps to function end, jumps in for..in return/break ### Changed - Icon of "Deobfuscation options" menu from pile of pills to medkit diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java index 6e43ad879..401b97811 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java @@ -3767,7 +3767,7 @@ public final class SWF implements SWFContainerItem, Timelined, Openable { ip = code.adr2pos(addr); addr += size; int nextip = code.adr2pos(addr); - getVariables(aLocalData.insideDoInitAction, variables, functions, strings, usageTypes, new ActionGraphSource(path, aLocalData.insideDoInitAction, code.getActions().subList(ip, nextip), code.version, new HashMap<>(), new HashMap<>(), new HashMap<>(), code.getCharset()), 0, path + (cntName == null ? "" : "/" + cntName)); + getVariables(aLocalData.insideDoInitAction, variables, functions, strings, usageTypes, new ActionGraphSource(path, aLocalData.insideDoInitAction, code.getActions().subList(0, nextip), code.version, new HashMap<>(), new HashMap<>(), new HashMap<>(), code.getCharset(), ip), 0, path + (cntName == null ? "" : "/" + cntName)); ip = nextip; } List> r = new ArrayList<>(); @@ -3895,7 +3895,7 @@ public final class SWF implements SWFContainerItem, Timelined, Openable { ActionList actions = src.getActions(); actionsMap.put(src, actions); boolean insideDoInitAction = src instanceof DoInitActionTag; - getVariables(insideDoInitAction, variables, functions, strings, usageTypes, new ActionGraphSource(path, insideDoInitAction, actions, version, new HashMap<>(), new HashMap<>(), new HashMap<>(), src.getSwf().getCharset()), 0, path); + getVariables(insideDoInitAction, variables, functions, strings, usageTypes, new ActionGraphSource(path, insideDoInitAction, actions, version, new HashMap<>(), new HashMap<>(), new HashMap<>(), src.getSwf().getCharset(), 0), 0, path); return ret; } 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 f4519b3ee..e45ff31d5 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 @@ -222,7 +222,7 @@ public class AVM2Graph extends Graph { * @param localRegAssignmentIps Local register assignment IPs */ public AVM2Graph(int swfVersion, AbcIndexing abcIndex, AVM2Code code, ABC abc, MethodBody body, boolean isStatic, int scriptIndex, int classIndex, HashMap localRegs, ScopeStack scopeStack, ScopeStack localScopeStack, HashMap localRegNames, List fullyQualifiedNames, HashMap localRegAssignmentIps) { - super(AVM2GraphTargetDialect.INSTANCE, new AVM2GraphSource(code, isStatic, scriptIndex, classIndex, localRegs, abc, body, localRegNames, fullyQualifiedNames, localRegAssignmentIps), getExceptionEntries(body)); + super(AVM2GraphTargetDialect.INSTANCE, new AVM2GraphSource(code, isStatic, scriptIndex, classIndex, localRegs, abc, body, localRegNames, fullyQualifiedNames, localRegAssignmentIps), getExceptionEntries(body), 0); this.avm2code = code; this.abc = abc; this.body = body; @@ -1818,6 +1818,7 @@ public class AVM2Graph extends Graph { Reference nextRef = new Reference<>(null); Reference tiRef = new Reference<>(null); + makeAllCommands(output, stack); SwitchItem sw = handleSwitch(switchedObject, switchStartItem, foundGotos, partCodes, partCodePos, visited, allParts, stack, stopPart, stopPartKind, loops, throwStates, localData, staticOperation, path, caseValuesMap, defaultPart, caseBodyParts, nextRef, tiRef); ret = new ArrayList<>(); ret.addAll(output); 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 8c820f3af..02ff00273 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 @@ -50,6 +50,7 @@ import com.jpexs.decompiler.flash.action.swf4.RegisterNumber; import com.jpexs.decompiler.flash.action.swf5.ActionConstantPool; import com.jpexs.decompiler.flash.action.swf5.ActionDefineFunction; import com.jpexs.decompiler.flash.action.swf5.ActionEquals2; +import com.jpexs.decompiler.flash.action.swf5.ActionStoreRegister; import com.jpexs.decompiler.flash.action.swf5.ActionWith; import com.jpexs.decompiler.flash.action.swf7.ActionDefineFunction2; import com.jpexs.decompiler.flash.action.swf7.ActionTry; @@ -1071,13 +1072,13 @@ public abstract class Action implements GraphSourceItem { HashMap variablesBackup = new LinkedHashMap<>(variables); HashMap functionsBackup = new LinkedHashMap<>(functions); try { - return ActionGraph.translateViaGraph(uninitializedClassTraits, null, insideDoInitAction, insideFunction, regNames, variables, functions, actions, version, staticOperation, path, charset); + return ActionGraph.translateViaGraph(uninitializedClassTraits, null, insideDoInitAction, insideFunction, regNames, variables, functions, actions, version, staticOperation, path, charset, 0); } catch (SecondPassException spe) { variables.clear(); variables.putAll(variablesBackup); functions.clear(); functions.putAll(functionsBackup); - return ActionGraph.translateViaGraph(uninitializedClassTraits, spe.getData(), insideDoInitAction, insideFunction, regNames, variables, functions, actions, version, staticOperation, path, charset); + return ActionGraph.translateViaGraph(uninitializedClassTraits, spe.getData(), insideDoInitAction, insideFunction, regNames, variables, functions, actions, version, staticOperation, path, charset, 0); } } @@ -1251,7 +1252,7 @@ public abstract class Action implements GraphSourceItem { ip++; continue; } - + //FunctionActionItem after DefineFunction(/2) are left on the stack. For linestart offsets we consider this kind of stack empty. boolean isStackEmpty = true; for (int i = 0; i < stack.size(); i++) { @@ -1287,11 +1288,12 @@ public abstract class Action implements GraphSourceItem { } } } - try { - out = ActionGraph.translateViaGraph(graph.getUninitializedClassTraits(), null, insideDoInitAction, true, regNames, variables2, functions, actions.subList(adr2ip(actions, endAddr), adr2ip(actions, endAddr + size)), version, staticOperation, path + (cntName == null ? "" : "/" + cntName), charset); + int startIp = adr2ip(actions, endAddr); + try { + out = ActionGraph.translateViaGraph(graph.getUninitializedClassTraits(), null, insideDoInitAction, true, regNames, variables2, functions, actions.subList(0, adr2ip(actions, endAddr + size)), version, staticOperation, path + (cntName == null ? "" : "/" + cntName), charset, startIp); } catch (SecondPassException spe) { variables2 = prepareVariables(cnt, variables); - out = ActionGraph.translateViaGraph(graph.getUninitializedClassTraits(), spe.getData(), insideDoInitAction, true, regNames, variables2, functions, actions.subList(adr2ip(actions, endAddr), adr2ip(actions, endAddr + size)), version, staticOperation, path + (cntName == null ? "" : "/" + cntName), charset); + out = ActionGraph.translateViaGraph(graph.getUninitializedClassTraits(), spe.getData(), insideDoInitAction, true, regNames, variables2, functions, actions.subList(0, adr2ip(actions, endAddr + size)), version, staticOperation, path + (cntName == null ? "" : "/" + cntName), charset, startIp); } } catch (OutOfMemoryError | TranslateException | StackOverflowError ex) { logger.log(Level.SEVERE, "Decompilation error in: " + path, ex); @@ -1320,7 +1322,7 @@ public abstract class Action implements GraphSourceItem { } //return in for..in - if ((action instanceof ActionPush) && (((ActionPush) action).values.size() == 1) && (((ActionPush) action).values.get(0) == Null.INSTANCE)) { + /*if ((action instanceof ActionPush) && (((ActionPush) action).values.size() == 1) && (((ActionPush) action).values.get(0) == Null.INSTANCE)) { if (ip + 3 <= end) { if ((actions.get(ip + 1) instanceof ActionEquals) || (actions.get(ip + 1) instanceof ActionEquals2)) { if (actions.get(ip + 2) instanceof ActionNot) { @@ -1334,6 +1336,14 @@ public abstract class Action implements GraphSourceItem { } } } + }*/ + int nip = graph.checkIp(ip); + if (nip != ip) { + ip = nip; + if (ip > end) { + break; + } + action = actions.get(ip); } if (action instanceof ActionStore) { 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 090dcca54..6ceeb22f3 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 @@ -125,9 +125,10 @@ public class ActionGraph extends Graph { * @param functions Functions * @param version Version * @param charset Charset + * @param startIp Start IP */ - public ActionGraph(Map> uninitializedClassTraits, String path, boolean insideDoInitAction, boolean insideFunction, List code, HashMap registerNames, HashMap variables, HashMap functions, int version, String charset) { - super(ActionGraphTargetDialect.INSTANCE, new ActionGraphSource(path, insideDoInitAction, code, version, registerNames, variables, functions, charset), new ArrayList<>()); + public ActionGraph(Map> uninitializedClassTraits, String path, boolean insideDoInitAction, boolean insideFunction, List code, HashMap registerNames, HashMap variables, HashMap functions, int version, String charset, int startIp) { + super(ActionGraphTargetDialect.INSTANCE, new ActionGraphSource(path, insideDoInitAction, code, version, registerNames, variables, functions, charset, startIp), new ArrayList<>(), startIp); this.uninitializedClassTraits = uninitializedClassTraits; this.insideDoInitAction = insideDoInitAction; this.insideFunction = insideFunction; @@ -164,18 +165,23 @@ public class ActionGraph extends Graph { String functionName = (action instanceof ActionDefineFunction) ? ((ActionDefineFunction) action).functionName : ((ActionDefineFunction2) action).functionName; long endAddr = action.getAddress() + cnt.getHeaderSize(); List outs = new ArrayList<>(); + List startIps = new ArrayList<>(); for (long size : cnt.getContainerSizes()) { if (size == 0) { outs.add(new ActionList(((ActionGraphSource) code).getCharset())); continue; } - outs.add(new ActionList(alist.subList(Action.adr2ip(alist, endAddr), Action.adr2ip(alist, endAddr + size)), getGraphCode().getCharset())); + int startIp = Action.adr2ip(alist, endAddr); + startIps.add(startIp); + outs.add(new ActionList(alist.subList(0, Action.adr2ip(alist, endAddr + size)), getGraphCode().getCharset())); endAddr += size; } - for (ActionList al : outs) { + for (int i = 0; i < outs.size(); i++) { + ActionList al = outs.get(i); + int startIp = startIps.get(i); subgraphs.put("loc" + Helper.formatAddress(code.pos2adr(ip)) + ": function " + functionName, - new ActionGraph(uninitializedClassTraits, "", false, false, al, new HashMap<>(), new HashMap<>(), new HashMap<>(), SWF.DEFAULT_VERSION, ((ActionGraphSource) getGraphCode()).getCharset()) + new ActionGraph(uninitializedClassTraits, "", false, false, al, new HashMap<>(), new HashMap<>(), new HashMap<>(), SWF.DEFAULT_VERSION, ((ActionGraphSource) getGraphCode()).getCharset(), startIp) ); } } @@ -221,8 +227,8 @@ public class ActionGraph extends Graph { * @return List of graph target items * @throws InterruptedException On interrupt */ - public static List translateViaGraph(Map> uninitializedClassTraits, SecondPassData secondPassData, boolean insideDoInitAction, boolean insideFunction, HashMap registerNames, HashMap variables, HashMap functions, List code, int version, int staticOperation, String path, String charset) throws InterruptedException { - ActionGraph g = new ActionGraph(uninitializedClassTraits, path, insideDoInitAction, insideFunction, code, registerNames, variables, functions, version, charset); + public static List translateViaGraph(Map> uninitializedClassTraits, SecondPassData secondPassData, boolean insideDoInitAction, boolean insideFunction, HashMap registerNames, HashMap variables, HashMap functions, List code, int version, int staticOperation, String path, String charset, int startIp) throws InterruptedException { + ActionGraph g = new ActionGraph(uninitializedClassTraits, path, insideDoInitAction, insideFunction, code, registerNames, variables, functions, version, charset, startIp); ActionLocalData localData = new ActionLocalData(secondPassData, insideDoInitAction, registerNames, uninitializedClassTraits); g.init(localData); return g.translate(localData, staticOperation, path); @@ -280,7 +286,7 @@ public class ActionGraph extends Graph { @Override protected void finalProcess(GraphTargetItem parent, List list, int level, FinalProcessLocalData localData, String path) throws InterruptedException { - + if (level == 0) { List removed = new ArrayList<>(); for (int i = list.size() - 1; i >= 0; i--) { @@ -295,7 +301,7 @@ public class ActionGraph extends Graph { } list.addAll(0, removed); } - + int targetStart; int targetEnd; GraphTargetItem targetStartItem = null; @@ -867,6 +873,7 @@ public class ActionGraph extends Graph { Reference nextRef = new Reference<>(null); Reference tiRef = new Reference<>(null); + makeAllCommands(output, stack); SwitchItem sw = handleSwitch(switchedObject, switchStartItem, foundGotos, partCodes, partCodePos, visited, allParts, stack, stopPart, stopPartKind, loops, throwStates, localData, staticOperation, path, caseValuesMap, defaultPart, caseBodyParts, nextRef, tiRef); ret = new ArrayList<>(); ret.addAll(output); @@ -882,7 +889,19 @@ public class ActionGraph extends Graph { } return ret; } - + + private int ipAfterJumps(int nip) { + while (nip < code.size() && code.get(nip) instanceof ActionJump) { + ActionJump j = (ActionJump) code.get(nip); + int nip2 = code.adr2pos(j.getTargetAddress()); + if (nip2 == nip) { + break; + } + nip = nip2; + } + return nip; + } + /** * Checks IP and allows to modify it. * @@ -891,22 +910,67 @@ public class ActionGraph extends Graph { */ @Override protected int checkIp(int ip) { - int oldIp = ip; + + if (ip >= code.size()) { + return ip; + } + + int oldIp = ip; + //return/break in for..in + /* + We need to skip following: + + locA:Push null + Equals/Equals2 + Not + If locA + ... + + Beware: There can be obfuscation jumps anywhere on the path! + */ GraphSourceItem action = code.get(ip); if ((action instanceof ActionPush) && (((ActionPush) action).values.size() == 1) && (((ActionPush) action).values.get(0) == Null.INSTANCE)) { + int nip = ip; + if (nip + 1 < code.size()) { + nip++; + nip = ipAfterJumps(nip); + if (nip < code.size() && ((code.get(nip) instanceof ActionEquals) || (code.get(nip) instanceof ActionEquals2))) { + nip++; + nip = ipAfterJumps(nip); + if (nip < code.size() && code.get(nip) instanceof ActionNot) { + nip++; + nip = ipAfterJumps(nip); + if (nip < code.size() && code.get(nip) instanceof ActionIf) { + ActionIf aif = (ActionIf) code.get(nip); + + int jip = code.adr2pos(aif.getTargetAddress()); + jip = ipAfterJumps(jip); + if (jip == ip) { + nip++; + ip = nip; + } + } + } + } + } + + //The simple approach is not working, there may be jumps inside + /* if (ip + 3 <= code.size()) { if ((code.get(ip + 1) instanceof ActionEquals) || (code.get(ip + 1) instanceof ActionEquals2)) { if (code.get(ip + 2) instanceof ActionNot) { if (code.get(ip + 3) instanceof ActionIf) { ActionIf aif = (ActionIf) code.get(ip + 3); - if (code.adr2pos(code.pos2adr(ip + 3) + 5 /*IF numbytes*/ + aif.getJumpOffset()) == ip) { + if (code.adr2pos(code.pos2adr(ip + 3) + 5 //IF numbytes + + aif.getJumpOffset()) == ip) { ip += 4; } } } } } + */ } if (oldIp != ip) { if (ip == code.size()) { //no next checkIp call since its after code size diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraphSource.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraphSource.java index e23d93678..8bd8ad110 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraphSource.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraphSource.java @@ -107,8 +107,9 @@ public class ActionGraphSource extends GraphSource { * @param functions Functions * @param charset Charset */ - public ActionGraphSource(String path, boolean insideDoInitAction, List actions, int version, HashMap registerNames, HashMap variables, HashMap functions, String charset) { - this.actions = actions instanceof ActionList ? (ActionList) actions : new ActionList(actions, charset); + public ActionGraphSource(String path, boolean insideDoInitAction, List actions, int version, HashMap registerNames, HashMap variables, HashMap functions, String charset, int startIp) { + this.startIp = startIp; + this.actions = actions instanceof ActionList ? (ActionList) actions : new ActionList(actions, charset); this.version = version; this.registerNames = registerNames; this.variables = variables; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/deobfuscation/ActionDeobfuscator.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/deobfuscation/ActionDeobfuscator.java index cd0e5282b..949630b72 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/deobfuscation/ActionDeobfuscator.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/deobfuscation/ActionDeobfuscator.java @@ -43,6 +43,7 @@ import com.jpexs.decompiler.flash.action.swf4.ActionMBStringLength; import com.jpexs.decompiler.flash.action.swf4.ActionMultiply; import com.jpexs.decompiler.flash.action.swf4.ActionNot; import com.jpexs.decompiler.flash.action.swf4.ActionOr; +import com.jpexs.decompiler.flash.action.swf4.ActionPop; import com.jpexs.decompiler.flash.action.swf4.ActionPush; import com.jpexs.decompiler.flash.action.swf4.ActionSetVariable; import com.jpexs.decompiler.flash.action.swf4.ActionStringAdd; @@ -84,6 +85,7 @@ import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.model.FalseItem; import com.jpexs.decompiler.graph.model.PushItem; import com.jpexs.helpers.CancellableWorker; +import com.jpexs.helpers.Helper; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -146,7 +148,7 @@ public class ActionDeobfuscator extends SWFDecompilerAdapter { actions.removeUnreachableActions(); actions.removeZeroJumps(); getTimeCount = 0; - + // GetTime, If => Jump, assume GetTime > 0 FastActionListIterator iterator = actions.iterator(); while (iterator.hasNext()) { @@ -162,10 +164,30 @@ public class ActionDeobfuscator extends SWFDecompilerAdapter { ActionJump jump = new ActionJump(0, actions.getCharset()); ActionItem jumpItem = new ActionItem(jump); jumpItem.setJumpTarget(a2Item.getJumpTarget()); + + /* This simple approach does not work + iterator.remove(); // GetTime iterator.next(); iterator.remove(); // If iterator.add(jumpItem); // replace If with Jump + */ + + //Must remove + add in this particular order, + //otherwise if will map the jumpsTo after the new jumpItem. + + iterator.next(); //to If + iterator.add(jumpItem); // Add Jump after If + + //Now go back and remove GetTime, If... + iterator.prev(); //to If + iterator.prev(); //to GetTime + + iterator.remove(); //GetTime + iterator.next(); + iterator.remove(); //If + iterator.next(); + changed = true; ret = true; getTimeCount--; @@ -184,12 +206,36 @@ public class ActionDeobfuscator extends SWFDecompilerAdapter { ActionJump jump = new ActionJump(0, actions.getCharset()); ActionItem jumpItem = new ActionItem(jump); jumpItem.setJumpTarget(a2Item.getJumpTarget()); + /* This simple approach does not work iterator.remove(); // GetTime iterator.next(); iterator.remove(); // Increment iterator.next(); iterator.remove(); // If iterator.add(jumpItem); // replace If with Jump + */ + + + //Must remove + add in this particular order, + //otherwise if will map the jumpsTo after the new jumpItem. + + iterator.next(); //to Increment + iterator.next(); //to If + iterator.add(jumpItem); // Add Jump after If + + //Now go back and remove GetTime, Increment, If... + iterator.prev(); //to If + iterator.prev(); //to Increment + iterator.prev(); //to GetTime + + iterator.remove(); //GetTime + iterator.next(); + iterator.remove(); //Increment + iterator.next(); + iterator.remove(); //If + + iterator.next(); + changed = true; ret = true; } @@ -208,7 +254,7 @@ public class ActionDeobfuscator extends SWFDecompilerAdapter { boolean ret = false; actions.removeUnreachableActions(); actions.removeZeroJumps(); - + ActionConstantPool cPool = getConstantPool(actions); LocalDataArea localData = new LocalDataArea(new Stage(null), true); localData.stack = new FixItemCounterStack(); @@ -481,7 +527,7 @@ public class ActionDeobfuscator extends SWFDecompilerAdapter { if (item.action.isExit()) { return; } - + FixItemCounterStack stack = (FixItemCounterStack) localData.stack; int instructionsProcessed = 0; int skippedInstructions = 0; @@ -560,7 +606,7 @@ public class ActionDeobfuscator extends SWFDecompilerAdapter { if (!(action instanceof ActionPush || action instanceof ActionPushDuplicate - //|| action instanceof ActionPop + || action instanceof ActionPop || action instanceof ActionAsciiToChar || action instanceof ActionCharToAscii || action instanceof ActionDecrement @@ -660,7 +706,7 @@ public class ActionDeobfuscator extends SWFDecompilerAdapter { } } - if (isEnd || (stack.allItemsFixed() && (action instanceof ActionIf || (jumpFound && action instanceof ActionJump) || action instanceof ActionSetVariable))) { + if (isEnd || (stack.allItemsFixed() && (action instanceof ActionPop || action instanceof ActionIf || (jumpFound && action instanceof ActionJump) || action instanceof ActionSetVariable))) { result.item = item; result.instructionsProcessed = instructionsProcessed; result.minSkippedInstructions = skippedInstructions; @@ -676,7 +722,11 @@ public class ActionDeobfuscator extends SWFDecompilerAdapter { if (isEnd) { break; - } + } + } + + if (jumpedHere && item.prev.isContainerLastAction()) { + break; } if (action instanceof ActionReturn) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/fastactionlist/FastActionListIterator.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/fastactionlist/FastActionListIterator.java index aa5e98c9f..c9a380746 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/fastactionlist/FastActionListIterator.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/fastactionlist/FastActionListIterator.java @@ -132,7 +132,7 @@ public final class FastActionListIterator implements Iterator { public void remove() { item = list.removeItem(item.prev); } - + /** * Adds an action after the current item. * 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 a0a4bd21a..dc29bf326 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 @@ -136,13 +136,13 @@ public class ActionWaitForFrame extends Action implements ActionStore { HashMap functionsBackup = new LinkedHashMap<>(functions); try { - body = ActionGraph.translateViaGraph(uninitializedClassTraits, null, insideDoInitAction, true, regNames, variables, functions, skipped, SWF.DEFAULT_VERSION, staticOperation, path, getCharset()); + body = ActionGraph.translateViaGraph(uninitializedClassTraits, null, insideDoInitAction, true, regNames, variables, functions, skipped, SWF.DEFAULT_VERSION, staticOperation, path, getCharset(), 0); } catch (SecondPassException spe) { variables.clear(); variables.putAll(variablesBackup); functions.clear(); functions.putAll(functionsBackup); - body = ActionGraph.translateViaGraph(uninitializedClassTraits, spe.getData(), insideDoInitAction, true, regNames, variables, functions, skipped, SWF.DEFAULT_VERSION, staticOperation, path, getCharset()); + body = ActionGraph.translateViaGraph(uninitializedClassTraits, spe.getData(), insideDoInitAction, true, regNames, variables, functions, skipped, SWF.DEFAULT_VERSION, staticOperation, path, getCharset(), 0); } 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 649c086b1..dc16aab55 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 @@ -182,13 +182,13 @@ public class ActionWaitForFrame2 extends Action implements ActionStore { HashMap variablesBackup = new LinkedHashMap<>(variables); HashMap functionsBackup = new LinkedHashMap<>(functions); try { - body = ActionGraph.translateViaGraph(uninitializedClassTraits, null, insideDoInitAction, true, regNames, variables, functions, skipped, SWF.DEFAULT_VERSION, staticOperation, path, getCharset()); + body = ActionGraph.translateViaGraph(uninitializedClassTraits, null, insideDoInitAction, true, regNames, variables, functions, skipped, SWF.DEFAULT_VERSION, staticOperation, path, getCharset(), 0); } catch (SecondPassException spe) { variables.clear(); variables.putAll(variablesBackup); functions.clear(); functions.putAll(functionsBackup); - body = ActionGraph.translateViaGraph(uninitializedClassTraits, spe.getData(), insideDoInitAction, true, regNames, variables, functions, skipped, SWF.DEFAULT_VERSION, staticOperation, path, getCharset()); + body = ActionGraph.translateViaGraph(uninitializedClassTraits, spe.getData(), insideDoInitAction, true, regNames, variables, functions, skipped, SWF.DEFAULT_VERSION, staticOperation, path, getCharset(), 0); } output.add(new IfFrameLoadedActionItem(frame, body, this, lineStartAction)); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/script/PcodeGraphVizExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/script/PcodeGraphVizExporter.java index 01498ae96..e5c4ba9be 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/script/PcodeGraphVizExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/script/PcodeGraphVizExporter.java @@ -88,7 +88,7 @@ public class PcodeGraphVizExporter { */ public void exportAs12(ASMSource src, GraphTextWriter writer) throws InterruptedException { ActionList alist = src.getActions(); - ActionGraph gr = new ActionGraph(new HashMap<>(), "", false, false, alist, new HashMap<>(), new HashMap<>(), new HashMap<>(), SWF.DEFAULT_VERSION, Utf8Helper.charsetName); + ActionGraph gr = new ActionGraph(new HashMap<>(), "", false, false, alist, new HashMap<>(), new HashMap<>(), new HashMap<>(), SWF.DEFAULT_VERSION, Utf8Helper.charsetName, 0); export(gr, writer); } 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 813b6740f..5d507f94b 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java @@ -54,6 +54,7 @@ import com.jpexs.decompiler.graph.model.UniversalLoopItem; import com.jpexs.decompiler.graph.model.WhileItem; import com.jpexs.decompiler.graph.precontinues.GraphPrecontinueDetector; import com.jpexs.helpers.CancellableWorker; +import com.jpexs.helpers.Helper; import com.jpexs.helpers.Reference; import java.util.ArrayDeque; import java.util.ArrayList; @@ -101,6 +102,11 @@ public class Graph { * Exceptions in the graph */ private final List exceptions; + + /** + * Graph startIp + */ + protected int startIp = 0; /** * Debug flag to print all parts @@ -122,7 +128,7 @@ public class Graph { * Debug flag to not process Ifs */ protected boolean debugDoNotProcess = false; - + /** * Logger */ @@ -152,11 +158,13 @@ public class Graph { * @param dialect Dialect * @param code Graph source * @param exceptions Exceptions in the graph + * @param startIp Start ip */ - public Graph(GraphTargetDialect dialect, GraphSource code, List exceptions) { + public Graph(GraphTargetDialect dialect, GraphSource code, List exceptions, int startIp) { this.dialect = dialect; this.code = code; this.exceptions = exceptions; + this.startIp = startIp; } /** @@ -2950,7 +2958,7 @@ public class Graph { if (vCanHandleVisited) { if (visited.contains(part)) { - String labelName = "addr" + part.start; + String labelName = "addr" + Helper.formatAddress(code.pos2adr(part.start, true)); //was: part.start; List firstCode = partCodes.get(part); int firstCodePos = partCodePos.get(part); if (firstCodePos > firstCode.size()) { @@ -3298,6 +3306,7 @@ public class Graph { } Reference nextRef = new Reference<>(null); Reference tiRef = new Reference<>(null); + makeAllCommands(currentRet, stack); SwitchItem sw = handleSwitch(switchedItem, originalSwitchedItem.getSrc(), foundGotos, partCodes, partCodePos, visited, allParts, stack, stopPart, stopPartKind, loops, throwStates, localData, staticOperation, path, caseValues, defaultPart, caseBodyParts, nextRef, tiRef); GraphPart next = nextRef.getVal(); @@ -3767,7 +3776,7 @@ public class Graph { HashMap> refs = code.visitCode(alternateEntries); List ret = new ArrayList<>(); boolean[] visited = new boolean[code.size()]; - ret.add(makeGraph(null, new GraphPath(), code, 0, 0, allBlocks, refs, visited)); + ret.add(makeGraph(null, new GraphPath(), code, startIp, 0, allBlocks, refs, visited)); for (int pos : alternateEntries) { GraphPart e1 = new GraphPart(-1, -1); e1.path = new GraphPath("e"); @@ -3811,9 +3820,9 @@ public class Graph { if (parent != null) { ret.refs.add(parent); parent.nextParts.add(ret); - } + } while (ip < code.size()) { - ip = checkIp(ip); + ip = checkIp(ip); if (ip >= code.size()) { break; } @@ -3870,8 +3879,10 @@ public class Graph { } else if (ins.isJump()) { part.end = ip; allBlocks.add(part); - ip = ins.getBranches(code).get(0); + ip = ins.getBranches(code).get(0); + ip = checkIp(ip); makeGraph(part, path, code, ip, lastIp, allBlocks, refs, visited); + lastIp = -1; break; } else if (ins.isBranch()) { part.end = ip; @@ -3879,7 +3890,7 @@ public class Graph { allBlocks.add(part); List branches = ins.getBranches(code); for (int i = 0; i < branches.size(); i++) { - makeGraph(part, path.sub(i, ip), code, branches.get(i), ip, allBlocks, refs, visited); + makeGraph(part, path.sub(i, ip), code, checkIp(branches.get(i)), ip, allBlocks, refs, visited); } break; } @@ -4083,6 +4094,7 @@ public class Graph { protected SwitchItem handleSwitch(GraphTargetItem switchedObject, GraphSourceItem switchStartItem, List foundGotos, Map> partCodes, Map partCodePos, Set visited, Set allParts, TranslateStack stack, List stopPart, List stopPartKind, List loops, List throwStates, BaseLocalData localData, int staticOperation, String path, List caseValuesMap, GraphPart defaultPart, List caseBodyParts, Reference nextRef, Reference tiRef) throws InterruptedException { + boolean hasDefault = false; /* case 4: diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphSource.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphSource.java index fb139a1a8..1e010a4d1 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphSource.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphSource.java @@ -32,6 +32,11 @@ import java.util.Set; */ public abstract class GraphSource implements Serializable { + /** + * Start IP + */ + protected int startIp = 0; + /** * Gets the size of the graph source * @@ -84,7 +89,7 @@ public abstract class GraphSource implements Serializable { * @param pos Position of the instruction * @return Instruction as string */ - public abstract String insToString(int pos); + public abstract String insToString(int pos); /** * Visits the code @@ -162,7 +167,7 @@ public abstract class GraphSource implements Serializable { for (int i = 0; i < siz; i++) { refs.put(i, new ArrayList<>()); } - visitCode(0, 0, refs, -1); + visitCode(startIp, 0, refs, -1); int pos = 0; for (int e : alternateEntries) { pos++; diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionDefineFunctionPushRegisterCleanerTest.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionDefineFunctionPushRegisterCleanerTest.java index e47a0e854..7d697d54d 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionDefineFunctionPushRegisterCleanerTest.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionDefineFunctionPushRegisterCleanerTest.java @@ -46,6 +46,7 @@ public class ActionDefineFunctionPushRegisterCleanerTest extends ActionScript2Te Configuration.simplifyExpressions.set(false); Configuration.decompile.set(true); Configuration.registerNameFormat.set("_loc%d_"); + Configuration.skipDetectionOfUnitializedClassFields.set(false); swf = new SWF(new BufferedInputStream(new FileInputStream("testdata/as2_definefunc_regs/as2_definefunc_regs.swf")), false); } diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript2ClassesTest.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript2ClassesTest.java index c96d39f88..ec7954b8b 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript2ClassesTest.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript2ClassesTest.java @@ -47,6 +47,7 @@ public class ActionScript2ClassesTest extends ActionScript2TestBase { Configuration.simplifyExpressions.set(false); Configuration.decompile.set(true); Configuration.registerNameFormat.set("_loc%d_"); + Configuration.skipDetectionOfUnitializedClassFields.set(false); swf = new SWF(new BufferedInputStream(new FileInputStream("testdata/as2/as2.swf")), false); } diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript2DeobfuscatorTest.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript2DeobfuscatorTest.java index 9f312f6f3..47ae71fba 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript2DeobfuscatorTest.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript2DeobfuscatorTest.java @@ -35,6 +35,9 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.concurrent.TimeoutException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.testng.Assert; import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; import org.testng.annotations.BeforeClass; @@ -293,6 +296,38 @@ public class ActionScript2DeobfuscatorTest extends ActionScript2TestBase { fail(); } } + + @Test + public void testRemoveGetTimeWithJumpTo() { + String actionsString = "ConstantPool \"a\"\n" + + "Jump loc3\n" + + "loc4:Push 1\n" + + "Trace\n" + + "Jump loc5\n" + + "loc3:GetTime\n" + + "If loc1\n" + + "Push \"FAIL\"\n" + + "Trace\n" + + "loc1:Push \"OK\"\n" + + "Trace\n" + + "loc2:Jump loc4\n" + + "loc5:"; + try { + List actions = ASMParser.parse(0, true, actionsString, swf.version, false, swf.getCharset()); + + DoActionTag doa = getFirstActionTag(); + doa.setActionBytes(Action.actionsToBytes(actions, true, swf.version)); + HighlightedTextWriter writer = new HighlightedTextWriter(new CodeFormatting(), false); + Action.actionsToSource(new HashMap<>(), doa, doa.getActions(), "", writer, swf.getCharset()); + writer.finishHilights(); + String actualResult = writer.toString(); + + assertTrue(!actualResult.contains("FAIL")); + assertTrue(actualResult.contains("OK")); + } catch (IOException | ActionParseException | InterruptedException ex) { + fail(); + } + } @Test public void testRemoveGetTimeAndIncrement() { @@ -321,4 +356,145 @@ public class ActionScript2DeobfuscatorTest extends ActionScript2TestBase { fail(); } } + + @Test + public void testRemoveGetTimeAndIncrementWithJumpTo() { + String actionsString = "ConstantPool \"a\"\n" + + "Jump loc3\n" + + "loc4: Push 1\n" + + "Trace\n" + + "Jump loc5\n" + + "loc3:GetTime\n" + + "Increment\n" + + "If loc1\n" + + "Push \"FAIL\"\n" + + "Trace\n" + + "loc1:Push \"OK\"\n" + + "Trace\n" + + "loc2:Jump loc4\n" + + "loc5:\n"; + try { + List actions = ASMParser.parse(0, true, actionsString, swf.version, false, swf.getCharset()); + + DoActionTag doa = getFirstActionTag(); + doa.setActionBytes(Action.actionsToBytes(actions, true, swf.version)); + HighlightedTextWriter writer = new HighlightedTextWriter(new CodeFormatting(), false); + Action.actionsToSource(new HashMap<>(), doa, doa.getActions(), "", writer, swf.getCharset()); + writer.finishHilights(); + String actualResult = writer.toString(); + + assertTrue(!actualResult.contains("FAIL")); + assertTrue(actualResult.contains("OK")); + } catch (IOException | ActionParseException | InterruptedException ex) { + fail(); + } + } + + @Test + public void testJumpAfterFunctionEnd() { + String actionsString = "ConstantPool \"a\", \"b\", \"c\", \"d\"\n" + + "Jump loc0026\n" + + "loc0012:Push \"once\"\n" + + "Trace\n" + + "Jump loc0058\n" + + "loc0021:Jump loc0053\n" + + "loc0026:DefineFunction \"f\", 0 {\n" + + "Push \"a\"\n" + + "Trace\n" + + "Push register1\n" + + "Push 2\n" + + "Equals\n" + + "If loc004d\n" + + "Jump loc0021\n" + + "loc004d:Push \"b\"\n" + + "Trace\n" + + "}\n" + + "loc0053:Jump loc0012\n" + + "loc0058:Push \"c\"\n" + + "Trace"; + try { + List actions = ASMParser.parse(0, true, actionsString, swf.version, false, swf.getCharset()); + + DoActionTag doa = getFirstActionTag(); + doa.setActionBytes(Action.actionsToBytes(actions, true, swf.version)); + HighlightedTextWriter writer = new HighlightedTextWriter(new CodeFormatting(), false); + Action.actionsToSource(new HashMap<>(), doa, doa.getActions(), "", writer, swf.getCharset()); + writer.finishHilights(); + String actualResult = writer.toString(); + + Pattern patOnce = Pattern.compile("\"once\""); + Matcher m = patOnce.matcher(actualResult); + int count = 0; + while(m.find()) { + count++; + } + + Assert.assertEquals(count, 1, "The string \"once\" should only appear once."); + } catch (IOException | ActionParseException | InterruptedException ex) { + fail(); + } + } + + @Test + public void testRemoveForInReturnsWithJumpsEnd() { + String actionsString = "Jump locA\n" + + "locC: Not\n" + + "Jump locD\n" + + "locB: Equals2\n" + + "Jump locC\n" + + "locA: Push null\n" + + "Jump locB\n" + + "locD: If locA\n" + + "Push 1\n" + + "Trace\n"; + try { + List actions = ASMParser.parse(0, true, actionsString, swf.version, false, swf.getCharset()); + + DoActionTag doa = getFirstActionTag(); + doa.setActionBytes(Action.actionsToBytes(actions, true, swf.version)); + HighlightedTextWriter writer = new HighlightedTextWriter(new CodeFormatting(), false); + Action.actionsToSource(new HashMap<>(), doa, doa.getActions(), "", writer, swf.getCharset()); + writer.finishHilights(); + String actualResult = writer.toString().trim(); + + Assert.assertEquals(actualResult, "trace(1);"); + } catch (IOException | ActionParseException | InterruptedException ex) { + fail(); + } + } + + @Test + public void testRemoveAndOr() { + String actionsString = "Push 1\n" + + "Push 2\n" + + "Equals\n" + + "PushDuplicate\n" + + "If locA\n" + + "Pop\n" + + "Push 3\n" + + "Push 4\n" + + "Equals\n" + + "locA:If locB\n" + + "Push \"One\"\n" + + "Trace\n" + + "Jump locC\n" + + "locB: Push \"Two\"\n" + + "Trace\n" + + "locC:Push \"End\"\n" + + "Trace\n"; + try { + List actions = ASMParser.parse(0, true, actionsString, swf.version, false, swf.getCharset()); + + DoActionTag doa = getFirstActionTag(); + doa.setActionBytes(Action.actionsToBytes(actions, true, swf.version)); + HighlightedTextWriter writer = new HighlightedTextWriter(new CodeFormatting(), false); + Action.actionsToSource(new HashMap<>(), doa, doa.getActions(), "", writer, swf.getCharset()); + writer.finishHilights(); + String actualResult = writer.toString().trim().replace("\r\n", "\n"); + + Assert.assertEquals(actualResult, "trace(\"One\");\ntrace(\"End\");"); + } catch (IOException | ActionParseException | InterruptedException ex) { + fail(); + } + } } 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 5a4edbd15..404622e8b 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 @@ -38,6 +38,58 @@ public class ActionScript3AssembledDecompileTest extends ActionScript3DecompileT false); } + @Test + public void testAlwaysBreak() { + decompileMethod("assembled", "testAlwaysBreak", "if(true)\r\n" + + "{\r\n" + + "var v:* = 5;\r\n" + + "trace(\"a\");\r\n" + + "if(v > 4)\r\n" + + "{\r\n" + + "trace(\"b\");\r\n" + + "if(v > 10)\r\n" + + "{\r\n" + + "trace(\"c\");\r\n" + + "}\r\n" + + "else\r\n" + + "{\r\n" + + "trace(\"d\");\r\n" + + "addr003e:\r\n" + + "trace(\"e\");\r\n" + + "}\r\n" + + "§§goto(addr004e);\r\n" + + "}\r\n" + + "§§goto(addr003e);\r\n" + + "}\r\n" + + "addr004e:\r\n" + + "trace(\"f\");\r\n", + false); + } + + @Test + public void testAlwaysBreak2() { + decompileMethod("assembled", "testAlwaysBreak2", "var v:* = 5;\r\n" + + "trace(\"a\");\r\n" + + "if(v > 4)\r\n" + + "{\r\n" + + "trace(\"b\");\r\n" + + "if(v > 10)\r\n" + + "{\r\n" + + "trace(\"c\");\r\n" + + "}\r\n" + + "else\r\n" + + "{\r\n" + + "trace(\"d\");\r\n" + + "addr003e:\r\n" + + "trace(\"e\");\r\n" + + "}\r\n" + + "trace(\"f\");\r\n" + + "return;\r\n" + + "}\r\n" + + "§§goto(addr003e);\r\n", + false); + } + @Test public void testDeclareReg() { decompileMethod("assembled", "testDeclareReg", "var other:XML;\r\n" @@ -133,6 +185,83 @@ public class ActionScript3AssembledDecompileTest extends ActionScript3DecompileT false); } + @Test + public void testGoto() { + decompileMethod("assembled", "testGoto", "var v:* = 5;\r\n" + + "if(v > 1)\r\n" + + "{\r\n" + + "trace(\"a\");\r\n" + + "if(v > 2)\r\n" + + "{\r\n" + + "trace(\"goto\");\r\n" + + "addr0052:\r\n" + + "trace(\"f\");\r\n" + + "}\r\n" + + "else\r\n" + + "{\r\n" + + "trace(\"b\");\r\n" + + "addr003d:\r\n" + + "trace(\"d\");\r\n" + + "if(v > 3)\r\n" + + "{\r\n" + + "trace(\"e\");\r\n" + + "§§goto(addr0052);\r\n" + + "}\r\n" + + "else\r\n" + + "{\r\n" + + "trace(\"g\");\r\n" + + "}\r\n" + + "}\r\n" + + "trace(\"end\");\r\n" + + "return;\r\n" + + "}\r\n" + + "trace(\"c\");\r\n" + + "§§goto(addr003d);\r\n", + false); + } + + @Test + public void testGoto2() { + decompileMethod("assembled", "testGoto2", "var v:* = 5;\r\n" + + "if(v > 1)\r\n" + + "{\r\n" + + "trace(\"a\");\r\n" + + "if(v > 2)\r\n" + + "{\r\n" + + "trace(\"goto\");\r\n" + + "addr0062:\r\n" + + "trace(\"g\");\r\n" + + "addr0069:\r\n" + + "trace(\"h\");\r\n" + + "}\r\n" + + "else\r\n" + + "{\r\n" + + "trace(\"b\");\r\n" + + "addr003d:\r\n" + + "trace(\"d\");\r\n" + + "if(v > 3)\r\n" + + "{\r\n" + + "trace(\"e\");\r\n" + + "if(b > 5)\r\n" + + "{\r\n" + + "trace(\"f\");\r\n" + + "§§goto(addr0062);\r\n" + + "}\r\n" + + "§§goto(addr0069);\r\n" + + "}\r\n" + + "else\r\n" + + "{\r\n" + + "trace(\"i\");\r\n" + + "}\r\n" + + "}\r\n" + + "trace(\"end\");\r\n" + + "return;\r\n" + + "}\r\n" + + "trace(\"c\");\r\n" + + "§§goto(addr003d);\r\n", + false); + } + @Test public void testIncrement() { decompileMethod("assembled", "testIncrement", "super();\r\n" @@ -283,13 +412,13 @@ public class ActionScript3AssembledDecompileTest extends ActionScript3DecompileT + "if(b)\r\n" + "{\r\n" + "trace(\"a\");\r\n" - + "addr39:\r\n" + + "addr0053:\r\n" + "trace(\"c\");\r\n" + "}\r\n" + "break;\r\n" + "}\r\n" + "trace(\"b\");\r\n" - + "§§goto(addr39);\r\n" + + "§§goto(addr0053);\r\n" + "case 2:\r\n" + "trace(\"case2\");\r\n" + "}\r\n", @@ -309,33 +438,33 @@ public class ActionScript3AssembledDecompileTest extends ActionScript3DecompileT + "case 1:\r\n" + "case 6:\r\n" + "trace(\"1-6\");\r\n" - + "addr106:\r\n" + + "addr0120:\r\n" + "trace(\"F\");\r\n" + "break;\r\n" + "case 5:\r\n" + "trace(\"5\");\r\n" - + "addr103:\r\n" + + "addr0119:\r\n" + "trace(\"E\");\r\n" - + "§§goto(addr106);\r\n" + + "§§goto(addr0120);\r\n" + "case 7:\r\n" + "trace(\"7\");\r\n" - + "addr100:\r\n" + + "addr0112:\r\n" + "trace(\"D\");\r\n" - + "§§goto(addr103);\r\n" + + "§§goto(addr0119);\r\n" + "case 2:\r\n" + "trace(\"2\");\r\n" - + "addr97:\r\n" + + "addr010b:\r\n" + "trace(\"C\");\r\n" - + "§§goto(addr100);\r\n" + + "§§goto(addr0112);\r\n" + "case 8:\r\n" + "trace(\"8\");\r\n" - + "addr94:\r\n" + + "addr0104:\r\n" + "trace(\"B\");\r\n" - + "§§goto(addr97);\r\n" + + "§§goto(addr010b);\r\n" + "default:\r\n" + "trace(\"def\");\r\n" + "trace(\"A\");\r\n" - + "§§goto(addr94);\r\n" + + "§§goto(addr0104);\r\n" + "}\r\n" + "trace(\"G\");\r\n" + "return null;\r\n", diff --git a/src/com/jpexs/decompiler/flash/gui/action/ActionPanel.java b/src/com/jpexs/decompiler/flash/gui/action/ActionPanel.java index 9d4e6c89f..d5bac0210 100644 --- a/src/com/jpexs/decompiler/flash/gui/action/ActionPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/action/ActionPanel.java @@ -1292,7 +1292,7 @@ public class ActionPanel extends JPanel implements SearchListener(), this.src.getScriptName(), insideDoInitAction, false, lastCode, new HashMap<>(), new HashMap<>(), new HashMap<>(), SWF.DEFAULT_VERSION, Utf8Helper.charsetName), ""); + GraphDialog gf = new GraphDialog(mainPanel.getMainFrame().getWindow(), new ActionGraph(new HashMap<>(), this.src.getScriptName(), insideDoInitAction, false, lastCode, new HashMap<>(), new HashMap<>(), new HashMap<>(), SWF.DEFAULT_VERSION, Utf8Helper.charsetName, 0), ""); gf.setVisible(true); } catch (InterruptedException ex) { logger.log(Level.SEVERE, null, ex);