mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-07-15 23:08:13 +00:00
better actionlist deobfuscation
This commit is contained in:
@@ -24,7 +24,7 @@ import com.jpexs.decompiler.flash.abc.ClassPath;
|
||||
import com.jpexs.decompiler.flash.abc.RenameType;
|
||||
import com.jpexs.decompiler.flash.abc.ScriptPack;
|
||||
import com.jpexs.decompiler.flash.action.Action;
|
||||
import com.jpexs.decompiler.flash.action.ActionDeobfuscation;
|
||||
import com.jpexs.decompiler.flash.action.Deobfuscation;
|
||||
import com.jpexs.decompiler.flash.action.ActionGraphSource;
|
||||
import com.jpexs.decompiler.flash.action.ActionList;
|
||||
import com.jpexs.decompiler.flash.action.ActionLocalData;
|
||||
@@ -1672,7 +1672,7 @@ public final class SWF implements TreeItem, Timelined {
|
||||
private List<GraphSourceItem> allFunctions = new ArrayList<>();
|
||||
private HashMap<DirectValueActionItem, ConstantPool> allStrings = new HashMap<>();
|
||||
private final HashMap<DirectValueActionItem, String> usageTypes = new HashMap<>();
|
||||
private final ActionDeobfuscation deobfuscation = new ActionDeobfuscation();
|
||||
private final Deobfuscation deobfuscation = new Deobfuscation();
|
||||
|
||||
private static void getVariables(ConstantPool constantPool, BaseLocalData localData, Stack<GraphTargetItem> stack, List<GraphTargetItem> output, ActionGraphSource code, int ip, List<MyEntry<DirectValueActionItem, ConstantPool>> variables, List<GraphSourceItem> functions, HashMap<DirectValueActionItem, ConstantPool> strings, List<Integer> visited, HashMap<DirectValueActionItem, String> usageTypes, String path) throws InterruptedException {
|
||||
boolean debugMode = false;
|
||||
@@ -1683,7 +1683,7 @@ public final class SWF implements TreeItem, Timelined {
|
||||
GraphSourceItem ins = code.get(ip);
|
||||
|
||||
if (debugMode) {
|
||||
System.err.println("Visit " + ip + ": ofs" + Helper.formatAddress(((Action) ins).getAddress()) + ":" + ((Action) ins).getASMSource(new ArrayList<GraphSourceItem>(), new ArrayList<Long>(), new ArrayList<String>(), ScriptExportMode.PCODE) + " stack:" + Helper.stackToString(stack, LocalData.create(new ConstantPool())));
|
||||
System.err.println("Visit " + ip + ": ofs" + Helper.formatAddress(((Action) ins).getAddress()) + ":" + ((Action) ins).getASMSource(new ActionList(), new ArrayList<Long>(), ScriptExportMode.PCODE) + " stack:" + Helper.stackToString(stack, LocalData.create(new ConstantPool())));
|
||||
}
|
||||
if (ins.isExit()) {
|
||||
break;
|
||||
|
||||
@@ -398,25 +398,9 @@ public class Action implements GraphSourceItem {
|
||||
* @param version SWF version
|
||||
* @param exportMode PCode or hex?
|
||||
* @param writer
|
||||
* @return HilightedTextWriter
|
||||
* @return GraphTextWriter
|
||||
*/
|
||||
public static GraphTextWriter actionsToString(List<DisassemblyListener> listeners, long address, List<Action> list, int version, ScriptExportMode exportMode, GraphTextWriter writer) {
|
||||
return actionsToString(listeners, address, list, new ArrayList<String>(), version, exportMode, writer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts list of actions to ASM source
|
||||
*
|
||||
* @param listeners
|
||||
* @param address
|
||||
* @param list List of actions
|
||||
* @param importantOffsets List of important offsets to mark as labels
|
||||
* @param constantPool Constant pool
|
||||
* @param version SWF version
|
||||
* @param hex Add hexadecimal?
|
||||
* @return HilightedTextWriter
|
||||
*/
|
||||
private static GraphTextWriter actionsToString(List<DisassemblyListener> listeners, long address, List<Action> list, List<String> constantPool, int version, ScriptExportMode exportMode, GraphTextWriter writer) {
|
||||
public static GraphTextWriter actionsToString(List<DisassemblyListener> listeners, long address, ActionList list, int version, ScriptExportMode exportMode, GraphTextWriter writer) {
|
||||
long offset;
|
||||
List<Long> importantOffsets = getActionsAllRefs(list);
|
||||
/*List<ConstantPool> cps = SWFInputStream.getConstantPool(new ArrayList<DisassemblyListener>(), new ActionGraphSource(list, version, new HashMap<Integer, String>(), new HashMap<String, GraphTargetItem>(), new HashMap<String, GraphTargetItem>()), 0, version, path);
|
||||
@@ -467,8 +451,11 @@ public class Action implements GraphSourceItem {
|
||||
|
||||
if (containers.containsKey(offset)) {
|
||||
for (int i = 0; i < containers.get(offset).size(); i++) {
|
||||
if (lastPush) {
|
||||
writer.newLine();
|
||||
lastPush = false;
|
||||
}
|
||||
writer.appendNoHilight("}").newLine();
|
||||
lastPush = false;
|
||||
GraphSourceItemContainer cnt = containers.get(offset).get(i);
|
||||
int cntPos = containersPos.get(cnt);
|
||||
writer.appendNoHilight(cnt.getASMSourceBetween(cntPos));
|
||||
@@ -517,7 +504,7 @@ public class Action implements GraphSourceItem {
|
||||
add = "";*/
|
||||
if ((a instanceof ActionPush) && lastPush) {
|
||||
writer.appendNoHilight(" ");
|
||||
((ActionPush) a).paramsToStringReplaced(list, importantOffsets, constantPool, version, exportMode, writer);
|
||||
((ActionPush) a).paramsToStringReplaced(list, importantOffsets, exportMode, writer);
|
||||
} else {
|
||||
if (lastPush) {
|
||||
writer.newLine();
|
||||
@@ -547,7 +534,7 @@ public class Action implements GraphSourceItem {
|
||||
//nojump, ignore
|
||||
}
|
||||
} else {
|
||||
a.getASMSourceReplaced(list, importantOffsets, constantPool, exportMode, writer);
|
||||
a.getASMSourceReplaced(list, importantOffsets, exportMode, writer);
|
||||
}
|
||||
writer.appendNoHilight(a.isIgnored() ? "; ignored" : "");
|
||||
writer.appendNoHilight(add);
|
||||
@@ -592,11 +579,10 @@ public class Action implements GraphSourceItem {
|
||||
*
|
||||
* @param container
|
||||
* @param knownAddreses List of important offsets to mark as labels
|
||||
* @param constantPool Constant pool
|
||||
* @param exportMode PCode or hex?
|
||||
* @return String of P-code source
|
||||
*/
|
||||
public String getASMSource(List<? extends GraphSourceItem> container, List<Long> knownAddreses, List<String> constantPool, ScriptExportMode exportMode) {
|
||||
public String getASMSource(ActionList container, List<Long> knownAddreses, ScriptExportMode exportMode) {
|
||||
return toString();
|
||||
}
|
||||
|
||||
@@ -1209,8 +1195,8 @@ public class Action implements GraphSourceItem {
|
||||
}
|
||||
}
|
||||
|
||||
public GraphTextWriter getASMSourceReplaced(List<? extends GraphSourceItem> container, List<Long> knownAddreses, List<String> constantPool, ScriptExportMode exportMode, GraphTextWriter writer) {
|
||||
writer.appendNoHilight(getASMSource(container, knownAddreses, constantPool, exportMode));
|
||||
public GraphTextWriter getASMSourceReplaced(ActionList container, List<Long> knownAddreses, ScriptExportMode exportMode, GraphTextWriter writer) {
|
||||
writer.appendNoHilight(getASMSource(container, knownAddreses, exportMode));
|
||||
return writer;
|
||||
}
|
||||
|
||||
|
||||
357
src/com/jpexs/decompiler/flash/action/ActionDeobfuscator.java
Normal file
357
src/com/jpexs/decompiler/flash/action/ActionDeobfuscator.java
Normal file
@@ -0,0 +1,357 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.action;
|
||||
|
||||
import com.jpexs.decompiler.flash.action.special.ActionStore;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionAdd;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionEquals;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionGetVariable;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionIf;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionJump;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionNot;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionPush;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionSetVariable;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionSubtract;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionAdd2;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionConstantPool;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionDefineFunction;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionDefineLocal;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionReturn;
|
||||
import com.jpexs.decompiler.flash.ecma.EcmaScript;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
|
||||
import com.jpexs.decompiler.flash.helpers.SWFDecompilerListener;
|
||||
import com.jpexs.decompiler.graph.Graph;
|
||||
import com.jpexs.decompiler.graph.GraphSourceItemContainer;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.TranslateException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EmptyStackException;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ActionDeobfuscator implements SWFDecompilerListener {
|
||||
|
||||
@Override
|
||||
public void actionListParsed(ActionList actions) {
|
||||
combinePushs(actions);
|
||||
removeFakeFunction(actions);
|
||||
removeUnreachableActions(actions);
|
||||
removeObfuscationIfs(actions);
|
||||
removeUnreachableActions(actions);
|
||||
removeZeroJumps(actions);
|
||||
}
|
||||
|
||||
private void combinePushs(ActionList actions) {
|
||||
for (int i = 0; i < actions.size() - 1; i++) {
|
||||
Action action = actions.get(i);
|
||||
Action action2 = actions.get(i + 1);
|
||||
if (action instanceof ActionPush && action2 instanceof ActionPush) {
|
||||
if (actions.getReferencesFor(action2).hasNext()) {
|
||||
ActionPush push = (ActionPush) action;
|
||||
ActionPush push2 = (ActionPush) action2;
|
||||
push.values.addAll(push2.values);
|
||||
actions.remove(i + 1);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean removeUnreachableActions(ActionList actions) {
|
||||
Set<Action> reachableActions = new HashSet<>();
|
||||
Set<Action> processedActions = new HashSet<>();
|
||||
reachableActions.add(actions.get(0));
|
||||
boolean modified = true;
|
||||
while (modified) {
|
||||
modified = false;
|
||||
for (int i = 0; i < actions.size(); i++) {
|
||||
Action action = actions.get(i);
|
||||
if (reachableActions.contains(action) && !processedActions.contains(action)) {
|
||||
if (!action.isExit() && !(action instanceof ActionJump) && i != actions.size() - 1) {
|
||||
Action next = actions.get(i + 1);
|
||||
if (!reachableActions.contains(next)) {
|
||||
reachableActions.add(next);
|
||||
}
|
||||
}
|
||||
|
||||
if (action instanceof ActionJump) {
|
||||
ActionJump aJump = (ActionJump) action;
|
||||
long ref = aJump.getAddress() + aJump.getTotalActionLength() + aJump.getJumpOffset();
|
||||
Action target = actions.getByAddress(ref);
|
||||
if (target != null && !reachableActions.contains(target)) {
|
||||
reachableActions.add(target);
|
||||
}
|
||||
} else if (action instanceof ActionIf) {
|
||||
ActionIf aIf = (ActionIf) action;
|
||||
long ref = aIf.getAddress() + aIf.getTotalActionLength() + aIf.getJumpOffset();
|
||||
Action target = actions.getByAddress(ref);
|
||||
if (target != null && !reachableActions.contains(target)) {
|
||||
reachableActions.add(target);
|
||||
}
|
||||
} else if (action instanceof ActionStore) {
|
||||
ActionStore aStore = (ActionStore) action;
|
||||
int storeSize = aStore.getStoreSize();
|
||||
if (actions.size() > i + storeSize) {
|
||||
Action target = actions.get(i + storeSize);
|
||||
if (!reachableActions.contains(target)) {
|
||||
reachableActions.add(target);
|
||||
}
|
||||
}
|
||||
} else if (action instanceof GraphSourceItemContainer) {
|
||||
GraphSourceItemContainer container = (GraphSourceItemContainer) action;
|
||||
long ref = action.getAddress() + action.getTotalActionLength();
|
||||
for (Long size : container.getContainerSizes()) {
|
||||
ref += size;
|
||||
Action target = actions.getByAddress(ref);
|
||||
if (target != null && !reachableActions.contains(target)) {
|
||||
reachableActions.add(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
processedActions.add(action);
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean result = false;
|
||||
for (int i = 0; i < actions.size(); i++) {
|
||||
if (!reachableActions.contains(actions.get(i))) {
|
||||
actions.removeAction(i);
|
||||
i--;
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean removeZeroJumps(ActionList actions) {
|
||||
boolean result = false;
|
||||
for (int i = 0; i < actions.size(); i++) {
|
||||
Action action = actions.get(i);
|
||||
if (action instanceof ActionJump && ((ActionJump) action).getJumpOffset() == 0) {
|
||||
actions.removeAction(i);
|
||||
i--;
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean removeObfuscationIfs(ActionList actions) {
|
||||
if (actions.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < actions.size(); i++) {
|
||||
int idx = i;
|
||||
List<GraphTargetItem> output = new ArrayList<>();
|
||||
ActionLocalData localData = new ActionLocalData();
|
||||
Stack<GraphTargetItem> stack = new Stack<>();
|
||||
|
||||
try {
|
||||
int lastOkIdx = -1;
|
||||
int lastOkInstructionsProcessed = -1;
|
||||
int instructionsProcessed = 0;
|
||||
Map<String, Object> variables = new HashMap<>();
|
||||
Set<String> defines = new HashSet<>();
|
||||
ActionConstantPool constantPool = null;
|
||||
while (true) {
|
||||
Action action = actions.get(idx);
|
||||
instructionsProcessed++;
|
||||
|
||||
System.out.print(action.getASMSource(actions, new ArrayList<Long>(), ScriptExportMode.PCODE));
|
||||
for (int j = 0; j < stack.size(); j++) {
|
||||
System.out.print(" '" + stack.get(j).getResult() + "'");
|
||||
}
|
||||
System.out.println();
|
||||
|
||||
if (action instanceof ActionConstantPool) {
|
||||
constantPool = (ActionConstantPool) action;
|
||||
}
|
||||
|
||||
if (action instanceof ActionDefineLocal) {
|
||||
GraphTargetItem top = stack.pop();
|
||||
String variableName = stack.peek().getResult().toString();
|
||||
defines.add(variableName);
|
||||
stack.push(top);
|
||||
}
|
||||
|
||||
action.translate(localData, stack, output, Graph.SOP_USE_STATIC, "");
|
||||
|
||||
if (!(action instanceof ActionPush ||
|
||||
action instanceof ActionAdd ||
|
||||
action instanceof ActionAdd2 ||
|
||||
action instanceof ActionSubtract ||
|
||||
action instanceof ActionDefineLocal ||
|
||||
action instanceof ActionJump ||
|
||||
action instanceof ActionGetVariable ||
|
||||
action instanceof ActionSetVariable ||
|
||||
action instanceof ActionEquals ||
|
||||
action instanceof ActionNot ||
|
||||
action instanceof ActionIf ||
|
||||
action instanceof ActionConstantPool)) {
|
||||
break;
|
||||
}
|
||||
|
||||
/*for (String variable : localData.variables.keySet()) {
|
||||
System.out.println(Helper.byteArrToString(variable.getBytes()));
|
||||
}*/
|
||||
|
||||
idx++;
|
||||
|
||||
if (action instanceof ActionJump) {
|
||||
ActionJump jump = (ActionJump) action;
|
||||
long address = jump.getAddress() + jump.getTotalActionLength() + jump.getJumpOffset();
|
||||
idx = actions.indexOf(actions.getByAddress(address));
|
||||
if (idx == -1) {
|
||||
int a = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (action instanceof ActionIf) {
|
||||
ActionIf aif = (ActionIf) action;
|
||||
if (EcmaScript.toBoolean(stack.pop().getResult())) {
|
||||
System.out.println("if true");
|
||||
long address = aif.getAddress() + aif.getTotalActionLength() + aif.getJumpOffset();
|
||||
idx = actions.indexOf(actions.getByAddress(address));
|
||||
if (idx == -1) {
|
||||
int a = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (/*localData.variables.size() == 1 && */stack.empty()) {
|
||||
lastOkIdx = idx;
|
||||
lastOkInstructionsProcessed = instructionsProcessed;
|
||||
variables.clear();
|
||||
for (String variableName : localData.variables.keySet()) {
|
||||
Object value = localData.variables.get(variableName).getResult();
|
||||
variables.put(variableName, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (lastOkIdx != -1) {
|
||||
int newIstructionCount = constantPool != null ? 2 : 1;
|
||||
newIstructionCount += 2 * variables.size();
|
||||
|
||||
if (newIstructionCount < lastOkInstructionsProcessed) {
|
||||
Action target = actions.get(lastOkIdx);
|
||||
Action prevAction = actions.get(i);
|
||||
|
||||
if (constantPool != null) {
|
||||
actions.addAction(i++, constantPool);
|
||||
prevAction = constantPool;
|
||||
}
|
||||
|
||||
for (String variableName : variables.keySet()) {
|
||||
Object value = variables.get(variableName);
|
||||
ActionPush push = new ActionPush(variableName);
|
||||
push.values.add(value);
|
||||
push.setAddress(prevAction.getAddress());
|
||||
actions.addAction(i++, push);
|
||||
prevAction = push;
|
||||
|
||||
if (defines.contains(variableName)) {
|
||||
Action defineLocal = new ActionDefineLocal();
|
||||
defineLocal.setAddress(prevAction.getAddress());
|
||||
actions.addAction(i++, defineLocal);
|
||||
prevAction = defineLocal;
|
||||
} else {
|
||||
Action setVariable = new ActionSetVariable();
|
||||
setVariable.setAddress(prevAction.getAddress());
|
||||
actions.addAction(i++, setVariable);
|
||||
prevAction = setVariable;
|
||||
}
|
||||
}
|
||||
|
||||
ActionJump jump = new ActionJump(0);
|
||||
jump.setAddress(prevAction.getAddress());
|
||||
jump.setJumpOffset((int) (target.getAddress() - jump.getAddress() - jump.getTotalActionLength()));
|
||||
actions.addAction(i++, jump);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (EmptyStackException | TranslateException | InterruptedException ex) {
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean removeFakeFunction(ActionList actions) {
|
||||
/*
|
||||
DefineFunction "fakeName" 0 {
|
||||
Push 1777
|
||||
Return
|
||||
}
|
||||
*/
|
||||
|
||||
for (int i = 0; i < actions.size() - 2; i++) {
|
||||
Action action = actions.get(i);
|
||||
if (action instanceof ActionDefineFunction) {
|
||||
Action action2 = actions.get(i + 1);
|
||||
Action action3 = actions.get(i + 2);
|
||||
if (action2 instanceof ActionPush && action3 instanceof ActionReturn) {
|
||||
ActionDefineFunction def = (ActionDefineFunction) action;
|
||||
ActionPush push = (ActionPush) action2;
|
||||
if (def.paramNames.isEmpty() && push.values.size() == 1) {
|
||||
Object pushValueObj = push.values.get(0);
|
||||
if (pushValueObj instanceof Long) {
|
||||
String functionName = def.functionName;
|
||||
long pushValue = (Long) pushValueObj;
|
||||
for (int j = 0; j < 3; j++) {
|
||||
actions.removeAction(i);
|
||||
}
|
||||
|
||||
for (int j = 0; j < actions.size() - 1; j++) {
|
||||
action = actions.get(j);
|
||||
if (action instanceof ActionPush) {
|
||||
push = (ActionPush) action;
|
||||
int pushValuesCount = push.values.size();
|
||||
if (pushValuesCount >= 2
|
||||
&& push.values.get(pushValuesCount - 1).equals(functionName)) {
|
||||
push.values.remove(pushValuesCount - 1);
|
||||
push.values.remove(pushValuesCount - 2);
|
||||
push.values.add(pushValue);
|
||||
actions.removeAction(j + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -16,15 +16,38 @@
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.action;
|
||||
|
||||
import com.jpexs.decompiler.flash.DisassemblyListener;
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.action.special.ActionNop;
|
||||
import com.jpexs.decompiler.flash.action.special.ActionStore;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionIf;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionJump;
|
||||
import com.jpexs.decompiler.flash.configuration.Configuration;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
|
||||
import com.jpexs.decompiler.flash.helpers.EmptySWFDecompilerListener;
|
||||
import com.jpexs.decompiler.flash.helpers.FileTextWriter;
|
||||
import com.jpexs.decompiler.graph.GraphSourceItemContainer;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ActionList extends ArrayList<Action> {
|
||||
|
||||
public ActionList() {
|
||||
}
|
||||
|
||||
public ActionList(Collection<Action> actions) {
|
||||
super(actions);
|
||||
}
|
||||
|
||||
public void removeAction(int index) {
|
||||
ActionListReader.removeAction(this, index, SWF.DEFAULT_VERSION, true);
|
||||
@@ -42,7 +65,70 @@ public class ActionList extends ArrayList<Action> {
|
||||
}
|
||||
|
||||
public void addAction(int index, Action action) {
|
||||
ActionListReader.removeAction(this, index, SWF.DEFAULT_VERSION, true);
|
||||
ActionListReader.addAction(this, index, action, SWF.DEFAULT_VERSION, false, false);
|
||||
}
|
||||
|
||||
public void fixActionList() {
|
||||
ActionListReader.fixActionList(this, null, SWF.DEFAULT_VERSION);
|
||||
}
|
||||
|
||||
public Iterator<Action> getReferencesFor(final Action target) {
|
||||
final ActionList diz = this;
|
||||
return new Iterator<Action>() {
|
||||
|
||||
private final Iterator<Action> iterator = diz.iterator();
|
||||
|
||||
private Action action = getNext();
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return action != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Action next() {
|
||||
Action a = action;
|
||||
action = getNext();
|
||||
return a;
|
||||
}
|
||||
|
||||
private Action getNext() {
|
||||
while (iterator.hasNext()) {
|
||||
Action a = iterator.next();
|
||||
if (a instanceof ActionJump) {
|
||||
ActionJump aJump = (ActionJump) a;
|
||||
long ref = aJump.getAddress() + aJump.getTotalActionLength() + aJump.getJumpOffset();
|
||||
if (target.getAddress() == ref) {
|
||||
return aJump;
|
||||
}
|
||||
} else if (a instanceof ActionIf) {
|
||||
ActionIf aIf = (ActionIf) a;
|
||||
long ref = aIf.getAddress() + aIf.getTotalActionLength() + aIf.getJumpOffset();
|
||||
if (target.getAddress() == ref) {
|
||||
return aIf;
|
||||
}
|
||||
} else if (a instanceof ActionStore) {
|
||||
ActionStore aStore = (ActionStore) a;
|
||||
int storeSize = aStore.getStoreSize();
|
||||
int idx = indexOf(a);
|
||||
int idx2 = indexOf(target);
|
||||
if (idx != -1 && idx2 == idx + storeSize) {
|
||||
return a;
|
||||
}
|
||||
} else if (a instanceof GraphSourceItemContainer) {
|
||||
GraphSourceItemContainer container = (GraphSourceItemContainer) a;
|
||||
long ref = a.getAddress() + a.getTotalActionLength();
|
||||
for (Long size : container.getContainerSizes()) {
|
||||
ref += size;
|
||||
if (target.getAddress() == ref) {
|
||||
return a;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void removeNops() {
|
||||
@@ -54,11 +140,36 @@ public class ActionList extends ArrayList<Action> {
|
||||
}
|
||||
|
||||
public Action getByAddress(long address) {
|
||||
for (Action action : this) {
|
||||
if (action.getAddress() == address) {
|
||||
return action;
|
||||
int idx = getIndexByAddress(address);
|
||||
return idx == -1 ? null : get(idx);
|
||||
}
|
||||
|
||||
public int getIndexByAddress(long address) {
|
||||
int min = 0;
|
||||
int max = size() - 1;
|
||||
|
||||
while (max >= min) {
|
||||
int mid = (min + max) / 2;
|
||||
long midValue = get(mid).getAddress();
|
||||
if (midValue == address) {
|
||||
return mid;
|
||||
} else if (midValue < address) {
|
||||
min = mid + 1;
|
||||
} else {
|
||||
max = mid - 1;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public void saveToFile(String fileName) {
|
||||
File file = new File(fileName);
|
||||
try (FileTextWriter writer = new FileTextWriter(Configuration.getCodeFormatting(), new FileOutputStream(file))) {
|
||||
Action.actionsToString(new ArrayList<DisassemblyListener>(), 0, this, SWF.DEFAULT_VERSION, ScriptExportMode.PCODE, writer);
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(EmptySWFDecompilerListener.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -41,7 +41,6 @@ import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
|
||||
import com.jpexs.decompiler.flash.gui.View;
|
||||
import com.jpexs.decompiler.flash.helpers.SWFDecompilerPlugin;
|
||||
import com.jpexs.decompiler.graph.Graph;
|
||||
import com.jpexs.decompiler.graph.GraphSourceItem;
|
||||
import com.jpexs.decompiler.graph.GraphSourceItemContainer;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.graph.NotCompileTimeItem;
|
||||
@@ -132,90 +131,56 @@ public class ActionListReader {
|
||||
ConstantPool cpool = new ConstantPool();
|
||||
|
||||
// Map of the actions. Use TreeMap to sort the keys in ascending order
|
||||
// actionMap and nextOffsets should contain exaclty the same keys
|
||||
Map<Long, Action> actionMap = new TreeMap<>();
|
||||
Map<Long, Long> nextOffsets = new HashMap<>();
|
||||
Action entryAction = readActionListAtPos(listeners, cpool,
|
||||
sis, actionMap, nextOffsets,
|
||||
ip, 0, endIp, path, false, new ArrayList<Long>());
|
||||
|
||||
ActionList actions = new ActionList();
|
||||
if (actionMap.isEmpty()) {
|
||||
return actions;
|
||||
return new ActionList();
|
||||
}
|
||||
|
||||
Map<Action, List<Action>> containerLastActions = new HashMap<>();
|
||||
List<Long> addresses = new ArrayList<>(actionMap.keySet());
|
||||
getContainerLastActions(actionMap, addresses, containerLastActions);
|
||||
|
||||
// jump to the entry action when it is diffrent from the first action in the map
|
||||
long index = addresses.get(0);
|
||||
if (index != -1 && entryAction != actionMap.get(index)) {
|
||||
ActionJump jump = new ActionDeobfuscateJump(0);
|
||||
int size = jump.getTotalActionLength();
|
||||
jump.setJumpOffset((int) (entryAction.getAddress() - size));
|
||||
actions.add(jump);
|
||||
}
|
||||
|
||||
// remove nulls
|
||||
index = getNearAddress(addresses, index, true);
|
||||
while (index > -1) {
|
||||
Action action = actionMap.get(index);
|
||||
long nextOffset = nextOffsets.get(index);
|
||||
long nextIndex = getNearAddress(addresses, index + 1, true);
|
||||
actions.add(action);
|
||||
if (nextIndex != -1 && nextOffset != nextIndex) {
|
||||
if (!action.isExit() && !(action instanceof ActionJump)) {
|
||||
ActionJump jump = new ActionDeobfuscateJump(0);
|
||||
jump.setAddress(action.getAddress());
|
||||
int size = jump.getTotalActionLength();
|
||||
jump.setJumpOffset((int) (nextOffset - action.getAddress() - size));
|
||||
actions.add(jump);
|
||||
}
|
||||
}
|
||||
index = nextIndex;
|
||||
}
|
||||
|
||||
// Map for storing the targers of the "jump" actions
|
||||
// "jump" action can be ActionIf, ActionJump and any ActionStore
|
||||
Map<Action, Action> jumps = new HashMap<>();
|
||||
getJumps(actions, jumps);
|
||||
|
||||
updateActionLengths(actions, version);
|
||||
long endAddress = updateAddresses(actions, 0);
|
||||
|
||||
// add end action
|
||||
Action lastAction = actions.get(actions.size() - 1);
|
||||
Action aEnd = new ActionEnd();
|
||||
Action lastAction = actionMap.get(addresses.get(addresses.size() - 1));
|
||||
long endAddress;
|
||||
if (!(lastAction instanceof ActionEnd)) {
|
||||
aEnd.setAddress(endAddress);
|
||||
actions.add(aEnd);
|
||||
} else {
|
||||
endAddress -= aEnd.getTotalActionLength();
|
||||
Action aEnd = new ActionEnd();
|
||||
aEnd.setAddress(nextOffsets.get(lastAction.getAddress()));
|
||||
endAddress = aEnd.getAddress();
|
||||
actionMap.put(aEnd.getAddress(), aEnd);
|
||||
nextOffsets.put(endAddress, endAddress + 1);
|
||||
}
|
||||
|
||||
ActionList actions = fixActionList(new ActionList(actionMap.values()), nextOffsets, version);
|
||||
|
||||
updateJumps(actions, jumps, containerLastActions, endAddress);
|
||||
updateActionStores(actions, jumps);
|
||||
updateContainerSizes(actions, containerLastActions);
|
||||
// jump to the entry action when it is diffrent from the first action in the map
|
||||
if (entryAction != actions.get(0)) {
|
||||
ActionJump jump = new ActionDeobfuscateJump(0);
|
||||
actions.addAction(0, jump);
|
||||
jump.setJumpOffset((int) (entryAction.getAddress() - jump.getTotalActionLength()));
|
||||
}
|
||||
|
||||
if (SWFDecompilerPlugin.listener != null) {
|
||||
try {
|
||||
SWFDecompilerPlugin.listener.actionListParsed(actions);
|
||||
|
||||
updateActionLengths(actions, version);
|
||||
updateAddresses(actions, 0);
|
||||
updateJumps(actions, jumps, containerLastActions, endAddress);
|
||||
updateActionStores(actions, jumps);
|
||||
updateContainerSizes(actions, containerLastActions);
|
||||
actions = fixActionList(actions, null, version);
|
||||
} catch (Throwable e) {
|
||||
Logger.getLogger(ActionListReader.class.getName()).log(Level.SEVERE, null, e);
|
||||
View.showMessageDialog(null, "Failed to call plugin method actionListParsed. Exception: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
if (Configuration.autoDeobfuscate.get()) {
|
||||
try {
|
||||
actions = deobfuscateActionList(listeners, actions, version, 0, path);
|
||||
new ActionDeobfuscator().actionListParsed(actions);
|
||||
/*actions = deobfuscateActionList(listeners, actions, version, 0, path);
|
||||
updateActionLengths(actions, version);
|
||||
removeZeroJumps(actions, version);
|
||||
removeZeroJumps(actions, version);*/
|
||||
} catch (OutOfMemoryError | StackOverflowError | TranslateException ex) {
|
||||
// keep orignal (not deobfuscated) actions
|
||||
Logger.getLogger(ActionListReader.class.getName()).log(Level.SEVERE, null, ex);
|
||||
@@ -224,6 +189,51 @@ public class ActionListReader {
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
public static ActionList fixActionList(ActionList actions, Map<Long, Long> nextOffsets, int version) {
|
||||
Map<Action, List<Action>> containerLastActions = new HashMap<>();
|
||||
getContainerLastActions(actions, containerLastActions);
|
||||
|
||||
ActionList ret = new ActionList();
|
||||
|
||||
if (nextOffsets != null) {
|
||||
int index = 0;
|
||||
while (index != -1 && index < actions.size()) {
|
||||
Action action = actions.get(index);
|
||||
ret.add(action);
|
||||
index++;
|
||||
if (index < actions.size()) {
|
||||
long nextAddress = nextOffsets.get(action.getAddress());
|
||||
if (actions.get(index).getAddress() != nextAddress) {
|
||||
if (!action.isExit() && !(action instanceof ActionJump)) {
|
||||
ActionJump jump = new ActionDeobfuscateJump(0);
|
||||
jump.setAddress(action.getAddress());
|
||||
int size = jump.getTotalActionLength();
|
||||
jump.setJumpOffset((int) (nextAddress - action.getAddress() - size));
|
||||
ret.add(jump);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ret.addAll(actions);
|
||||
}
|
||||
|
||||
// Map for storing the targers of the "jump" actions
|
||||
// "jump" action can be ActionIf, ActionJump and any ActionStore
|
||||
Map<Action, Action> jumps = new HashMap<>();
|
||||
getJumps(ret, jumps);
|
||||
|
||||
updateActionLengths(ret, version);
|
||||
updateAddresses(ret, 0);
|
||||
long endAddress = ret.get(ret.size() - 1).getAddress();
|
||||
|
||||
updateJumps(ret, jumps, containerLastActions, endAddress);
|
||||
updateActionStores(ret, jumps);
|
||||
updateContainerSizes(ret, containerLastActions);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static List<Action> getOriginalActions(SWFInputStream sis, int startIp, int endIp) throws IOException, InterruptedException {
|
||||
ConstantPool cpool = new ConstantPool();
|
||||
@@ -313,13 +323,13 @@ public class ActionListReader {
|
||||
return reta;
|
||||
}
|
||||
|
||||
private static long getNearAddress(List<Long> addresses, long address, boolean next) {
|
||||
private static long getNearAddress(ActionList actions, long address, boolean next) {
|
||||
int min = 0;
|
||||
int max = addresses.size() - 1;
|
||||
int max = actions.size() - 1;
|
||||
|
||||
while (max >= min) {
|
||||
int mid = (min + max) / 2;
|
||||
long midValue = addresses.get(mid);
|
||||
long midValue = actions.get(mid).getAddress();
|
||||
if (midValue == address) {
|
||||
return address;
|
||||
} else if (midValue < address) {
|
||||
@@ -330,8 +340,8 @@ public class ActionListReader {
|
||||
}
|
||||
|
||||
return next
|
||||
? (min < addresses.size() ? addresses.get(min) : -1)
|
||||
: (max > 0 ? addresses.get(max) : -1);
|
||||
? (min < actions.size() ? actions.get(min).getAddress() : -1)
|
||||
: (max > 0 ? actions.get(max).getAddress() : -1);
|
||||
}
|
||||
|
||||
private static Map<Long, Action> actionListToMap(List<Action> actions) {
|
||||
@@ -378,10 +388,8 @@ public class ActionListReader {
|
||||
}
|
||||
}
|
||||
|
||||
private static void getContainerLastActions(Map<Long, Action> actionMap, List<Long> addresses, Map<Action, List<Action>> lastActions) {
|
||||
for (Long address : actionMap.keySet()) {
|
||||
Action a = actionMap.get(address);
|
||||
|
||||
private static void getContainerLastActions(ActionList actions, Map<Action, List<Action>> lastActions) {
|
||||
for (Action a : actions) {
|
||||
if (a instanceof GraphSourceItemContainer) {
|
||||
GraphSourceItemContainer container = (GraphSourceItemContainer) a;
|
||||
List<Long> sizes = container.getContainerSizes();
|
||||
@@ -389,10 +397,10 @@ public class ActionListReader {
|
||||
List<Action> lasts = new ArrayList<>(sizes.size());
|
||||
for (long size : sizes) {
|
||||
endAddress += size;
|
||||
long lastActionIndex = getNearAddress(addresses, endAddress - 1, false);
|
||||
long lastActionAddress = getNearAddress(actions, endAddress - 1, false);
|
||||
Action lastAction = null;
|
||||
if (lastActionIndex != -1) {
|
||||
lastAction = actionMap.get(lastActionIndex);
|
||||
if (lastActionAddress != -1) {
|
||||
lastAction = actions.getByAddress(lastActionAddress);
|
||||
}
|
||||
lasts.add(lastAction);
|
||||
}
|
||||
@@ -518,20 +526,6 @@ public class ActionListReader {
|
||||
}
|
||||
}
|
||||
|
||||
private static void removeZeroJumps(List<Action> actions, int version) {
|
||||
for (int i = 0; i < actions.size(); i++) {
|
||||
Action a = actions.get(i);
|
||||
if (a instanceof ActionJump) {
|
||||
ActionJump aJump = (ActionJump) a;
|
||||
if (aJump.getJumpOffset() == 0) {
|
||||
if (removeAction(actions, i, version, false)) {
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an action from the action list, and updates all references
|
||||
* This method will keep the inner actions of the container when you remove the container
|
||||
@@ -542,7 +536,7 @@ public class ActionListReader {
|
||||
* @param removeWhenLast
|
||||
* @return
|
||||
*/
|
||||
public static boolean removeAction(List<Action> actions, int index, int version, boolean removeWhenLast) {
|
||||
public static boolean removeAction(ActionList actions, int index, int version, boolean removeWhenLast) {
|
||||
|
||||
if (index < 0 || actions.size() <= index) {
|
||||
return false;
|
||||
@@ -552,14 +546,8 @@ public class ActionListReader {
|
||||
Action lastAction = actions.get(actions.size() - 1);
|
||||
long endAddress = lastAction.getAddress() + lastAction.getTotalActionLength();
|
||||
|
||||
Map<Long, Action> actionMap = new TreeMap<>();
|
||||
for (Action a : actions) {
|
||||
actionMap.put(a.getAddress(), a);
|
||||
}
|
||||
List<Long> addresses = new ArrayList<>(actionMap.keySet());
|
||||
|
||||
Map<Action, List<Action>> containerLastActions = new HashMap<>();
|
||||
getContainerLastActions(actionMap, addresses, containerLastActions);
|
||||
getContainerLastActions(actions, containerLastActions);
|
||||
|
||||
Map<Action, Action> jumps = new HashMap<>();
|
||||
getJumps(actions, jumps);
|
||||
@@ -602,6 +590,75 @@ public class ActionListReader {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an action to the action list to the specified location, and updates all references
|
||||
*
|
||||
* @param actions
|
||||
* @param index
|
||||
* @param action
|
||||
* @param version
|
||||
* @param addToContainer
|
||||
* @param replaceJump
|
||||
* @return
|
||||
*/
|
||||
public static boolean addAction(ActionList actions, int index, Action action,
|
||||
int version, boolean addToContainer, boolean replaceJump) {
|
||||
|
||||
if (index < 0 || actions.size() < index) {
|
||||
return false;
|
||||
}
|
||||
|
||||
long startIp = actions.get(0).getAddress();
|
||||
Action lastAction = actions.get(actions.size() - 1);
|
||||
if (!(lastAction instanceof ActionEnd)) {
|
||||
Action aEnd = new ActionEnd();
|
||||
aEnd.setAddress(lastAction.getAddress() + lastAction.getTotalActionLength());
|
||||
actions.add(aEnd);
|
||||
lastAction = aEnd;
|
||||
}
|
||||
|
||||
long endAddress = lastAction.getAddress();
|
||||
|
||||
Map<Action, List<Action>> containerLastActions = new HashMap<>();
|
||||
getContainerLastActions(actions, containerLastActions);
|
||||
|
||||
Map<Action, Action> jumps = new HashMap<>();
|
||||
List<Action> tempActions = new ArrayList<>(actions);
|
||||
tempActions.add(action);
|
||||
getJumps(tempActions, jumps);
|
||||
|
||||
Action prevAction = actions.get(index);
|
||||
if (addToContainer) {
|
||||
for (Action a : containerLastActions.keySet()) {
|
||||
List<Action> lastActions = containerLastActions.get(a);
|
||||
for (int i = 0; i < lastActions.size(); i++) {
|
||||
if (lastActions.get(i) == prevAction) {
|
||||
lastActions.set(i, action);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (replaceJump) {
|
||||
for (Action a : jumps.keySet()) {
|
||||
Action targetAction = jumps.get(a);
|
||||
if (targetAction == prevAction) {
|
||||
jumps.put(a, action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
actions.add(index, action);
|
||||
|
||||
updateActionLengths(actions, version);
|
||||
updateAddresses(actions, startIp);
|
||||
updateJumps(actions, jumps, containerLastActions, endAddress);
|
||||
updateActionStores(actions, jumps);
|
||||
updateContainerSizes(actions, containerLastActions);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static Action readActionListAtPos(List<DisassemblyListener> listeners, ConstantPool cpool,
|
||||
SWFInputStream sis, Map<Long, Action> actions, Map<Long, Long> nextOffsets,
|
||||
long ip, long startIp, long endIp, String path, boolean indeterminate, List<Long> visitedContainers) throws IOException {
|
||||
@@ -742,7 +799,7 @@ public class ActionListReader {
|
||||
}
|
||||
|
||||
if (debugMode) {
|
||||
String atos = a.getASMSource(new ArrayList<GraphSourceItem>(), new ArrayList<Long>(), cpool.constants, ScriptExportMode.PCODE);
|
||||
String atos = a.getASMSource(new ActionList(), new ArrayList<Long>(), ScriptExportMode.PCODE);
|
||||
if (a instanceof GraphSourceItemContainer) {
|
||||
atos = a.toString();
|
||||
}
|
||||
@@ -928,8 +985,10 @@ public class ActionListReader {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Stack<GraphTargetItem> substack = (Stack<GraphTargetItem>) stack.clone();
|
||||
deobfustaceActionListAtPosRecursive(listeners, output, containers, prepareLocalBranch(localData), substack, cpool, actions, ip + actionLen + aif.getJumpOffset(), ret, startIp, endip, path, visited, indeterminate, decisionStates, version, recursionLevel + 1, maxRecursionLevel);
|
||||
Stack<GraphTargetItem> subStack = (Stack<GraphTargetItem>) stack.clone();
|
||||
ActionLocalData subLocalData = new ActionLocalData(new HashMap<>(localData.regNames),
|
||||
new HashMap<>(localData.variables), new HashMap<>(localData.functions));
|
||||
deobfustaceActionListAtPosRecursive(listeners, output, containers, subLocalData, subStack, cpool, actions, ip + actionLen + aif.getJumpOffset(), ret, startIp, endip, path, visited, indeterminate, decisionStates, version, recursionLevel + 1, maxRecursionLevel);
|
||||
}
|
||||
|
||||
if (newip > -1) {
|
||||
@@ -946,10 +1005,4 @@ public class ActionListReader {
|
||||
listener.progress(AppStrings.translate("disassemblingProgress.deobfuscating"), ip, actions.size());
|
||||
}
|
||||
}
|
||||
|
||||
private static ActionLocalData prepareLocalBranch(ActionLocalData localData) {
|
||||
|
||||
return new ActionLocalData(new HashMap<>(localData.regNames),
|
||||
new HashMap<>(localData.variables), new HashMap<>(localData.functions));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ import java.util.regex.Pattern;
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ActionDeobfuscation {
|
||||
public class Deobfuscation {
|
||||
|
||||
private final Random rnd = new Random();
|
||||
private final int DEFAULT_FOO_SIZE = 10;
|
||||
@@ -23,6 +23,7 @@ import com.jpexs.decompiler.flash.action.flashlite.ActionStrictMode;
|
||||
import com.jpexs.decompiler.flash.action.parser.ParseException;
|
||||
import com.jpexs.decompiler.flash.action.special.ActionDeobfuscateJump;
|
||||
import com.jpexs.decompiler.flash.action.special.ActionDeobfuscatePop;
|
||||
import com.jpexs.decompiler.flash.action.special.ActionEnd;
|
||||
import com.jpexs.decompiler.flash.action.special.ActionNop;
|
||||
import com.jpexs.decompiler.flash.action.swf3.ActionGetURL;
|
||||
import com.jpexs.decompiler.flash.action.swf3.ActionGoToLabel;
|
||||
@@ -408,6 +409,8 @@ public class ASMParser {
|
||||
a = (new ActionStrictMode(lexer));
|
||||
} else if (instructionName.compareToIgnoreCase("Nop") == 0) {
|
||||
a = (new ActionNop());
|
||||
} else if (instructionName.compareToIgnoreCase("End") == 0) {
|
||||
a = (new ActionEnd());
|
||||
} else if (instructionName.compareToIgnoreCase("FFDec_DeobfuscatePop") == 0) {
|
||||
a = (new ActionDeobfuscatePop());
|
||||
} else if (instructionName.compareToIgnoreCase("FFDec_DeobfuscateJump") == 0) {
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.action.Action;
|
||||
import com.jpexs.decompiler.flash.action.ActionGraph;
|
||||
import com.jpexs.decompiler.flash.action.ActionList;
|
||||
import com.jpexs.decompiler.flash.action.model.ConstantPool;
|
||||
import com.jpexs.decompiler.flash.action.model.DirectValueActionItem;
|
||||
import com.jpexs.decompiler.flash.action.model.clauses.IfFrameLoadedActionItem;
|
||||
@@ -28,7 +29,6 @@ import com.jpexs.decompiler.flash.action.parser.ParseException;
|
||||
import com.jpexs.decompiler.flash.action.parser.pcode.FlasmLexer;
|
||||
import com.jpexs.decompiler.flash.action.special.ActionStore;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
|
||||
import com.jpexs.decompiler.graph.GraphSourceItem;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
@@ -56,7 +56,7 @@ public class ActionWaitForFrame extends Action implements ActionStore {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getASMSource(List<? extends GraphSourceItem> container, List<Long> knownAddreses, List<String> constantPool, ScriptExportMode exportMode) {
|
||||
public String getASMSource(ActionList container, List<Long> knownAddreses, ScriptExportMode exportMode) {
|
||||
String ret = "WaitForFrame " + frame + " " + skipCount;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -19,11 +19,11 @@ package com.jpexs.decompiler.flash.action.swf4;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.action.Action;
|
||||
import com.jpexs.decompiler.flash.action.ActionList;
|
||||
import com.jpexs.decompiler.flash.action.parser.ParseException;
|
||||
import com.jpexs.decompiler.flash.action.parser.pcode.FlasmLexer;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
|
||||
import com.jpexs.decompiler.graph.GraphSource;
|
||||
import com.jpexs.decompiler.graph.GraphSourceItem;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
@@ -74,8 +74,9 @@ public class ActionIf extends Action {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getASMSource(List<? extends GraphSourceItem> container, List<Long> knownAddreses, List<String> constantPool, ScriptExportMode exportMode) {
|
||||
String ofsStr = Helper.formatAddress(getAddress() + getTotalActionLength() + offset);
|
||||
public String getASMSource(ActionList container, List<Long> knownAddreses, ScriptExportMode exportMode) {
|
||||
long address = getAddress() + getTotalActionLength() + offset;
|
||||
String ofsStr = Helper.formatAddress(address);
|
||||
return "If loc" + ofsStr + (!jumpUsed ? " ;compileTimeIgnore" : (!ignoreUsed ? " ;compileTimeJump" : ""));
|
||||
}
|
||||
|
||||
|
||||
@@ -20,11 +20,11 @@ import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.action.Action;
|
||||
import com.jpexs.decompiler.flash.action.ActionGraphSource;
|
||||
import com.jpexs.decompiler.flash.action.ActionList;
|
||||
import com.jpexs.decompiler.flash.action.parser.ParseException;
|
||||
import com.jpexs.decompiler.flash.action.parser.pcode.FlasmLexer;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
|
||||
import com.jpexs.decompiler.graph.GraphSource;
|
||||
import com.jpexs.decompiler.graph.GraphSourceItem;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
@@ -75,8 +75,9 @@ public class ActionJump extends Action {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getASMSource(List<? extends GraphSourceItem> container, List<Long> knownAddreses, List<String> constantPool, ScriptExportMode exportMode) {
|
||||
String ofsStr = Helper.formatAddress(getAddress() + getTotalActionLength() + offset);
|
||||
public String getASMSource(ActionList container, List<Long> knownAddreses, ScriptExportMode exportMode) {
|
||||
long address = getAddress() + getTotalActionLength() + offset;
|
||||
String ofsStr = Helper.formatAddress(address);
|
||||
return "Jump loc" + ofsStr;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.jpexs.decompiler.flash.EndOfStreamException;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.action.Action;
|
||||
import com.jpexs.decompiler.flash.action.ActionList;
|
||||
import com.jpexs.decompiler.flash.action.model.DirectValueActionItem;
|
||||
import com.jpexs.decompiler.flash.action.model.TemporaryRegister;
|
||||
import com.jpexs.decompiler.flash.action.parser.ParseException;
|
||||
@@ -231,7 +232,7 @@ public class ActionPush extends Action {
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphTextWriter getASMSourceReplaced(List<? extends GraphSourceItem> container, List<Long> knownAddreses, List<String> constantPool, ScriptExportMode exportMode, GraphTextWriter writer) {
|
||||
public GraphTextWriter getASMSourceReplaced(ActionList container, List<Long> knownAddreses, ScriptExportMode exportMode, GraphTextWriter writer) {
|
||||
if (replacement == null || replacement.size() < values.size()) {
|
||||
return toString(writer);
|
||||
}
|
||||
@@ -242,7 +243,7 @@ public class ActionPush extends Action {
|
||||
return writer;
|
||||
}
|
||||
|
||||
public GraphTextWriter paramsToStringReplaced(List<? extends GraphSourceItem> container, List<Long> knownAddreses, List<String> constantPool, int version, ScriptExportMode exportMode, GraphTextWriter writer) {
|
||||
public GraphTextWriter paramsToStringReplaced(List<? extends GraphSourceItem> container, List<Long> knownAddreses, ScriptExportMode exportMode, GraphTextWriter writer) {
|
||||
if (replacement == null || replacement.size() < values.size()) {
|
||||
return paramsToString(writer);
|
||||
}
|
||||
|
||||
@@ -21,13 +21,13 @@ import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.action.Action;
|
||||
import com.jpexs.decompiler.flash.action.ActionGraph;
|
||||
import com.jpexs.decompiler.flash.action.ActionList;
|
||||
import com.jpexs.decompiler.flash.action.model.ConstantPool;
|
||||
import com.jpexs.decompiler.flash.action.model.clauses.IfFrameLoadedActionItem;
|
||||
import com.jpexs.decompiler.flash.action.parser.ParseException;
|
||||
import com.jpexs.decompiler.flash.action.parser.pcode.FlasmLexer;
|
||||
import com.jpexs.decompiler.flash.action.special.ActionStore;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
|
||||
import com.jpexs.decompiler.graph.GraphSourceItem;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
@@ -116,13 +116,13 @@ public class ActionWaitForFrame2 extends Action implements ActionStore {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getASMSource(List<? extends GraphSourceItem> container, List<Long> knownAddreses, List<String> constantPool, ScriptExportMode exportMode) {
|
||||
public String getASMSource(ActionList container, List<Long> knownAddreses, ScriptExportMode exportMode) {
|
||||
String ret = "WaitForFrame2 " + skipCount;
|
||||
/*for (int i = 0; i < skipped.size(); i++) {
|
||||
if (skipped.get(i) instanceof ActionEnd) {
|
||||
break;
|
||||
}
|
||||
ret += "\r\n" + skipped.get(i).getASMSource(container, knownAddreses, constantPool, version, exportMode);
|
||||
ret += "\r\n" + skipped.get(i).getASMSource(container, knownAddreses, version, exportMode);
|
||||
}*/
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -19,13 +19,13 @@ package com.jpexs.decompiler.flash.action.swf5;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.action.Action;
|
||||
import com.jpexs.decompiler.flash.action.ActionList;
|
||||
import com.jpexs.decompiler.flash.action.model.FunctionActionItem;
|
||||
import com.jpexs.decompiler.flash.action.parser.ParseException;
|
||||
import com.jpexs.decompiler.flash.action.parser.pcode.FlasmLexer;
|
||||
import com.jpexs.decompiler.flash.action.parser.script.VariableActionItem;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
|
||||
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
|
||||
import com.jpexs.decompiler.graph.GraphSourceItem;
|
||||
import com.jpexs.decompiler.graph.GraphSourceItemContainer;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.helpers.Helper;
|
||||
@@ -146,7 +146,7 @@ public class ActionDefineFunction extends Action implements GraphSourceItemConta
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getASMSource(List<? extends GraphSourceItem> container, List<Long> knownAddreses, List<String> constantPool, ScriptExportMode exportMode) {
|
||||
public String getASMSource(ActionList container, List<Long> knownAddreses, ScriptExportMode exportMode) {
|
||||
StringBuilder paramStr = new StringBuilder();
|
||||
for (int i = 0; i < paramNames.size(); i++) {
|
||||
paramStr.append("\"").append(Helper.escapeString(paramNames.get(i))).append("\" ");
|
||||
@@ -156,7 +156,7 @@ public class ActionDefineFunction extends Action implements GraphSourceItemConta
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphTextWriter getASMSourceReplaced(List<? extends GraphSourceItem> container, List<Long> knownAddreses, List<String> constantPool, ScriptExportMode exportMode, GraphTextWriter writer) {
|
||||
public GraphTextWriter getASMSourceReplaced(ActionList container, List<Long> knownAddreses, ScriptExportMode exportMode, GraphTextWriter writer) {
|
||||
List<String> oldParamNames = paramNames;
|
||||
if (replacedParamNames != null) {
|
||||
paramNames = replacedParamNames;
|
||||
@@ -165,7 +165,7 @@ public class ActionDefineFunction extends Action implements GraphSourceItemConta
|
||||
if (replacedFunctionName != null) {
|
||||
functionName = replacedFunctionName;
|
||||
}
|
||||
String ret = getASMSource(container, knownAddreses, constantPool, exportMode);
|
||||
String ret = getASMSource(container, knownAddreses, exportMode);
|
||||
paramNames = oldParamNames;
|
||||
functionName = oldFunctionName;
|
||||
writer.appendNoHilight(ret);
|
||||
|
||||
@@ -19,11 +19,11 @@ package com.jpexs.decompiler.flash.action.swf5;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.action.Action;
|
||||
import com.jpexs.decompiler.flash.action.ActionList;
|
||||
import com.jpexs.decompiler.flash.action.model.clauses.WithActionItem;
|
||||
import com.jpexs.decompiler.flash.action.parser.ParseException;
|
||||
import com.jpexs.decompiler.flash.action.parser.pcode.FlasmLexer;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
|
||||
import com.jpexs.decompiler.graph.GraphSourceItem;
|
||||
import com.jpexs.decompiler.graph.GraphSourceItemContainer;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
@@ -75,7 +75,7 @@ public class ActionWith extends Action implements GraphSourceItemContainer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getASMSource(List<? extends GraphSourceItem> container, List<Long> knownAddreses, List<String> constantPool, ScriptExportMode exportMode) {
|
||||
public String getASMSource(ActionList container, List<Long> knownAddreses, ScriptExportMode exportMode) {
|
||||
return "With {";
|
||||
}
|
||||
|
||||
|
||||
@@ -19,13 +19,13 @@ package com.jpexs.decompiler.flash.action.swf7;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.action.Action;
|
||||
import com.jpexs.decompiler.flash.action.ActionList;
|
||||
import com.jpexs.decompiler.flash.action.model.FunctionActionItem;
|
||||
import com.jpexs.decompiler.flash.action.parser.ParseException;
|
||||
import com.jpexs.decompiler.flash.action.parser.pcode.FlasmLexer;
|
||||
import com.jpexs.decompiler.flash.action.parser.script.VariableActionItem;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
|
||||
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
|
||||
import com.jpexs.decompiler.graph.GraphSourceItem;
|
||||
import com.jpexs.decompiler.graph.GraphSourceItemContainer;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.helpers.Helper;
|
||||
@@ -226,7 +226,7 @@ public class ActionDefineFunction2 extends Action implements GraphSourceItemCont
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphTextWriter getASMSourceReplaced(List<? extends GraphSourceItem> container, List<Long> knownAddreses, List<String> constantPool, ScriptExportMode exportMode, GraphTextWriter writer) {
|
||||
public GraphTextWriter getASMSourceReplaced(ActionList container, List<Long> knownAddreses, ScriptExportMode exportMode, GraphTextWriter writer) {
|
||||
List<String> oldParamNames = paramNames;
|
||||
if (replacedParamNames != null) {
|
||||
paramNames = replacedParamNames;
|
||||
@@ -235,7 +235,7 @@ public class ActionDefineFunction2 extends Action implements GraphSourceItemCont
|
||||
if (replacedFunctionName != null) {
|
||||
functionName = replacedFunctionName;
|
||||
}
|
||||
String ret = getASMSource(container, knownAddreses, constantPool, exportMode);
|
||||
String ret = getASMSource(container, knownAddreses, exportMode);
|
||||
paramNames = oldParamNames;
|
||||
functionName = oldFunctionName;
|
||||
writer.appendNoHilight(ret);
|
||||
@@ -244,7 +244,7 @@ public class ActionDefineFunction2 extends Action implements GraphSourceItemCont
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getASMSource(List<? extends GraphSourceItem> container, List<Long> knownAddreses, List<String> constantPool, ScriptExportMode exportMode) {
|
||||
public String getASMSource(ActionList container, List<Long> knownAddreses, ScriptExportMode exportMode) {
|
||||
StringBuilder paramStr = new StringBuilder();
|
||||
for (int i = 0; i < paramNames.size(); i++) {
|
||||
paramStr.append(paramRegisters.get(i)).append(" \"").append(Helper.escapeString(paramNames.get(i))).append("\" ");
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.jpexs.decompiler.flash.action.swf7;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.action.Action;
|
||||
import com.jpexs.decompiler.flash.action.ActionList;
|
||||
import com.jpexs.decompiler.flash.action.model.ActionItem;
|
||||
import com.jpexs.decompiler.flash.action.model.DirectValueActionItem;
|
||||
import com.jpexs.decompiler.flash.action.model.clauses.TryActionItem;
|
||||
@@ -27,7 +28,6 @@ import com.jpexs.decompiler.flash.action.parser.pcode.ASMParsedSymbol;
|
||||
import com.jpexs.decompiler.flash.action.parser.pcode.FlasmLexer;
|
||||
import com.jpexs.decompiler.flash.action.swf4.RegisterNumber;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
|
||||
import com.jpexs.decompiler.graph.GraphSourceItem;
|
||||
import com.jpexs.decompiler.graph.GraphSourceItemContainer;
|
||||
import com.jpexs.decompiler.graph.GraphTargetItem;
|
||||
import com.jpexs.helpers.Helper;
|
||||
@@ -148,7 +148,7 @@ public class ActionTry extends Action implements GraphSourceItemContainer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getASMSource(List<? extends GraphSourceItem> container, List<Long> knownAddreses, List<String> constantPool, ScriptExportMode exportMode) {
|
||||
public String getASMSource(ActionList container, List<Long> knownAddreses, ScriptExportMode exportMode) {
|
||||
String ret = "";
|
||||
ret += "Try ";
|
||||
if (catchBlockFlag) {
|
||||
|
||||
@@ -29,6 +29,7 @@ import com.jpexs.decompiler.flash.configuration.Configuration;
|
||||
import com.jpexs.decompiler.flash.console.CommandLineArgumentParser;
|
||||
import com.jpexs.decompiler.flash.console.ContextMenuTools;
|
||||
import com.jpexs.decompiler.flash.gui.proxy.ProxyFrame;
|
||||
import com.jpexs.decompiler.flash.helpers.EmptySWFDecompilerListener;
|
||||
import com.jpexs.decompiler.flash.helpers.SWFDecompilerPlugin;
|
||||
import com.jpexs.decompiler.flash.tags.base.FontTag;
|
||||
import com.jpexs.decompiler.flash.treeitems.SWFList;
|
||||
@@ -880,7 +881,7 @@ public class Main {
|
||||
public static void main(String[] args) throws IOException {
|
||||
|
||||
String pluginPath = Configuration.pluginPath.get();
|
||||
if (pluginPath != null) {
|
||||
if (pluginPath != null && !pluginPath.isEmpty()) {
|
||||
try {
|
||||
SWFDecompilerPlugin.loadPlugin(pluginPath);
|
||||
} catch (Throwable e) {
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.jpexs.decompiler.flash.DisassemblyListener;
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.action.Action;
|
||||
import com.jpexs.decompiler.flash.action.ActionGraph;
|
||||
import com.jpexs.decompiler.flash.action.ActionList;
|
||||
import com.jpexs.decompiler.flash.action.parser.ParseException;
|
||||
import com.jpexs.decompiler.flash.action.parser.pcode.ASMParser;
|
||||
import com.jpexs.decompiler.flash.action.parser.script.ActionScriptParser;
|
||||
@@ -112,7 +113,7 @@ public class ActionPanel extends JPanel implements ActionListener, SearchListene
|
||||
private boolean ignoreCarret = false;
|
||||
private boolean editMode = false;
|
||||
private boolean editDecompiledMode = false;
|
||||
private List<Action> lastCode;
|
||||
private ActionList lastCode;
|
||||
private ASMSource src;
|
||||
public JPanel topButtonsPan;
|
||||
private HilightedText srcWithHex;
|
||||
@@ -395,7 +396,7 @@ public class ActionPanel extends JPanel implements ActionListener, SearchListene
|
||||
}
|
||||
DisassemblyListener listener = getDisassemblyListener();
|
||||
asm.addDisassemblyListener(listener);
|
||||
List<Action> actions = asm.getActions();
|
||||
ActionList actions = asm.getActions();
|
||||
lastCode = actions;
|
||||
asm.removeDisassemblyListener(listener);
|
||||
srcWithHex = null;
|
||||
|
||||
@@ -28,5 +28,5 @@ public class EmptySWFDecompilerListener implements SWFDecompilerListener {
|
||||
public void actionListParsed(ActionList actions) {
|
||||
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -71,7 +71,6 @@ public class SWFDecompilerPlugin {
|
||||
// Creating an instance of our compiled class and
|
||||
try {
|
||||
listener = (SWFDecompilerListener) fileManager.getClassLoader(null).loadClass(fullName).newInstance();
|
||||
listener = new EmptySWFDecompilerListener();
|
||||
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException ex) {
|
||||
Logger.getLogger(SWFDecompilerPlugin.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
|
||||
@@ -136,13 +136,14 @@ public class DefineButtonTag extends ButtonTag implements ASMSource {
|
||||
/**
|
||||
* Converts actions to ASM source
|
||||
*
|
||||
* @param actions
|
||||
* @param exportMode PCode or hex?
|
||||
* @param writer
|
||||
* @param actions
|
||||
* @return ASM source
|
||||
* @throws java.lang.InterruptedException
|
||||
*/
|
||||
@Override
|
||||
public GraphTextWriter getASMSource(ScriptExportMode exportMode, GraphTextWriter writer, List<Action> actions) throws InterruptedException {
|
||||
public GraphTextWriter getASMSource(ScriptExportMode exportMode, GraphTextWriter writer, ActionList actions) throws InterruptedException {
|
||||
if (actions == null) {
|
||||
actions = getActions();
|
||||
}
|
||||
|
||||
@@ -86,13 +86,14 @@ public class DoActionTag extends Tag implements ASMSource {
|
||||
/**
|
||||
* Converts actions to ASM source
|
||||
*
|
||||
* @param actions
|
||||
* @param exportMode PCode or hex?
|
||||
* @param writer
|
||||
* @param actions
|
||||
* @return ASM source
|
||||
* @throws java.lang.InterruptedException
|
||||
*/
|
||||
@Override
|
||||
public GraphTextWriter getASMSource(ScriptExportMode exportMode, GraphTextWriter writer, List<Action> actions) throws InterruptedException {
|
||||
public GraphTextWriter getASMSource(ScriptExportMode exportMode, GraphTextWriter writer, ActionList actions) throws InterruptedException {
|
||||
if (actions == null) {
|
||||
actions = getActions();
|
||||
}
|
||||
|
||||
@@ -100,13 +100,14 @@ public class DoInitActionTag extends CharacterIdTag implements ASMSource {
|
||||
/**
|
||||
* Converts actions to ASM source
|
||||
*
|
||||
* @param actions
|
||||
* @param exportMode PCode or hex?
|
||||
* @param writer
|
||||
* @param actions
|
||||
* @return ASM source
|
||||
* @throws java.lang.InterruptedException
|
||||
*/
|
||||
@Override
|
||||
public GraphTextWriter getASMSource(ScriptExportMode exportMode, GraphTextWriter writer, List<Action> actions) throws InterruptedException {
|
||||
public GraphTextWriter getASMSource(ScriptExportMode exportMode, GraphTextWriter writer, ActionList actions) throws InterruptedException {
|
||||
if (actions == null) {
|
||||
actions = getActions();
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ public interface ASMSource extends TreeItem {
|
||||
* @return ASM source
|
||||
* @throws java.lang.InterruptedException
|
||||
*/
|
||||
public GraphTextWriter getASMSource(ScriptExportMode exportMode, GraphTextWriter writer, List<Action> actions) throws InterruptedException;
|
||||
public GraphTextWriter getASMSource(ScriptExportMode exportMode, GraphTextWriter writer, ActionList actions) throws InterruptedException;
|
||||
|
||||
/**
|
||||
* Whether or not this object contains ASM source
|
||||
|
||||
@@ -155,13 +155,14 @@ public class BUTTONCONDACTION implements ASMSource, Exportable, ContainerItem, S
|
||||
/**
|
||||
* Converts actions to ASM source
|
||||
*
|
||||
* @param actions
|
||||
* @param exportMode PCode or hex?
|
||||
* @param writer
|
||||
* @param actions
|
||||
* @return ASM source
|
||||
* @throws java.lang.InterruptedException
|
||||
*/
|
||||
@Override
|
||||
public GraphTextWriter getASMSource(ScriptExportMode exportMode, GraphTextWriter writer, List<Action> actions) throws InterruptedException {
|
||||
public GraphTextWriter getASMSource(ScriptExportMode exportMode, GraphTextWriter writer, ActionList actions) throws InterruptedException {
|
||||
if (actions == null) {
|
||||
actions = getActions();
|
||||
}
|
||||
|
||||
@@ -171,13 +171,14 @@ public class CLIPACTIONRECORD implements ASMSource, Exportable, ContainerItem, S
|
||||
/**
|
||||
* Converts actions to ASM source
|
||||
*
|
||||
* @param actions
|
||||
* @param exportMode PCode or hex?
|
||||
* @param writer
|
||||
* @param actions
|
||||
* @return ASM source
|
||||
* @throws java.lang.InterruptedException
|
||||
*/
|
||||
@Override
|
||||
public GraphTextWriter getASMSource(ScriptExportMode exportMode, GraphTextWriter writer, List<Action> actions) throws InterruptedException {
|
||||
public GraphTextWriter getASMSource(ScriptExportMode exportMode, GraphTextWriter writer, ActionList actions) throws InterruptedException {
|
||||
if (actions == null) {
|
||||
actions = getActions();
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@ import com.jpexs.decompiler.flash.action.Action;
|
||||
import com.jpexs.decompiler.flash.action.ActionList;
|
||||
import com.jpexs.decompiler.flash.action.parser.ParseException;
|
||||
import com.jpexs.decompiler.flash.action.parser.pcode.ASMParser;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionJump;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionGetMember;
|
||||
import com.jpexs.decompiler.flash.configuration.Configuration;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
|
||||
import com.jpexs.decompiler.flash.gui.Main;
|
||||
@@ -80,8 +82,29 @@ public class ActionScript2ModificationTest extends ActionStript2TestBase {
|
||||
doa.getASMSource(ScriptExportMode.PCODE, writer, doa.getActions());
|
||||
String actualResult = normalizeLabels(writer.toString());
|
||||
|
||||
actualResult = actualResult.replaceAll("[ \r\n]", "");
|
||||
expectedResult = expectedResult.replaceAll("[ \r\n]", "");
|
||||
actualResult = cleanPCode(actualResult);
|
||||
expectedResult = cleanPCode(expectedResult);
|
||||
|
||||
Assert.assertEquals(actualResult, expectedResult);
|
||||
} catch (IOException | ParseException | InterruptedException ex) {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
|
||||
public void testAddAction(String actionsString, String expectedResult, Action action, int index) {
|
||||
try {
|
||||
ActionList actions = ASMParser.parse(0, true, actionsString, swf.version, false);
|
||||
|
||||
actions.addAction(index, action);
|
||||
|
||||
DoActionTag doa = getFirstActionTag();
|
||||
doa.setActionBytes(Action.actionsToBytes(actions, true, swf.version));
|
||||
HilightedTextWriter writer = new HilightedTextWriter(new CodeFormatting(), false);
|
||||
doa.getASMSource(ScriptExportMode.PCODE, writer, doa.getActions());
|
||||
String actualResult = normalizeLabels(writer.toString());
|
||||
|
||||
actualResult = cleanPCode(actualResult);
|
||||
expectedResult = cleanPCode(expectedResult);
|
||||
|
||||
Assert.assertEquals(actualResult, expectedResult);
|
||||
} catch (IOException | ParseException | InterruptedException ex) {
|
||||
@@ -204,4 +227,107 @@ public class ActionScript2ModificationTest extends ActionStript2TestBase {
|
||||
"label_1:";
|
||||
testRemoveAction(actionsString, expectedResult, new int[] {7});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddAtion1() {
|
||||
String actionsString =
|
||||
"ConstantPool\n" +
|
||||
"DefineFunction \"test\" 1 \"p1\" {\n" +
|
||||
"Push 1\n" +
|
||||
"GetVariable\n" +
|
||||
"}\n" +
|
||||
"Push 2\n" +
|
||||
"If label_1\n" +
|
||||
"Push 3\n" +
|
||||
"label_1:Push 4";
|
||||
String expectedResult =
|
||||
"ConstantPool\n" +
|
||||
"GetMember\n" +
|
||||
"DefineFunction \"test\" 1 \"p1\" {\n" +
|
||||
"Push 1\n" +
|
||||
"GetVariable\n" +
|
||||
"}\n" +
|
||||
"Push 2\n" +
|
||||
"If label_1\n" +
|
||||
"Push 3\n" +
|
||||
"label_1:Push 4";
|
||||
testAddAction(actionsString, expectedResult, new ActionGetMember(), 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddAtionToContainer() {
|
||||
String actionsString =
|
||||
"ConstantPool\n" +
|
||||
"DefineFunction \"test\" 1 \"p1\" {\n" +
|
||||
"Push 1\n" +
|
||||
"GetVariable\n" +
|
||||
"}\n" +
|
||||
"Push 2\n" +
|
||||
"If label_1\n" +
|
||||
"Push 3\n" +
|
||||
"label_1:Push 4";
|
||||
String expectedResult =
|
||||
"ConstantPool\n" +
|
||||
"DefineFunction \"test\" 1 \"p1\" {\n" +
|
||||
"GetMember\n" +
|
||||
"Push 1\n" +
|
||||
"GetVariable\n" +
|
||||
"}\n" +
|
||||
"Push 2\n" +
|
||||
"If label_1\n" +
|
||||
"Push 3\n" +
|
||||
"label_1:Push 4";
|
||||
testAddAction(actionsString, expectedResult, new ActionGetMember(), 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddActionIf() {
|
||||
String actionsString =
|
||||
"ConstantPool\n" +
|
||||
"DefineFunction \"test\" 1 \"p1\" {\n" +
|
||||
"Push 1\n" +
|
||||
"GetVariable\n" +
|
||||
"}\n" +
|
||||
"Push 2\n" +
|
||||
"If label_1\n" +
|
||||
"Push 3\n" +
|
||||
"label_1:Push 4";
|
||||
String expectedResult =
|
||||
"ConstantPool\n" +
|
||||
"DefineFunction \"test\" 1 \"p1\" {\n" +
|
||||
"Push 1\n" +
|
||||
"GetVariable\n" +
|
||||
"}\n" +
|
||||
"Push 2\n" +
|
||||
"If label_1\n" +
|
||||
"Push 3\n" +
|
||||
"GetMember\n" +
|
||||
"label_1:Push 4";
|
||||
testAddAction(actionsString, expectedResult, new ActionGetMember(), 7);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddToJumpTarget() {
|
||||
String actionsString =
|
||||
"ConstantPool\n" +
|
||||
"If label_1\n" +
|
||||
"GetMember\n" +
|
||||
"label_1:Jump label_2\n" + // address 9
|
||||
"label_2:Jump label_3\n" +
|
||||
"label_3:Jump labelend\n" +
|
||||
"labelend:End"; // address 24
|
||||
String expectedResult =
|
||||
"ConstantPool\n" +
|
||||
"If label_1\n" +
|
||||
"GetMember\n" +
|
||||
"Jump label_4\n" +
|
||||
"label_1:Jump label_2\n" +
|
||||
"label_2:Jump label_3\n" +
|
||||
"label_3:Jump label_4\n" +
|
||||
"label_4:";
|
||||
ActionJump jump = new ActionJump(0);
|
||||
jump.setAddress(9);
|
||||
jump.setJumpOffset(24 - 9 - 5);
|
||||
testAddAction(actionsString, expectedResult, jump, 3);
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
30
test/com/jpexs/decompiler/flash/ActionScriptTestBase.java
Normal file
30
test/com/jpexs/decompiler/flash/ActionScriptTestBase.java
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ActionScriptTestBase {
|
||||
|
||||
protected String cleanPCode(String pCode) {
|
||||
pCode = pCode.replaceAll(" *[\r\n]+ *", "\n").trim();
|
||||
pCode = pCode.replaceAll(" +", " ").trim();
|
||||
return pCode;
|
||||
}
|
||||
}
|
||||
@@ -1,39 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
import com.jpexs.decompiler.flash.tags.DoActionTag;
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ActionStript2TestBase {
|
||||
|
||||
protected SWF swf;
|
||||
|
||||
protected DoActionTag getFirstActionTag() {
|
||||
for (Tag t : swf.tags) {
|
||||
if (t instanceof DoActionTag) {
|
||||
return (DoActionTag) t;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2010-2014 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
import com.jpexs.decompiler.flash.tags.DoActionTag;
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ActionStript2TestBase extends ActionScriptTestBase {
|
||||
|
||||
protected SWF swf;
|
||||
|
||||
protected DoActionTag getFirstActionTag() {
|
||||
for (Tag t : swf.tags) {
|
||||
if (t instanceof DoActionTag) {
|
||||
return (DoActionTag) t;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user