From d1ab3119825425f9d8754e4f6fe0d403005a993a Mon Sep 17 00:00:00 2001 From: "honfika@gmail.com" Date: Fri, 25 Sep 2015 13:22:51 +0200 Subject: [PATCH] action deobfuscator improved again --- .../decompiler/flash/action/ActionList.java | 106 ++++++++++++++++++ .../flash/action/ActionListReader.java | 2 +- .../deobfuscation/ActionDeobfuscator.java | 13 ++- .../ActionDeobfuscatorSimple.java | 102 ++--------------- .../action/model/DirectValueActionItem.java | 3 +- 5 files changed, 126 insertions(+), 100 deletions(-) diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionList.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionList.java index 5150cf150..dc489db9c 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionList.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionList.java @@ -323,6 +323,10 @@ public class ActionList extends ArrayList { 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 { return -1; } + public List getUnreachableActions() { + int[] isReachable = getUnreachableActionsMap(-1, 0); + List 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 getUnreachableActions(int jumpIndex, int jumpTargetIndex) { + int[] isReachable = getUnreachableActionsMap(jumpIndex, jumpTargetIndex); + List 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))) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionListReader.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionListReader.java index de1b3fea9..87faa133b 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionListReader.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionListReader.java @@ -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()) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/deobfuscation/ActionDeobfuscator.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/deobfuscation/ActionDeobfuscator.java index b77790401..a1d58a164 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/deobfuscation/ActionDeobfuscator.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/deobfuscation/ActionDeobfuscator.java @@ -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 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 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); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/deobfuscation/ActionDeobfuscatorSimple.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/deobfuscation/ActionDeobfuscatorSimple.java index e0eb0f268..abeaa9b73 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/deobfuscation/ActionDeobfuscatorSimple.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/deobfuscation/ActionDeobfuscatorSimple.java @@ -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 reachableActions = new HashSet<>(); - Set 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 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 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); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/DirectValueActionItem.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/DirectValueActionItem.java index 95a0a518a..819f64c2b 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/DirectValueActionItem.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/model/DirectValueActionItem.java @@ -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