From ae0ad85df2ac6ccbb72e6dcaa2496fa419f0fea0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=F8=EDk?= Date: Sat, 3 Aug 2013 08:49:17 +0200 Subject: [PATCH] Improved deobfuscation --- .../decompiler/flash/SWFInputStream.java | 147 ++++++++---------- .../decompiler/flash/abc/avm2/AVM2Code.java | 86 +++++++++- .../instructions/localregs/DecLocalIIns.java | 14 +- .../instructions/localregs/DecLocalIns.java | 14 +- .../localregs/GetLocalTypeIns.java | 21 ++- .../instructions/localregs/IncLocalIIns.java | 14 +- .../instructions/localregs/IncLocalIns.java | 14 +- .../localregs/SetLocalTypeIns.java | 25 +-- .../instructions/other/SetPropertyIns.java | 8 +- .../avm2/instructions/other/SetSlotIns.java | 8 +- .../abc/avm2/model/DecrementAVM2Item.java | 17 +- .../abc/avm2/model/IncrementAVM2Item.java | 17 +- .../abc/avm2/model/LocalRegAVM2Item.java | 20 ++- .../avm2/model/NotCompileTimeAVM2Item.java | 2 +- .../flash/abc/types/MethodBody.java | 4 +- .../jpexs/decompiler/flash/action/Action.java | 24 ++- .../flash/action/parser/pcode/ASMParser.java | 3 + .../action/special/ActionDeobfuscatePop.java | 45 ++++++ .../flash/action/swf3/ActionWaitForFrame.java | 42 ++++- .../action/swf4/ActionWaitForFrame2.java | 44 +++++- .../decompiler/flash/gui/RenameDialog.java | 3 +- .../flash/tags/DefineSpriteTag.java | 7 +- .../decompiler/flash/tags/DoActionTag.java | 2 + .../decompiler/flash/tags/base/TextTag.java | 4 +- 24 files changed, 415 insertions(+), 170 deletions(-) create mode 100644 trunk/src/com/jpexs/decompiler/flash/action/special/ActionDeobfuscatePop.java diff --git a/trunk/src/com/jpexs/decompiler/flash/SWFInputStream.java b/trunk/src/com/jpexs/decompiler/flash/SWFInputStream.java index 59d385e9b..cf0eb6619 100644 --- a/trunk/src/com/jpexs/decompiler/flash/SWFInputStream.java +++ b/trunk/src/com/jpexs/decompiler/flash/SWFInputStream.java @@ -61,6 +61,7 @@ import java.io.PrintStream; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Map.Entry; import java.util.Scanner; import java.util.Stack; @@ -90,6 +91,10 @@ public class SWFInputStream extends InputStream { private ByteArrayOutputStream buffer; private static boolean DEOBFUSCATION_ALL_CODE_IN_PREVIOUS_TAG = (Boolean) Configuration.getConfig("deobfuscateUsePrevTagOnly", true); + public int getVersion() { + return version; + } + public int getBufferLength() { return buffer.size(); } @@ -636,33 +641,6 @@ public class SWFInputStream extends InputStream { if (ins.isBranch() || ins.isJump()) { if (deobfuscate && (ins instanceof ActionIf) && !stack.isEmpty() && (stack.peek().isCompileTime() && (!stack.peek().hasSideEffect()))) { - ActionIf aif = (ActionIf) ins; - if (aif.ignoreUsed && (!aif.jumpUsed)) { - ins.setIgnored(true, 0); - } - if ((!aif.ignoreUsed) && aif.jumpUsed) { - ActionJump jmpIns = new ActionJump(aif.getJumpOffset()); - ((ActionJump) jmpIns).setAddress(aif.getAddress(), version); - code.set(ip, (ActionJump) jmpIns); - } - - if ((aif.ignoreUsed && (!aif.jumpUsed)) || ((!aif.ignoreUsed) && aif.jumpUsed)) { - List needed = stack.peek().getNeededSources(); - for (GraphSourceItemPos ig : needed) { - /*if (ig.item instanceof ActionPush) { - if (!((ActionPush) ig.item).ignoredParts.contains(ig.pos)) { - ((ActionPush) ig.item).ignoredParts.add(ig.pos); - - if (((ActionPush) ig.item).ignoredParts.size() == ((ActionPush) ig.item).values.size()) { - ((Action) ig.item).setIgnored(true, 0); - } - } - } else { - - }*/ - ((Action) ig.item).setIgnored(true, ig.pos); - } - } boolean condition = EcmaScript.toBoolean(stack.peek().getResult()); if (debugMode) { if (condition) { @@ -683,7 +661,7 @@ public class SWFInputStream extends InputStream { @SuppressWarnings("unchecked") Stack brStack = (Stack) stack.clone(); if (b >= 0) { - getConstantPool(listeners, cpool, localData, brStack, output, code, b, constantPools, visited, version, endIp, path); + getConstantPool(listeners, cpool, prepareLocalBranch(localData), brStack, output, code, b, constantPools, visited, version, endIp, path); } else { if (debugMode) { System.out.println("Negative branch:" + b); @@ -714,6 +692,20 @@ public class SWFInputStream extends InputStream { return ret; } + private static List prepareLocalBranch(List localData) { + @SuppressWarnings("unchecked") + HashMap regNames = (HashMap) localData.get(0); + @SuppressWarnings("unchecked") + HashMap variables = (HashMap) localData.get(1); + @SuppressWarnings("unchecked") + HashMap functions = (HashMap) localData.get(2); + List ret = new ArrayList<>(); + ret.add(new HashMap(regNames)); + ret.add(new HashMap(variables)); + ret.add(new HashMap(functions)); + return ret; + } + /** * Reads list of actions from the stream. Reading ends with * ActionEndFlag(=0) or end of the stream. @@ -747,7 +739,7 @@ public class SWFInputStream extends InputStream { method = 2; goesPrev = readActionListAtPos(true, localData, stack, cpool, sis, rri, ip, retdups, ip); }*/ - goesPrev = readActionListAtPos(listeners, new ArrayList(), new HashMap>(), address, containerSWFOffset, false, true, localData, stack, cpool, sis, rri, ip, retdups, ip, endip, path); + goesPrev = readActionListAtPos(listeners, new ArrayList(), new HashMap>(), address, containerSWFOffset, localData, stack, cpool, sis, rri, ip, retdups, ip, endip, path, new HashMap()); if (goesPrev) { } else { @@ -777,15 +769,6 @@ public class SWFInputStream extends InputStream { } List pools; - StringBuilder br = new StringBuilder(); - for (int i = 0; i < ret.size(); i++) { - br.append(i); - br.append(", loc"); - br.append(Helper.formatAddress(((Action) ret.get(i)).getAddress())); - br.append(": "); - br.append(((Action) ret.get(i)).getASMSource(new ArrayList(), new ArrayList(), cpool.constants, version, false)); - br.append("\r\n"); - } ret = Action.removeNops(0, ret, version, 0, path); pools = getConstantPool(listeners, new ActionGraphSource(ret, version, new HashMap(), new HashMap(), new HashMap()), 0, version, path); @@ -815,7 +798,7 @@ public class SWFInputStream extends InputStream { } @SuppressWarnings("unchecked") - private static boolean readActionListAtPos(List listeners, List output, HashMap> containers, long address, long containerSWFOffset, boolean notCompileTime, boolean enableVariables, List localData, Stack stack, ConstantPool cpool, SWFInputStream sis, ReReadableInputStream rri, int ip, List ret, int startIp, int endip, String path) throws IOException { + private static boolean readActionListAtPos(List listeners, List output, HashMap> containers, long address, long containerSWFOffset, List localData, Stack stack, ConstantPool cpool, SWFInputStream sis, ReReadableInputStream rri, int ip, List ret, int startIp, int endip, String path, Map visited) throws IOException { boolean debugMode = false; boolean decideBranch = false; @@ -826,7 +809,14 @@ public class SWFInputStream extends InputStream { long filePos = rri.getPos(); Scanner sc = new Scanner(System.in, "utf-8"); int prevIp = ip; + loopip: while (((endip == -1) || (endip > ip)) && (a = sis.readAction(rri)) != null) { + if (!visited.containsKey(ip)) { + visited.put(ip, 0); + } + int curVisited = visited.get(ip); + curVisited++; + visited.put(ip, curVisited); for (int i = 0; i < listeners.size(); i++) { listeners.get(i).progress("Reading", rri.getCount(), rri.length()); } @@ -908,9 +898,6 @@ public class SWFInputStream extends InputStream { ensureCapacity(ret, ip); int newip = -1; - if (!enableVariables && (!(ret.get(ip) instanceof ActionNop))) { - break; - } if (a instanceof ActionConstantPool) { if (cpool == null) { @@ -943,22 +930,13 @@ public class SWFInputStream extends InputStream { } else if (next.equals("c")) { goaif = true; } - } else if (deobfuscate && top.isCompileTime() && (!top.hasSideEffect()) && ((!top.isVariableComputed()) || (top.isVariableComputed() && enableVariables && (!notCompileTime)))) { - //if(top.isCompileTime()) { - //if(false){ - if (enableVariables) { - ((ActionIf) a).compileTime = true; - } + } else if (deobfuscate && top.isCompileTime() && (!top.hasSideEffect())) { + ((ActionIf) a).compileTime = true; if (debugMode) { System.err.print("is compiletime -> "); } if (EcmaScript.toBoolean(top.getResult())) { newip = rri.getPos() + aif.getJumpOffset(); - //rri.setPos(newip); - if (((!enableVariables) || (!top.isVariableComputed())) && (!aif.ignoreUsed)) { - a = new ActionJump(aif.getJumpOffset()); - a.setAddress(aif.getAddress(), SWF.DEFAULT_VERSION); - } aif.jumpUsed = true; if (aif.ignoreUsed) { aif.compileTime = false; @@ -974,32 +952,7 @@ public class SWFInputStream extends InputStream { if (debugMode) { System.err.println("ignore"); } - if (((!enableVariables) || (!top.isVariableComputed())) && (!aif.jumpUsed)) { - //a = new ActionNop(); - aif.setIgnored(true, 0); - //a.setAddress(aif.getAddress(), SWF.DEFAULT_VERSION); - } } - if (((!enableVariables) || (!top.isVariableComputed())) && (!(aif.jumpUsed && aif.ignoreUsed))) { - List needed = top.getNeededSources(); - for (GraphSourceItemPos ig : needed) { - if (ig.item == null) { - continue; - } - if (ig.item instanceof ActionPush) { - if (!((ActionPush) ig.item).ignoredParts.contains(ig.pos)) { - ((ActionPush) ig.item).ignoredParts.add(ig.pos); - - if (((ActionPush) ig.item).ignoredParts.size() == ((ActionPush) ig.item).values.size()) { - ((Action) ig.item).setIgnored(true, 0); - } - } - } else { - ((Action) ig.item).setIgnored(true, 0); - } - } - } - } else { if (debugMode) { System.err.println("goaif"); @@ -1025,9 +978,9 @@ public class SWFInputStream extends InputStream { } } } catch (RuntimeException ex) { - if (!enableVariables) { - throw ex; - } + /*if (!enableVariables) { + throw ex; + }*/ log.log(Level.SEVERE, "Disassembly exception", ex); break; } @@ -1064,9 +1017,14 @@ public class SWFInputStream extends InputStream { output2s.add(new ArrayList()); continue; } - List localData2 = Helper.toList(new HashMap(), new HashMap(), new HashMap()); + List localData2; List output2 = new ArrayList<>(); - readActionListAtPos(listeners, output2, containers, address, containerSWFOffset, notCompileTime, enableVariables, localData2, new Stack(), cpool, sis, rri, (int) endAddr, ret, startIp, (int) (endAddr + size), path + (cntName == null ? "" : "/" + cntName)); + if ((cnt instanceof ActionDefineFunction) || (cnt instanceof ActionDefineFunction2)) { + localData2 = Helper.toList(new HashMap(), new HashMap(), new HashMap()); + } else { + localData2 = localData; + } + readActionListAtPos(listeners, output2, containers, address, containerSWFOffset, localData2, new Stack(), cpool, sis, rri, (int) endAddr, ret, startIp, (int) (endAddr + size), path + (cntName == null ? "" : "/" + cntName), visited); output2s.add(output2); endAddr += size; } @@ -1098,14 +1056,33 @@ public class SWFInputStream extends InputStream { } aif.ignoreUsed = true; aif.jumpUsed = true; + + if (curVisited > 1) { + List branches = new ArrayList<>(); + branches.add(rri.getPos() + aif.getJumpOffset()); + branches.add(rri.getPos()); + for (int br : branches) { + int visc = 0; + if (visited.containsKey(br)) { + visc = visited.get(br); + } + if (visc == 0) {// substack = (Stack) stack.clone(); - if (readActionListAtPos(listeners, output, containers, address, containerSWFOffset, true, enableVariables, localData, substack, cpool, sis, rri, rri.getPos() + aif.getJumpOffset(), ret, startIp, endip, path)) { + if (readActionListAtPos(listeners, output, containers, address, containerSWFOffset, prepareLocalBranch(localData), substack, cpool, sis, rri, rri.getPos() + aif.getJumpOffset(), ret, startIp, endip, path, visited)) { retv = true; } rri.setPos(oldPos); - notCompileTime = true; } prevIp = ip; if (a.isExit()) { 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 5aad3921d..c3eabd378 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java @@ -1483,6 +1483,30 @@ public class AVM2Code implements Serializable { code.add(pos, instruction); } + @SuppressWarnings("unchecked") + private static List prepareBranchLocalData(List localData) { + List ret = new ArrayList<>(); + ret.add(localData.get(0)); //isStatic + ret.add(localData.get(1)); //classIndex + ret.add(new HashMap((HashMap) localData.get(2))); + ret.add((Stack) ((Stack) localData.get(3)).clone()); + ret.add(localData.get(4)); //constants + ret.add(localData.get(5)); //method_info + ret.add(localData.get(6)); //body + ret.add(localData.get(7)); //abc + ret.add(localData.get(8)); //localgetNames + ret.add(localData.get(9)); + ret.add(localData.get(10)); + ret.add(localData.get(11)); + ret.add(localData.get(12)); + ret.add(localData.get(13)); + ret.add(localData.get(14)); + ret.add(localData.get(15)); + ret.add(localData.get(16)); + ret.add(localData.get(17)); + return ret; + } + public int removeTraps(ConstantPool constants, MethodBody body, ABC abc, int scriptIndex, int classIndex, boolean isStatic, String path) { removeDeadCode(constants, body); List localData = new ArrayList<>(); @@ -2212,6 +2236,14 @@ public class AVM2Code implements Serializable { } + int curVisited; + if (!visited.containsKey(ip)) { + curVisited = 1; + } else { + curVisited = visited.get(ip) + 1; + } + visited.put(ip, curVisited); + List r = refs.get(ip); /*if (r != null) { if (r.size() > 1) { @@ -2245,6 +2277,16 @@ public class AVM2Code implements Serializable { } if (debugMode) { System.out.println((useVisited ? "useV " : "") + (secondPass ? "secondPass " : "") + "Visit " + ip + ": " + ins + " stack:" + Highlighting.stripHilights(stack.toString())); + HashMap registers = (HashMap) localData.get(2); + System.out.print("Registers:"); + for (int reg : registers.keySet()) { + try { + System.out.print(" r" + reg + ": " + registers.get(reg).getResult()); + } catch (NullPointerException npe) { + System.out.print(" r" + reg + ": " + "null"); + } + } + System.out.println(""); } if (secondPass) { /*if ((ins instanceof AVM2Instruction) && (((AVM2Instruction) ins).definition instanceof PopIns)) { @@ -2349,12 +2391,26 @@ public class AVM2Code implements Serializable { } dec.jumpUsed = true; dec.skipUsed = true; + + if (curVisited > 1) { + for (int b : branches) { + int visc = 0; + if (visited.containsKey(b)) { + visc = visited.get(b); + } + if (visc == 0) {// brStack = (Stack) stack.clone(); - if (b >= 0) { - ret += removeTraps(refs, secondPass, useVisited || (!ins.isJump()), localData, brStack, output, code, b, visited, visitedStates, decisions, path); + if (b >= 0) { //useVisited || (!ins.isJump()) + ret += removeTraps(refs, secondPass, false, prepareBranchLocalData(localData), brStack, output, code, b, visited, visitedStates, decisions, path); } else { if (debugMode) { System.out.println("Negative branch:" + b); @@ -2375,8 +2431,30 @@ public class AVM2Code implements Serializable { public static int removeTraps(ConstantPool constants, MethodBody body, List localData, AVM2GraphSource code, int addr, String path, HashMap> refs) { HashMap decisions = new HashMap<>(); removeTraps(refs, false, false, localData, new Stack(), new ArrayList(), code, code.adr2pos(addr), new HashMap(), new HashMap>(), decisions, path); - localData.set(2, new HashMap()); - int cnt = removeTraps(refs, true, false, localData, new Stack(), new ArrayList(), code, code.adr2pos(addr), new HashMap(), new HashMap>(), decisions, path); + int cnt = 0; + for (GraphSourceItem src : decisions.keySet()) { + Decision dec = decisions.get(src); + if (dec != null) { + if ((src instanceof AVM2Instruction) && (((AVM2Instruction) src).definition instanceof LookupSwitchIns)) { + if (dec.casesUsed.size() == 1) { + for (int c : dec.casesUsed) { + src.setFixBranch(c); + cnt++; + } + } + } else { + if (dec.jumpUsed && !dec.skipUsed) { + src.setFixBranch(0); + cnt++; + } + if (!dec.jumpUsed && dec.skipUsed) { + src.setFixBranch(1); + cnt++; + } + } + } + } + //int cnt = removeTraps(refs, true, false, localData, new Stack(), new ArrayList(), code, code.adr2pos(addr), new HashMap(), new HashMap>(), decisions, path); code.getCode().removeIgnored(constants, body); return cnt; } diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/DecLocalIIns.java b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/DecLocalIIns.java index a75fc1b92..25a100319 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/DecLocalIIns.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/DecLocalIIns.java @@ -57,14 +57,18 @@ public class DecLocalIIns extends InstructionDefinition { } @Override - public void translate(boolean isStatic, int scriptIndex, 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, String path, HashMap localRegsAssignmentIps, int ip, HashMap> refs, AVM2Code code) { - int regIndex = ins.operands[0]; - output.add(new DecLocalAVM2Item(ins, regIndex)); - if (localRegs.containsKey(regIndex)) { - localRegs.put(regIndex, new NotCompileTimeAVM2Item(ins, new SubtractAVM2Item(ins, localRegs.get(regIndex), new IntegerValueAVM2Item(ins, Long.valueOf(1))))); + public void translate(boolean isStatic, int scriptIndex, 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, String path, HashMap regAssignCount, int ip, HashMap> refs, AVM2Code code) { + int regId = ins.operands[0]; + output.add(new DecLocalAVM2Item(ins, regId)); + if (localRegs.containsKey(regId)) { + localRegs.put(regId, new SubtractAVM2Item(ins, localRegs.get(regId), new IntegerValueAVM2Item(ins, Long.valueOf(1)))); } else { //localRegs.put(regIndex, new SubtractAVM2Item(ins, new IntegerValueAVM2Item(ins, new Long(0)), new IntegerValueAVM2Item(ins, new Long(1)))); } + if (!regAssignCount.containsKey(regId)) { + regAssignCount.put(regId, 0); + } + regAssignCount.put(regId, regAssignCount.get(regId) + 1); } } diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/DecLocalIns.java b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/DecLocalIns.java index 4a4537a1d..8e529e09b 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/DecLocalIns.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/DecLocalIns.java @@ -57,13 +57,17 @@ public class DecLocalIns extends InstructionDefinition { } @Override - public void translate(boolean isStatic, int scriptIndex, 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, String path, HashMap localRegsAssignmentIps, int ip, HashMap> refs, AVM2Code code) { - int regIndex = ins.operands[0]; - output.add(new DecLocalAVM2Item(ins, regIndex)); - if (localRegs.containsKey(regIndex)) { - localRegs.put(regIndex, new NotCompileTimeAVM2Item(ins, new SubtractAVM2Item(ins, localRegs.get(regIndex), new IntegerValueAVM2Item(ins, Long.valueOf(1))))); + public void translate(boolean isStatic, int scriptIndex, 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, String path, HashMap regAssignCount, int ip, HashMap> refs, AVM2Code code) { + int regId = ins.operands[0]; + output.add(new DecLocalAVM2Item(ins, regId)); + if (localRegs.containsKey(regId)) { + localRegs.put(regId, new SubtractAVM2Item(ins, localRegs.get(regId), new IntegerValueAVM2Item(ins, Long.valueOf(1)))); } else { //localRegs.put(regIndex, new SubtractAVM2Item(ins, new IntegerValueAVM2Item(ins, new Long(0)), new IntegerValueAVM2Item(ins, new Long(1)))); } + if (!regAssignCount.containsKey(regId)) { + regAssignCount.put(regId, 0); + } + regAssignCount.put(regId, regAssignCount.get(regId) + 1); } } diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/GetLocalTypeIns.java b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/GetLocalTypeIns.java index 9e7ed6b59..3ba1ceedd 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/GetLocalTypeIns.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/GetLocalTypeIns.java @@ -37,17 +37,24 @@ public abstract class GetLocalTypeIns extends InstructionDefinition { } @Override - public void translate(boolean isStatic, int scriptIndex, 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, String path, HashMap localRegsAssignmentIps, int ip, HashMap> refs, AVM2Code code) { + public void translate(boolean isStatic, int scriptIndex, 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, String path, HashMap regAssignCount, int ip, HashMap> refs, AVM2Code code) { int regId = getRegisterId(ins); GraphTargetItem computedValue = localRegs.get(regId); - if (!isRegisterCompileTime(regId, ip, refs, code)) { + int assignCount = 0; + if (regAssignCount.containsKey(regId)) { + assignCount = regAssignCount.get(regId); + } + if (assignCount > 5) { //Do not allow change register more than 5 - for deobfuscation computedValue = new NotCompileTimeAVM2Item(ins, computedValue); } - if (computedValue == null) { - if (!localRegNames.containsKey(regId)) { - computedValue = new UndefinedAVM2Item(null); //In some obfuscated code there seems to be reading of undefined registers - } - } + /*if (!isRegisterCompileTime(regId, ip, refs, code)) { + computedValue = new NotCompileTimeAVM2Item(ins, computedValue); + } + if (computedValue == null) { + if (!localRegNames.containsKey(regId)) { + computedValue = new UndefinedAVM2Item(null); //In some obfuscated code there seems to be reading of undefined registers + } + }*/ stack.push(new LocalRegAVM2Item(ins, regId, computedValue)); } diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/IncLocalIIns.java b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/IncLocalIIns.java index 335cec057..9eab0cabd 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/IncLocalIIns.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/IncLocalIIns.java @@ -37,13 +37,17 @@ public class IncLocalIIns extends InstructionDefinition { } @Override - public void translate(boolean isStatic, int scriptIndex, 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, String path, HashMap localRegsAssignmentIps, int ip, HashMap> refs, AVM2Code code) { - int regIndex = ins.operands[0]; - output.add(new IncLocalAVM2Item(ins, regIndex)); - if (localRegs.containsKey(regIndex)) { - localRegs.put(regIndex, new NotCompileTimeAVM2Item(ins, new AddAVM2Item(ins, localRegs.get(regIndex), new IntegerValueAVM2Item(ins, Long.valueOf(1))))); + public void translate(boolean isStatic, int scriptIndex, 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, String path, HashMap regAssignCount, int ip, HashMap> refs, AVM2Code code) { + int regId = ins.operands[0]; + output.add(new IncLocalAVM2Item(ins, regId)); + if (localRegs.containsKey(regId)) { + localRegs.put(regId, new AddAVM2Item(ins, localRegs.get(regId), new IntegerValueAVM2Item(ins, Long.valueOf(1)))); } else { //localRegs.put(regIndex, new AddAVM2Item(ins, null, new IntegerValueAVM2Item(ins, new Long(1)))); } + if (!regAssignCount.containsKey(regId)) { + regAssignCount.put(regId, 0); + } + regAssignCount.put(regId, regAssignCount.get(regId) + 1); } } diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/IncLocalIns.java b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/IncLocalIns.java index 7b7c3cbb9..393dc580e 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/IncLocalIns.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/IncLocalIns.java @@ -37,13 +37,17 @@ public class IncLocalIns extends InstructionDefinition { } @Override - public void translate(boolean isStatic, int scriptIndex, 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, String path, HashMap localRegsAssignmentIps, int ip, HashMap> refs, AVM2Code code) { - int regIndex = ins.operands[0]; - output.add(new IncLocalAVM2Item(ins, regIndex)); - if (localRegs.containsKey(regIndex)) { - localRegs.put(regIndex, new NotCompileTimeAVM2Item(ins, new AddAVM2Item(ins, localRegs.get(regIndex), new IntegerValueAVM2Item(ins, Long.valueOf(1))))); + public void translate(boolean isStatic, int scriptIndex, 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, String path, HashMap regAssignCount, int ip, HashMap> refs, AVM2Code code) { + int regId = ins.operands[0]; + output.add(new IncLocalAVM2Item(ins, regId)); + if (localRegs.containsKey(regId)) { + localRegs.put(regId, new AddAVM2Item(ins, localRegs.get(regId), new IntegerValueAVM2Item(ins, Long.valueOf(1)))); } else { //localRegs.put(regIndex, new AddAVM2Item(ins, null, new IntegerValueAVM2Item(ins, new Long(1)))); } + if (!regAssignCount.containsKey(regId)) { + regAssignCount.put(regId, 0); + } + regAssignCount.put(regId, regAssignCount.get(regId) + 1); } } diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/SetLocalTypeIns.java b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/SetLocalTypeIns.java index 6f8e5afaf..f1a3d84ba 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/SetLocalTypeIns.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/SetLocalTypeIns.java @@ -47,15 +47,20 @@ public abstract class SetLocalTypeIns extends InstructionDefinition implements S } @Override - public void translate(boolean isStatic, int scriptIndex, 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, String path, HashMap localRegsAssignmentIps, int ip, HashMap> refs, AVM2Code code) { + public void translate(boolean isStatic, int scriptIndex, 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, String path, HashMap regAssignCount, int ip, HashMap> refs, AVM2Code code) { int regId = getRegisterId(ins); GraphTargetItem value = (GraphTargetItem) stack.pop(); - if (localRegs.containsKey(regId)) { - localRegs.put(regId, new NotCompileTimeAVM2Item(ins, value)); - } else { - localRegs.put(regId, value); + /*if (localRegs.containsKey(regId)) { + localRegs.put(regId, new NotCompileTimeAVM2Item(ins, value)); + } else { + localRegs.put(regId, value); + }*/ + localRegs.put(regId, value); + if (!regAssignCount.containsKey(regId)) { + regAssignCount.put(regId, 0); } - localRegsAssignmentIps.put(regId, ip); + regAssignCount.put(regId, regAssignCount.get(regId) + 1); + //localRegsAssignmentIps.put(regId, ip); if (value instanceof NewActivationAVM2Item) { return; } @@ -63,7 +68,7 @@ public abstract class SetLocalTypeIns extends InstructionDefinition implements S return; } if (value.getNotCoerced() instanceof IncrementAVM2Item) { - GraphTargetItem inside = ((IncrementAVM2Item) value.getNotCoerced()).object.getNotCoerced().getThroughDuplicate(); + GraphTargetItem inside = ((IncrementAVM2Item) value.getNotCoerced()).value.getNotCoerced().getThroughDuplicate(); if (inside instanceof LocalRegAVM2Item) { if (((LocalRegAVM2Item) inside).regIndex == regId) { if (stack.size() > 0) { @@ -71,7 +76,7 @@ public abstract class SetLocalTypeIns extends InstructionDefinition implements S if (top == inside) { stack.pop(); stack.push(new PostIncrementAVM2Item(ins, inside)); - } else if ((top instanceof IncrementAVM2Item) && (((IncrementAVM2Item) top).object == inside)) { + } else if ((top instanceof IncrementAVM2Item) && (((IncrementAVM2Item) top).value == inside)) { stack.pop(); stack.push(new PreIncrementAVM2Item(ins, inside)); } else { @@ -86,7 +91,7 @@ public abstract class SetLocalTypeIns extends InstructionDefinition implements S } if (value.getNotCoerced() instanceof DecrementAVM2Item) { - GraphTargetItem inside = ((DecrementAVM2Item) value.getNotCoerced()).object.getNotCoerced().getThroughDuplicate(); + GraphTargetItem inside = ((DecrementAVM2Item) value.getNotCoerced()).value.getNotCoerced().getThroughDuplicate(); if (inside instanceof LocalRegAVM2Item) { if (((LocalRegAVM2Item) inside).regIndex == regId) { if (stack.size() > 0) { @@ -94,7 +99,7 @@ public abstract class SetLocalTypeIns extends InstructionDefinition implements S if (top == inside) { stack.pop(); stack.push(new PostDecrementAVM2Item(ins, inside)); - } else if ((top instanceof DecrementAVM2Item) && (((DecrementAVM2Item) top).object == inside)) { + } else if ((top instanceof DecrementAVM2Item) && (((DecrementAVM2Item) top).value == inside)) { stack.pop(); stack.push(new PreDecrementAVM2Item(ins, inside)); } else { diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/instructions/other/SetPropertyIns.java b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/instructions/other/SetPropertyIns.java index 178dd829d..4bb4c5c90 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/instructions/other/SetPropertyIns.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/instructions/other/SetPropertyIns.java @@ -52,7 +52,7 @@ public class SetPropertyIns extends InstructionDefinition implements SetTypeIns FullMultinameAVM2Item multiname = resolveMultiname(stack, constants, multinameIndex, ins); GraphTargetItem obj = (GraphTargetItem) stack.pop(); if (value.getThroughDuplicate().getThroughRegister().getThroughDuplicate() instanceof IncrementAVM2Item) { - GraphTargetItem inside = ((IncrementAVM2Item) value.getThroughDuplicate().getThroughRegister().getThroughDuplicate()).object.getThroughRegister().getNotCoerced().getThroughDuplicate(); + GraphTargetItem inside = ((IncrementAVM2Item) value.getThroughDuplicate().getThroughRegister().getThroughDuplicate()).value.getThroughRegister().getNotCoerced().getThroughDuplicate(); if (inside instanceof GetPropertyAVM2Item) { GetPropertyAVM2Item insideProp = ((GetPropertyAVM2Item) inside); if (insideProp.propertyName.compareSame(multiname)) { @@ -68,7 +68,7 @@ public class SetPropertyIns extends InstructionDefinition implements SetTypeIns if (top == insideProp) { stack.pop(); stack.push(new PostIncrementAVM2Item(ins, insideProp)); - } else if ((top instanceof IncrementAVM2Item) && (((IncrementAVM2Item) top).object == inside)) { + } else if ((top instanceof IncrementAVM2Item) && (((IncrementAVM2Item) top).value == inside)) { stack.pop(); stack.push(new PreIncrementAVM2Item(ins, insideProp)); } else { @@ -84,7 +84,7 @@ public class SetPropertyIns extends InstructionDefinition implements SetTypeIns } if (value.getThroughDuplicate().getThroughRegister().getThroughDuplicate() instanceof DecrementAVM2Item) { - GraphTargetItem inside = ((DecrementAVM2Item) value.getThroughDuplicate().getThroughRegister().getThroughDuplicate()).object.getThroughRegister().getNotCoerced().getThroughDuplicate(); + GraphTargetItem inside = ((DecrementAVM2Item) value.getThroughDuplicate().getThroughRegister().getThroughDuplicate()).value.getThroughRegister().getNotCoerced().getThroughDuplicate(); if (inside instanceof GetPropertyAVM2Item) { GetPropertyAVM2Item insideProp = ((GetPropertyAVM2Item) inside); if (insideProp.propertyName.compareSame(multiname)) { @@ -100,7 +100,7 @@ public class SetPropertyIns extends InstructionDefinition implements SetTypeIns if (top == insideProp) { stack.pop(); stack.push(new PostDecrementAVM2Item(ins, insideProp)); - } else if ((top instanceof DecrementAVM2Item) && (((DecrementAVM2Item) top).object == inside)) { + } else if ((top instanceof DecrementAVM2Item) && (((DecrementAVM2Item) top).value == inside)) { stack.pop(); stack.push(new PreDecrementAVM2Item(ins, insideProp)); } else { diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/instructions/other/SetSlotIns.java b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/instructions/other/SetSlotIns.java index 4fad7ae7d..f26ce23e5 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/instructions/other/SetSlotIns.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/instructions/other/SetSlotIns.java @@ -105,7 +105,7 @@ public class SetSlotIns extends InstructionDefinition implements SetTypeIns { } if (value.getNotCoerced().getThroughDuplicate() instanceof IncrementAVM2Item) { - GraphTargetItem inside = ((IncrementAVM2Item) value.getNotCoerced()).object.getThroughRegister().getNotCoerced().getThroughDuplicate(); + GraphTargetItem inside = ((IncrementAVM2Item) value.getNotCoerced()).value.getThroughRegister().getNotCoerced().getThroughDuplicate(); if (inside instanceof GetSlotAVM2Item) { GetSlotAVM2Item slotItem = (GetSlotAVM2Item) inside; if ((slotItem.scope.getThroughRegister() == obj.getThroughRegister()) @@ -115,7 +115,7 @@ public class SetSlotIns extends InstructionDefinition implements SetTypeIns { if (top == inside) { stack.pop(); stack.push(new PostIncrementAVM2Item(ins, inside)); - } else if ((top instanceof IncrementAVM2Item) && (((IncrementAVM2Item) top).object == inside)) { + } else if ((top instanceof IncrementAVM2Item) && (((IncrementAVM2Item) top).value == inside)) { stack.pop(); stack.push(new PreIncrementAVM2Item(ins, inside)); } else { @@ -130,7 +130,7 @@ public class SetSlotIns extends InstructionDefinition implements SetTypeIns { } if (value.getNotCoerced().getThroughDuplicate() instanceof DecrementAVM2Item) { - GraphTargetItem inside = ((DecrementAVM2Item) value.getNotCoerced()).object.getThroughRegister().getNotCoerced().getThroughDuplicate(); + GraphTargetItem inside = ((DecrementAVM2Item) value.getNotCoerced()).value.getThroughRegister().getNotCoerced().getThroughDuplicate(); if (inside instanceof GetSlotAVM2Item) { GetSlotAVM2Item slotItem = (GetSlotAVM2Item) inside; if ((slotItem.scope.getThroughRegister() == obj.getThroughRegister()) @@ -140,7 +140,7 @@ public class SetSlotIns extends InstructionDefinition implements SetTypeIns { if (top == inside) { stack.pop(); stack.push(new PostDecrementAVM2Item(ins, inside)); - } else if ((top instanceof DecrementAVM2Item) && (((DecrementAVM2Item) top).object == inside)) { + } else if ((top instanceof DecrementAVM2Item) && (((DecrementAVM2Item) top).value == inside)) { stack.pop(); stack.push(new PreDecrementAVM2Item(ins, inside)); } else { diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/model/DecrementAVM2Item.java b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/model/DecrementAVM2Item.java index 2242bd584..d52122ba3 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/model/DecrementAVM2Item.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/model/DecrementAVM2Item.java @@ -18,21 +18,30 @@ package com.jpexs.decompiler.flash.abc.avm2.model; import com.jpexs.decompiler.flash.abc.avm2.ConstantPool; import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction; +import com.jpexs.decompiler.flash.ecma.EcmaScript; import com.jpexs.decompiler.graph.GraphTargetItem; import java.util.HashMap; import java.util.List; public class DecrementAVM2Item extends AVM2Item { - public GraphTargetItem object; - public DecrementAVM2Item(AVM2Instruction instruction, GraphTargetItem object) { super(instruction, PRECEDENCE_ADDITIVE); - this.object = object; + this.value = object; } @Override public String toString(ConstantPool constants, HashMap localRegNames, List fullyQualifiedNames) { - return object.toString(constants, localRegNames, fullyQualifiedNames) + hilight("-1"); + return value.toString(constants, localRegNames, fullyQualifiedNames) + hilight("-1"); + } + + @Override + public boolean isCompileTime() { + return value.isCompileTime(); + } + + @Override + public Object getResult() { + return EcmaScript.toNumber(value.getResult()) - 1; } } diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/model/IncrementAVM2Item.java b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/model/IncrementAVM2Item.java index dfc023b96..f292151d8 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/model/IncrementAVM2Item.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/model/IncrementAVM2Item.java @@ -18,21 +18,30 @@ package com.jpexs.decompiler.flash.abc.avm2.model; import com.jpexs.decompiler.flash.abc.avm2.ConstantPool; import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction; +import com.jpexs.decompiler.flash.ecma.EcmaScript; import com.jpexs.decompiler.graph.GraphTargetItem; import java.util.HashMap; import java.util.List; public class IncrementAVM2Item extends AVM2Item { - public GraphTargetItem object; - public IncrementAVM2Item(AVM2Instruction instruction, GraphTargetItem object) { super(instruction, PRECEDENCE_ADDITIVE); - this.object = object; + this.value = object; } @Override public String toString(ConstantPool constants, HashMap localRegNames, List fullyQualifiedNames) { - return object.toString(constants, localRegNames, fullyQualifiedNames) + hilight("+1"); + return value.toString(constants, localRegNames, fullyQualifiedNames) + hilight("+1"); + } + + @Override + public boolean isCompileTime() { + return value.isCompileTime(); + } + + @Override + public Object getResult() { + return EcmaScript.toNumber(value.getResult()) + 1; } } diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/model/LocalRegAVM2Item.java b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/model/LocalRegAVM2Item.java index 4bb1b6a0e..a9a164dfc 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/model/LocalRegAVM2Item.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/model/LocalRegAVM2Item.java @@ -29,12 +29,21 @@ public class LocalRegAVM2Item extends AVM2Item { public int regIndex; public GraphTargetItem computedValue; + private Object computedResult; + private boolean isCT = false; public LocalRegAVM2Item(AVM2Instruction instruction, int regIndex, GraphTargetItem computedValue) { super(instruction, PRECEDENCE_PRIMARY); this.regIndex = regIndex; if (computedValue == null) { - //computedValue = new UndefinedAVM2Item(instruction); + computedResult = null; + } else { + if (computedValue.isCompileTime()) { + computedResult = computedValue.getResult(); + isCT = true; + } else { + computedResult = null; + } } this.computedValue = computedValue; } @@ -57,18 +66,15 @@ public class LocalRegAVM2Item extends AVM2Item { @Override public Object getResult() { - if (computedValue == null) { + if (computedResult == null) { return new Undefined(); } - return computedValue.getResult(); + return computedResult; } @Override public boolean isCompileTime() { - if (computedValue == null) { - return false; - } - return computedValue.isCompileTime(); + return isCT; } } diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/model/NotCompileTimeAVM2Item.java b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/model/NotCompileTimeAVM2Item.java index 3c30b3be1..d85761471 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/model/NotCompileTimeAVM2Item.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/model/NotCompileTimeAVM2Item.java @@ -47,7 +47,7 @@ public class NotCompileTimeAVM2Item extends AVM2Item { @Override public GraphTargetItem getThroughNotCompilable() { - if(object==null){ + if (object == null) { return object; } return object.getThroughNotCompilable(); diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java b/trunk/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java index 6ffa82de9..45bcdd748 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java @@ -125,8 +125,8 @@ public class MethodBody implements Cloneable, Serializable { if ((Boolean) Configuration.getConfig("autoDeobfuscate", true)) { try { deobfuscated.removeTraps(constants, b, abc, scriptIndex, classIndex, isStatic, path); - } catch (Exception ex) { - Logger.getLogger(MethodBody.class.getName()).log(Level.SEVERE, "Error during remove traps", ex); + } catch (Exception | StackOverflowError ex) { + Logger.getLogger(MethodBody.class.getName()).log(Level.SEVERE, "Error during remove traps in " + path, ex); } } //deobfuscated.restoreControlFlow(constants, b); diff --git a/trunk/src/com/jpexs/decompiler/flash/action/Action.java b/trunk/src/com/jpexs/decompiler/flash/action/Action.java index 49c3b2141..d904de64f 100644 --- a/trunk/src/com/jpexs/decompiler/flash/action/Action.java +++ b/trunk/src/com/jpexs/decompiler/flash/action/Action.java @@ -536,13 +536,23 @@ public class Action implements GraphSourceItem { ret.append(Highlighting.hilighOffset("", offset)); + if (a instanceof ActionIf) { + ActionIf aif = (ActionIf) a; + if (aif.jumpUsed && !aif.ignoreUsed) { + aif.setFixBranch(0); + } + if (!aif.jumpUsed && aif.ignoreUsed) { + aif.setFixBranch(1); + } + } + int fixBranch = a.getFixBranch(); if (fixBranch > -1) { if (a instanceof ActionIf) { - ret.append("pop\r\n"); + ret.append("ffdec_deobfuscatepop\r\n"); if (fixBranch == 0) { //jump - ret.append("jump ofs"); - ret.append(Helper.formatAddress(offset + ((ActionIf) a).getJumpOffset())); + ret.append("jump loc"); + ret.append(Helper.formatAddress(a.getAddress() + a.getBytes(version).length + ((ActionIf) a).getJumpOffset())); } else { //nojump, ignore } @@ -1337,10 +1347,10 @@ public class Action implements GraphSourceItem { if (o instanceof Long) { return (Long) o; } - if(o instanceof String){ - try{ - return Double.parseDouble((String)o); - }catch(NumberFormatException nfe){ + if (o instanceof String) { + try { + return Double.parseDouble((String) o); + } catch (NumberFormatException nfe) { return 0; } } diff --git a/trunk/src/com/jpexs/decompiler/flash/action/parser/pcode/ASMParser.java b/trunk/src/com/jpexs/decompiler/flash/action/parser/pcode/ASMParser.java index a2588a0b4..fef9d9d7e 100644 --- a/trunk/src/com/jpexs/decompiler/flash/action/parser/pcode/ASMParser.java +++ b/trunk/src/com/jpexs/decompiler/flash/action/parser/pcode/ASMParser.java @@ -20,6 +20,7 @@ import com.jpexs.decompiler.flash.action.Action; import com.jpexs.decompiler.flash.action.flashlite.ActionFSCommand2; import com.jpexs.decompiler.flash.action.flashlite.ActionStrictMode; import com.jpexs.decompiler.flash.action.parser.ParseException; +import com.jpexs.decompiler.flash.action.special.ActionDeobfuscatePop; import com.jpexs.decompiler.flash.action.special.ActionNop; import com.jpexs.decompiler.flash.action.special.ActionStore; import com.jpexs.decompiler.flash.action.swf3.*; @@ -282,6 +283,8 @@ public class ASMParser { if (!ignoreNops) { a = (new ActionNop()); } + } else if (instructionName.equals("FFDec_DeobfuscatePop".toLowerCase())) { + a = new ActionDeobfuscatePop(); }/* else if(instructionName.startsWith("ofs")) { continue; }*/ else { diff --git a/trunk/src/com/jpexs/decompiler/flash/action/special/ActionDeobfuscatePop.java b/trunk/src/com/jpexs/decompiler/flash/action/special/ActionDeobfuscatePop.java new file mode 100644 index 000000000..cdeab633c --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/action/special/ActionDeobfuscatePop.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2013 JPEXS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.jpexs.decompiler.flash.action.special; + +import com.jpexs.decompiler.flash.action.swf4.ActionPop; +import com.jpexs.decompiler.graph.GraphTargetItem; +import java.util.List; +import java.util.Stack; + +/** + * + * @author JPEXS + */ +public class ActionDeobfuscatePop extends ActionPop { + + public ActionDeobfuscatePop() { + } + + @Override + public String toString() { + return "FFDec_DeobfuscatePop"; + } + + @Override + public void translate(List localData, Stack stack, List output, int staticOperation, String path) { + if (stack.isEmpty()) { + return; + } + GraphTargetItem val = stack.pop(); + } +} diff --git a/trunk/src/com/jpexs/decompiler/flash/action/swf3/ActionWaitForFrame.java b/trunk/src/com/jpexs/decompiler/flash/action/swf3/ActionWaitForFrame.java index 76ba554c2..2fda699d1 100644 --- a/trunk/src/com/jpexs/decompiler/flash/action/swf3/ActionWaitForFrame.java +++ b/trunk/src/com/jpexs/decompiler/flash/action/swf3/ActionWaitForFrame.java @@ -16,6 +16,8 @@ */ package com.jpexs.decompiler.flash.action.swf3; +import com.jpexs.decompiler.flash.Configuration; +import com.jpexs.decompiler.flash.DisassemblyListener; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFOutputStream; @@ -25,8 +27,11 @@ import com.jpexs.decompiler.flash.action.model.DirectValueActionItem; import com.jpexs.decompiler.flash.action.model.clauses.IfFrameLoadedActionItem; import com.jpexs.decompiler.flash.action.parser.ParseException; import com.jpexs.decompiler.flash.action.parser.pcode.FlasmLexer; +import com.jpexs.decompiler.flash.action.special.ActionEnd; import com.jpexs.decompiler.flash.action.special.ActionStore; +import com.jpexs.decompiler.graph.GraphSourceItem; import com.jpexs.decompiler.graph.GraphTargetItem; +import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.ArrayList; @@ -46,15 +51,48 @@ public class ActionWaitForFrame extends Action implements ActionStore { skipCount = sis.readUI8(); skipped = new ArrayList<>(); for (int i = 0; i < skipCount; i++) { - skipped.add(sis.readAction()); + Action a = sis.readAction(); + if (a instanceof ActionEnd) { + skipCount = i; + break; + } + if (a == null) { + skipCount = i; + break; + } + skipped.add(a); + } + boolean deobfuscate = (Boolean) Configuration.getConfig("autoDeobfuscate", true); + if (deobfuscate) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + for (int i = 0; i < skipCount; i++) { + baos.write(skipped.get(i).getBytes(sis.getVersion())); + } + baos.write(new ActionEnd().getBytes(sis.getVersion())); + SWFInputStream sis2 = new SWFInputStream(new ByteArrayInputStream(baos.toByteArray()), sis.getVersion()); + skipped = sis2.readActionList(new ArrayList(), 0, 0, ""); + if (!skipped.isEmpty()) { + if (skipped.get(skipped.size() - 1) instanceof ActionEnd) { + skipped.remove(skipped.size() - 1); + } + } + skipCount = skipped.size(); } } @Override public String toString() { + return "WaitForFrame"; + } + + @Override + public String getASMSource(List container, List knownAddreses, List constantPool, int version, boolean hex) { String ret = "WaitForFrame " + frame + " " + skipCount; for (int i = 0; i < skipped.size(); i++) { - ret += "\r\n" + skipped.get(i).toString(); + if (skipped.get(i) instanceof ActionEnd) { + break; + } + ret += "\r\n" + skipped.get(i).getASMSource(container, knownAddreses, constantPool, version, hex); } return ret; } diff --git a/trunk/src/com/jpexs/decompiler/flash/action/swf4/ActionWaitForFrame2.java b/trunk/src/com/jpexs/decompiler/flash/action/swf4/ActionWaitForFrame2.java index 826a2f2e5..dde0d4934 100644 --- a/trunk/src/com/jpexs/decompiler/flash/action/swf4/ActionWaitForFrame2.java +++ b/trunk/src/com/jpexs/decompiler/flash/action/swf4/ActionWaitForFrame2.java @@ -16,6 +16,8 @@ */ package com.jpexs.decompiler.flash.action.swf4; +import com.jpexs.decompiler.flash.Configuration; +import com.jpexs.decompiler.flash.DisassemblyListener; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFOutputStream; @@ -24,8 +26,11 @@ import com.jpexs.decompiler.flash.action.ActionGraph; import com.jpexs.decompiler.flash.action.model.clauses.IfFrameLoadedActionItem; import com.jpexs.decompiler.flash.action.parser.ParseException; import com.jpexs.decompiler.flash.action.parser.pcode.FlasmLexer; +import com.jpexs.decompiler.flash.action.special.ActionEnd; import com.jpexs.decompiler.flash.action.special.ActionStore; +import com.jpexs.decompiler.graph.GraphSourceItem; import com.jpexs.decompiler.graph.GraphTargetItem; +import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.ArrayList; @@ -59,7 +64,32 @@ public class ActionWaitForFrame2 extends Action implements ActionStore { skipCount = sis.readUI8(); skipped = new ArrayList<>(); for (int i = 0; i < skipCount; i++) { - skipped.add(sis.readAction()); + Action a = sis.readAction(); + if (a instanceof ActionEnd) { + skipCount = i; + break; + } + if (a == null) { + skipCount = i; + break; + } + skipped.add(a); + } + boolean deobfuscate = (Boolean) Configuration.getConfig("autoDeobfuscate", true); + if (deobfuscate) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + for (int i = 0; i < skipCount; i++) { + baos.write(skipped.get(i).getBytes(sis.getVersion())); + } + baos.write(new ActionEnd().getBytes(sis.getVersion())); + SWFInputStream sis2 = new SWFInputStream(new ByteArrayInputStream(baos.toByteArray()), sis.getVersion()); + skipped = sis2.readActionList(new ArrayList(), 0, 0, ""); + if (!skipped.isEmpty()) { + if (skipped.get(skipped.size() - 1) instanceof ActionEnd) { + skipped.remove(skipped.size() - 1); + } + } + skipCount = skipped.size(); } } @@ -82,9 +112,17 @@ public class ActionWaitForFrame2 extends Action implements ActionStore { @Override public String toString() { + return "WaitForFrame2"; + } + + @Override + public String getASMSource(List container, List knownAddreses, List constantPool, int version, boolean hex) { String ret = "WaitForFrame2 " + skipCount; - for (Action a : skipped) { - ret += "\r\n" + a.toString(); + for (int i = 0; i < skipped.size(); i++) { + if (skipped.get(i) instanceof ActionEnd) { + break; + } + ret += "\r\n" + skipped.get(i).getASMSource(container, knownAddreses, constantPool, version, hex); } return ret; } diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/RenameDialog.java b/trunk/src/com/jpexs/decompiler/flash/gui/RenameDialog.java index 88b12e666..f946d501a 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/RenameDialog.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/RenameDialog.java @@ -77,10 +77,11 @@ public class RenameDialog extends AppDialog implements ActionListener { cancelButton.addActionListener(this); add(panButtons, BorderLayout.SOUTH); setModalityType(ModalityType.APPLICATION_MODAL); - View.centerScreen(this); View.setWindowIcon(this); setTitle(translate("dialog.title")); getRootPane().setDefaultButton(okButton); + pack(); + View.centerScreen(this); } @Override diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java index 1b329b323..197e321e5 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java @@ -128,9 +128,10 @@ public class DefineSpriteTag extends CharacterTag implements Container, BoundedT depthMap.put(pot.getDepth(), charId); characterId = (charId); } else { - Integer chi= (depthMap.get(pot.getDepth())); - if(chi!=null) - characterId = chi; + Integer chi = (depthMap.get(pot.getDepth())); + if (chi != null) { + characterId = chi; + } } } if (characterId == -1) { diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DoActionTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DoActionTag.java index 43f744a19..a260ccec0 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DoActionTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DoActionTag.java @@ -23,6 +23,7 @@ import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFOutputStream; import com.jpexs.decompiler.flash.action.Action; +import com.jpexs.decompiler.flash.helpers.Helper; import com.jpexs.decompiler.flash.tags.base.ASMSource; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -47,6 +48,7 @@ public class DoActionTag extends Tag implements ASMSource { /** * Constructor * + * @param swf * @param data Data bytes * @param version SWF version * @param pos diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/base/TextTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/base/TextTag.java index 06992c325..8efde8bc5 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/base/TextTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/base/TextTag.java @@ -175,12 +175,12 @@ public abstract class TextTag extends CharacterTag implements BoundedTag { updateRect(textBounds, x + rect.Xmin, y + rect.Ymin); updateRect(textBounds, x + rect.Xmax, y + rect.Ymax); int adv = entry.glyphAdvance; - + int defaultAdvance; if (font.hasLayout()) { defaultAdvance = 20 * (int) Math.round((double) textHeight * font.getGlyphAdvance(entry.glyphIndex) / (font.getDivider() * 1024.0)); } else { - defaultAdvance = 20 * FontTag.getSystemFontAdvance(aFont, font.glyphToChar(tags, entry.glyphIndex)); + defaultAdvance = 20 * FontTag.getSystemFontAdvance(aFont, font.glyphToChar(tags, entry.glyphIndex)); } letterSpacing = adv - defaultAdvance; x += adv;