diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/deobfuscation/ActionDeobfuscatorSimpleFast.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/deobfuscation/ActionDeobfuscatorSimpleFast.java index 699277d1c..e32bbb4b0 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/deobfuscation/ActionDeobfuscatorSimpleFast.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/deobfuscation/ActionDeobfuscatorSimpleFast.java @@ -57,6 +57,7 @@ import com.jpexs.decompiler.flash.action.swf5.ActionBitRShift; import com.jpexs.decompiler.flash.action.swf5.ActionBitURShift; import com.jpexs.decompiler.flash.action.swf5.ActionBitXor; import com.jpexs.decompiler.flash.action.swf5.ActionDecrement; +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; @@ -73,7 +74,9 @@ import com.jpexs.decompiler.graph.Graph; import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.TranslateStack; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * @@ -91,6 +94,7 @@ public class ActionDeobfuscatorSimpleFast implements SWFDecompilerListener { while (changed) { changed = removeGetTimes(fastActions); changed |= removeObfuscationIfs(fastActions); + changed |= removeObfuscatedUnusedVariables(fastActions); } actions.setActions(fastActions.toActionList()); @@ -216,6 +220,59 @@ public class ActionDeobfuscatorSimpleFast implements SWFDecompilerListener { return ret; } + private boolean removeObfuscatedUnusedVariables(FastActionList actions) throws InterruptedException { + if (actions.isEmpty()) { + return false; + } + + Map pushValues = getPushValues(actions); + + boolean ret = false; + + // Push, Push DefineLocal => remove when first pushed value is obfuscated and never used + FastActionListIterator iterator = actions.iterator(); + while (iterator.hasNext()) { + Action a = iterator.next().action; + Action a1 = iterator.peek(0).action; + Action a2 = iterator.peek(1).action; + if (a instanceof ActionPush && a1 instanceof ActionPush && a2 instanceof ActionDefineLocal) { + ActionPush pushName = (ActionPush) a; + ActionPush pushValue = (ActionPush) a1; + if (pushName.values.size() == 1 && pushValue.values.size() == 1) { + String strName = EcmaScript.toString(pushName.values.get(0), pushName.constantPool); + if (isFakeName(strName) && pushValues.get(strName) == 1) { + iterator.remove(); // Push name + iterator.next(); + iterator.remove(); // Push value + iterator.next(); + iterator.remove(); // DefineLocal + ret = true; + } + } + } + } + + return ret; + } + + private Map getPushValues(FastActionList actions) { + Map ret = new HashMap<>(); + for (ActionItem actionItem : actions) { + Action action = actionItem.action; + if (action instanceof ActionPush) { + ActionPush push = (ActionPush) action; + for (int i = 0; i < push.values.size(); i++) { + String str = EcmaScript.toString(push.values.get(i), push.constantPool); + Integer cnt = ret.get(str); + cnt = cnt == null ? 1 : cnt + 1; + ret.put(str, cnt); + } + } + } + + return ret; + } + protected boolean isFakeName(String name) { for (char ch : name.toCharArray()) { if (ch > 31) {