action deobfuscator improved again

This commit is contained in:
honfika@gmail.com
2015-09-25 13:22:51 +02:00
parent d5029139bb
commit d1ab311982
5 changed files with 126 additions and 100 deletions

View File

@@ -323,6 +323,10 @@ public class ActionList extends ArrayList<Action> {
return idx == -1 ? null : get(idx);
}
public int getIndexByAction(Action action) {
return getIndexByAddress(action.getAddress());
}
public int getIndexByAddress(long address) {
int min = 0;
int max = size() - 1;
@@ -361,6 +365,108 @@ public class ActionList extends ArrayList<Action> {
return -1;
}
public List<Action> getUnreachableActions() {
int[] isReachable = getUnreachableActionsMap(-1, 0);
List<Action> unreachableActions = new ArrayList<>();
for (int i = 0; i < size(); i++) {
if (isReachable[i] == 0) {
unreachableActions.add(get(i));
}
}
if (unreachableActions.isEmpty()) {
unreachableActions = null;
}
return unreachableActions;
}
public List<Action> getUnreachableActions(int jumpIndex, int jumpTargetIndex) {
int[] isReachable = getUnreachableActionsMap(jumpIndex, jumpTargetIndex);
List<Action> unreachableActions = new ArrayList<>();
for (int i = 0; i < size(); i++) {
if (isReachable[i] == 0) {
unreachableActions.add(get(i));
}
}
if (unreachableActions.isEmpty()) {
unreachableActions = null;
}
return unreachableActions;
}
private int[] getUnreachableActionsMap(int jumpIndex, int jumpTargetIndex) {
int size = size();
// one item for each action. 1 means reachable, 2 means reachable and processed
int[] isReachable = new int[size];
isReachable[0] = 1;
boolean modified = true;
while (modified) {
modified = false;
for (int i = 0; i < size; i++) {
Action action = get(i);
if (isReachable[i] == 1) {
isReachable[i] = 2;
modified = true;
if (i == jumpIndex) {
if (isReachable[jumpTargetIndex] == 0) {
isReachable[jumpTargetIndex] = 1;
}
continue;
}
if (!action.isExit() && !(action instanceof ActionJump) && i != size - 1) {
if (isReachable[i + 1] == 0) {
isReachable[i + 1] = 1;
}
}
if (action instanceof ActionJump) {
ActionJump aJump = (ActionJump) action;
long ref = aJump.getAddress() + aJump.getTotalActionLength() + aJump.getJumpOffset();
int targetIndex = getIndexByAddress(ref);
if (targetIndex != -1 && isReachable[targetIndex] == 0) {
isReachable[targetIndex] = 1;
}
} else if (action instanceof ActionIf) {
ActionIf aIf = (ActionIf) action;
long ref = aIf.getAddress() + aIf.getTotalActionLength() + aIf.getJumpOffset();
int targetIndex = getIndexByAddress(ref);
if (targetIndex != -1 && isReachable[targetIndex] == 0) {
isReachable[targetIndex] = 1;
}
} else if (action instanceof ActionStore) {
ActionStore aStore = (ActionStore) action;
int storeSize = aStore.getStoreSize();
if (size > i + storeSize) {
int targetIndex = i + storeSize;
if (isReachable[targetIndex] == 0) {
isReachable[targetIndex] = 1;
}
}
} else if (action instanceof GraphSourceItemContainer) {
GraphSourceItemContainer container = (GraphSourceItemContainer) action;
long ref = action.getAddress() + action.getTotalActionLength();
for (Long containerSize : container.getContainerSizes()) {
ref += containerSize;
int targetIndex = getIndexByAddress(ref);
if (targetIndex != -1 && isReachable[targetIndex] == 0) {
isReachable[targetIndex] = 1;
}
}
}
}
}
}
return isReachable;
}
public void saveToFile(String fileName) {
File file = new File(fileName);
try (FileTextWriter writer = new FileTextWriter(Configuration.getCodeFormatting(), new FileOutputStream(file))) {

View File

@@ -620,7 +620,7 @@ public class ActionListReader {
getJumps(actions, jumps);
for (Action actionToRemove : actionsToRemove) {
int index = actions.indexOf(actionToRemove);
int index = actions.getIndexByAction(actionToRemove);
Action prevAction = index > 0 ? actions.get(index - 1) : null;
Action nextAction = index + 1 < actions.size() ? actions.get(index + 1) : null;
for (Action a : containerLastActions.keySet()) {

View File

@@ -170,6 +170,7 @@ public class ActionDeobfuscator extends ActionDeobfuscatorSimple {
if (!result.stack.isEmpty()) {
newIstructionCount++;
}
newIstructionCount += 2 * result.variables.size();
boolean allValueValid = true;
@@ -180,7 +181,9 @@ public class ActionDeobfuscator extends ActionDeobfuscatorSimple {
}
}
if (allValueValid && newIstructionCount * 2 < result.instructionsProcessed) {
int unreachableCount = actions.getUnreachableActions(i, result.idx).size();
if (allValueValid && newIstructionCount + 2 < unreachableCount) {
Action target = actions.get(result.idx);
Action prevAction = actions.get(i);
@@ -415,7 +418,7 @@ public class ActionDeobfuscator extends ActionDeobfuscatorSimple {
if (action instanceof ActionJump) {
ActionJump jump = (ActionJump) action;
long address = jump.getAddress() + jump.getTotalActionLength() + jump.getJumpOffset();
idx = actions.indexOf(actions.getByAddress(address));
idx = actions.getIndexByAddress(address);
if (idx == -1) {
throw new TranslateException("Jump target not found: " + address);
}
@@ -429,7 +432,7 @@ public class ActionDeobfuscator extends ActionDeobfuscatorSimple {
if (EcmaScript.toBoolean(stack.pop().getResult())) {
long address = aif.getAddress() + aif.getTotalActionLength() + aif.getJumpOffset();
idx = actions.indexOf(actions.getByAddress(address));
idx = actions.getIndexByAddress(address);
if (idx == -1) {
throw new TranslateException("If target not found: " + address);
}
@@ -438,7 +441,7 @@ public class ActionDeobfuscator extends ActionDeobfuscatorSimple {
if (action instanceof ActionDefineFunction) {
List<Action> lastActions = actions.getContainerLastActions(action);
int lastActionIdx = actions.indexOf(lastActions.get(0));
int lastActionIdx = actions.getIndexByAction(lastActions.get(0));
idx = lastActionIdx != -1 ? lastActionIdx + 1 : -1;
}
@@ -495,7 +498,7 @@ public class ActionDeobfuscator extends ActionDeobfuscatorSimple {
ExecutionResult result = new ExecutionResult();
List<Action> lastActions = actions.getContainerLastActions(action);
int lastActionIdx = actions.indexOf(lastActions.get(0));
int lastActionIdx = actions.getIndexByAction(lastActions.get(0));
executeActions(actions, i + 1, lastActionIdx, null, result, null);
if (result.resultValue != null) {
results.put(def.functionName, result.resultValue);

View File

@@ -22,7 +22,6 @@ import com.jpexs.decompiler.flash.abc.types.MethodBody;
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.special.ActionStore;
import com.jpexs.decompiler.flash.action.swf4.ActionAdd;
import com.jpexs.decompiler.flash.action.swf4.ActionAnd;
import com.jpexs.decompiler.flash.action.swf4.ActionAsciiToChar;
@@ -68,14 +67,11 @@ import com.jpexs.decompiler.flash.action.swf6.ActionStringGreater;
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.HashSet;
import java.util.List;
import java.util.Set;
/**
*
@@ -157,12 +153,10 @@ public class ActionDeobfuscatorSimple implements SWFDecompilerListener {
executeActions(actions, i, actions.size() - 1, result);
if (result.idx != -1) {
int newIstructionCount = 1; // jump
if (!result.stack.isEmpty()) {
newIstructionCount += result.stack.size();
}
int newIstructionCount = 1 /*jump */ + result.stack.size();
int unreachableCount = actions.getUnreachableActions(i, result.idx).size();
if (newIstructionCount < result.instructionsProcessed) {
if (newIstructionCount < unreachableCount) {
Action target = actions.get(result.idx);
Action prevAction = actions.get(i);
@@ -206,90 +200,12 @@ public class ActionDeobfuscatorSimple implements SWFDecompilerListener {
}
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;
}
}
List<Action> unreachableActions = actions.getUnreachableActions();
if (unreachableActions != null) {
actions.removeActions(unreachableActions);
}
/*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;*/
List<Action> actionsToRemove = null;
for (int i = 0; i < actions.size(); i++) {
Action action = actions.get(i);
if (!reachableActions.contains(action)) {
if (actionsToRemove == null) {
actionsToRemove = new ArrayList<>();
}
actionsToRemove.add(action);
}
}
if (actionsToRemove != null) {
actions.removeActions(actionsToRemove);
}
return actionsToRemove != null;
return unreachableActions != null;
}
protected boolean removeZeroJumpsOld(ActionList actions) {
@@ -422,7 +338,7 @@ public class ActionDeobfuscatorSimple implements SWFDecompilerListener {
if (action instanceof ActionJump) {
ActionJump jump = (ActionJump) action;
long address = jump.getAddress() + jump.getTotalActionLength() + jump.getJumpOffset();
idx = actions.indexOf(actions.getByAddress(address));
idx = actions.getIndexByAddress(address);
if (idx == -1) {
throw new TranslateException("Jump target not found: " + address);
}
@@ -436,7 +352,7 @@ public class ActionDeobfuscatorSimple implements SWFDecompilerListener {
if (EcmaScript.toBoolean(stack.pop().getResult())) {
long address = aif.getAddress() + aif.getTotalActionLength() + aif.getJumpOffset();
idx = actions.indexOf(actions.getByAddress(address));
idx = actions.getIndexByAddress(address);
if (idx == -1) {
throw new TranslateException("If target not found: " + address);
}

View File

@@ -165,7 +165,8 @@ public class DirectValueActionItem extends ActionItem implements SimpleValue {
if (value instanceof RegisterNumber) {
return writer.append(((RegisterNumber) value).translate());
}
return writer.append(EcmaScript.toString(value, true));
return writer.append(value.toString());
//return writer.append(EcmaScript.toString(value, true)); // todo, use this line
}
@Override