Fixed: #2477 AS1/2 deobfuscation - and/or operators, jumps before function start,

jumps to function end, jumps in for..in return/break
This commit is contained in:
Jindra Petřík
2025-07-11 19:51:18 +02:00
parent 24566d609f
commit 7b948f92a3
18 changed files with 511 additions and 59 deletions

View File

@@ -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<List<GraphTargetItem>> 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;
}

View File

@@ -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<Integer, GraphTargetItem> localRegs, ScopeStack scopeStack, ScopeStack localScopeStack, HashMap<Integer, String> localRegNames, List<DottedChain> fullyQualifiedNames, HashMap<Integer, Integer> 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<GraphPart> nextRef = new Reference<>(null);
Reference<GraphTargetItem> 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);

View File

@@ -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<String, GraphTargetItem> variablesBackup = new LinkedHashMap<>(variables);
HashMap<String, GraphTargetItem> 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) {

View File

@@ -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<String, Map<String, Trait>> uninitializedClassTraits, String path, boolean insideDoInitAction, boolean insideFunction, List<Action> code, HashMap<Integer, String> registerNames, HashMap<String, GraphTargetItem> variables, HashMap<String, GraphTargetItem> functions, int version, String charset) {
super(ActionGraphTargetDialect.INSTANCE, new ActionGraphSource(path, insideDoInitAction, code, version, registerNames, variables, functions, charset), new ArrayList<>());
public ActionGraph(Map<String, Map<String, Trait>> uninitializedClassTraits, String path, boolean insideDoInitAction, boolean insideFunction, List<Action> code, HashMap<Integer, String> registerNames, HashMap<String, GraphTargetItem> variables, HashMap<String, GraphTargetItem> 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<ActionList> outs = new ArrayList<>();
List<Integer> 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<GraphTargetItem> translateViaGraph(Map<String, Map<String, Trait>> uninitializedClassTraits, SecondPassData secondPassData, boolean insideDoInitAction, boolean insideFunction, HashMap<Integer, String> registerNames, HashMap<String, GraphTargetItem> variables, HashMap<String, GraphTargetItem> functions, List<Action> 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<GraphTargetItem> translateViaGraph(Map<String, Map<String, Trait>> uninitializedClassTraits, SecondPassData secondPassData, boolean insideDoInitAction, boolean insideFunction, HashMap<Integer, String> registerNames, HashMap<String, GraphTargetItem> variables, HashMap<String, GraphTargetItem> functions, List<Action> 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<GraphTargetItem> list, int level, FinalProcessLocalData localData, String path) throws InterruptedException {
if (level == 0) {
List<GraphTargetItem> 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<GraphPart> nextRef = new Reference<>(null);
Reference<GraphTargetItem> 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

View File

@@ -107,8 +107,9 @@ public class ActionGraphSource extends GraphSource {
* @param functions Functions
* @param charset Charset
*/
public ActionGraphSource(String path, boolean insideDoInitAction, List<Action> actions, int version, HashMap<Integer, String> registerNames, HashMap<String, GraphTargetItem> variables, HashMap<String, GraphTargetItem> functions, String charset) {
this.actions = actions instanceof ActionList ? (ActionList) actions : new ActionList(actions, charset);
public ActionGraphSource(String path, boolean insideDoInitAction, List<Action> actions, int version, HashMap<Integer, String> registerNames, HashMap<String, GraphTargetItem> variables, HashMap<String, GraphTargetItem> 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;

View File

@@ -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) {

View File

@@ -132,7 +132,7 @@ public final class FastActionListIterator implements Iterator<ActionItem> {
public void remove() {
item = list.removeItem(item.prev);
}
/**
* Adds an action after the current item.
*

View File

@@ -136,13 +136,13 @@ public class ActionWaitForFrame extends Action implements ActionStore {
HashMap<String, GraphTargetItem> 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));
}

View File

@@ -182,13 +182,13 @@ public class ActionWaitForFrame2 extends Action implements ActionStore {
HashMap<String, GraphTargetItem> variablesBackup = new LinkedHashMap<>(variables);
HashMap<String, GraphTargetItem> 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));
}

View File

@@ -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);
}

View File

@@ -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<GraphException> 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<GraphException> exceptions) {
public Graph(GraphTargetDialect dialect, GraphSource code, List<GraphException> 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<GraphTargetItem> firstCode = partCodes.get(part);
int firstCodePos = partCodePos.get(part);
if (firstCodePos > firstCode.size()) {
@@ -3298,6 +3306,7 @@ public class Graph {
}
Reference<GraphPart> nextRef = new Reference<>(null);
Reference<GraphTargetItem> 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<Integer, List<Integer>> refs = code.visitCode(alternateEntries);
List<GraphPart> 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<Integer> 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<GotoItem> foundGotos, Map<GraphPart, List<GraphTargetItem>> partCodes, Map<GraphPart, Integer> partCodePos, Set<GraphPart> visited, Set<GraphPart> allParts, TranslateStack stack, List<GraphPart> stopPart, List<StopPartKind> stopPartKind, List<Loop> loops, List<ThrowState> throwStates, BaseLocalData localData, int staticOperation, String path,
List<GraphTargetItem> caseValuesMap, GraphPart defaultPart, List<GraphPart> caseBodyParts, Reference<GraphPart> nextRef, Reference<GraphTargetItem> tiRef) throws InterruptedException {
boolean hasDefault = false;
/*
case 4:

View File

@@ -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++;