AS2 deobfuscation improved / faster

This commit is contained in:
2015-10-17 09:52:21 +02:00
parent d2eaaa9fab
commit 85788e258c
8 changed files with 204 additions and 151 deletions
@@ -19,7 +19,6 @@ package com.jpexs.decompiler.flash.action;
import com.jpexs.decompiler.flash.DisassemblyListener;
import com.jpexs.decompiler.flash.SWFInputStream;
import com.jpexs.decompiler.flash.action.deobfuscation.ActionDeobfuscator;
import com.jpexs.decompiler.flash.action.deobfuscation.ActionDeobfuscatorSimple;
import com.jpexs.decompiler.flash.action.deobfuscation.ActionDeobfuscatorSimpleFast;
import com.jpexs.decompiler.flash.action.model.ConstantPool;
import com.jpexs.decompiler.flash.action.model.DirectValueActionItem;
@@ -184,9 +183,9 @@ public class ActionListReader {
try (Statistics s = new Statistics("ActionDeobfuscatorSimpleFast")) {
new ActionDeobfuscatorSimpleFast().actionListParsed(actions, sis.getSwf());
}
try (Statistics s = new Statistics("ActionDeobfuscatorSimple")) {
new ActionDeobfuscatorSimple().actionListParsed(actions, sis.getSwf());
}
/*try (Statistics s = new Statistics("ActionDeobfuscatorSimple")) {
new ActionDeobfuscatorSimple().actionListParsed(actions, sis.getSwf());
}*/
try (Statistics s = new Statistics("ActionDeobfuscator")) {
new ActionDeobfuscator().actionListParsed(actions, sis.getSwf());
}
@@ -894,7 +893,8 @@ public class ActionListReader {
}
try {
fixConstantPools(listeners, new ConstantPool(), actionMap, new TreeMap<>(), 0, 0, endIp, null, true, new ArrayList<>());
int startIp = (int) actions.get(0).getAddress();
fixConstantPools(listeners, new ConstantPool(), actionMap, new TreeMap<>(), startIp, startIp, endIp, null, true, new ArrayList<>());
} catch (IOException ex) {
// ignore
}
@@ -71,7 +71,6 @@ 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.GraphTargetItem;
import com.jpexs.decompiler.graph.TranslateException;
import com.jpexs.decompiler.graph.TranslateStack;
import java.util.ArrayList;
import java.util.List;
@@ -88,8 +87,12 @@ public class ActionDeobfuscatorSimpleFast implements SWFDecompilerListener {
public void actionListParsed(ActionList actions, SWF swf) throws InterruptedException {
FastActionList fastActions = new FastActionList(actions);
fastActions.expandPushes();
removeGetTimes(fastActions);
//removeObfuscationIfs(fastActions);
boolean changed = true;
while (changed) {
changed = removeGetTimes(fastActions);
changed |= removeObfuscationIfs(fastActions);
}
actions.setActions(fastActions.toActionList());
}
@@ -98,6 +101,7 @@ public class ActionDeobfuscatorSimpleFast implements SWFDecompilerListener {
return false;
}
boolean ret = false;
boolean changed = true;
int getTimeCount = 1;
while (changed && getTimeCount > 0) {
@@ -126,6 +130,7 @@ public class ActionDeobfuscatorSimpleFast implements SWFDecompilerListener {
iterator.remove(); // If
iterator.add(jumpItem); // replace If with Jump
changed = true;
ret = true;
getTimeCount--;
}
}
@@ -149,12 +154,13 @@ public class ActionDeobfuscatorSimpleFast implements SWFDecompilerListener {
iterator.remove(); // If
iterator.add(jumpItem); // replace If with Jump
changed = true;
ret = true;
}
}
}
}
return false;
return ret;
}
private boolean removeObfuscationIfs(FastActionList actions) throws InterruptedException {
@@ -162,60 +168,52 @@ public class ActionDeobfuscatorSimpleFast implements SWFDecompilerListener {
return false;
}
boolean ret = false;
actions.removeUnreachableActions();
actions.removeZeroJumps();
// FastActionListIterator iterator = actions.iterator();
// while (iterator.hasNext()) {
// ActionItem actionItem = iterator.next();
// ExecutionResult result = new ExecutionResult();
// executeActions(actions, i, actions.size() - 1, result);
//
// if (result.idx != -1) {
// int newIstructionCount = 1 /*jump */ + result.stack.size();
// List<Action> unreachable = actions.getUnreachableActions(i, result.idx);
// int unreachableCount = unreachable.size();
//
// if (newIstructionCount < unreachableCount) {
// Action target = actions.get(result.idx);
// Action prevAction = actions.get(i);
//
// if (result.stack.isEmpty() && prevAction instanceof ActionJump) {
// ActionJump jump = (ActionJump) prevAction;
// jump.setJumpOffset((int) (target.getAddress() - jump.getAddress() - jump.getTotalActionLength()));
// } else {
// if (!result.stack.isEmpty()) {
// ActionPush push = new ActionPush(0);
// push.values.clear();
// for (GraphTargetItem graphTargetItem : result.stack) {
// push.values.add(graphTargetItem.getResult());
// }
// push.setAddress(prevAction.getAddress());
// actions.addAction(i++, push);
// prevAction = push;
// }
//
// ActionJump jump = new ActionJump(0);
// 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;
//
// actions.removeUnreachableActions();
// actions.removeZeroJumps();
//
// if (nextAction != null) {
// int nextIdx = actions.indexOf(nextAction);
// if (nextIdx < i) {
// i = nextIdx;
// }
// }
// }
// }
// }
return false;
FastActionListIterator iterator = actions.iterator();
while (iterator.hasNext()) {
ActionItem actionItem = iterator.next();
ExecutionResult result = new ExecutionResult();
executeActions(actionItem, actions.last(), result);
if (result.item != null) {
int newIstructionCount = 1 /*jump */ + result.stack.size();
int unreachableCount = actions.getUnreachableActionCount(actionItem, result.item);
if (newIstructionCount < unreachableCount) {
if (result.stack.isEmpty() && actionItem.action instanceof ActionJump) {
actionItem.setJumpTarget(result.item);
} else {
ActionItem prevActionItem = actionItem.prev;
if (!result.stack.isEmpty()) {
for (GraphTargetItem graphTargetItem : result.stack) {
ActionPush push = new ActionPush(graphTargetItem.getResult());
ActionItem pushItem = new ActionItem(push);
iterator.addBefore(pushItem);
}
}
ActionJump jump = new ActionJump(0);
ActionItem jumpItem = new ActionItem(jump);
jumpItem.setJumpTarget(result.item);
iterator.addBefore(jumpItem);
actions.replaceJumpTargets(actionItem, prevActionItem.next);
}
ActionItem prevItem = actionItem.prev;
actions.removeUnreachableActions();
actions.removeZeroJumps();
iterator.setCurrent(prevItem.next.next);
ret = true;
}
}
}
return ret;
}
protected boolean isFakeName(String name) {
@@ -228,7 +226,7 @@ public class ActionDeobfuscatorSimpleFast implements SWFDecompilerListener {
return true;
}
private void executeActions(ActionList actions, int idx, int endIdx, ExecutionResult result) throws InterruptedException {
private void executeActions(ActionItem item, ActionItem endItem, ExecutionResult result) throws InterruptedException {
List<GraphTargetItem> output = new ArrayList<>();
ActionLocalData localData = new ActionLocalData();
FixItemCounterTranslateStack stack = new FixItemCounterTranslateStack("");
@@ -239,15 +237,11 @@ public class ActionDeobfuscatorSimpleFast implements SWFDecompilerListener {
throw new InterruptedException();
}
if (idx > endIdx) {
break;
}
if (instructionsProcessed > executionLimit) {
break;
}
Action action = actions.get(idx);
Action action = item.action;
/*System.out.print(action.getASMSource(actions, new ArrayList<Long>(), ScriptExportMode.PCODE));
for (int j = 0; j < stack.size(); j++) {
@@ -320,36 +314,26 @@ public class ActionDeobfuscatorSimpleFast implements SWFDecompilerListener {
}
}
idx++;
if (action instanceof ActionJump) {
ActionJump jump = (ActionJump) action;
long address = jump.getTargetAddress();
idx = actions.getIndexByAddress(address);
if (idx == -1) {
throw new TranslateException("Jump target not found: " + address);
}
}
if (action instanceof ActionIf) {
ActionIf aif = (ActionIf) action;
item = item.getJumpTarget();
} else if (action instanceof ActionIf) {
if (stack.isEmpty()) {
return;
}
if (EcmaScript.toBoolean(stack.pop().getResult())) {
long address = aif.getTargetAddress();
idx = actions.getIndexByAddress(address);
if (idx == -1) {
throw new TranslateException("If target not found: " + address);
}
item = item.getJumpTarget();
} else {
item = item.next;
}
} else {
item = item.next;
}
instructionsProcessed++;
if (stack.allItemsFixed() && !(action instanceof ActionPush)) {
result.idx = idx == actions.size() ? idx - 1 : idx;
result.item = item;
result.instructionsProcessed = instructionsProcessed;
result.stack.clear();
result.stack.addAll(stack);
@@ -376,7 +360,7 @@ public class ActionDeobfuscatorSimpleFast implements SWFDecompilerListener {
class ExecutionResult {
public int idx = -1;
public ActionItem item = null;
public int instructionsProcessed = -1;
@@ -39,7 +39,7 @@ public class FastActionList implements Collection<ActionItem> {
private int size;
private ActionItem firstAction;
private ActionItem firstItem;
private final Map<Action, ActionItem> actionItemMap;
@@ -62,15 +62,24 @@ public class FastActionList implements Collection<ActionItem> {
return insertItemAfter(item, newItem);
}
final ActionItem insertItemBefore(ActionItem item, ActionItem newItem) {
insertItemAfter(item.prev, newItem);
if (item == firstItem) {
firstItem = newItem;
}
return newItem;
}
final ActionItem insertItemAfter(ActionItem item, ActionItem newItem) {
if (item == null && firstAction == null) {
firstAction = newItem;
if (item == null && firstItem == null) {
firstItem = newItem;
newItem.next = newItem;
newItem.prev = newItem;
} else {
if (item == null) {
// insert to the end
item = firstAction.prev;
item = firstItem.prev;
}
ActionItem oldNext = item.next;
@@ -88,13 +97,13 @@ public class FastActionList implements Collection<ActionItem> {
ActionItem removeItem(ActionItem item) {
ActionItem next = null;
if (item == firstAction) {
if (item == firstItem) {
if (item.next == item) {
// there is only 1 item
firstAction = null;
firstItem = null;
} else {
next = item.next;
firstAction = next;
firstItem = next;
next.prev = item.prev;
item.prev.next = next;
}
@@ -126,23 +135,16 @@ public class FastActionList implements Collection<ActionItem> {
return next;
}
private void replaceJumpTargets(ActionItem target, ActionItem newTarget) {
ActionItem item = firstAction;
if (item == null) {
return;
}
do {
if (item.getJumpTarget() == target) {
public void replaceJumpTargets(ActionItem target, ActionItem newTarget) {
if (target.jumpsHere != null) {
for (ActionItem item : new ArrayList<>(target.jumpsHere)) {
item.setJumpTarget(newTarget);
}
item = item.next;
} while (item != firstAction);
}
}
private void getContainerLastActions(ActionList actions, Map<Action, ActionItem> actionItemMap) {
ActionItem item = firstAction;
ActionItem item = firstItem;
if (item == null) {
return;
}
@@ -154,7 +156,7 @@ public class FastActionList implements Collection<ActionItem> {
}
item = item.next;
} while (item != firstAction);
} while (item != firstItem);
}
private List<ActionItem> getContainerLastActions(ActionList actions, Action action, Map<Action, ActionItem> actionItemMap) {
@@ -201,7 +203,7 @@ public class FastActionList implements Collection<ActionItem> {
}
private void getJumps(ActionList actions, Map<Action, ActionItem> actionItemMap) {
ActionItem item = firstAction;
ActionItem item = firstItem;
if (item == null) {
return;
}
@@ -234,11 +236,11 @@ public class FastActionList implements Collection<ActionItem> {
}
item = item.next;
} while (item != firstAction);
} while (item != firstItem);
}
private void updateActionAddressesAndLengths() {
ActionItem item = firstAction;
ActionItem item = firstItem;
if (item == null) {
return;
}
@@ -250,11 +252,11 @@ public class FastActionList implements Collection<ActionItem> {
action.updateLength();
address += action.getTotalActionLength();
item = item.next;
} while (item != firstAction);
} while (item != firstItem);
}
private void updateJumps() {
ActionItem item = firstAction;
ActionItem item = firstItem;
if (item == null) {
return;
}
@@ -285,11 +287,11 @@ public class FastActionList implements Collection<ActionItem> {
}
item = item.next;
} while (item != firstAction);
} while (item != firstItem);
}
private void updateActionStores() {
ActionItem item = firstAction;
ActionItem item = firstItem;
if (item == null) {
return;
}
@@ -303,7 +305,7 @@ public class FastActionList implements Collection<ActionItem> {
List<Action> store = new ArrayList<>();
while (true) {
item1 = item1.next;
if (item1 == firstAction || item1.action == nextActionAfterStore) {
if (item1 == firstItem || item1.action == nextActionAfterStore) {
break;
}
@@ -314,11 +316,11 @@ public class FastActionList implements Collection<ActionItem> {
}
item = item.next;
} while (item != firstAction);
} while (item != firstItem);
}
private void updateContainerSizes() {
ActionItem item = firstAction;
ActionItem item = firstItem;
if (item == null) {
return;
}
@@ -338,11 +340,11 @@ public class FastActionList implements Collection<ActionItem> {
}
item = item.next;
} while (item != firstAction);
} while (item != firstItem);
}
public void expandPushes() {
ActionItem item = firstAction;
ActionItem item = firstItem;
if (item == null) {
return;
}
@@ -367,11 +369,11 @@ public class FastActionList implements Collection<ActionItem> {
}
item = item.next;
} while (item != firstAction);
} while (item != firstItem);
}
public void removeZeroJumps() {
ActionItem item = firstAction;
ActionItem item = firstItem;
if (item == null) {
return;
}
@@ -379,18 +381,18 @@ public class FastActionList implements Collection<ActionItem> {
do {
Action action = item.action;
if (action instanceof ActionJump) {
if (item.getJumpTarget() == item.next && item.getJumpTarget() != firstAction) {
if (item.getJumpTarget() == item.next && item.getJumpTarget() != firstItem) {
item = removeItem(item);
continue;
}
}
item = item.next;
} while (item != firstAction);
} while (item != firstItem);
}
public void removeUnreachableActions() {
ActionItem item = firstAction;
ActionItem item = firstItem;
if (item == null) {
return;
}
@@ -404,11 +406,32 @@ public class FastActionList implements Collection<ActionItem> {
}
item = item.next;
} while (item != firstAction);
} while (item != firstItem);
}
public int getUnreachableActionCount(ActionItem jump, ActionItem jumpTarget) {
ActionItem item = firstItem;
if (item == null) {
return 0;
}
updateReachableFlags(jump, jumpTarget);
jump.reachable = 0;
int count = 0;
do {
if (item.reachable == 0) {
count++;
}
item = item.next;
} while (item != firstItem);
return count;
}
private void clearReachableFlags() {
ActionItem item = firstAction;
ActionItem item = firstItem;
if (item == null) {
return;
}
@@ -416,21 +439,20 @@ public class FastActionList implements Collection<ActionItem> {
do {
item.reachable = 0;
item = item.next;
} while (item != firstAction);
} while (item != firstItem);
}
private void updateReachableFlags(ActionItem jump, ActionItem jumpTarget) {
if (firstAction == null) {
if (firstItem == null) {
return;
}
clearReachableFlags();
firstAction.reachable = 1;
firstItem.reachable = 1;
boolean modified = true;
while (modified) {
modified = false;
int i = 0;
FastActionListIterator iterator = iterator();
while (iterator.hasNext()) {
ActionItem item = iterator.next();
@@ -474,7 +496,7 @@ public class FastActionList implements Collection<ActionItem> {
public ActionList updateActions() {
List<Action> resultList = new ArrayList<>(size);
ActionItem item = firstAction;
ActionItem item = firstItem;
if (item == null) {
return new ActionList(resultList);
}
@@ -482,7 +504,7 @@ public class FastActionList implements Collection<ActionItem> {
do {
resultList.add(item.action);
item = item.next;
} while (item != firstAction);
} while (item != firstItem);
ActionList result = new ActionList(resultList);
updateActionAddressesAndLengths();
@@ -492,6 +514,14 @@ public class FastActionList implements Collection<ActionItem> {
return result;
}
public ActionItem first() {
return firstItem;
}
public ActionItem last() {
return firstItem == null ? null : firstItem.prev;
}
public ActionList toActionList() {
return updateActions();
}
@@ -519,14 +549,14 @@ public class FastActionList implements Collection<ActionItem> {
@Override
public FastActionListIterator iterator() {
return new FastActionListIterator(firstAction, this);
return new FastActionListIterator(this);
}
@Override
public Object[] toArray() {
Object[] result = new Object[size];
ActionItem item = firstAction;
ActionItem item = firstItem;
if (item == null) {
return result;
}
@@ -536,7 +566,7 @@ public class FastActionList implements Collection<ActionItem> {
result[i] = item.action;
item = item.next;
i++;
} while (item != firstAction);
} while (item != firstItem);
return null;
}
@@ -547,7 +577,7 @@ public class FastActionList implements Collection<ActionItem> {
a = (T[]) new ActionItem[size];
}
ActionItem item = firstAction;
ActionItem item = firstItem;
if (item == null) {
return a;
}
@@ -557,7 +587,7 @@ public class FastActionList implements Collection<ActionItem> {
a[i] = (T) item;
item = item.next;
i++;
} while (item != firstAction);
} while (item != firstItem);
return null;
}
@@ -616,7 +646,7 @@ public class FastActionList implements Collection<ActionItem> {
@Override
public boolean retainAll(Collection<?> c) {
ActionItem item = firstAction;
ActionItem item = firstItem;
if (item == null) {
return false;
}
@@ -630,13 +660,13 @@ public class FastActionList implements Collection<ActionItem> {
}
item = item.next;
} while (item != firstAction);
} while (item != firstItem);
return modified;
}
@Override
public void clear() {
firstAction = null;
firstItem = null;
size = 0;
}
}
@@ -29,40 +29,64 @@ public class FastActionListIterator implements Iterator<ActionItem> {
private final FastActionList list;
private int index;
private boolean started = false;
FastActionListIterator(ActionItem firstAction, FastActionList list) {
item = firstAction;
FastActionListIterator(FastActionList list) {
item = list.first();
this.list = list;
}
@Override
public boolean hasNext() {
return index < list.size();
return item != null && (!started || item != list.first());
}
@Override
public ActionItem next() {
ActionItem result = item;
index++;
item = item.next;
started = true;
/*if (!list.contains(result)) {
throw new Error();
}*/
return result;
}
public ActionItem prev() {
item = item.prev;
if (item == list.first()) {
started = false;
}
/*if (!list.contains(item)) {
throw new Error();
}*/
return item;
}
public void setCurrent(ActionItem item) {
this.item = item;
if (item == list.first()) {
started = false;
}
}
@Override
public void remove() {
item = list.removeItem(item.prev);
index--;
}
public void add(Action action) {
item = list.insertItemAfter(item.prev, action).next;
index++;
}
public void add(ActionItem actionItem) {
item = list.insertItemAfter(item.prev, actionItem).next;
index++;
}
public void addBefore(ActionItem actionItem) {
list.insertItemBefore(item.prev, actionItem);
}
public ActionItem peek(int index) {
@@ -27,6 +27,7 @@ import com.jpexs.decompiler.flash.action.swf4.RegisterNumber;
import com.jpexs.decompiler.flash.action.swf5.ActionDecrement;
import com.jpexs.decompiler.flash.action.swf5.ActionSetMember;
import com.jpexs.decompiler.flash.action.swf5.ActionStoreRegister;
import com.jpexs.decompiler.flash.ecma.EcmaScript;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
import com.jpexs.decompiler.graph.CompilationException;
import com.jpexs.decompiler.graph.GraphSourceItem;
@@ -60,6 +61,11 @@ public class PostDecrementActionItem extends ActionItem implements SetTypeAction
return writer.append("--");
}
@Override
public Object getResult() {
return EcmaScript.toNumber(object.getResult());
}
@Override
public boolean hasSideEffect() {
return true;
@@ -27,6 +27,7 @@ import com.jpexs.decompiler.flash.action.swf4.RegisterNumber;
import com.jpexs.decompiler.flash.action.swf5.ActionIncrement;
import com.jpexs.decompiler.flash.action.swf5.ActionSetMember;
import com.jpexs.decompiler.flash.action.swf5.ActionStoreRegister;
import com.jpexs.decompiler.flash.ecma.EcmaScript;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
import com.jpexs.decompiler.graph.CompilationException;
import com.jpexs.decompiler.graph.GraphSourceItem;
@@ -60,6 +61,11 @@ public class PostIncrementActionItem extends ActionItem implements SetTypeAction
return writer.append("++");
}
@Override
public Object getResult() {
return EcmaScript.toNumber(object.getResult());
}
@Override
public boolean hasSideEffect() {
return true;