more AS2 deobfuscation fixes & cleanup

This commit is contained in:
honfika@gmail.com
2014-09-21 00:07:04 +02:00
parent 60f7e5e36f
commit 824f40c803
40 changed files with 279 additions and 261 deletions

View File

@@ -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
*

View File

@@ -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, "");

View File

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

View File

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

View File

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

View File

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