mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-08-02 15:51:16 +00:00
more AS2 deobfuscation fixes & cleanup
This commit is contained in:
@@ -403,14 +403,14 @@ public class Action implements GraphSourceItem {
|
||||
* @param version SWF version
|
||||
* @param exportMode PCode or hex?
|
||||
* @return source ASM
|
||||
*
|
||||
*
|
||||
*/
|
||||
public static String actionsToString(List<DisassemblyListener> listeners, long address, ActionList list, int version, ScriptExportMode exportMode) {
|
||||
HilightedTextWriter writer = new HilightedTextWriter(new CodeFormatting(), false);
|
||||
actionsToString(listeners, address, list, version, exportMode, writer);
|
||||
return writer.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Converts list of actions to ASM source
|
||||
*
|
||||
|
||||
@@ -190,7 +190,7 @@ public class ActionList extends ArrayList<Action> {
|
||||
public String toString() {
|
||||
return Action.actionsToString(new ArrayList<DisassemblyListener>(), 0, this, SWF.DEFAULT_VERSION, ScriptExportMode.PCODE);
|
||||
}
|
||||
|
||||
|
||||
public String toSource() {
|
||||
try {
|
||||
return Action.actionsToSource(null, this, "");
|
||||
|
||||
@@ -28,12 +28,12 @@ import com.jpexs.decompiler.flash.action.ActionLocalData;
|
||||
import com.jpexs.decompiler.flash.action.model.DirectValueActionItem;
|
||||
import com.jpexs.decompiler.flash.action.model.ReturnActionItem;
|
||||
import com.jpexs.decompiler.flash.action.special.ActionEnd;
|
||||
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.ActionLess;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionMultiply;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionNot;
|
||||
import com.jpexs.decompiler.flash.action.swf4.ActionPush;
|
||||
@@ -54,14 +54,13 @@ import com.jpexs.decompiler.flash.action.swf5.ActionDefineFunction;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionDefineLocal;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionEquals2;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionIncrement;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionLess2;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionModulo;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionPushDuplicate;
|
||||
import com.jpexs.decompiler.flash.action.swf5.ActionReturn;
|
||||
import com.jpexs.decompiler.flash.action.swf6.ActionGreater;
|
||||
import com.jpexs.decompiler.flash.ecma.EcmaScript;
|
||||
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 com.jpexs.decompiler.graph.TranslateStack;
|
||||
@@ -80,7 +79,7 @@ import java.util.logging.Logger;
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ActionDeobfuscator implements SWFDecompilerListener {
|
||||
public class ActionDeobfuscator extends ActionDeobfuscatorSimple {
|
||||
|
||||
private final int executionLimit = 30000;
|
||||
|
||||
@@ -131,89 +130,6 @@ public class ActionDeobfuscator implements SWFDecompilerListener {
|
||||
return true;
|
||||
}
|
||||
|
||||
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, Map<String, Object> fakeFunctions) {
|
||||
if (actions.size() == 0) {
|
||||
return false;
|
||||
@@ -303,7 +219,7 @@ public class ActionDeobfuscator implements SWFDecompilerListener {
|
||||
}
|
||||
return cPool;
|
||||
}
|
||||
|
||||
|
||||
private void executeActions(ActionList actions, int idx, int endIdx, ActionConstantPool constantPool, ExecutionResult result, Map<String, Object> fakeFunctions) {
|
||||
List<GraphTargetItem> output = new ArrayList<>();
|
||||
ActionLocalData localData = new ActionLocalData();
|
||||
@@ -383,6 +299,8 @@ public class ActionDeobfuscator implements SWFDecompilerListener {
|
||||
|| action instanceof ActionSetVariable
|
||||
|| action instanceof ActionEquals
|
||||
|| action instanceof ActionEquals2
|
||||
|| action instanceof ActionLess
|
||||
|| action instanceof ActionLess2
|
||||
|| action instanceof ActionGreater
|
||||
|| action instanceof ActionNot
|
||||
|| action instanceof ActionIf
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.jpexs.decompiler.flash.action.Action;
|
||||
import com.jpexs.decompiler.flash.action.ActionList;
|
||||
import com.jpexs.decompiler.flash.action.ActionLocalData;
|
||||
import com.jpexs.decompiler.flash.action.model.DirectValueActionItem;
|
||||
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.ActionIf;
|
||||
@@ -44,12 +45,15 @@ import com.jpexs.decompiler.flash.action.swf5.ActionPushDuplicate;
|
||||
import com.jpexs.decompiler.flash.ecma.EcmaScript;
|
||||
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 com.jpexs.decompiler.graph.TranslateStack;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EmptyStackException;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -69,6 +73,9 @@ public class ActionDeobfuscatorSimple implements SWFDecompilerListener {
|
||||
return false;
|
||||
}
|
||||
|
||||
removeUnreachableActions(actions);
|
||||
removeZeroJumps(actions);
|
||||
|
||||
for (int i = 0; i < actions.size(); i++) {
|
||||
ExecutionResult result = new ExecutionResult();
|
||||
executeActions(actions, i, actions.size() - 1, result);
|
||||
@@ -79,7 +86,7 @@ public class ActionDeobfuscatorSimple implements SWFDecompilerListener {
|
||||
newIstructionCount++;
|
||||
}
|
||||
|
||||
if (newIstructionCount * 2 < result.instructionsProcessed) {
|
||||
if (newIstructionCount + 1 < result.instructionsProcessed) {
|
||||
Action target = actions.get(result.idx);
|
||||
Action prevAction = actions.get(i);
|
||||
|
||||
@@ -99,6 +106,18 @@ public class ActionDeobfuscatorSimple implements SWFDecompilerListener {
|
||||
jump.setAddress(prevAction.getAddress());
|
||||
jump.setJumpOffset((int) (target.getAddress() - jump.getAddress() - jump.getTotalActionLength()));
|
||||
actions.addAction(i++, jump);
|
||||
|
||||
Action nextAction = actions.size() > i ? actions.get(i) : null;
|
||||
|
||||
removeUnreachableActions(actions);
|
||||
removeZeroJumps(actions);
|
||||
|
||||
if (nextAction != null) {
|
||||
int nextIdx = actions.indexOf(nextAction);
|
||||
if (nextIdx < i) {
|
||||
i = nextIdx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -106,6 +125,89 @@ public class ActionDeobfuscatorSimple implements SWFDecompilerListener {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected 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;
|
||||
}
|
||||
|
||||
protected 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 void executeActions(ActionList actions, int idx, int endIdx, ExecutionResult result) {
|
||||
List<GraphTargetItem> output = new ArrayList<>();
|
||||
ActionLocalData localData = new ActionLocalData();
|
||||
@@ -146,7 +248,8 @@ public class ActionDeobfuscatorSimple implements SWFDecompilerListener {
|
||||
|| action instanceof ActionBitRShift
|
||||
|| action instanceof ActionEquals
|
||||
|| action instanceof ActionNot
|
||||
|| action instanceof ActionIf)) {
|
||||
|| action instanceof ActionIf
|
||||
|| action instanceof ActionJump)) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -166,6 +269,15 @@ public class ActionDeobfuscatorSimple implements SWFDecompilerListener {
|
||||
|
||||
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) {
|
||||
throw new TranslateException("Jump target not found: " + address);
|
||||
}
|
||||
}
|
||||
|
||||
if (action instanceof ActionIf) {
|
||||
ActionIf aif = (ActionIf) action;
|
||||
if (EcmaScript.toBoolean(stack.pop().getResult())) {
|
||||
|
||||
@@ -181,8 +181,8 @@ public class ActionSourceGenerator implements SourceGenerator {
|
||||
|
||||
private void fixLoop(List<Action> code, int breakOffset, int continueOffset) {
|
||||
int pos = 0;
|
||||
for (Action a : code) {
|
||||
pos += a.getBytes(SWF.DEFAULT_VERSION).length;
|
||||
for (Action a : code) {
|
||||
pos += a.getTotalActionLength();
|
||||
if (a instanceof ActionJump) {
|
||||
ActionJump aj = (ActionJump) a;
|
||||
if (aj.isContinue && (continueOffset != Integer.MAX_VALUE)) {
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.jpexs.decompiler.flash.action.swf4;
|
||||
|
||||
import com.jpexs.decompiler.flash.EndOfStreamException;
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.action.Action;
|
||||
@@ -185,6 +186,7 @@ public class ActionPush extends Action {
|
||||
super(0x96, 0);
|
||||
this.values = new ArrayList<>();
|
||||
this.values.add(value);
|
||||
updateLength(SWF.DEFAULT_VERSION);
|
||||
}
|
||||
|
||||
public ActionPush(FlasmLexer lexer, List<String> constantPool) throws IOException, ActionParseException {
|
||||
|
||||
Reference in New Issue
Block a user