Fixed: #2493 Incorrect placement of §§push instructions

This commit is contained in:
Jindra Petřík
2025-07-24 21:12:24 +02:00
parent 84b92a9d46
commit 7559970c17
18 changed files with 225 additions and 64 deletions

View File

@@ -1826,6 +1826,7 @@ public class AVM2Code implements Cloneable {
/**
* Converts to source output.
*
* @param output Output
* @param swfVersion SWF version
* @param switchParts Switch parts
* @param callStack Call stack
@@ -1853,11 +1854,10 @@ public class AVM2Code implements Cloneable {
* @param visited Visited
* @param localRegAssignmentIps Local register assignment IPs
* @param bottomStackSetLocals Set locals on bottom of the stack
* @return Convert output
* @throws ConvertException On convert error
* @throws InterruptedException On interrupt
*/
public ConvertOutput toSourceOutput(int swfVersion, Set<GraphPart> switchParts, List<MethodBody> callStack, AbcIndexing abcIndex, Map<Integer, Set<Integer>> setLocalPosToGetLocalPos, boolean thisHasDefaultToPrimitive, Reference<GraphSourceItem> lineStartItem, String path, GraphPart part, boolean processJumps, boolean isStatic, int scriptIndex, int classIndex, HashMap<Integer, GraphTargetItem> localRegs, TranslateStack stack, ScopeStack scopeStack, ScopeStack localScopeStack, ABC abc, MethodBody body, int start, int end, HashMap<Integer, String> localRegNames, HashMap<Integer, GraphTargetItem> localRegTypes, List<DottedChain> fullyQualifiedNames, boolean[] visited, HashMap<Integer, Integer> localRegAssignmentIps, LinkedIdentityHashSet<SetLocalAVM2Item> bottomStackSetLocals) throws ConvertException, InterruptedException {
public void toSourceOutput(List<GraphTargetItem> output, int swfVersion, Set<GraphPart> switchParts, List<MethodBody> callStack, AbcIndexing abcIndex, Map<Integer, Set<Integer>> setLocalPosToGetLocalPos, boolean thisHasDefaultToPrimitive, Reference<GraphSourceItem> lineStartItem, String path, GraphPart part, boolean processJumps, boolean isStatic, int scriptIndex, int classIndex, HashMap<Integer, GraphTargetItem> localRegs, TranslateStack stack, ScopeStack scopeStack, ScopeStack localScopeStack, ABC abc, MethodBody body, int start, int end, HashMap<Integer, String> localRegNames, HashMap<Integer, GraphTargetItem> localRegTypes, List<DottedChain> fullyQualifiedNames, boolean[] visited, HashMap<Integer, Integer> localRegAssignmentIps, LinkedIdentityHashSet<SetLocalAVM2Item> bottomStackSetLocals) throws ConvertException, InterruptedException {
boolean debugMode = DEBUG_MODE;
if (debugMode) {
System.err.println("OPEN SubSource:" + start + "-" + end + " " + code.get(start).toString() + " to " + code.get(end).toString());
@@ -1870,7 +1870,6 @@ public class AVM2Code implements Cloneable {
if (toSourceLimit > 0 && toSourceCount >= toSourceLimit) {
throw new ConvertException("Limit of subs(" + toSourceLimit + ") was reached", start);
}
List<GraphTargetItem> output = new ArrayList<>();
int ip = start;
//try {
//int addr;
@@ -2043,14 +2042,7 @@ public class AVM2Code implements Cloneable {
}
if (debugMode) {
System.err.println("CLOSE SubSource:" + start + "-" + end + " " + code.get(start).toString() + " to " + code.get(end).toString());
}
/*if (hideTemporaryRegisters) {
clearTemporaryRegisters(output);
}*/
return new ConvertOutput(stack, output);
/*} catch (ConvertException cex) {
throw cex;
}*/
}
}
/**

View File

@@ -360,7 +360,7 @@ public class AVM2DeobfuscatorRegisters extends AVM2DeobfuscatorSimple {
}
@Override
public List<GraphTargetItem> translatePart(Graph graph, GraphPart part, BaseLocalData localData, TranslateStack stack, int start, int end, int staticOperation, String path) throws InterruptedException {
public void translatePart(List<GraphTargetItem> output, Graph graph, GraphPart part, BaseLocalData localData, TranslateStack stack, int start, int end, int staticOperation, String path) throws InterruptedException {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}

View File

@@ -383,7 +383,7 @@ public class AVM2DeobfuscatorRegistersOld extends AVM2DeobfuscatorSimpleOld {
}
@Override
public List<GraphTargetItem> translatePart(Graph graph, GraphPart part, BaseLocalData localData, TranslateStack stack, int start, int end, int staticOperation, String path) throws InterruptedException {
public void translatePart(List<GraphTargetItem> output, Graph graph, GraphPart part, BaseLocalData localData, TranslateStack stack, int start, int end, int staticOperation, String path) throws InterruptedException {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}

View File

@@ -98,6 +98,7 @@ import com.jpexs.decompiler.graph.Graph;
import com.jpexs.decompiler.graph.GraphException;
import com.jpexs.decompiler.graph.GraphPart;
import com.jpexs.decompiler.graph.GraphPartChangeException;
import com.jpexs.decompiler.graph.GraphPartMarkedArrayList;
import com.jpexs.decompiler.graph.GraphSource;
import com.jpexs.decompiler.graph.GraphSourceItem;
import com.jpexs.decompiler.graph.GraphTargetItem;
@@ -340,11 +341,11 @@ public class AVM2Graph extends Graph {
//localData2.scopeStack = new ScopeStack();
localData2.localScopeStack = new ScopeStack();
List<GraphTargetItem> targetOutput;
List<GraphTargetItem> targetOutput = new GraphPartMarkedArrayList<>();
try {
targetOutput = translatePart(localData2, finallyTryTargetPart, finallyTryTargetStack, 0 /*??*/, "try_target");
translatePart(targetOutput, localData2, finallyTryTargetPart, finallyTryTargetStack, 0 /*??*/, "try_target");
} catch (GraphPartChangeException ex1) { //should not happen
targetOutput = new ArrayList<>();
targetOutput.clear();
}
int switchedReg = -1;
@@ -1173,9 +1174,9 @@ public class AVM2Graph extends Graph {
if (finallyIndex > -1) {
parsedExceptionIds.add(finallyIndex);
}
List<GraphTargetItem> tryCommands = new ArrayList<>();
List<List<GraphTargetItem>> catchCommands = new ArrayList<>();
List<GraphTargetItem> finallyCommands = new ArrayList<>();
List<GraphTargetItem> tryCommands = new GraphPartMarkedArrayList<>();
List<List<GraphTargetItem>> catchCommands = new GraphPartMarkedArrayList<>();
List<GraphTargetItem> finallyCommands = new GraphPartMarkedArrayList<>();
GraphPart afterPart = null;
@@ -1255,7 +1256,7 @@ public class AVM2Graph extends Graph {
boolean inlinedFinally = false;
boolean finallyAsUnnamedException = false;
List<GraphTargetItem> finallyTargetItems = new ArrayList<>();
List<GraphTargetItem> finallyTargetItems = new GraphPartMarkedArrayList<>();
GraphPart defaultPart = null;
GraphPart finallyPart = null;
@@ -1289,12 +1290,12 @@ public class AVM2Graph extends Graph {
AVM2LocalData localData2 = new AVM2LocalData(localData);
//localData2.scopeStack = new ScopeStack();
localData2.localScopeStack = new ScopeStack();
try {
//We are assuming Finally target has only 1 part
finallyTargetItems = translatePart(localData2, finallyTryTargetPart, st2, staticOperation, path);
translatePart(finallyTargetItems, localData2, finallyTryTargetPart, st2, staticOperation, path);
} catch (GraphPartChangeException ex) { //should not happen
finallyTargetItems = new ArrayList<>();
finallyTargetItems.clear();
}
//boolean targetHasThrow = false;
if (!finallyTargetItems.isEmpty() && (finallyTargetItems.get(finallyTargetItems.size() - 1) instanceof ThrowAVM2Item)) {
@@ -1385,9 +1386,10 @@ public class AVM2Graph extends Graph {
}
if (switchPart != null) {
try {
finallyCommands.addAll(translatePart(localData, switchPart, stack, staticOperation, path));
translatePart(finallyCommands, localData, switchPart, stack, staticOperation, path);
} catch (GraphPartChangeException ex) {
//should not happen
finallyCommands.clear();
}
stack.pop(); //value switched by lookupswitch
}
@@ -2249,13 +2251,21 @@ public class AVM2Graph extends Graph {
}
}
int firstPushPos = -1;
for (int i = output.size() - 2 /*last is loop*/; i >= 0; i--) {
if (output.get(i) instanceof PushItem) {
PushItem pu = (PushItem) output.remove(i);
stack.push(pu.value);
firstPushPos = i;
} else {
break;
}
}
if (firstPushPos > -1) {
int max = output.size() - 2;
for (int i = firstPushPos; i <= max; i++) {
PushItem pu = (PushItem) output.remove(firstPushPos);
stack.push(pu.value);
}
}
if (usages.isEmpty()) {
output.add(filter);

View File

@@ -188,6 +188,7 @@ public class AVM2GraphSource extends GraphSource {
/**
* Translates the part of the graph source
*
* @param output Output
* @param graph Graph
* @param part Graph part
* @param localData Local data
@@ -196,17 +197,13 @@ public class AVM2GraphSource extends GraphSource {
* @param end End position
* @param staticOperation Unused
* @param path Path
* @return List of graph target items
* @throws InterruptedException On interrupt
*/
@Override
public List<GraphTargetItem> translatePart(Graph graph, GraphPart part, BaseLocalData localData, TranslateStack stack, int start, int end, int staticOperation, String path) throws InterruptedException {
List<GraphTargetItem> ret = new ArrayList<>();
public void translatePart(List<GraphTargetItem> output, Graph graph, GraphPart part, BaseLocalData localData, TranslateStack stack, int start, int end, int staticOperation, String path) throws InterruptedException {
Reference<GraphSourceItem> lineStartItem = new Reference<>(localData.lineStartInstruction);
ConvertOutput co = code.toSourceOutput(localData.swfVersion, localData.allSwitchParts, ((AVM2LocalData) localData).callStack, ((AVM2LocalData) localData).abcIndex, ((AVM2LocalData) localData).setLocalPosToGetLocalPos, ((AVM2LocalData) localData).thisHasDefaultToPrimitive, lineStartItem, path, part, false, isStatic, scriptIndex, classIndex, localRegs, stack, ((AVM2LocalData) localData).scopeStack, ((AVM2LocalData) localData).localScopeStack, abc, body, start, end, localRegNames, ((AVM2LocalData) localData).localRegTypes, fullyQualifiedNames, new boolean[size()], localRegAssignmentIps, ((AVM2LocalData) localData).bottomSetLocals);
localData.lineStartInstruction = lineStartItem.getVal();
ret.addAll(co.output);
return ret;
code.toSourceOutput(output, localData.swfVersion, localData.allSwitchParts, ((AVM2LocalData) localData).callStack, ((AVM2LocalData) localData).abcIndex, ((AVM2LocalData) localData).setLocalPosToGetLocalPos, ((AVM2LocalData) localData).thisHasDefaultToPrimitive, lineStartItem, path, part, false, isStatic, scriptIndex, classIndex, localRegs, stack, ((AVM2LocalData) localData).scopeStack, ((AVM2LocalData) localData).localScopeStack, abc, body, start, end, localRegNames, ((AVM2LocalData) localData).localRegTypes, fullyQualifiedNames, new boolean[size()], localRegAssignmentIps, ((AVM2LocalData) localData).bottomSetLocals);
localData.lineStartInstruction = lineStartItem.getVal();
}
/**

View File

@@ -1225,6 +1225,7 @@ public abstract class Action implements GraphSourceItem {
/**
* Converts list of actions to tree.
*
* @param output Output
* @param graph ActionGraph
* @param switchParts Switch parts
* @param secondPassData Second pass data
@@ -1241,17 +1242,15 @@ public abstract class Action implements GraphSourceItem {
* @param staticOperation Static operation
* @param path Path
* @param charset Charset
* @return List of tree items
* @throws InterruptedException On interrupt
* @throws GraphPartChangeException On graph part change
*/
public static List<GraphTargetItem> actionsPartToTree(ActionGraph graph, Set<GraphPart> switchParts, SecondPassData secondPassData, boolean insideDoInitAction, Reference<GraphSourceItem> lineStartActionRef, HashMap<Integer, String> registerNames, HashMap<String, GraphTargetItem> variables, HashMap<String, GraphTargetItem> functions, TranslateStack stack, List<Action> actions, int start, int end, int version, int staticOperation, String path, String charset) throws InterruptedException, GraphPartChangeException {
public static void actionsPartToTree(List<GraphTargetItem> output, ActionGraph graph, Set<GraphPart> switchParts, SecondPassData secondPassData, boolean insideDoInitAction, Reference<GraphSourceItem> lineStartActionRef, HashMap<Integer, String> registerNames, HashMap<String, GraphTargetItem> variables, HashMap<String, GraphTargetItem> functions, TranslateStack stack, List<Action> actions, int start, int end, int version, int staticOperation, String path, String charset) 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) + ")") : ""});
}
ActionLocalData localData = new ActionLocalData(switchParts, secondPassData, insideDoInitAction, registerNames, variables, functions, graph.getUninitializedClassTraits());
localData.lineStartAction = lineStartActionRef.getVal();
List<GraphTargetItem> output = new ArrayList<>();
int ip = start;
boolean isWhile = false;
boolean isForIn = false;
@@ -1389,8 +1388,7 @@ public abstract class Action implements GraphSourceItem {
if (ip > end + 1) {
throw new GraphPartChangeException(output, ip);
}
logger.log(Level.FINE, "Leaving {0}-{1}", new Object[]{start, end});
return output;
logger.log(Level.FINE, "Leaving {0}-{1}", new Object[]{start, end});
}
/**

View File

@@ -197,6 +197,7 @@ public class ActionGraphSource extends GraphSource {
/**
* Translates the part of the graph source
*
* @param output Output
* @param graph Graph
* @param part Graph part
* @param localData Local data
@@ -210,12 +211,11 @@ public class ActionGraphSource extends GraphSource {
* @throws GraphPartChangeException On graph part change
*/
@Override
public List<GraphTargetItem> translatePart(Graph graph, GraphPart part, BaseLocalData localData, TranslateStack stack, int start, int end, int staticOperation, String path) throws InterruptedException, GraphPartChangeException {
public void translatePart(List<GraphTargetItem> output, Graph graph, GraphPart part, BaseLocalData localData, TranslateStack stack, int start, int end, int staticOperation, String path) throws InterruptedException, GraphPartChangeException {
Reference<GraphSourceItem> fi = new Reference<>(localData.lineStartInstruction);
List<GraphTargetItem> r = Action.actionsPartToTree((ActionGraph) graph, localData.allSwitchParts, localData.secondPassData, this.insideDoInitAction, fi, registerNames, variables, functions, stack, actions, start, end, version, staticOperation, path, charset);
Action.actionsPartToTree(output, (ActionGraph) graph, localData.allSwitchParts, localData.secondPassData, this.insideDoInitAction, fi, registerNames, variables, functions, stack, actions, start, end, version, staticOperation, path, charset);
localData.lineStartInstruction = fi.getVal();
return r;
}
/**

View File

@@ -27,7 +27,6 @@ import com.jpexs.decompiler.graph.model.BinaryOpItem;
import com.jpexs.decompiler.graph.model.BranchStackResistant;
import com.jpexs.decompiler.graph.model.BreakItem;
import com.jpexs.decompiler.graph.model.CommaExpressionItem;
import com.jpexs.decompiler.graph.model.CommentItem;
import com.jpexs.decompiler.graph.model.ContinueItem;
import com.jpexs.decompiler.graph.model.DefaultItem;
import com.jpexs.decompiler.graph.model.DoWhileItem;
@@ -2354,7 +2353,7 @@ public class Graph {
//@SuppressWarnings("unchecked")
protected final GraphTargetItem translatePartGetStack(BaseLocalData localData, GraphPart part, TranslateStack stack, int staticOperation) throws InterruptedException, GraphPartChangeException {
stack = (TranslateStack) stack.clone();
translatePart(localData, part, stack, staticOperation, null);
translatePart(new ArrayList<>(), localData, part, stack, staticOperation, null);
return stack.pop();
}
@@ -2373,13 +2372,14 @@ public class Graph {
protected final GraphTargetItem translatePartGetStack(BaseLocalData localData, GraphPart part, TranslateStack stack, int staticOperation, List<GraphTargetItem> output) throws InterruptedException, GraphPartChangeException {
stack = (TranslateStack) stack.clone();
output.clear();
output.addAll(translatePart(localData, part, stack, staticOperation, null));
translatePart(output, localData, part, stack, staticOperation, null);
return stack.pop();
}
/**
* Translates part.
*
* @param output Output
* @param localData Local data
* @param part Part
* @param stack Translate stack
@@ -2389,9 +2389,8 @@ public class Graph {
* @throws InterruptedException On interrupt
* @throws GraphPartChangeException On graph part change
*/
protected final List<GraphTargetItem> translatePart(BaseLocalData localData, GraphPart part, TranslateStack stack, int staticOperation, String path) throws InterruptedException, GraphPartChangeException {
protected final void translatePart(List<GraphTargetItem> output, BaseLocalData localData, GraphPart part, TranslateStack stack, int staticOperation, String path) throws InterruptedException, GraphPartChangeException {
List<GraphPart> sub = part.getSubParts();
List<GraphTargetItem> ret = new ArrayList<>();
int end;
for (GraphPart p : sub) {
if (p.end == -1) {
@@ -2404,9 +2403,8 @@ public class Graph {
}
end = p.end;
int start = p.start;
ret.addAll(code.translatePart(this, part, localData, stack, start, end, staticOperation, path));
code.translatePart(output, this, part, localData, stack, start, end, staticOperation, path);
}
return ret;
}
/**
@@ -3469,6 +3467,7 @@ public class Graph {
if (currentRet instanceof GraphPartMarkedArrayList) {
((GraphPartMarkedArrayList) currentRet).startPart(part);
}
stack.setConnectedOutput(0, currentRet);
if (checkPartOutput(currentRet, foundGotos, partCodes, partCodePos, visited, code, localData, allParts, stack, parent, part, stopPart, stopPartKind, loops, throwStates, currentLoop, staticOperation, path, recursionLevel)) {
parseNext = false;
} else {
@@ -3477,9 +3476,10 @@ public class Graph {
do {
exHappened = false;
try {
output.addAll(code.translatePart(this, part, localData, stack, ipStart, part.end, staticOperation, path));
stack.setConnectedOutput(currentRet.size(), output);
code.translatePart(output, this, part, localData, stack, ipStart, part.end, staticOperation, path);
} catch (GraphPartChangeException ex) { //Special case for ifFrameLoaded when it's over multiple parts
output.addAll(ex.getOutput());
//output.addAll(ex.getOutput());
for (GraphPart p : allParts) {
if (p.containsIP(ex.getIp())) {
if (ex.getIp() == p.start) {
@@ -4542,7 +4542,12 @@ public class Graph {
//ASC2 leaves some function calls unpopped on stack before returning from a method
commands.add(clen, p);
} else {
commands.add(clen, new PushItem(p));
int pos = 0;
if (p.outputPos < commands.size()) {
commands.add(p.outputPos, new PushItem(p));
} else {
commands.add(clen + pos, new PushItem(p));
}
}
}
}

View File

@@ -62,6 +62,7 @@ public abstract class GraphSource implements Serializable {
/**
* Translates the part of the graph source
*
* @param output Output
* @param graph Graph
* @param part Graph part
* @param localData Local data
@@ -70,11 +71,10 @@ public abstract class GraphSource implements Serializable {
* @param end End position
* @param staticOperation Unused
* @param path Path
* @return List of graph target items
* @throws InterruptedException On interrupt
* @throws GraphPartChangeException On graph part change
*/
public abstract List<GraphTargetItem> translatePart(Graph graph, GraphPart part, BaseLocalData localData, TranslateStack stack, int start, int end, int staticOperation, String path) throws InterruptedException, GraphPartChangeException;
public abstract void translatePart(List<GraphTargetItem> output, Graph graph, GraphPart part, BaseLocalData localData, TranslateStack stack, int start, int end, int staticOperation, String path) throws InterruptedException, GraphPartChangeException;
/**
* Gets the important addresses

View File

@@ -128,7 +128,12 @@ public abstract class GraphTargetItem implements Serializable, Cloneable {
* Dialect
*/
public GraphTargetDialect dialect;
/**
* Position in output - current list of GraphTargetItems
*/
public int outputPos = -1;
/**
* Gets the line start item
*

View File

@@ -18,6 +18,7 @@ package com.jpexs.decompiler.graph;
import com.jpexs.decompiler.graph.model.PopItem;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import java.util.logging.Level;
@@ -39,9 +40,25 @@ public class TranslateStack extends Stack<GraphTargetItem> {
* Path
*/
private final String path;
private List<GraphTargetItem> connectedOutput = null;
private int prevOutputSize = 0;
private Map<String, GraphTargetItem> marks = new HashMap<>();
public void setConnectedOutput(int prevOutputSize, List<GraphTargetItem> connectedOutput) {
this.prevOutputSize = prevOutputSize;
this.connectedOutput = connectedOutput;
}
@Override
public GraphTargetItem push(GraphTargetItem item) {
if (connectedOutput != null && item != null) {
item.outputPos = prevOutputSize + connectedOutput.size();
}
return super.push(item);
}
/**
* Sets mark.