From 7e081b1ba5e547ad99a332ef8416e05e39dcc67b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=F8=EDk?= Date: Sat, 13 Apr 2013 09:46:16 +0200 Subject: [PATCH] Issue #72 ternar operator fix AS3: chained assignments deobfuscation fix --- .../decompiler/flash/abc/avm2/AVM2Code.java | 59 ++++++++++++++++++- .../flash/abc/avm2/graph/AVM2Graph.java | 6 ++ .../flash/abc/avm2/graph/AVM2GraphSource.java | 6 ++ .../abc/avm2/instructions/jumps/JumpIns.java | 2 +- .../avm2/treemodel/PostDecrementTreeItem.java | 5 ++ .../avm2/treemodel/PostIncrementTreeItem.java | 5 ++ .../avm2/treemodel/SetGlobalSlotTreeItem.java | 5 ++ .../abc/avm2/treemodel/SetLocalTreeItem.java | 7 +++ .../avm2/treemodel/SetPropertyTreeItem.java | 5 ++ .../abc/avm2/treemodel/SetSlotTreeItem.java | 5 ++ .../abc/avm2/treemodel/SetSuperTreeItem.java | 5 ++ .../operations/PreDecrementTreeItem.java | 5 ++ .../operations/PreIncrementTreeItem.java | 5 ++ .../jpexs/decompiler/flash/action/Action.java | 3 + .../decompiler/flash/graph/BinaryOpItem.java | 5 ++ .../flash/graph/GraphTargetItem.java | 5 ++ .../decompiler/flash/graph/UnaryOpItem.java | 5 ++ .../decompiler/flash/ActionScript3Test.java | 2 +- 18 files changed, 136 insertions(+), 4 deletions(-) diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java index 577608b4e..7cb031653 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java @@ -2414,7 +2414,7 @@ public class AVM2Code implements Serializable { private static int removeTraps(boolean secondPass, boolean useVisited, List localData, Stack stack, List output, AVM2GraphSource code, int ip, int lastIp, List visited, HashMap decisions) { boolean debugMode = false; int ret = 0; - while ((ip > -1) && ip < code.size()) { + iploop:while ((ip > -1) && ip < code.size()) { if (useVisited && visited.contains(ip)) { break; } @@ -2430,6 +2430,60 @@ public class AVM2Code implements Serializable { if (debugMode) { System.out.println((useVisited ? "useV " : "") + "Visit " + ip + ": " + ins + " stack:" + Highlighting.stripHilights(stack.toString())); } + AVM2Instruction ains=(AVM2Instruction)ins; + if (ains.definition instanceof DupIns) { + do { + AVM2Instruction insAfter = (AVM2Instruction)code.get(ip + 1); + if (insAfter.definition instanceof ConvertBIns) { //SWF compiled with debug contain convert_b + ip++; + insAfter = (AVM2Instruction)code.get(ip + 1); + } + + if (insAfter.definition instanceof SetLocalTypeIns) { + //chained assignments + int reg = (((SetLocalTypeIns) insAfter.definition).getRegisterId(insAfter)); + for (int t = ip + 1; t < code.size(); t++) { + if (((AVM2Instruction)code.get(t)).definition instanceof KillIns) { + if (((AVM2Instruction)code.get(t)).operands[0] == reg) { + break; + } + } + if (((AVM2Instruction)code.get(t)).definition instanceof GetLocalTypeIns) { + if (((GetLocalTypeIns) ((AVM2Instruction)code.get(t)).definition).getRegisterId((AVM2Instruction)code.get(t)) == reg) { + if (((AVM2Instruction)code.get(t + 1)).definition instanceof KillIns) { + if (((AVM2Instruction)code.get(t + 1)).operands[0] == reg) { + code.getCode().initToSource(); + ConvertOutput assignment = code.getCode().toSourceOutput(false, (Boolean)localData.get(0), (Integer)localData.get(1), (HashMap)localData.get(2), stack, (Stack)localData.get(3), (ABC)localData.get(7), (ConstantPool)localData.get(4), (MethodInfo[])localData.get(5), (MethodBody)localData.get(6), ip + 2, t - 1, (HashMap)localData.get(8), (List)localData.get(9), null); + stack.push(assignment.output.remove(assignment.output.size() - 1)); + ip = t + 2; + continue iploop; + } + } + } + } + } + if (!code.getCode().isKilled(reg, 0, code.size()-1)) { + for (int i = ip; i >= 0; i--) { + if (((AVM2Instruction)code.get(i)).definition instanceof DupIns) { + GraphTargetItem v = stack.pop(); + stack.push(new LocalRegTreeItem((AVM2Instruction)ins, reg, v)); + stack.push(v); + } else { + break; + } + } + } else { + break; + } + ip++; + continue iploop; + //} + + } else { + break; + } + } while (((AVM2Instruction)ins).definition instanceof DupIns); + } if ((ins instanceof AVM2Instruction) && (((AVM2Instruction) ins).definition instanceof NewFunctionIns)) { stack.push(new BooleanTreeItem(null, true)); } else { @@ -2439,10 +2493,11 @@ public class AVM2Code implements Serializable { break; } + if (ins.isBranch() || ins.isJump()) { List branches = ins.getBranches(code); if ((ins instanceof AVM2Instruction) && ((AVM2Instruction) ins).definition instanceof IfTypeIns - && (!(((AVM2Instruction) ins).definition instanceof JumpIns)) && (!stack.isEmpty()) && (stack.peek().isCompileTime())) { + && (!(((AVM2Instruction) ins).definition instanceof JumpIns)) && (!stack.isEmpty()) && (stack.peek().isCompileTime())&&(!stack.peek().hasSideEffect())) { boolean condition = stack.peek().toBoolean(); if (debugMode) { if (condition) { diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java index 807c08bde..53d046035 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java @@ -70,6 +70,12 @@ public class AVM2Graph extends Graph { private ABC abc; private MethodBody body; + public AVM2Code getCode() { + return code; + } + + + public AVM2Graph(AVM2Code code, ABC abc, MethodBody body, boolean isStatic, int classIndex, HashMap localRegs, Stack scopeStack, HashMap localRegNames, List fullyQualifiedNames) { super(new AVM2GraphSource(code, isStatic, classIndex, localRegs, scopeStack, abc, body, localRegNames, fullyQualifiedNames), body.getExceptionEntries()); this.code = code; diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2GraphSource.java b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2GraphSource.java index 79825a0d4..6343ad75f 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2GraphSource.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2GraphSource.java @@ -28,6 +28,12 @@ public class AVM2GraphSource extends GraphSource { HashMap localRegNames; List fullyQualifiedNames; + public AVM2Code getCode() { + return code; + } + + + public AVM2GraphSource(AVM2Code code, boolean isStatic, int classIndex, HashMap localRegs, Stack scopeStack, ABC abc, MethodBody body, HashMap localRegNames, List fullyQualifiedNames) { this.code = code; this.isStatic = isStatic; diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/instructions/jumps/JumpIns.java b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/instructions/jumps/JumpIns.java index 6a17f11d7..0bcc7379c 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/instructions/jumps/JumpIns.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/instructions/jumps/JumpIns.java @@ -36,7 +36,7 @@ public class JumpIns extends InstructionDefinition implements IfTypeIns { @Override public void translate(boolean isStatic, int classIndex, java.util.HashMap localRegs, Stack stack, java.util.Stack scopeStack, ConstantPool constants, AVM2Instruction ins, MethodInfo[] method_info, List output, com.jpexs.decompiler.flash.abc.types.MethodBody body, com.jpexs.decompiler.flash.abc.ABC abc, HashMap localRegNames, List fullyQualifiedNames) { - stack.push(new BooleanTreeItem(ins, Boolean.TRUE));// + ins.operands[0]); + //stack.push(new BooleanTreeItem(ins, Boolean.TRUE));// + ins.operands[0]); } @Override diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/PostDecrementTreeItem.java b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/PostDecrementTreeItem.java index b0a83eb75..8bba3c9bb 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/PostDecrementTreeItem.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/PostDecrementTreeItem.java @@ -37,4 +37,9 @@ public class PostDecrementTreeItem extends TreeItem implements AssignmentTreeIte public String toString(ConstantPool constants, HashMap localRegNames, List fullyQualifiedNames) { return object.toString(Helper.toList(constants, localRegNames, fullyQualifiedNames)) + hilight("--"); } + + @Override + public boolean hasSideEffect() { + return true; + } } diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/PostIncrementTreeItem.java b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/PostIncrementTreeItem.java index 3c069b3e5..57684611b 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/PostIncrementTreeItem.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/PostIncrementTreeItem.java @@ -37,4 +37,9 @@ public class PostIncrementTreeItem extends TreeItem implements AssignmentTreeIte public String toString(ConstantPool constants, HashMap localRegNames, List fullyQualifiedNames) { return object.toString(Helper.toList(constants, localRegNames, fullyQualifiedNames)) + hilight("++"); } + + @Override + public boolean hasSideEffect() { + return true; + } } diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/SetGlobalSlotTreeItem.java b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/SetGlobalSlotTreeItem.java index 811420df3..4cb267617 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/SetGlobalSlotTreeItem.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/SetGlobalSlotTreeItem.java @@ -37,4 +37,9 @@ public class SetGlobalSlotTreeItem extends TreeItem { public String toString(ConstantPool constants, HashMap localRegNames, List fullyQualifiedNames) { return hilight("setglobalslot(" + slotId + ",") + value.toString(constants, localRegNames, fullyQualifiedNames) + hilight(")"); } + + @Override + public boolean hasSideEffect() { + return true; + } } diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/SetLocalTreeItem.java b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/SetLocalTreeItem.java index 7f534605f..61a71b2a1 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/SetLocalTreeItem.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/SetLocalTreeItem.java @@ -48,4 +48,11 @@ public class SetLocalTreeItem extends TreeItem implements SetTypeTreeItem, Assig public GraphTargetItem getValue() { return value; } + + @Override + public boolean hasSideEffect() { + return true; + } + + } diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/SetPropertyTreeItem.java b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/SetPropertyTreeItem.java index 1d74d3869..dabe8ff2b 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/SetPropertyTreeItem.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/SetPropertyTreeItem.java @@ -50,4 +50,9 @@ public class SetPropertyTreeItem extends TreeItem implements SetTypeTreeItem, As public GraphTargetItem getValue() { return value; } + + @Override + public boolean hasSideEffect() { + return true; + } } diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/SetSlotTreeItem.java b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/SetSlotTreeItem.java index d7dd8533f..815b57f8b 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/SetSlotTreeItem.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/SetSlotTreeItem.java @@ -72,4 +72,9 @@ public class SetSlotTreeItem extends TreeItem implements SetTypeTreeItem, Assign public GraphTargetItem getValue() { return value; } + + @Override + public boolean hasSideEffect() { + return true; + } } diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/SetSuperTreeItem.java b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/SetSuperTreeItem.java index 0ce3eca84..50ebc4a6c 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/SetSuperTreeItem.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/SetSuperTreeItem.java @@ -44,4 +44,9 @@ public class SetSuperTreeItem extends TreeItem { } return calee + hilight("super.") + propertyName.toString(constants, localRegNames, fullyQualifiedNames) + hilight("=") + value.toString(constants, localRegNames, fullyQualifiedNames); } + + @Override + public boolean hasSideEffect() { + return true; + } } diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/operations/PreDecrementTreeItem.java b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/operations/PreDecrementTreeItem.java index 4688377b3..604944d82 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/operations/PreDecrementTreeItem.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/operations/PreDecrementTreeItem.java @@ -26,4 +26,9 @@ public class PreDecrementTreeItem extends UnaryOpItem implements AssignmentTreeI public PreDecrementTreeItem(AVM2Instruction instruction, GraphTargetItem object) { super(instruction, PRECEDENCE_UNARY, object, "--"); } + + @Override + public boolean hasSideEffect() { + return true; + } } diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/operations/PreIncrementTreeItem.java b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/operations/PreIncrementTreeItem.java index 68cef5952..34d1fd911 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/operations/PreIncrementTreeItem.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/treemodel/operations/PreIncrementTreeItem.java @@ -25,4 +25,9 @@ public class PreIncrementTreeItem extends UnaryOpItem { public PreIncrementTreeItem(AVM2Instruction instruction, GraphTargetItem object) { super(instruction, PRECEDENCE_UNARY, object, "++"); } + + @Override + public boolean hasSideEffect() { + return true; + } } diff --git a/trunk/src/com/jpexs/decompiler/flash/action/Action.java b/trunk/src/com/jpexs/decompiler/flash/action/Action.java index da4a7df61..c5ee8bc75 100644 --- a/trunk/src/com/jpexs/decompiler/flash/action/Action.java +++ b/trunk/src/com/jpexs/decompiler/flash/action/Action.java @@ -910,6 +910,9 @@ public class Action implements GraphSourceItem { } public static List checkClass(List output) { + if(true){ + return output; + } List ret = new ArrayList(); List functions = new ArrayList(); List staticFunctions = new ArrayList(); diff --git a/trunk/src/com/jpexs/decompiler/flash/graph/BinaryOpItem.java b/trunk/src/com/jpexs/decompiler/flash/graph/BinaryOpItem.java index 64ccdf052..a5b97ae41 100644 --- a/trunk/src/com/jpexs/decompiler/flash/graph/BinaryOpItem.java +++ b/trunk/src/com/jpexs/decompiler/flash/graph/BinaryOpItem.java @@ -65,4 +65,9 @@ public abstract class BinaryOpItem extends GraphTargetItem { public boolean isVariableComputed() { return leftSide.isVariableComputed() || rightSide.isVariableComputed(); } + + @Override + public boolean hasSideEffect() { + return leftSide.hasSideEffect()||rightSide.hasSideEffect(); + } } diff --git a/trunk/src/com/jpexs/decompiler/flash/graph/GraphTargetItem.java b/trunk/src/com/jpexs/decompiler/flash/graph/GraphTargetItem.java index 479097701..de8354b8a 100644 --- a/trunk/src/com/jpexs/decompiler/flash/graph/GraphTargetItem.java +++ b/trunk/src/com/jpexs/decompiler/flash/graph/GraphTargetItem.java @@ -89,6 +89,11 @@ public abstract class GraphTargetItem { public boolean isCompileTime() { return false; } + + public boolean hasSideEffect() + { + return false; + } public boolean isVariableComputed() { return false; diff --git a/trunk/src/com/jpexs/decompiler/flash/graph/UnaryOpItem.java b/trunk/src/com/jpexs/decompiler/flash/graph/UnaryOpItem.java index 98117fb56..68576076d 100644 --- a/trunk/src/com/jpexs/decompiler/flash/graph/UnaryOpItem.java +++ b/trunk/src/com/jpexs/decompiler/flash/graph/UnaryOpItem.java @@ -56,4 +56,9 @@ public abstract class UnaryOpItem extends GraphTargetItem { ret.addAll(value.getNeededSources()); return ret; } + + @Override + public boolean hasSideEffect() { + return value.hasSideEffect(); + } } diff --git a/trunk/test/com/jpexs/decompiler/flash/ActionScript3Test.java b/trunk/test/com/jpexs/decompiler/flash/ActionScript3Test.java index 01a470a58..d19bd9df4 100644 --- a/trunk/test/com/jpexs/decompiler/flash/ActionScript3Test.java +++ b/trunk/test/com/jpexs/decompiler/flash/ActionScript3Test.java @@ -44,7 +44,7 @@ public class ActionScript3Test { String actualResult = abc.bodies[bodyIndex].toString(methodName, false, isStatic, clsIndex, abc, abc.constants, abc.method_info, new Stack(), false, false, new ArrayList(), abc.instance_info[clsIndex].instance_traits); actualResult = actualResult.replaceAll("[ \r\n]", ""); expectedResult = expectedResult.replaceAll("[ \r\n]", ""); - assertEquals(expectedResult, actualResult); + assertEquals(actualResult,expectedResult); } @Test