diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ScriptPack.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ScriptPack.java index a912b94fe..86a174697 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ScriptPack.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ScriptPack.java @@ -17,11 +17,9 @@ package com.jpexs.decompiler.flash.abc; import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.abc.avm2.AVM2Code; import com.jpexs.decompiler.flash.abc.avm2.ConvertException; import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction; import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instructions; -import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition; import com.jpexs.decompiler.flash.abc.avm2.instructions.debug.DebugFileIns; import com.jpexs.decompiler.flash.abc.avm2.instructions.debug.DebugIns; import com.jpexs.decompiler.flash.abc.avm2.instructions.debug.DebugLineIns; @@ -54,7 +52,6 @@ import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; -import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java index d893694a4..5e97ee298 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java @@ -1176,7 +1176,7 @@ public class AVM2Code implements Cloneable { } writer.newLine(); - List offsets = new ArrayList<>(); + Set importantOffsets = getImportantOffsets(body); if (body != null) { writer.appendNoHilight("body").newLine(); @@ -1197,28 +1197,26 @@ public class AVM2Code implements Cloneable { writer.newLine(); for (int e = 0; e < body.exceptions.length; e++) { + ABCException exception = body.exceptions[e]; writer.appendNoHilight("try"); writer.appendNoHilight(" from "); writer.appendNoHilight("ofs"); - writer.appendNoHilight(Helper.formatAddress(body.exceptions[e].start)); - offsets.add((long) body.exceptions[e].start); + writer.appendNoHilight(Helper.formatAddress(exception.start)); writer.appendNoHilight(" to "); writer.appendNoHilight("ofs"); - writer.appendNoHilight(Helper.formatAddress(body.exceptions[e].end)); - offsets.add((long) body.exceptions[e].end); + writer.appendNoHilight(Helper.formatAddress(exception.end)); writer.appendNoHilight(" target "); writer.appendNoHilight("ofs"); - writer.appendNoHilight(Helper.formatAddress(body.exceptions[e].target)); - offsets.add((long) body.exceptions[e].target); + writer.appendNoHilight(Helper.formatAddress(exception.target)); writer.appendNoHilight(" type "); - writer.hilightSpecial(body.exceptions[e].type_index == 0 ? "null" : constants.getMultiname(body.exceptions[e].type_index).toString(constants, new ArrayList<>()), HighlightSpecialType.TRY_TYPE, e); + writer.hilightSpecial(exception.type_index == 0 ? "null" : constants.getMultiname(exception.type_index).toString(constants, new ArrayList<>()), HighlightSpecialType.TRY_TYPE, e); writer.appendNoHilight(" name "); - writer.hilightSpecial(body.exceptions[e].name_index == 0 ? "null" : constants.getMultiname(body.exceptions[e].name_index).toString(constants, new ArrayList<>()), HighlightSpecialType.TRY_NAME, e); + writer.hilightSpecial(exception.name_index == 0 ? "null" : constants.getMultiname(exception.name_index).toString(constants, new ArrayList<>()), HighlightSpecialType.TRY_NAME, e); writer.newLine(); } } @@ -1226,21 +1224,6 @@ public class AVM2Code implements Cloneable { writer.newLine(); writer.appendNoHilight("code").newLine(); - for (AVM2Instruction ins : code) { - offsets.addAll(ins.getOffsets()); - } - for (AVM2Instruction ins : code) { - if (ins.replaceWith != null) { - for (Object o : ins.replaceWith) { - if (o instanceof ControlFlowTag) { - ControlFlowTag cft = (ControlFlowTag) o; - if (cft.name.equals("appendjump")) { - offsets.add((long) pos2adr(cft.value)); - } - } - } - } - } int ip = 0; int largeLimit = 20000; boolean markOffsets = code.size() <= largeLimit; @@ -1255,7 +1238,7 @@ public class AVM2Code implements Cloneable { writer.appendNoHilight(Helper.bytesToHexString(ins.getBytes())); writer.newLine(); } - if (Configuration.showAllAddresses.get() || offsets.contains(ofs)) { + if (Configuration.showAllAddresses.get() || importantOffsets.contains(ofs)) { writer.appendNoHilight("ofs" + Helper.formatAddress(ofs) + ":"); } /*for (int e = 0; e < body.exceptions.length; e++) { @@ -1329,6 +1312,33 @@ public class AVM2Code implements Cloneable { return writer; } + public Set getImportantOffsets(MethodBody body) { + Set ret = new HashSet<>(); + if (body != null) { + for (ABCException exception : body.exceptions) { + ret.add((long) exception.start); + ret.add((long) exception.end); + ret.add((long) exception.target); + } + } + + for (AVM2Instruction ins : code) { + ret.addAll(ins.getOffsets()); + if (ins.replaceWith != null) { + for (Object o : ins.replaceWith) { + if (o instanceof ControlFlowTag) { + ControlFlowTag cft = (ControlFlowTag) o; + if (cft.name.equals("appendjump")) { + ret.add((long) pos2adr(cft.value)); + } + } + } + } + } + + return ret; + } + public int adr2pos(long address) throws ConvertException { return adr2pos(address, false); } @@ -1383,12 +1393,6 @@ public class AVM2Code implements Cloneable { return (int) (ins.offset + ins.getBytesLength()); } - private List unknownJumps; - - private List ignoredIns; - - boolean isCatched = false; - /** * Test for killed register. CalcKilledStats must be called before * @@ -1516,11 +1520,6 @@ public class AVM2Code implements Cloneable { iploop: while (ip <= end) { - if (ignoredIns.contains(ip)) { - ip++; - continue; - } - boolean processTry = processJumps; //addr = pos2adr(ip); //int ipfix = fixIPAfterDebugLine(ip); @@ -1531,10 +1530,6 @@ public class AVM2Code implements Cloneable { break; } - if (unknownJumps.contains(ip)) { - unknownJumps.remove(Integer.valueOf(ip)); - throw new UnknownJumpException(stack, ip, output); - } if (visited[ip]) { //logger.warning(path + ": Code already visited, ofs:" + Helper.formatAddress(pos2adr(ip)) + ", ip:" + ip); break; @@ -1840,8 +1835,6 @@ public class AVM2Code implements Cloneable { public void initToSource() { toSourceCount = 0; - unknownJumps = new ArrayList<>(); - ignoredIns = new ArrayList<>(); } private void injectDeclarations(List list, boolean[] declaredRegisters, List declaredSlots, ABC abc, MethodBody body) { @@ -2073,7 +2066,7 @@ public class AVM2Code implements Cloneable { for (Long insAddr : insAddrToRemove) { int pos = adr2posNoEx(insAddr); if (pos > -1) { - code.get(pos).ignored = true; + code.get(pos).setIgnored(true, 0); someIgnored = true; } } @@ -2174,14 +2167,9 @@ public class AVM2Code implements Cloneable { * @param body */ public void replaceInstruction(int pos, AVM2Instruction instruction, MethodBody body) { - if (pos < 0) { - pos = 0; - } - if (pos > code.size()) { - pos = code.size(); - } - instruction.offset = code.get(pos).offset; - int oldByteCount = code.get(pos).getBytesLength(); + AVM2Instruction oldInstruction = code.get(pos); + instruction.offset = oldInstruction.offset; + int oldByteCount = oldInstruction.getBytesLength(); int newByteCount = instruction.getBytesLength(); int byteDelta = newByteCount - oldByteCount; @@ -2209,7 +2197,6 @@ public class AVM2Code implements Cloneable { }, body); } code.set(pos, instruction); - //checkValidOffsets(body); } /** @@ -2555,7 +2542,6 @@ public class AVM2Code implements Cloneable { for (int i = 2; i < ins.operands.length; i++) { toVisit.add(adr2pos(pos2adr(ip) + ins.operands[i])); toVisitLast.add(ip); - //visitCode(, ip, refs); } ip = adr2pos(pos2adr(ip) + ins.operands[0]); continue; @@ -2573,7 +2559,6 @@ public class AVM2Code implements Cloneable { try { toVisit.add(adr2pos(pos2adr(ip) + ins.getBytesLength() + ins.operands[0])); toVisitLast.add(ip); - //visitCode(adr2pos(pos2adr(ip) + ins.getBytesLength() + ins.operands[0]), ip, refs); } catch (ConvertException ex) { logger.log(Level.FINE, null, ex); } @@ -2604,119 +2589,6 @@ public class AVM2Code implements Cloneable { return refs; } - private int visitCodeTrap(int ip, int[] visited, AVM2Instruction prev, AVM2Instruction prev2) { - int ret = 0; - while (ip < visited.length) { - visited[ip]++; - if (visited[ip] > 1) { - break; - } - AVM2Instruction ins = code.get(ip); - if (ins.definition instanceof ThrowIns) { - break; - } - if (ins.definition instanceof ReturnValueIns) { - break; - } - if (ins.definition instanceof ReturnVoidIns) { - break; - } - if (ins.definition instanceof LookupSwitchIns) { - try { - for (int i = 2; i < ins.operands.length; i++) { - ret += visitCodeTrap(adr2pos(pos2adr(ip) + ins.operands[i]), visited, prev, prev2); - } - ip = adr2pos(pos2adr(ip) + ins.operands[0]); - prev2 = prev; - prev = ins; - continue; - } catch (ConvertException ex) { - } - } - if (ins.definition instanceof JumpIns) { - try { - ip = adr2pos(pos2adr(ip) + ins.getBytesLength() + ins.operands[0]); - prev2 = prev; - prev = ins; - continue; - } catch (ConvertException ex) { - logger.log(Level.FINE, null, ex); - } - } else if (ins.definition instanceof IfTypeIns) { - if ((prev != null) && (prev2 != null)) { - if ((prev.definition instanceof PushByteIns) && (prev2.definition instanceof PushByteIns)) { - if (ins.definition instanceof IfEqIns) { - prev.ignored = true; - prev2.ignored = true; - if (prev.operands[0] == prev2.operands[0]) { - ins.definition = AVM2Code.instructionSet[AVM2Instructions.Jump]; - visited[ip]--; - } else { - ins.ignored = true; - ip++; - } - ret++; - continue; - } - if (ins.definition instanceof IfNeIns) { - prev.ignored = true; - prev2.ignored = true; - if (prev.operands[0] != prev2.operands[0]) { - ins.definition = AVM2Code.instructionSet[AVM2Instructions.Jump]; - visited[ip]--; - } else { - ins.ignored = true; - ip++; - } - ret++; - continue; - } - } - } - if ((prev != null) && ins.definition instanceof IfTrueIns) { - if (prev.definition instanceof PushTrueIns) { - prev.ignored = true; - ins.definition = AVM2Code.instructionSet[AVM2Instructions.Jump]; - visited[ip]--; - ret++; - continue; - } else if (prev.definition instanceof PushFalseIns) { - prev.ignored = true; - ins.ignored = true; - ret++; - ip++; - continue; - } - } - if ((prev != null) && ins.definition instanceof IfFalseIns) { - if (prev.definition instanceof PushFalseIns) { - prev.ignored = true; - ins.definition = AVM2Code.instructionSet[AVM2Instructions.Jump]; - visited[ip]--; - ret++; - continue; - } else if (prev.definition instanceof PushTrueIns) { - prev.ignored = true; - ins.ignored = true; - ret++; - ip++; - continue; - } - } - try { - ret += visitCodeTrap(adr2pos(pos2adr(ip) + ins.getBytesLength() + ins.operands[0]), visited, prev, prev2); - } catch (ConvertException ex) { - logger.log(Level.FINE, null, ex); - } - } - ip++; - prev2 = prev; - prev = ins; - }; - return ret; - - } - private static class ControlFlowTag { public String name; @@ -2819,26 +2691,24 @@ public class AVM2Code implements Cloneable { } - private void restoreControlFlowPass(AVM2ConstantPool constants, Trait trait, MethodInfo info, MethodBody body, boolean secondpass) throws InterruptedException { + private void restoreControlFlowPass(AVM2ConstantPool constants, Trait trait, MethodInfo info, MethodBody body) throws InterruptedException { try { HashMap> refs; int[] visited2 = new int[code.size()]; refs = visitCode(body); HashMap> appended = new HashMap<>(); - /*if (secondpass) { - restoreControlFlow(code.size() - 1, refs, visited2, appended); - } else*/ { - restoreControlFlow(0, refs, visited2, appended); - for (ABCException e : body.exceptions) { - try { - restoreControlFlow(adr2pos(e.start, true), refs, visited2, appended); - restoreControlFlow(adr2pos(e.target), refs, visited2, appended); - restoreControlFlow(adr2pos(e.end, true), refs, visited2, appended); - } catch (ConvertException ex) { - logger.log(Level.FINE, null, ex); - } + + restoreControlFlow(0, refs, visited2, appended); + for (ABCException e : body.exceptions) { + try { + restoreControlFlow(adr2pos(e.start, true), refs, visited2, appended); + restoreControlFlow(adr2pos(e.target), refs, visited2, appended); + restoreControlFlow(adr2pos(e.end, true), refs, visited2, appended); + } catch (ConvertException ex) { + logger.log(Level.FINE, null, ex); } } + for (int ip : appended.keySet()) { code.get(ip).replaceWith = appended.get(ip); } @@ -2861,7 +2731,6 @@ public class AVM2Code implements Cloneable { } else { acode.code.get(i).mappedOffset = pos2adr(tpos); } - } } this.code = acode.code; @@ -2874,38 +2743,13 @@ public class AVM2Code implements Cloneable { } public void restoreControlFlow(AVM2ConstantPool constants, Trait trait, MethodInfo info, MethodBody body) throws InterruptedException { - restoreControlFlowPass(constants, trait, info, body, false); - //restoreControlFlowPass(constants, body, true); + restoreControlFlowPass(constants, trait, info, body); } - /* - public void removeIgnored(AVM2ConstantPool constants, Trait trait, MethodInfo info, MethodBody body) throws InterruptedException { - try { - List outputMap = new ArrayList<>(); - HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), false); - toASMSource(constants, trait, info, body, outputMap, ScriptExportMode.PCODE, writer); - String src = writer.toString(); - AVM2Code acode = ASM3Parser.parse(new StringReader(src), constants, trait, body, info); - for (int i = 0; i < acode.code.size(); i++) { - if (outputMap.size() > i) { - int tpos = outputMap.get(i); - if (tpos == -1) { - } else if (code.get(tpos).mappedOffset >= 0) { - acode.code.get(i).mappedOffset = code.get(tpos).mappedOffset; - } else { - acode.code.get(i).mappedOffset = pos2adr(tpos); - } - } - } - this.code = acode.code; - } catch (IOException | AVM2ParseException ex) { - } - invalidateCache(); - }*/ public void removeIgnored(MethodBody body) throws InterruptedException { //System.err.println("removing ignored..."); for (int i = 0; i < code.size(); i++) { - if (code.get(i).ignored) { + if (code.get(i).isIgnored()) { removeInstruction(i, body); i--; } @@ -2918,8 +2762,7 @@ public class AVM2Code implements Cloneable { int cnt = 0; for (int i = code.size() - 1; i >= 0; i--) { if (refs.get(i).isEmpty()) { - code.get(i).ignored = true; - //removeInstruction(i, body); + code.get(i).setIgnored(true, 0); cnt++; } } @@ -2930,7 +2773,7 @@ public class AVM2Code implements Cloneable { AVM2Instruction ins = code.get(i); if (ins.definition instanceof JumpIns) { if (ins.operands[0] == 0) { - ins.ignored = true; + ins.setIgnored(true, 0); cnt++; } } @@ -2941,7 +2784,8 @@ public class AVM2Code implements Cloneable { return cnt; } - public void inlineJumpExit() { + public boolean inlineJumpExit() { + boolean modified = false; int csize = code.size(); for (int i = 0; i < csize; i++) { AVM2Instruction ins = code.get(i); @@ -2955,6 +2799,7 @@ public class AVM2Code implements Cloneable { AVM2Instruction ins2 = code.get(ni); if (ins2.isExit()) { code.set(i, new AVM2Instruction(ofs, ins2.definition, ins2.operands)); + // todo: honfika: why to add 3 NOPs? AVM2Instruction nopIns; nopIns = new AVM2Instruction(ofs + 1, AVM2Instructions.Nop, null); code.add(i + 1, nopIns); @@ -2964,14 +2809,16 @@ public class AVM2Code implements Cloneable { code.add(i + 3, nopIns); i += 3; csize = code.size(); + modified = true; } } } catch (ConvertException ex) { //ignore } } - //ofs += insLen; } + + return modified; } public void markMappedOffsets() { @@ -3436,9 +3283,7 @@ public class AVM2Code implements Cloneable { ret.code = codeCopy; } - ret.ignoredIns = new ArrayList<>(); ret.killedRegs = new HashMap<>(); - ret.unknownJumps = new ArrayList<>(); return ret; } catch (CloneNotSupportedException ex) { throw new RuntimeException(); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2ConstantPool.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2ConstantPool.java index 79ca4d1dc..0600d21c1 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2ConstantPool.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2ConstantPool.java @@ -16,10 +16,14 @@ */ package com.jpexs.decompiler.flash.abc.avm2; +import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction; +import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instructions; import com.jpexs.decompiler.flash.abc.types.Decimal; import com.jpexs.decompiler.flash.abc.types.Multiname; import com.jpexs.decompiler.flash.abc.types.Namespace; import com.jpexs.decompiler.flash.abc.types.NamespaceSet; +import com.jpexs.decompiler.flash.ecma.Null; +import com.jpexs.decompiler.flash.ecma.Undefined; import com.jpexs.decompiler.flash.types.annotations.Internal; import com.jpexs.decompiler.graph.DottedChain; import com.jpexs.helpers.HashArrayList; @@ -563,4 +567,36 @@ public class AVM2ConstantPool implements Cloneable { throw new RuntimeException(); } } + + public AVM2Instruction makePush(Object ovalue) { + if (ovalue instanceof Long) { + long value = (Long) ovalue; + if (value >= -128 && value <= 127) { + return new AVM2Instruction(0, AVM2Instructions.PushByte, new int[]{(int) (long) value}); + } else if (value >= -32768 && value <= 32767) { + return new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{((int) (long) value) & 0xffff}); + } else { + return new AVM2Instruction(0, AVM2Instructions.PushInt, new int[]{getIntId(value, true)}); + } + } + if (ovalue instanceof Double) { + return new AVM2Instruction(0, AVM2Instructions.PushDouble, new int[]{getDoubleId((Double) ovalue, true)}); + } + if (ovalue instanceof String) { + return new AVM2Instruction(0, AVM2Instructions.PushString, new int[]{getStringId((String) ovalue, true)}); + } + if (ovalue instanceof Boolean) { + if ((Boolean) ovalue) { + return new AVM2Instruction(0, AVM2Instructions.PushTrue, null); + } + return new AVM2Instruction(0, AVM2Instructions.PushFalse, null); + } + if (ovalue == Null.INSTANCE) { + return new AVM2Instruction(0, AVM2Instructions.PushNull, null); + } + if (ovalue == Undefined.INSTANCE) { + return new AVM2Instruction(0, AVM2Instructions.PushUndefined, null); + } + return null; + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/LocalDataArea.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/LocalDataArea.java index 5dc309659..deb48c1a0 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/LocalDataArea.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/LocalDataArea.java @@ -33,8 +33,6 @@ public class LocalDataArea { public Object returnValue; - public String executionException; - public AVM2RuntimeInfo runtimeInfo; private byte[] domainMemory; @@ -64,6 +62,5 @@ public class LocalDataArea { localRegisters.clear(); jump = null; returnValue = null; - executionException = null; } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorGetSet.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorGetSet.java index e2ee238fa..03b8bfaba 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorGetSet.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorGetSet.java @@ -16,14 +16,12 @@ */ package com.jpexs.decompiler.flash.abc.avm2.deobfuscation; -import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.abc.ABC; import com.jpexs.decompiler.flash.abc.AVM2LocalData; import com.jpexs.decompiler.flash.abc.avm2.AVM2Code; import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool; import com.jpexs.decompiler.flash.abc.avm2.FixItemCounterTranslateStack; import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction; -import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instructions; import com.jpexs.decompiler.flash.abc.avm2.instructions.DeobfuscatePopIns; import com.jpexs.decompiler.flash.abc.avm2.instructions.IfTypeIns; import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition; @@ -37,10 +35,7 @@ import com.jpexs.decompiler.flash.abc.avm2.model.LocalRegAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.UndefinedAVM2Item; import com.jpexs.decompiler.flash.abc.types.MethodBody; import com.jpexs.decompiler.flash.abc.types.traits.Trait; -import com.jpexs.decompiler.flash.action.ActionList; -import com.jpexs.decompiler.flash.ecma.Null; -import com.jpexs.decompiler.flash.ecma.Undefined; -import com.jpexs.decompiler.flash.helpers.SWFDecompilerListener; +import com.jpexs.decompiler.flash.helpers.SWFDecompilerAdapter; import com.jpexs.decompiler.graph.Graph; import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.NotCompileTimeItem; @@ -59,7 +54,7 @@ import java.util.Map; * * @author JPEXS */ -public class AVM2DeobfuscatorGetSet implements SWFDecompilerListener { +public class AVM2DeobfuscatorGetSet extends SWFDecompilerAdapter { private static final UndefinedAVM2Item UNDEFINED_ITEM = new UndefinedAVM2Item(null, null); @@ -67,43 +62,6 @@ public class AVM2DeobfuscatorGetSet implements SWFDecompilerListener { private final int executionLimit = 30000; - @Override - public void actionListParsed(ActionList actions, SWF swf) { - - } - - protected AVM2Instruction makePush(Object ovalue, AVM2ConstantPool cpool) { - if (ovalue instanceof Long) { - long value = (Long) ovalue; - if (value >= -128 && value <= 127) { - return new AVM2Instruction(0, AVM2Instructions.PushByte, new int[]{(int) (long) value}); - } else if (value >= -32768 && value <= 32767) { - return new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{((int) (long) value) & 0xffff}); - } else { - return new AVM2Instruction(0, AVM2Instructions.PushInt, new int[]{cpool.getIntId(value, true)}); - } - } - if (ovalue instanceof Double) { - return new AVM2Instruction(0, AVM2Instructions.PushDouble, new int[]{cpool.getDoubleId((Double) ovalue, true)}); - } - if (ovalue instanceof String) { - return new AVM2Instruction(0, AVM2Instructions.PushString, new int[]{cpool.getStringId((String) ovalue, true)}); - } - if (ovalue instanceof Boolean) { - if ((Boolean) ovalue) { - return new AVM2Instruction(0, AVM2Instructions.PushTrue, null); - } - return new AVM2Instruction(0, AVM2Instructions.PushFalse, null); - } - if (ovalue == Null.INSTANCE) { - return new AVM2Instruction(0, AVM2Instructions.PushNull, null); - } - if (ovalue == Undefined.INSTANCE) { - return new AVM2Instruction(0, AVM2Instructions.PushUndefined, null); - } - return null; - } - protected boolean removeObfuscationGetSets(int classIndex, boolean isStatic, int scriptIndex, ABC abc, MethodBody body, List inlineIns) throws InterruptedException { AVM2Code code = body.getCode(); if (code.code.isEmpty()) { @@ -253,28 +211,6 @@ public class AVM2DeobfuscatorGetSet implements SWFDecompilerListener { } } - @Override - public void actionTreeCreated(List tree, SWF swf) { - } - - @Override - public byte[] proxyFileCatched(byte[] data) { - return null; - } - - @Override - public void swfParsed(SWF swf) { - } - - @Override - public void abcParsed(ABC abc, SWF swf) { - } - - @Override - public void methodBodyParsed(MethodBody body, SWF swf) { - - } - @Override public void avm2CodeRemoveTraps(String path, int classIndex, boolean isStatic, int scriptIndex, ABC abc, Trait trait, int methodInfo, MethodBody body) throws InterruptedException { AVM2Code code = body.getCode(); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorJumps.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorJumps.java index a8567db80..c446e0a35 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorJumps.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorJumps.java @@ -16,7 +16,6 @@ */ package com.jpexs.decompiler.flash.abc.avm2.deobfuscation; -import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.abc.ABC; import com.jpexs.decompiler.flash.abc.avm2.AVM2Code; import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction; @@ -24,7 +23,7 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.IfTypeIns; import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.JumpIns; import com.jpexs.decompiler.flash.abc.types.MethodBody; import com.jpexs.decompiler.flash.abc.types.traits.Trait; -import com.jpexs.decompiler.flash.action.ActionList; +import com.jpexs.decompiler.flash.helpers.SWFDecompilerAdapter; import java.util.List; import java.util.Map; @@ -36,19 +35,11 @@ import java.util.Map; * * @author JPEXS */ -public class AVM2DeobfuscatorJumps extends AVM2DeobfuscatorSimple { - - //private final int executionLimit = 30000; - @Override - public void actionListParsed(ActionList actions, SWF swf) { - - } +public class AVM2DeobfuscatorJumps extends SWFDecompilerAdapter { @Override public void avm2CodeRemoveTraps(String path, int classIndex, boolean isStatic, int scriptIndex, ABC abc, Trait trait, int methodInfo, MethodBody body) throws InterruptedException { - //body.getCode().markMappedOffsets(); - //removeUnreachableInstructions(body.getCode(), cpool, trait, minfo, body); AVM2Code code = body.getCode(); boolean found; @@ -66,12 +57,10 @@ public class AVM2DeobfuscatorJumps extends AVM2DeobfuscatorSimple { AVM2Instruction srcIns = code.code.get(r); if ((srcIns.definition instanceof JumpIns) || ((srcIns.definition instanceof IfTypeIns) && (r != i - 1))) { - { - int oldop = srcIns.operands[0]; - srcIns.operands[0] = (int) (targetAddr - (srcIns.offset + srcIns.getBytesLength())); - if (srcIns.operands[0] != oldop) { - found = true; - } + int oldop = srcIns.operands[0]; + srcIns.operands[0] = (int) (targetAddr - (srcIns.offset + srcIns.getBytesLength())); + if (srcIns.operands[0] != oldop) { + found = true; } } } @@ -79,7 +68,8 @@ public class AVM2DeobfuscatorJumps extends AVM2DeobfuscatorSimple { } } } - removeUnreachableInstructions(body.getCode(), body); + + code.removeDeadCode(body); } while (found); } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorRegisters.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorRegisters.java index 2c470babd..da59bf986 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorRegisters.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorRegisters.java @@ -17,11 +17,11 @@ package com.jpexs.decompiler.flash.abc.avm2.deobfuscation; import com.jpexs.decompiler.flash.BaseLocalData; -import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.abc.ABC; -import com.jpexs.decompiler.flash.abc.AVM2LocalData; import com.jpexs.decompiler.flash.abc.avm2.AVM2Code; import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool; +import com.jpexs.decompiler.flash.abc.avm2.LocalDataArea; +import com.jpexs.decompiler.flash.abc.avm2.exceptions.AVM2ExecutionException; import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction; import com.jpexs.decompiler.flash.abc.avm2.instructions.DeobfuscatePopIns; import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition; @@ -31,13 +31,11 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.SetLocalTypeIn import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ReturnValueIns; import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ReturnVoidIns; import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ThrowIns; -import com.jpexs.decompiler.flash.abc.avm2.model.NullAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.parser.script.Reference; import com.jpexs.decompiler.flash.abc.types.MethodBody; import com.jpexs.decompiler.flash.abc.types.MethodInfo; import com.jpexs.decompiler.flash.abc.types.traits.Trait; -import com.jpexs.decompiler.flash.action.ActionList; -import com.jpexs.decompiler.graph.Graph; +import com.jpexs.decompiler.flash.ecma.Null; import com.jpexs.decompiler.graph.GraphPart; import com.jpexs.decompiler.graph.GraphSource; import com.jpexs.decompiler.graph.GraphSourceItem; @@ -45,11 +43,13 @@ 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.Arrays; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.Stack; +import java.util.logging.Level; +import java.util.logging.Logger; /** * @@ -61,11 +61,6 @@ import java.util.Set; */ public class AVM2DeobfuscatorRegisters extends AVM2DeobfuscatorSimple { - @Override - public void actionListParsed(ActionList actions, SWF swf) { - - } - private Set getRegisters(AVM2Code code) { Set regs = new HashSet<>(); for (AVM2Instruction ins : code.code) { @@ -95,7 +90,7 @@ public class AVM2DeobfuscatorRegisters extends AVM2DeobfuscatorSimple { //System.err.println("regdeo:" + path); MethodBody originalBody = body; - removeUnreachableInstructions(body.getCode(), body); + body.getCode().removeDeadCode(body); Set ignoredRegs = new HashSet<>(); int localReservedCount = body.getLocalReservedCount(); @@ -116,7 +111,7 @@ public class AVM2DeobfuscatorRegisters extends AVM2DeobfuscatorSimple { MethodBody bodybefore = body; body = bodybefore.clone(); - setReg = getFirstRegisterSetter(assignmentRef, classIndex, isStatic, scriptIndex, abc, body, ignoredRegs, ignoredRegGets); + setReg = getFirstRegisterSetter(assignmentRef, body, abc, ignoredRegs, ignoredRegGets); //System.err.println("setreg " + setReg + " ass:" + assignmentRef.getVal()); if (setReg < 0) { break; @@ -140,7 +135,7 @@ public class AVM2DeobfuscatorRegisters extends AVM2DeobfuscatorSimple { AVM2Instruction assignment = assignmentRef.getVal(); InstructionDefinition def = assignment.definition; if ((def instanceof SetLocalTypeIns) || (def instanceof GetLocalTypeIns /*First usage -> value undefined*/)) { - super.removeObfuscationIfs(classIndex, isStatic, scriptIndex, abc, body, Arrays.asList(assignment)); + super.removeObfuscationIfs(classIndex, isStatic, scriptIndex, abc, body, assignment); } if (def instanceof GetLocalTypeIns) { @@ -153,7 +148,7 @@ public class AVM2DeobfuscatorRegisters extends AVM2DeobfuscatorSimple { originalBody.exceptions = body.exceptions; originalBody.setCode(body.getCode()); - removeUnreachableInstructions(body.getCode(), body); + body.getCode().removeDeadCode(body); //System.err.println("/deo"); } @@ -178,31 +173,30 @@ public class AVM2DeobfuscatorRegisters extends AVM2DeobfuscatorSimple { GetLocalTypeIns glt = (GetLocalTypeIns) ins.definition; int regId = glt.getRegisterId(ins); if (singleRegisters.containsKey(regId)) { - code.replaceInstruction(i, makePush(singleRegisters.get(regId).getResult(), cpool), body); + code.replaceInstruction(i, cpool.makePush(singleRegisters.get(regId).getResult()), body); } } } } - private int getFirstRegisterSetter(Reference assignment, int classIndex, boolean isStatic, int scriptIndex, ABC abc, MethodBody body, Set ignoredRegisters, Set ignoredGets) throws InterruptedException { + private int getFirstRegisterSetter(Reference assignment, MethodBody body, ABC abc, Set ignoredRegisters, Set ignoredGets) throws InterruptedException { AVM2Code code = body.getCode(); if (code.code.isEmpty()) { return -1; } - return visitCode(assignment, new HashSet<>(), new TranslateStack("deo"), classIndex, isStatic, body, scriptIndex, abc, code, 0, code.code.size() - 1, ignoredRegisters, ignoredGets); + return visitCode(assignment, new HashSet<>(), new Stack<>(), body, abc, code, 0, code.code.size() - 1, ignoredRegisters, ignoredGets); } - private int visitCode(Reference assignment, Set visited, TranslateStack stack, int classIndex, boolean isStatic, MethodBody body, int scriptIndex, ABC abc, AVM2Code code, int idx, int endIdx, Set ignored, Set ignoredGets) throws InterruptedException { - List output = new ArrayList<>(); - AVM2LocalData localData = newLocalData(scriptIndex, abc, abc.constants, body, isStatic, classIndex); - initLocalRegs(localData, body.getLocalReservedCount(), body.max_regs); - localData.localRegs.put(0, new NullAVM2Item(null, null)); // this + private int visitCode(Reference assignment, Set visited, Stack stack, MethodBody body, ABC abc, AVM2Code code, int idx, int endIdx, Set ignored, Set ignoredGets) throws InterruptedException { + LocalDataArea localData = new LocalDataArea(); + initLocalRegs(localData, body.getLocalReservedCount(), body.max_regs, false); + localData.localRegisters.put(0, Null.INSTANCE); // this List toVisit = new ArrayList<>(); toVisit.add(idx); - List toVisitStacks = new ArrayList<>(); + List> toVisitStacks = new ArrayList<>(); toVisitStacks.add(stack); outer: while (!toVisit.isEmpty()) { @@ -227,12 +221,17 @@ public class AVM2DeobfuscatorRegisters extends AVM2DeobfuscatorSimple { //System.err.println("" + idx + ": " + ins + " stack:" + stack.size()); // do not throw EmptyStackException, much faster - int requiredStackSize = ins.getStackPopCount(localData); + int requiredStackSize = def.getStackPopCount(ins, abc); if (stack.size() < requiredStackSize) { continue outer; } - ins.translate(localData, stack, output, Graph.SOP_USE_STATIC, ""); + localData.operandStack = stack; + try { + ins.definition.execute(localData, abc.constants, ins); + } catch (AVM2ExecutionException ex) { + Logger.getLogger(AVM2DeobfuscatorRegisters.class.getName()).log(Level.SEVERE, null, ex); + } //if (!(def instanceof KillIns)) if (def instanceof SetLocalTypeIns) { @@ -312,7 +311,9 @@ public class AVM2DeobfuscatorRegisters extends AVM2DeobfuscatorSimple { continue; } toVisit.add(nidx); - toVisitStacks.add((TranslateStack) stack.clone()); + @SuppressWarnings("unchecked") + Stack cloneStack = (Stack) stack.clone(); + toVisitStacks.add(cloneStack); } } /*if (ins.definition instanceof IfTypeIns) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorRegistersOld.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorRegistersOld.java new file mode 100644 index 000000000..a52bfad12 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorRegistersOld.java @@ -0,0 +1,335 @@ +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.abc.avm2.deobfuscation; + +import com.jpexs.decompiler.flash.BaseLocalData; +import com.jpexs.decompiler.flash.abc.ABC; +import com.jpexs.decompiler.flash.abc.AVM2LocalData; +import com.jpexs.decompiler.flash.abc.avm2.AVM2Code; +import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool; +import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction; +import com.jpexs.decompiler.flash.abc.avm2.instructions.DeobfuscatePopIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition; +import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.JumpIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.GetLocalTypeIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.SetLocalTypeIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ReturnValueIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ReturnVoidIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ThrowIns; +import com.jpexs.decompiler.flash.abc.avm2.model.NullAVM2Item; +import com.jpexs.decompiler.flash.abc.avm2.parser.script.Reference; +import com.jpexs.decompiler.flash.abc.types.MethodBody; +import com.jpexs.decompiler.flash.abc.types.MethodInfo; +import com.jpexs.decompiler.flash.abc.types.traits.Trait; +import com.jpexs.decompiler.graph.Graph; +import com.jpexs.decompiler.graph.GraphPart; +import com.jpexs.decompiler.graph.GraphSource; +import com.jpexs.decompiler.graph.GraphSourceItem; +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.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * + * AVM2 Deobfuscator removing single assigned local registers. + * + * Example: var a = true; var b = false; ... if(a){ ...ok }else{ not executed } + * + * @author JPEXS + */ +public class AVM2DeobfuscatorRegistersOld extends AVM2DeobfuscatorSimpleOld { + + private Set getRegisters(AVM2Code code) { + Set regs = new HashSet<>(); + for (AVM2Instruction ins : code.code) { + InstructionDefinition def = ins.definition; + if (def instanceof SetLocalTypeIns) { + int regId = ((SetLocalTypeIns) def).getRegisterId(ins); + regs.add(regId); + } else if (def instanceof GetLocalTypeIns) { + int regId = ((GetLocalTypeIns) def).getRegisterId(ins); + regs.add(regId); + } else { + for (int p = 0; p < ins.definition.operands.length; p++) { + int op = ins.definition.operands[p]; + if (op == AVM2Code.DAT_REGISTER_INDEX || op == AVM2Code.DAT_LOCAL_REG_INDEX) { + int regId = ins.operands[p]; + regs.add(regId); + } + } + } + } + + return regs; + } + + @Override + public void avm2CodeRemoveTraps(String path, int classIndex, boolean isStatic, int scriptIndex, ABC abc, Trait trait, int methodInfo, MethodBody body) throws InterruptedException { + //System.err.println("regdeo:" + path); + + MethodBody originalBody = body; + body.getCode().removeDeadCode(body); + Set ignoredRegs = new HashSet<>(); + + int localReservedCount = body.getLocalReservedCount(); + for (int i = 0; i < localReservedCount; i++) { + ignoredRegs.add(i); + } + + int setReg = 0; + List listedRegs = new ArrayList<>(); + List listedLastBodies = new ArrayList<>(); + Set ignoredRegGets = new HashSet<>(); + Reference assignmentRef = new Reference<>(null); + + while (setReg > -1) { + if (Thread.currentThread().isInterrupted()) { + throw new InterruptedException(); + } + + MethodBody bodybefore = body; + body = bodybefore.clone(); + setReg = getFirstRegisterSetter(assignmentRef, classIndex, isStatic, scriptIndex, abc, body, ignoredRegs, ignoredRegGets); + //System.err.println("setreg " + setReg + " ass:" + assignmentRef.getVal()); + if (setReg < 0) { + break; + } + + // if there is second assignment + if (listedRegs.contains(setReg)) { + //System.err.println("second assignment of loc" + setReg + ", ignoring"); + int lindex = listedRegs.indexOf(setReg); + body = listedLastBodies.get(lindex); // switch to body before + ignoredRegs.add(setReg); // this is not obfuscated + for (int i = listedRegs.size() - 1; i >= lindex; i--) { + int r = listedRegs.get(i); + listedRegs.remove(i); + listedLastBodies.remove(i); + ignoredRegGets.remove(r); + } + continue; + } + + AVM2Instruction assignment = assignmentRef.getVal(); + InstructionDefinition def = assignment.definition; + if ((def instanceof SetLocalTypeIns) || (def instanceof GetLocalTypeIns /*First usage -> value undefined*/)) { + super.removeObfuscationIfs(classIndex, isStatic, scriptIndex, abc, body, Arrays.asList(assignment)); + } + + if (def instanceof GetLocalTypeIns) { + ignoredRegGets.add(setReg); + } + + listedRegs.add(setReg); + listedLastBodies.add(bodybefore); + } + + originalBody.exceptions = body.exceptions; + originalBody.setCode(body.getCode()); + body.getCode().removeDeadCode(body); + //System.err.println("/deo"); + } + + private void replaceSingleUseRegisters(Map singleRegisters, List setInss, int classIndex, boolean isStatic, int scriptIndex, ABC abc, AVM2ConstantPool cpool, Trait trait, MethodInfo minfo, MethodBody body) throws InterruptedException { + AVM2Code code = body.getCode(); + + for (int i = 0; i < code.code.size(); i++) { + if (Thread.currentThread().isInterrupted()) { + throw new InterruptedException(); + } + + AVM2Instruction ins = code.code.get(i); + if (((setInss == null) || setInss.contains(ins)) && (ins.definition instanceof SetLocalTypeIns)) { + SetLocalTypeIns slt = (SetLocalTypeIns) ins.definition; + int regId = slt.getRegisterId(ins); + if (singleRegisters.containsKey(regId)) { + code.replaceInstruction(i, new AVM2Instruction(ins.offset, DeobfuscatePopIns.getInstance(), null), body); + } + } + + if (ins.definition instanceof GetLocalTypeIns) { + GetLocalTypeIns glt = (GetLocalTypeIns) ins.definition; + int regId = glt.getRegisterId(ins); + if (singleRegisters.containsKey(regId)) { + code.replaceInstruction(i, cpool.makePush(singleRegisters.get(regId).getResult()), body); + } + } + } + } + + private int getFirstRegisterSetter(Reference assignment, int classIndex, boolean isStatic, int scriptIndex, ABC abc, MethodBody body, Set ignoredRegisters, Set ignoredGets) throws InterruptedException { + AVM2Code code = body.getCode(); + + if (code.code.isEmpty()) { + return -1; + } + + return visitCode(assignment, new HashSet<>(), new TranslateStack("deo"), classIndex, isStatic, body, scriptIndex, abc, code, 0, code.code.size() - 1, ignoredRegisters, ignoredGets); + } + + private int visitCode(Reference assignment, Set visited, TranslateStack stack, int classIndex, boolean isStatic, MethodBody body, int scriptIndex, ABC abc, AVM2Code code, int idx, int endIdx, Set ignored, Set ignoredGets) throws InterruptedException { + List output = new ArrayList<>(); + AVM2LocalData localData = newLocalData(scriptIndex, abc, abc.constants, body, isStatic, classIndex); + initLocalRegs(localData, body.getLocalReservedCount(), body.max_regs); + localData.localRegs.put(0, new NullAVM2Item(null, null)); // this + + List toVisit = new ArrayList<>(); + toVisit.add(idx); + List toVisitStacks = new ArrayList<>(); + toVisitStacks.add(stack); + outer: + while (!toVisit.isEmpty()) { + if (Thread.currentThread().isInterrupted()) { + throw new InterruptedException(); + } + + idx = toVisit.remove(0); + stack = toVisitStacks.remove(0); + + while (true) { + if (idx > endIdx) { + break; + } + if (visited.contains(idx)) { + break; + } + visited.add(idx); + + AVM2Instruction ins = code.code.get(idx); + InstructionDefinition def = ins.definition; + //System.err.println("" + idx + ": " + ins + " stack:" + stack.size()); + + // do not throw EmptyStackException, much faster + int requiredStackSize = ins.getStackPopCount(localData); + if (stack.size() < requiredStackSize) { + continue outer; + } + + ins.translate(localData, stack, output, Graph.SOP_USE_STATIC, ""); + + //if (!(def instanceof KillIns)) + if (def instanceof SetLocalTypeIns) { + int regId = ((SetLocalTypeIns) def).getRegisterId(ins); + if (!ignored.contains(regId)) { + assignment.setVal(ins); + return regId; + } + } else if (def instanceof GetLocalTypeIns) { + int regId = ((GetLocalTypeIns) def).getRegisterId(ins); + if (!ignored.contains(regId) && !ignoredGets.contains(regId)) { + assignment.setVal(ins); + return regId; + } + } else { + for (int p = 0; p < ins.definition.operands.length; p++) { + int op = ins.definition.operands[p]; + if (op == AVM2Code.DAT_REGISTER_INDEX/* || op == AVM2Code.DAT_LOCAL_REG_INDEX ???*/) { + int regId = ins.operands[p]; + if (!ignored.contains(regId)) { + assignment.setVal(ins); + return regId; + } + } + } + } + + idx++; + + if (ins.definition instanceof JumpIns) { + + long address = ins.offset + ins.getBytesLength() + ins.operands[0]; + idx = code.adr2pos(address);//code.indexOf(code.getByAddress(address)); + if (idx == -1) { + throw new TranslateException("Jump target not found: " + address); + } + } + + if (ins.isBranch()) { + List branches = ins.getBranches(new GraphSource() { + + @Override + public int size() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public GraphSourceItem get(int pos) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isEmpty() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public List translatePart(GraphPart part, BaseLocalData localData, TranslateStack stack, int start, int end, int staticOperation, String path) throws InterruptedException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public int adr2pos(long adr) { + return code.adr2pos(adr); + } + + @Override + public long pos2adr(int pos) { + return code.pos2adr(pos); + } + }); + idx = branches.get(0); + for (int n = 1; n < branches.size(); n++) { + //visitCode(visited, (TranslateStack) stack.clone(), classIndex, isStatic, body, scriptIndex, abc, code, branches.get(n), endIdx, result); + int nidx = branches.get(n); + if (visited.contains(nidx)) { + continue; + } + toVisit.add(nidx); + toVisitStacks.add((TranslateStack) stack.clone()); + } + } + /*if (ins.definition instanceof IfTypeIns) { + long address = ins.offset + ins.getBytes().length + ins.operands[0]; + int newIdx = code.adr2pos(address); + if (newIdx == -1) { + throw new TranslateException("If target not found: " + address); + } + visitCode(visited, (TranslateStack) stack.clone(), classIndex, isStatic, body, scriptIndex, abc, code, newIdx, endIdx, result); + }*/ + + if (ins.definition instanceof ReturnValueIns) { + break; + } + + if (ins.definition instanceof ThrowIns) { + break; + } + + if (ins.definition instanceof ReturnVoidIns) { + break; + } + } + } + return -1; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorSimple.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorSimple.java index aa0f37e5d..2eaaa1c6b 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorSimple.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorSimple.java @@ -16,12 +16,10 @@ */ package com.jpexs.decompiler.flash.abc.avm2.deobfuscation; -import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.abc.ABC; -import com.jpexs.decompiler.flash.abc.AVM2LocalData; import com.jpexs.decompiler.flash.abc.avm2.AVM2Code; -import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool; -import com.jpexs.decompiler.flash.abc.avm2.FixItemCounterTranslateStack; +import com.jpexs.decompiler.flash.abc.avm2.LocalDataArea; +import com.jpexs.decompiler.flash.abc.avm2.exceptions.AVM2ExecutionException; import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction; import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instructions; import com.jpexs.decompiler.flash.abc.avm2.instructions.DeobfuscatePopIns; @@ -71,144 +69,63 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushTrueIns; import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushUndefinedIns; import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.SwapIns; import com.jpexs.decompiler.flash.abc.avm2.instructions.types.CoerceOrConvertTypeIns; -import com.jpexs.decompiler.flash.abc.avm2.model.FloatValueAVM2Item; -import com.jpexs.decompiler.flash.abc.avm2.model.IntegerValueAVM2Item; -import com.jpexs.decompiler.flash.abc.avm2.model.NullAVM2Item; -import com.jpexs.decompiler.flash.abc.avm2.model.StringAVM2Item; -import com.jpexs.decompiler.flash.abc.avm2.model.UndefinedAVM2Item; import com.jpexs.decompiler.flash.abc.types.MethodBody; import com.jpexs.decompiler.flash.abc.types.traits.Trait; -import com.jpexs.decompiler.flash.action.ActionList; -import com.jpexs.decompiler.flash.ecma.EcmaScript; -import com.jpexs.decompiler.flash.ecma.Null; +import com.jpexs.decompiler.flash.ecma.NotCompileTime; import com.jpexs.decompiler.flash.ecma.Undefined; -import com.jpexs.decompiler.flash.helpers.SWFDecompilerListener; -import com.jpexs.decompiler.graph.Graph; -import com.jpexs.decompiler.graph.GraphTargetItem; -import com.jpexs.decompiler.graph.NotCompileTimeItem; -import com.jpexs.decompiler.graph.ScopeStack; +import com.jpexs.decompiler.flash.helpers.SWFDecompilerAdapter; +import com.jpexs.decompiler.flash.helpers.collections.FixItemCounterStack; import com.jpexs.decompiler.graph.TranslateException; -import com.jpexs.decompiler.graph.TranslateStack; -import com.jpexs.decompiler.graph.model.FalseItem; -import com.jpexs.decompiler.graph.model.TrueItem; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.Stack; /** * * @author JPEXS */ -public class AVM2DeobfuscatorSimple implements SWFDecompilerListener { - - private static final UndefinedAVM2Item UNDEFINED_ITEM = new UndefinedAVM2Item(null, null); - - private static final NotCompileTimeItem NOT_COMPILE_TIME_UNDEFINED_ITEM = new NotCompileTimeItem(null, null, UNDEFINED_ITEM); +public class AVM2DeobfuscatorSimple extends SWFDecompilerAdapter { private final int executionLimit = 30000; - @Override - public void actionListParsed(ActionList actions, SWF swf) { - - } - - protected AVM2Instruction makePush(Object ovalue, AVM2ConstantPool cpool) { - if (ovalue instanceof Long) { - long value = (Long) ovalue; - if (value >= -128 && value <= 127) { - return new AVM2Instruction(0, AVM2Instructions.PushByte, new int[]{(int) (long) value}); - } else if (value >= -32768 && value <= 32767) { - return new AVM2Instruction(0, AVM2Instructions.PushShort, new int[]{((int) (long) value) & 0xffff}); - } else { - return new AVM2Instruction(0, AVM2Instructions.PushInt, new int[]{cpool.getIntId(value, true)}); - } - } - if (ovalue instanceof Double) { - return new AVM2Instruction(0, AVM2Instructions.PushDouble, new int[]{cpool.getDoubleId((Double) ovalue, true)}); - } - if (ovalue instanceof String) { - return new AVM2Instruction(0, AVM2Instructions.PushString, new int[]{cpool.getStringId((String) ovalue, true)}); - } - if (ovalue instanceof Boolean) { - if ((Boolean) ovalue) { - return new AVM2Instruction(0, AVM2Instructions.PushTrue, null); - } - return new AVM2Instruction(0, AVM2Instructions.PushFalse, null); - } - if (ovalue instanceof Null) { - return new AVM2Instruction(0, AVM2Instructions.PushNull, null); - } - if (ovalue instanceof Undefined) { - return new AVM2Instruction(0, AVM2Instructions.PushUndefined, null); - } - return null; - } - - protected AVM2Instruction makePush(AVM2ConstantPool cpool, GraphTargetItem graphTargetItem) { - AVM2Instruction ins = null; - if (graphTargetItem instanceof IntegerValueAVM2Item) { - IntegerValueAVM2Item iv = (IntegerValueAVM2Item) graphTargetItem; - return makePush(iv.value, cpool); - } else if (graphTargetItem instanceof FloatValueAVM2Item) { - FloatValueAVM2Item fv = (FloatValueAVM2Item) graphTargetItem; - return makePush(fv.value, cpool); - } else if (graphTargetItem instanceof StringAVM2Item) { - StringAVM2Item fv = (StringAVM2Item) graphTargetItem; - return makePush(fv.getValue(), cpool); - } else if (graphTargetItem instanceof TrueItem) { - return makePush(Boolean.TRUE, cpool); - } else if (graphTargetItem instanceof FalseItem) { - return makePush(Boolean.FALSE, cpool); - } else if (graphTargetItem instanceof NullAVM2Item) { - return makePush(Null.INSTANCE, cpool); - } else if (graphTargetItem instanceof UndefinedAVM2Item) { - return makePush(Undefined.INSTANCE, cpool); - } else { - return null; - } - } - - protected boolean removeObfuscationIfs(int classIndex, boolean isStatic, int scriptIndex, ABC abc, MethodBody body, List inlineIns) throws InterruptedException { + protected boolean removeObfuscationIfs(int classIndex, boolean isStatic, int scriptIndex, ABC abc, MethodBody body, AVM2Instruction inlineIns) throws InterruptedException { AVM2Code code = body.getCode(); if (code.code.isEmpty()) { return false; } - Map staticRegs = new HashMap<>(); - for (AVM2Instruction ins : inlineIns) { - if (ins.definition instanceof GetLocalTypeIns) { - staticRegs.put(((GetLocalTypeIns) ins.definition).getRegisterId(ins), new UndefinedAVM2Item(ins, null)); - } + Map staticRegs = new HashMap<>(); + if (inlineIns != null && inlineIns.definition instanceof GetLocalTypeIns) { + staticRegs.put(((GetLocalTypeIns) inlineIns.definition).getRegisterId(inlineIns), Undefined.INSTANCE); } if (code.code.isEmpty()) { return false; } - AVM2LocalData localData = newLocalData(scriptIndex, abc, abc.constants, body, isStatic, classIndex); + FixItemCounterStack stack = new FixItemCounterStack(); + LocalDataArea localData = new LocalDataArea(); + localData.operandStack = stack; + int localReservedCount = body.getLocalReservedCount(); for (int i = 0; i < code.code.size(); i++) { if (Thread.currentThread().isInterrupted()) { throw new InterruptedException(); } - localData.scopeStack.clear(); - localData.localRegs.clear(); - localData.localRegAssignmentIps.clear(); - localData.localRegs.clear(); - initLocalRegs(localData, localReservedCount, body.max_regs); + localData.clear(); + initLocalRegs(localData, localReservedCount, body.max_regs, i == 0); - executeInstructions(staticRegs, body, abc, code, localData, i, code.code.size() - 1, null, inlineIns); + if (executeInstructions(staticRegs, body, abc, code, localData, i, code.code.size() - 1, null, inlineIns)) { + code.removeDeadCode(body); + i--; + } } return false; } - protected void removeUnreachableInstructions(AVM2Code code, MethodBody body) throws InterruptedException { - code.removeDeadCode(body); - } - protected boolean removeZeroJumps(AVM2Code code, MethodBody body) throws InterruptedException { boolean result = false; for (int i = 0; i < code.code.size(); i++) { @@ -228,37 +145,21 @@ public class AVM2DeobfuscatorSimple implements SWFDecompilerListener { return result; } - protected AVM2LocalData newLocalData(int scriptIndex, ABC abc, AVM2ConstantPool cpool, MethodBody body, boolean isStatic, int classIndex) { - AVM2LocalData localData = new AVM2LocalData(); - localData.isStatic = isStatic; - localData.classIndex = classIndex; - localData.localRegs = new HashMap<>(body.max_regs); - localData.localRegAssignmentIps = new HashMap<>(); - localData.scopeStack = new ScopeStack(true); - localData.methodBody = body; - localData.abc = abc; - localData.localRegNames = new HashMap<>(); - localData.scriptIndex = scriptIndex; - localData.ip = 0; - localData.code = body.getCode(); - return localData; - } - - protected void initLocalRegs(AVM2LocalData localData, int localReservedCount, int maxRegs) { + protected void initLocalRegs(LocalDataArea localData, int localReservedCount, int maxRegs, boolean executeFromFirst) { for (int i = 0; i < localReservedCount; i++) { - localData.localRegs.put(i, NOT_COMPILE_TIME_UNDEFINED_ITEM); + localData.localRegisters.put(i, NotCompileTime.INSTANCE); } for (int i = localReservedCount; i < maxRegs; i++) { - localData.localRegs.put(i, UNDEFINED_ITEM); + localData.localRegisters.put(i, executeFromFirst ? Undefined.INSTANCE : NotCompileTime.INSTANCE); } } - private void executeInstructions(Map staticRegs, MethodBody body, ABC abc, AVM2Code code, AVM2LocalData localData, int idx, int endIdx, ExecutionResult result, List inlineIns) throws InterruptedException { - List output = new ArrayList<>(); - - FixItemCounterTranslateStack stack = new FixItemCounterTranslateStack(""); + private boolean executeInstructions(Map staticRegs, MethodBody body, ABC abc, AVM2Code code, LocalDataArea localData, int idx, int endIdx, ExecutionResult result, AVM2Instruction inlineIns) throws InterruptedException { int instructionsProcessed = 0; + FixItemCounterStack stack = (FixItemCounterStack) localData.operandStack; + Set refs = code.getImportantOffsets(body); + boolean modified = false; while (true) { if (idx > endIdx) { break; @@ -269,56 +170,83 @@ public class AVM2DeobfuscatorSimple implements SWFDecompilerListener { } AVM2Instruction ins = code.code.get(idx); - if (ins.definition instanceof NewFunctionIns) { - if (idx + 1 < code.code.size()) { - if (code.code.get(idx + 1).definition instanceof PopIns) { - code.removeInstruction(idx + 1, body); - code.removeInstruction(idx, body); - continue; - } - } - } else { - // do not throw EmptyStackException, much faster - int requiredStackSize = ins.getStackPopCount(localData); - if (stack.size() < requiredStackSize) { - return; - } - - ins.translate(localData, stack, output, Graph.SOP_USE_STATIC, ""); + if (instructionsProcessed > 0 && refs.contains(ins.offset)) { + break; } + modified = modified | code.inlineJumpExit(); InstructionDefinition def = ins.definition; - - if (inlineIns.contains(ins)) { + if (inlineIns == ins) { if (def instanceof SetLocalTypeIns) { int regId = ((SetLocalTypeIns) def).getRegisterId(ins); - staticRegs.put(regId, localData.localRegs.get(regId).getNotCoerced()); + staticRegs.put(regId, localData.localRegisters.get(regId)); code.replaceInstruction(idx, new AVM2Instruction(0, DeobfuscatePopIns.getInstance(), null), body); } } if (def instanceof GetLocalTypeIns) { int regId = ((GetLocalTypeIns) def).getRegisterId(ins); if (staticRegs.containsKey(regId)) { - if (stack.isEmpty()) { - return; - } - - stack.pop(); - AVM2Instruction pushins = makePush(abc.constants, staticRegs.get(regId)); + AVM2Instruction pushins = abc.constants.makePush(staticRegs.get(regId)); if (pushins == null) { - return; + break; } code.replaceInstruction(idx, pushins, body); - stack.push(staticRegs.get(regId)); ins = pushins; def = ins.definition; } } + if (def instanceof NewFunctionIns) { + if (idx + 1 < code.code.size()) { + if (code.code.get(idx + 1).definition instanceof PopIns) { + code.removeInstruction(idx + 1, body); + code.removeInstruction(idx, body); + modified = true; + continue; + } + } + } else { + // do not throw EmptyStackException, much faster + int requiredStackSize = def.getStackPopCount(ins, abc); + if (stack.size() < requiredStackSize) { + break; + } + + if (requiredStackSize > 0 && !def.isNotCompileTimeSupported()) { + boolean notCompileTime = false; + for (int i = 0; i < requiredStackSize; i++) { + if (stack.peek(i + 1) == NotCompileTime.INSTANCE) { + notCompileTime = true; + break; + } + } + + if (notCompileTime) { + break; + } + } + + if (localData.scopeStack.size() < -def.getScopeStackDelta(ins, abc)) { + break; + } + + boolean supported; + try { + localData.jump = null; + supported = def.execute(localData, abc.constants, ins); + } catch (AVM2ExecutionException ex) { + supported = false; + } + + if (!supported) { + break; + } + } + boolean ok = false; // todo: honfika: order by statistics - if (def instanceof PushByteIns + if (def.isNotCompileTimeSupported() || def instanceof PushByteIns || def instanceof PushShortIns || def instanceof PushIntIns || def instanceof PushDoubleIns @@ -361,6 +289,7 @@ public class AVM2DeobfuscatorSimple implements SWFDecompilerListener { || def instanceof StrictEqualsIns || def instanceof PopIns || def instanceof GetLocalTypeIns + || def instanceof SetLocalTypeIns || def instanceof NewFunctionIns || def instanceof CoerceOrConvertTypeIns) { ok = true; @@ -370,43 +299,16 @@ public class AVM2DeobfuscatorSimple implements SWFDecompilerListener { break; } - if (def instanceof GetLocalTypeIns) { - int regId = ((GetLocalTypeIns) def).getRegisterId(ins); - if (staticRegs.containsKey(regId)) { - if (stack.isEmpty()) { - return; - } - - stack.pop(); - stack.push(staticRegs.get(regId)); - } else { - break; - } - } - boolean ifed = false; - if (def instanceof JumpIns) { + if (def instanceof IfTypeIns && !(def instanceof JumpIns)) { long address = ins.offset + ins.getBytesLength() + ins.operands[0]; - idx = code.adr2pos(address); - - if (idx == -1) { - throw new TranslateException("Jump target not found: " + address); - } - } else if (def instanceof IfTypeIns) { - if (stack.isEmpty()) { - return; - } - - GraphTargetItem top = stack.pop(); - Object res = top.getResult(); - long address = ins.offset + ins.getBytesLength() + ins.operands[0]; - int nidx = code.adr2pos(address);//code.indexOf(code.getByAddress(address)); + int nidx = code.adr2pos(address); AVM2Instruction tarIns = code.code.get(nidx); //Some IfType instructions need more than 1 operand, we must pop out all of them int stackCount = -def.getStackDelta(ins, abc); - if (EcmaScript.toBoolean(res)) { + if (localData.jump != null) { //System.err.println("replacing " + ins + " on " + idx + " with jump"); AVM2Instruction jumpIns = new AVM2Instruction(0, AVM2Instructions.Jump, new int[]{0}); //jumpIns.operands[0] = ins.operands[0] /*- ins.getBytes().length*/ + jumpIns.getBytes().length; @@ -426,8 +328,9 @@ public class AVM2DeobfuscatorSimple implements SWFDecompilerListener { //ins.definition = DeobfuscatePopIns.getInstance(); idx++; } + + modified = true; ifed = true; - //break; } else { idx++; } @@ -444,36 +347,24 @@ public class AVM2DeobfuscatorSimple implements SWFDecompilerListener { if (ifed) { break; } + + if (localData.jump != null) { + idx = code.adr2pos(localData.jump); + + if (idx == -1) { + throw new TranslateException("Jump target not found: " + localData.jump); + } + } } - } - - @Override - public void actionTreeCreated(List tree, SWF swf) { - } - - @Override - public byte[] proxyFileCatched(byte[] data) { - return null; - } - - @Override - public void swfParsed(SWF swf) { - } - - @Override - public void abcParsed(ABC abc, SWF swf) { - } - - @Override - public void methodBodyParsed(MethodBody body, SWF swf) { + return modified; } @Override public void avm2CodeRemoveTraps(String path, int classIndex, boolean isStatic, int scriptIndex, ABC abc, Trait trait, int methodInfo, MethodBody body) throws InterruptedException { AVM2Code code = body.getCode(); - removeUnreachableInstructions(code, body); - removeObfuscationIfs(classIndex, isStatic, scriptIndex, abc, body, new ArrayList<>()); + code.removeDeadCode(body); + removeObfuscationIfs(classIndex, isStatic, scriptIndex, abc, body, null); removeZeroJumps(code, body); } @@ -483,6 +374,6 @@ public class AVM2DeobfuscatorSimple implements SWFDecompilerListener { public int instructionsProcessed = -1; - public TranslateStack stack = new TranslateStack("?"); + public Stack stack = new Stack<>(); } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorSimpleOld.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorSimpleOld.java new file mode 100644 index 000000000..ada6efaa4 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorSimpleOld.java @@ -0,0 +1,422 @@ +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.abc.avm2.deobfuscation; + +import com.jpexs.decompiler.flash.abc.ABC; +import com.jpexs.decompiler.flash.abc.AVM2LocalData; +import com.jpexs.decompiler.flash.abc.avm2.AVM2Code; +import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool; +import com.jpexs.decompiler.flash.abc.avm2.FixItemCounterTranslateStack; +import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction; +import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instructions; +import com.jpexs.decompiler.flash.abc.avm2.instructions.DeobfuscatePopIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.IfTypeIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition; +import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.AddIIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.AddIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.DecrementIIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.DecrementIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.DivideIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.IncrementIIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.IncrementIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.ModuloIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.MultiplyIIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.MultiplyIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.NegateIIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.NegateIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.NotIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.SubtractIIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.arithmetic.SubtractIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.BitAndIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.BitOrIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.BitXorIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.LShiftIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.RShiftIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.bitwise.URShiftIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.EqualsIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.GreaterEqualsIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.GreaterThanIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.LessEqualsIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.LessThanIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.comparison.StrictEqualsIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.construction.NewFunctionIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.jumps.JumpIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.GetLocalTypeIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.SetLocalTypeIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.DupIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PopIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushByteIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushDoubleIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushFalseIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushIntIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushNullIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushShortIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushStringIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushTrueIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PushUndefinedIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.SwapIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.types.CoerceOrConvertTypeIns; +import com.jpexs.decompiler.flash.abc.avm2.model.FloatValueAVM2Item; +import com.jpexs.decompiler.flash.abc.avm2.model.IntegerValueAVM2Item; +import com.jpexs.decompiler.flash.abc.avm2.model.NullAVM2Item; +import com.jpexs.decompiler.flash.abc.avm2.model.StringAVM2Item; +import com.jpexs.decompiler.flash.abc.avm2.model.UndefinedAVM2Item; +import com.jpexs.decompiler.flash.abc.types.MethodBody; +import com.jpexs.decompiler.flash.abc.types.traits.Trait; +import com.jpexs.decompiler.flash.ecma.EcmaScript; +import com.jpexs.decompiler.flash.ecma.Null; +import com.jpexs.decompiler.flash.ecma.Undefined; +import com.jpexs.decompiler.flash.helpers.SWFDecompilerAdapter; +import com.jpexs.decompiler.graph.Graph; +import com.jpexs.decompiler.graph.GraphTargetItem; +import com.jpexs.decompiler.graph.NotCompileTimeItem; +import com.jpexs.decompiler.graph.ScopeStack; +import com.jpexs.decompiler.graph.TranslateException; +import com.jpexs.decompiler.graph.TranslateStack; +import com.jpexs.decompiler.graph.model.FalseItem; +import com.jpexs.decompiler.graph.model.TrueItem; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * + * @author JPEXS + */ +public class AVM2DeobfuscatorSimpleOld extends SWFDecompilerAdapter { + + private static final UndefinedAVM2Item UNDEFINED_ITEM = new UndefinedAVM2Item(null, null); + + private static final NotCompileTimeItem NOT_COMPILE_TIME_UNDEFINED_ITEM = new NotCompileTimeItem(null, null, UNDEFINED_ITEM); + + private final int executionLimit = 30000; + + protected AVM2Instruction makePush(AVM2ConstantPool cpool, GraphTargetItem graphTargetItem) { + if (graphTargetItem instanceof IntegerValueAVM2Item) { + IntegerValueAVM2Item iv = (IntegerValueAVM2Item) graphTargetItem; + return cpool.makePush(iv.value); + } else if (graphTargetItem instanceof FloatValueAVM2Item) { + FloatValueAVM2Item fv = (FloatValueAVM2Item) graphTargetItem; + return cpool.makePush(fv.value); + } else if (graphTargetItem instanceof StringAVM2Item) { + StringAVM2Item fv = (StringAVM2Item) graphTargetItem; + return cpool.makePush(fv.getValue()); + } else if (graphTargetItem instanceof TrueItem) { + return cpool.makePush(Boolean.TRUE); + } else if (graphTargetItem instanceof FalseItem) { + return cpool.makePush(Boolean.FALSE); + } else if (graphTargetItem instanceof NullAVM2Item) { + return cpool.makePush(Null.INSTANCE); + } else if (graphTargetItem instanceof UndefinedAVM2Item) { + return cpool.makePush(Undefined.INSTANCE); + } + + return null; + } + + protected boolean removeObfuscationIfs(int classIndex, boolean isStatic, int scriptIndex, ABC abc, MethodBody body, List inlineIns) throws InterruptedException { + AVM2Code code = body.getCode(); + if (code.code.isEmpty()) { + return false; + } + + Map staticRegs = new HashMap<>(); + for (AVM2Instruction ins : inlineIns) { + if (ins.definition instanceof GetLocalTypeIns) { + staticRegs.put(((GetLocalTypeIns) ins.definition).getRegisterId(ins), new UndefinedAVM2Item(ins, null)); + } + } + + if (code.code.isEmpty()) { + return false; + } + + AVM2LocalData localData = newLocalData(scriptIndex, abc, abc.constants, body, isStatic, classIndex); + int localReservedCount = body.getLocalReservedCount(); + for (int i = 0; i < code.code.size(); i++) { + if (Thread.currentThread().isInterrupted()) { + throw new InterruptedException(); + } + + localData.scopeStack.clear(); + localData.localRegs.clear(); + localData.localRegAssignmentIps.clear(); + localData.localRegs.clear(); + initLocalRegs(localData, localReservedCount, body.max_regs); + + executeInstructions(staticRegs, body, abc, code, localData, i, code.code.size() - 1, null, inlineIns); + } + + return false; + } + + protected boolean removeZeroJumps(AVM2Code code, MethodBody body) throws InterruptedException { + boolean result = false; + for (int i = 0; i < code.code.size(); i++) { + AVM2Instruction ins = code.code.get(i); + if (ins.definition instanceof JumpIns) { + if (ins.operands[0] == 0) { + if (Thread.currentThread().isInterrupted()) { + throw new InterruptedException(); + } + + code.removeInstruction(i, body); + i--; + result = true; + } + } + } + return result; + } + + protected AVM2LocalData newLocalData(int scriptIndex, ABC abc, AVM2ConstantPool cpool, MethodBody body, boolean isStatic, int classIndex) { + AVM2LocalData localData = new AVM2LocalData(); + localData.isStatic = isStatic; + localData.classIndex = classIndex; + localData.localRegs = new HashMap<>(body.max_regs); + localData.localRegAssignmentIps = new HashMap<>(); + localData.scopeStack = new ScopeStack(true); + localData.methodBody = body; + localData.abc = abc; + localData.localRegNames = new HashMap<>(); + localData.scriptIndex = scriptIndex; + localData.ip = 0; + localData.code = body.getCode(); + return localData; + } + + protected void initLocalRegs(AVM2LocalData localData, int localReservedCount, int maxRegs) { + for (int i = 0; i < localReservedCount; i++) { + localData.localRegs.put(i, NOT_COMPILE_TIME_UNDEFINED_ITEM); + } + for (int i = localReservedCount; i < maxRegs; i++) { + localData.localRegs.put(i, UNDEFINED_ITEM); + } + } + + private void executeInstructions(Map staticRegs, MethodBody body, ABC abc, AVM2Code code, AVM2LocalData localData, int idx, int endIdx, ExecutionResult result, List inlineIns) throws InterruptedException { + List output = new ArrayList<>(); + + FixItemCounterTranslateStack stack = new FixItemCounterTranslateStack(""); + int instructionsProcessed = 0; + + while (true) { + if (idx > endIdx) { + break; + } + + if (instructionsProcessed > executionLimit) { + break; + } + + AVM2Instruction ins = code.code.get(idx); + if (ins.definition instanceof NewFunctionIns) { + if (idx + 1 < code.code.size()) { + if (code.code.get(idx + 1).definition instanceof PopIns) { + code.removeInstruction(idx + 1, body); + code.removeInstruction(idx, body); + continue; + } + } + } else { + // do not throw EmptyStackException, much faster + int requiredStackSize = ins.getStackPopCount(localData); + if (stack.size() < requiredStackSize) { + return; + } + + ins.translate(localData, stack, output, Graph.SOP_USE_STATIC, ""); + } + + InstructionDefinition def = ins.definition; + + if (inlineIns.contains(ins)) { + if (def instanceof SetLocalTypeIns) { + int regId = ((SetLocalTypeIns) def).getRegisterId(ins); + staticRegs.put(regId, localData.localRegs.get(regId).getNotCoerced()); + code.replaceInstruction(idx, new AVM2Instruction(0, DeobfuscatePopIns.getInstance(), null), body); + } + } + if (def instanceof GetLocalTypeIns) { + int regId = ((GetLocalTypeIns) def).getRegisterId(ins); + if (staticRegs.containsKey(regId)) { + if (stack.isEmpty()) { + return; + } + + stack.pop(); + AVM2Instruction pushins = makePush(abc.constants, staticRegs.get(regId)); + if (pushins == null) { + return; + } + + code.replaceInstruction(idx, pushins, body); + stack.push(staticRegs.get(regId)); + ins = pushins; + def = ins.definition; + } + } + + boolean ok = false; + // todo: honfika: order by statistics + if (def instanceof PushByteIns + || def instanceof PushShortIns + || def instanceof PushIntIns + || def instanceof PushDoubleIns + || def instanceof PushStringIns + || def instanceof PushNullIns + || def instanceof PushUndefinedIns + || def instanceof PushFalseIns + || def instanceof PushTrueIns + || def instanceof DupIns + || def instanceof SwapIns + || def instanceof AddIns + || def instanceof AddIIns + || def instanceof SubtractIns + || def instanceof SubtractIIns + || def instanceof ModuloIns + || def instanceof MultiplyIns + || def instanceof MultiplyIIns// + || def instanceof DivideIns// + || def instanceof BitAndIns + || def instanceof BitXorIns + || def instanceof BitOrIns + || def instanceof LShiftIns + || def instanceof RShiftIns + || def instanceof URShiftIns + || def instanceof EqualsIns + || def instanceof NotIns + || def instanceof NegateIns// + || def instanceof NegateIIns// + || def instanceof IncrementIns// + || def instanceof IncrementIIns// + || def instanceof DecrementIns// + || def instanceof DecrementIIns // + || def instanceof IfTypeIns + || def instanceof JumpIns + || def instanceof EqualsIns + || def instanceof LessEqualsIns + || def instanceof GreaterEqualsIns + || def instanceof GreaterThanIns + || def instanceof LessThanIns + || def instanceof StrictEqualsIns + || def instanceof PopIns + || def instanceof GetLocalTypeIns + || def instanceof NewFunctionIns + || def instanceof CoerceOrConvertTypeIns) { + ok = true; + } + + if (!ok) { + break; + } + + if (def instanceof GetLocalTypeIns) { + int regId = ((GetLocalTypeIns) def).getRegisterId(ins); + if (staticRegs.containsKey(regId)) { + if (stack.isEmpty()) { + return; + } + + stack.pop(); + stack.push(staticRegs.get(regId)); + } else { + break; + } + } + + boolean ifed = false; + if (def instanceof JumpIns) { + long address = ins.offset + ins.getBytesLength() + ins.operands[0]; + idx = code.adr2pos(address); + + if (idx == -1) { + throw new TranslateException("Jump target not found: " + address); + } + } else if (def instanceof IfTypeIns) { + if (stack.isEmpty()) { + return; + } + + GraphTargetItem top = stack.pop(); + Object res = top.getResult(); + long address = ins.offset + ins.getBytesLength() + ins.operands[0]; + int nidx = code.adr2pos(address);//code.indexOf(code.getByAddress(address)); + AVM2Instruction tarIns = code.code.get(nidx); + + //Some IfType instructions need more than 1 operand, we must pop out all of them + int stackCount = -def.getStackDelta(ins, abc); + + if (EcmaScript.toBoolean(res)) { + //System.err.println("replacing " + ins + " on " + idx + " with jump"); + AVM2Instruction jumpIns = new AVM2Instruction(0, AVM2Instructions.Jump, new int[]{0}); + //jumpIns.operands[0] = ins.operands[0] /*- ins.getBytes().length*/ + jumpIns.getBytes().length; + code.replaceInstruction(idx, jumpIns, body); + jumpIns.operands[0] = (int) (tarIns.offset - jumpIns.offset - jumpIns.getBytesLength()); + for (int s = 0; s < stackCount; s++) { + code.insertInstruction(idx, new AVM2Instruction(ins.offset, DeobfuscatePopIns.getInstance(), null), true, body); + } + + idx = code.adr2pos(jumpIns.offset + jumpIns.getBytesLength() + jumpIns.operands[0]); + } else { + //System.err.println("replacing " + ins + " on " + idx + " with pop"); + code.replaceInstruction(idx, new AVM2Instruction(ins.offset, DeobfuscatePopIns.getInstance(), null), body); + for (int s = 1 /*first is replaced*/; s < stackCount; s++) { + code.insertInstruction(idx, new AVM2Instruction(ins.offset, DeobfuscatePopIns.getInstance(), null), true, body); + } + //ins.definition = DeobfuscatePopIns.getInstance(); + idx++; + } + ifed = true; + //break; + } else { + idx++; + } + + instructionsProcessed++; + + if (result != null && stack.allItemsFixed()) { + result.idx = idx == code.code.size() ? idx - 1 : idx; + result.instructionsProcessed = instructionsProcessed; + result.stack.clear(); + result.stack.addAll(stack); + } + + if (ifed) { + break; + } + } + } + + @Override + public void avm2CodeRemoveTraps(String path, int classIndex, boolean isStatic, int scriptIndex, ABC abc, Trait trait, int methodInfo, MethodBody body) throws InterruptedException { + AVM2Code code = body.getCode(); + code.removeDeadCode(body); + removeObfuscationIfs(classIndex, isStatic, scriptIndex, abc, body, new ArrayList<>()); + removeZeroJumps(code, body); + } + + class ExecutionResult { + + public int idx = -1; + + public int instructionsProcessed = -1; + + public TranslateStack stack = new TranslateStack("?"); + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/AVM2Instruction.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/AVM2Instruction.java index 36a84714d..c999dc1da 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/AVM2Instruction.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/AVM2Instruction.java @@ -51,7 +51,7 @@ public class AVM2Instruction implements Cloneable, GraphSourceItem { public String comment; - public boolean ignored = false; + private boolean ignored = false; public long mappedOffset = -1; @@ -303,7 +303,7 @@ public class AVM2Instruction implements Cloneable, GraphSourceItem { } public String getComment() { - if (ignored) { + if (isIgnored()) { return " ;ignored"; } if ((comment == null) || comment.isEmpty()) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/InstructionDefinition.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/InstructionDefinition.java index b413533fb..da8078e18 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/InstructionDefinition.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/InstructionDefinition.java @@ -32,6 +32,7 @@ import com.jpexs.decompiler.flash.abc.avm2.model.AVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.FullMultinameAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.parser.script.Reference; import com.jpexs.decompiler.flash.abc.types.MethodBody; +import com.jpexs.decompiler.flash.abc.types.Multiname; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; import com.jpexs.decompiler.graph.DottedChain; import com.jpexs.decompiler.graph.GraphSourceItem; @@ -124,6 +125,10 @@ public abstract class InstructionDefinition implements Serializable { } } + public boolean isNotCompileTimeSupported() { + return false; + } + public boolean execute(LocalDataArea lda, AVM2ConstantPool constants, AVM2Instruction ins) throws AVM2ExecutionException { //throw new UnsupportedOperationException("Instruction " + instructionName + " not implemented"); return false; @@ -164,18 +169,31 @@ public abstract class InstructionDefinition implements Serializable { return 0; } + protected void resolveMultiname(LocalDataArea localData, AVM2ConstantPool constants, int multinameIndex) { + if (multinameIndex > 0 && multinameIndex < constants.getMultinameCount()) { + Multiname multiname = constants.getMultiname(multinameIndex); + if (multiname.needsName()) { + Object name = localData.operandStack.pop(); + } + if (multiname.needsNs()) { + Object ns = localData.operandStack.pop(); + } + } + } + protected FullMultinameAVM2Item resolveMultiname(AVM2LocalData localData, boolean property, TranslateStack stack, AVM2ConstantPool constants, int multinameIndex, AVM2Instruction ins) { GraphTargetItem ns = null; GraphTargetItem name = null; if (multinameIndex > 0 && multinameIndex < constants.getMultinameCount()) { - if (constants.getMultiname(multinameIndex).needsName()) { + Multiname multiname = constants.getMultiname(multinameIndex); + if (multiname.needsName()) { name = stack.pop(); } - if (constants.getMultiname(multinameIndex).needsNs()) { + if (multiname.needsNs()) { ns = stack.pop(); } - } + return new FullMultinameAVM2Item(property, ins, localData.lineStartInstruction, multinameIndex, name, ns); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/construction/ConstructIns.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/construction/ConstructIns.java index 7b0342d59..f5cd3d684 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/construction/ConstructIns.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/construction/ConstructIns.java @@ -52,7 +52,7 @@ public class ConstructIns extends InstructionDefinition { passArguments.set(i, lda.operandStack.pop()); } Object obj = lda.operandStack.pop();*/ - lda.executionException = "Cannot call constructor"; + //lda.executionException = "Cannot call constructor"; return false; //call construct property of obj //push new instance diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/construction/ConstructPropIns.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/construction/ConstructPropIns.java index ea6a65f0c..d139f783a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/construction/ConstructPropIns.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/construction/ConstructPropIns.java @@ -48,7 +48,7 @@ public class ConstructPropIns extends InstructionDefinition { }*/ //if multiname[multinameIndex] is runtime //pop(name) pop(ns) - lda.executionException = "Cannot construct property"; + //lda.executionException = "Cannot construct property"; return false; //create property //push new instance diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/construction/ConstructSuperIns.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/construction/ConstructSuperIns.java index 1d3d23611..63249d270 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/construction/ConstructSuperIns.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/construction/ConstructSuperIns.java @@ -43,7 +43,7 @@ public class ConstructSuperIns extends InstructionDefinition { passArguments.set(i, lda.operandStack.pop()); } Object obj = lda.operandStack.pop();*/ - lda.executionException = "Cannot call super constructor"; + //lda.executionException = "Cannot call super constructor"; return false; //call construct property of obj //do not push anything diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/executing/CallIns.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/executing/CallIns.java index a8c88fcea..99873cbf6 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/executing/CallIns.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/executing/CallIns.java @@ -24,6 +24,7 @@ import com.jpexs.decompiler.flash.abc.avm2.LocalDataArea; import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction; import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition; import com.jpexs.decompiler.flash.abc.avm2.model.CallAVM2Item; +import com.jpexs.decompiler.flash.ecma.NotCompileTime; import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.TranslateStack; import java.util.ArrayList; @@ -35,18 +36,29 @@ public class CallIns extends InstructionDefinition { super(0x41, "call", new int[]{AVM2Code.DAT_ARG_COUNT}, true); } + @Override + public boolean isNotCompileTimeSupported() { + return true; + } + @Override public boolean execute(LocalDataArea lda, AVM2ConstantPool constants, AVM2Instruction ins) { - /*int argCount = ins.getParamAsLong(constants, 0).intValue(); - List passArguments = new ArrayList(); + int argCount = ins.getParamAsLong(constants, 0).intValue(); + /* List passArguments = new ArrayList(); for (int i = argCount - 1; i >= 0; i--) { passArguments.set(i, lda.operandStack.pop()); - } - Object receiver = lda.operandStack.pop(); - Object function = lda.operandStack.pop();*/ - lda.executionException = "Call to unknown function"; - return false; + }*/ + for (int i = 0; i < argCount; i++) { + lda.operandStack.pop(); + } + + Object receiver = lda.operandStack.pop(); + Object function = lda.operandStack.pop(); + //push(result) + lda.operandStack.push(NotCompileTime.INSTANCE); + //lda.executionException = "Call to unknown function"; + return true; } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/executing/CallMethodIns.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/executing/CallMethodIns.java index 86654667e..2a8925f13 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/executing/CallMethodIns.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/executing/CallMethodIns.java @@ -24,6 +24,7 @@ import com.jpexs.decompiler.flash.abc.avm2.LocalDataArea; import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction; import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition; import com.jpexs.decompiler.flash.abc.avm2.model.CallMethodAVM2Item; +import com.jpexs.decompiler.flash.ecma.NotCompileTime; import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.TranslateStack; import java.util.ArrayList; @@ -35,18 +36,29 @@ public class CallMethodIns extends InstructionDefinition { super(0x43, "callmethod", new int[]{AVM2Code.DAT_METHOD_INDEX, AVM2Code.DAT_ARG_COUNT}, true); } + @Override + public boolean isNotCompileTimeSupported() { + return true; + } + @Override public boolean execute(LocalDataArea lda, AVM2ConstantPool constants, AVM2Instruction ins) { - /*int methodIndex = ins.getParamAsLong(constants, 0).intValue(); //index of object's method - int argCount = ins.getParamAsLong(constants, 1).intValue(); - List passArguments = new ArrayList(); + //int methodIndex = ins.getParamAsLong(constants, 0).intValue(); //index of object's method + int argCount = ins.getParamAsLong(constants, 1).intValue(); + /*List passArguments = new ArrayList(); for (int i = argCount - 1; i >= 0; i--) { passArguments.set(i, lda.operandStack.pop()); - } - Object receiver = lda.operandStack.pop();*/ - lda.executionException = "Call to unknown method"; - return false; + }*/ + for (int i = 0; i < argCount; i++) { + lda.operandStack.pop(); + } + + Object receiver = lda.operandStack.pop(); + //push(result) + lda.operandStack.push(NotCompileTime.INSTANCE); + //lda.executionException = "Call to unknown method"; + return true; } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/executing/CallPropLexIns.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/executing/CallPropLexIns.java index b99c76a33..8e1754669 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/executing/CallPropLexIns.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/executing/CallPropLexIns.java @@ -18,9 +18,12 @@ package com.jpexs.decompiler.flash.abc.avm2.instructions.executing; import com.jpexs.decompiler.flash.abc.ABC; import com.jpexs.decompiler.flash.abc.AVM2LocalData; +import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool; +import com.jpexs.decompiler.flash.abc.avm2.LocalDataArea; import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction; import com.jpexs.decompiler.flash.abc.avm2.model.CallPropertyAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.FullMultinameAVM2Item; +import com.jpexs.decompiler.flash.ecma.NotCompileTime; import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.TranslateStack; import java.util.ArrayList; @@ -33,6 +36,33 @@ public class CallPropLexIns extends CallPropertyIns { instructionCode = 0x4c; } + @Override + public boolean isNotCompileTimeSupported() { + return true; + } + + @Override + public boolean execute(LocalDataArea lda, AVM2ConstantPool constants, AVM2Instruction ins) { + int multinameIndex = ins.operands[0]; + int argCount = ins.getParamAsLong(constants, 1).intValue(); + /*List passArguments = new ArrayList(); + for (int i = argCount - 1; i >= 0; i--) { + passArguments.set(i, lda.operandStack.pop()); + }*/ + for (int i = 0; i < argCount; i++) { + lda.operandStack.pop(); + } + + //if multiname[multinameIndex] is runtime + //pop(name) pop(ns) + resolveMultiname(lda, constants, multinameIndex); + Object obj = lda.operandStack.pop(); + + lda.operandStack.push(NotCompileTime.INSTANCE); + //lda.executionException = "Call to unknown property"; + return true; + } + @Override public void translate(AVM2LocalData localData, TranslateStack stack, AVM2Instruction ins, List output, String path) { int multinameIndex = ins.operands[0]; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/executing/CallPropVoidIns.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/executing/CallPropVoidIns.java index 70c3ce872..463f0f6e6 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/executing/CallPropVoidIns.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/executing/CallPropVoidIns.java @@ -36,22 +36,32 @@ public class CallPropVoidIns extends InstructionDefinition { super(0x4f, "callpropvoid", new int[]{AVM2Code.DAT_MULTINAME_INDEX, AVM2Code.DAT_ARG_COUNT}, true); } + @Override + public boolean isNotCompileTimeSupported() { + return true; + } + @Override public boolean execute(LocalDataArea lda, AVM2ConstantPool constants, AVM2Instruction ins) { //same as callproperty -/* - int multinameIndex = ins.getParamAsLong(constants, 0).intValue(); - int argCount = ins.getParamAsLong(constants, 1).intValue(); - List passArguments = new ArrayList(); + int multinameIndex = ins.operands[0]; + int argCount = ins.getParamAsLong(constants, 1).intValue(); + /*List passArguments = new ArrayList(); for (int i = argCount - 1; i >= 0; i--) { passArguments.set(i, lda.operandStack.pop()); - } - //if multiname[multinameIndex] is runtime - //pop(name) pop(ns) - Object obj = lda.operandStack.pop();*/ - lda.executionException = "Call to unknown property"; - return false; + }*/ + for (int i = 0; i < argCount; i++) { + lda.operandStack.pop(); + } + + //if multiname[multinameIndex] is runtime + //pop(name) pop(ns) + resolveMultiname(lda, constants, multinameIndex); + Object obj = lda.operandStack.pop(); + //do not push anything + //lda.executionException = "Call to unknown property"; + return true; } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/executing/CallPropertyIns.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/executing/CallPropertyIns.java index 809a4e597..17747183a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/executing/CallPropertyIns.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/executing/CallPropertyIns.java @@ -25,6 +25,7 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction; import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition; import com.jpexs.decompiler.flash.abc.avm2.model.CallPropertyAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.FullMultinameAVM2Item; +import com.jpexs.decompiler.flash.ecma.NotCompileTime; import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.TranslateStack; import java.util.ArrayList; @@ -36,20 +37,31 @@ public class CallPropertyIns extends InstructionDefinition { super(0x46, "callproperty", new int[]{AVM2Code.DAT_MULTINAME_INDEX, AVM2Code.DAT_ARG_COUNT}, true); } + @Override + public boolean isNotCompileTimeSupported() { + return true; + } + @Override public boolean execute(LocalDataArea lda, AVM2ConstantPool constants, AVM2Instruction ins) { - /*int multinameIndex = ins.getParamAsLong(constants, 0).intValue(); - int argCount = ins.getParamAsLong(constants, 1).intValue(); - List passArguments = new ArrayList(); + int multinameIndex = ins.operands[0]; + int argCount = ins.getParamAsLong(constants, 1).intValue(); + /*List passArguments = new ArrayList(); for (int i = argCount - 1; i >= 0; i--) { passArguments.set(i, lda.operandStack.pop()); - } - //if multiname[multinameIndex] is runtime - //pop(name) pop(ns) - Object obj = lda.operandStack.pop();*/ - lda.executionException = "Call to unknown property"; - return false; - //push(result) + }*/ + for (int i = 0; i < argCount; i++) { + lda.operandStack.pop(); + } + + //if multiname[multinameIndex] is runtime + //pop(name) pop(ns) + resolveMultiname(lda, constants, multinameIndex); + Object obj = lda.operandStack.pop(); + + lda.operandStack.push(NotCompileTime.INSTANCE); + //lda.executionException = "Call to unknown property"; + return true; } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/executing/CallStaticIns.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/executing/CallStaticIns.java index bdf6dd837..b6dc1a1b2 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/executing/CallStaticIns.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/executing/CallStaticIns.java @@ -24,6 +24,7 @@ import com.jpexs.decompiler.flash.abc.avm2.LocalDataArea; import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction; import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition; import com.jpexs.decompiler.flash.abc.avm2.model.CallStaticAVM2Item; +import com.jpexs.decompiler.flash.ecma.NotCompileTime; import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.TranslateStack; import java.util.ArrayList; @@ -35,18 +36,29 @@ public class CallStaticIns extends InstructionDefinition { super(0x44, "callstatic", new int[]{AVM2Code.DAT_METHOD_INDEX, AVM2Code.DAT_ARG_COUNT}, true); } + @Override + public boolean isNotCompileTimeSupported() { + return true; + } + @Override public boolean execute(LocalDataArea lda, AVM2ConstantPool constants, AVM2Instruction ins) { - /*int methodIndex = ins.getParamAsLong(constants, 0).intValue(); //index of method_info - int argCount = ins.getParamAsLong(constants, 1).intValue(); - List passArguments = new ArrayList(); + //int methodIndex = ins.getParamAsLong(constants, 0).intValue(); //index of method_info + int argCount = ins.getParamAsLong(constants, 1).intValue(); + /*List passArguments = new ArrayList(); for (int i = argCount - 1; i >= 0; i--) { passArguments.set(i, lda.operandStack.pop()); - } - Object receiver = lda.operandStack.pop();*/ - lda.executionException = "Call to unknown static method"; - return false; + }*/ + for (int i = 0; i < argCount; i++) { + lda.operandStack.pop(); + } + + Object receiver = lda.operandStack.pop(); + //push(result) + lda.operandStack.push(NotCompileTime.INSTANCE); + //lda.executionException = "Call to unknown static method"; + return true; } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/executing/CallSuperIns.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/executing/CallSuperIns.java index df4254781..cd6233fb4 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/executing/CallSuperIns.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/executing/CallSuperIns.java @@ -25,6 +25,7 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction; import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition; import com.jpexs.decompiler.flash.abc.avm2.model.CallSuperAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.FullMultinameAVM2Item; +import com.jpexs.decompiler.flash.ecma.NotCompileTime; import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.TranslateStack; import java.util.ArrayList; @@ -36,20 +37,31 @@ public class CallSuperIns extends InstructionDefinition { super(0x45, "callsuper", new int[]{AVM2Code.DAT_MULTINAME_INDEX, AVM2Code.DAT_ARG_COUNT}, true); } + @Override + public boolean isNotCompileTimeSupported() { + return true; + } + @Override public boolean execute(LocalDataArea lda, AVM2ConstantPool constants, AVM2Instruction ins) { - /*int multinameIndex = ins.getParamAsLong(constants, 0).intValue(); - int argCount = ins.getParamAsLong(constants, 1).intValue(); - List passArguments = new ArrayList(); + int multinameIndex = ins.operands[0]; + int argCount = ins.getParamAsLong(constants, 1).intValue(); + /*List passArguments = new ArrayList(); for (int i = argCount - 1; i >= 0; i--) { passArguments.set(i, lda.operandStack.pop()); - } - //if multiname[multinameIndex] is runtime - //pop(name) pop(ns) - Object receiver = lda.operandStack.pop();*/ - lda.executionException = "Call to unknown super method"; - return false; - //push(result) + }*/ + for (int i = 0; i < argCount; i++) { + lda.operandStack.pop(); + } + + //if multiname[multinameIndex] is runtime + //pop(name) pop(ns) + resolveMultiname(lda, constants, multinameIndex); + Object receiver = lda.operandStack.pop(); + + lda.operandStack.push(NotCompileTime.INSTANCE); + //lda.executionException = "Call to unknown super method"; + return true; } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/executing/CallSuperVoidIns.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/executing/CallSuperVoidIns.java index eece56e1d..f15499d7f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/executing/CallSuperVoidIns.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/executing/CallSuperVoidIns.java @@ -36,20 +36,31 @@ public class CallSuperVoidIns extends InstructionDefinition { super(0x4e, "callsupervoid", new int[]{AVM2Code.DAT_MULTINAME_INDEX, AVM2Code.DAT_ARG_COUNT}, true); } + @Override + public boolean isNotCompileTimeSupported() { + return true; + } + @Override public boolean execute(LocalDataArea lda, AVM2ConstantPool constants, AVM2Instruction ins) { - /*int multinameIndex = ins.getParamAsLong(constants, 0).intValue(); - int argCount = ins.getParamAsLong(constants, 1).intValue(); - List passArguments = new ArrayList(); + int multinameIndex = ins.operands[0]; + int argCount = ins.getParamAsLong(constants, 1).intValue(); + /*List passArguments = new ArrayList(); for (int i = argCount - 1; i >= 0; i--) { passArguments.set(i, lda.operandStack.pop()); - } - //if multiname[multinameIndex] is runtime - //pop(name) pop(ns) - Object receiver = lda.operandStack.pop();*/ - lda.executionException = "Call to unknown super method"; - return false; + }*/ + for (int i = 0; i < argCount; i++) { + lda.operandStack.pop(); + } + + //if multiname[multinameIndex] is runtime + //pop(name) pop(ns) + resolveMultiname(lda, constants, multinameIndex); + Object receiver = lda.operandStack.pop(); + //do not push anything + //lda.executionException = "Call to unknown super method"; + return true; } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/DecLocalIIns.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/DecLocalIIns.java index b23cccee0..c8e9c8fc9 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/DecLocalIIns.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/DecLocalIIns.java @@ -26,6 +26,7 @@ import com.jpexs.decompiler.flash.abc.avm2.model.DecLocalAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.IntegerValueAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.operations.SubtractAVM2Item; import com.jpexs.decompiler.flash.ecma.EcmaScript; +import com.jpexs.decompiler.flash.ecma.NotCompileTime; import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.TranslateStack; import java.util.List; @@ -40,7 +41,10 @@ public class DecLocalIIns extends InstructionDefinition { public boolean execute(LocalDataArea lda, AVM2ConstantPool constants, AVM2Instruction ins) { int locRegIndex = ins.getParamAsLong(constants, 0).intValue(); Object obj = lda.localRegisters.get(locRegIndex); - lda.localRegisters.put(locRegIndex, EcmaScript.toInt32(obj) - 1); + if (obj != NotCompileTime.INSTANCE) { + lda.localRegisters.put(locRegIndex, EcmaScript.toInt32(obj) - 1); + } + return true; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/DecLocalIns.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/DecLocalIns.java index 11fd1abe2..0799ba7c0 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/DecLocalIns.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/DecLocalIns.java @@ -26,6 +26,7 @@ import com.jpexs.decompiler.flash.abc.avm2.model.DecLocalAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.IntegerValueAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.operations.SubtractAVM2Item; import com.jpexs.decompiler.flash.ecma.EcmaScript; +import com.jpexs.decompiler.flash.ecma.NotCompileTime; import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.TranslateStack; import java.util.List; @@ -40,7 +41,10 @@ public class DecLocalIns extends InstructionDefinition { public boolean execute(LocalDataArea lda, AVM2ConstantPool constants, AVM2Instruction ins) { int locRegIndex = ins.getParamAsLong(constants, 0).intValue(); Object obj = lda.localRegisters.get(locRegIndex); - lda.localRegisters.put(locRegIndex, EcmaScript.toNumber(obj) - 1); + if (obj != NotCompileTime.INSTANCE) { + lda.localRegisters.put(locRegIndex, EcmaScript.toNumber(obj) - 1); + } + return true; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/IncLocalIIns.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/IncLocalIIns.java index 0b147bb4f..416f16965 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/IncLocalIIns.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/IncLocalIIns.java @@ -26,6 +26,7 @@ import com.jpexs.decompiler.flash.abc.avm2.model.IncLocalAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.IntegerValueAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.operations.AddAVM2Item; import com.jpexs.decompiler.flash.ecma.EcmaScript; +import com.jpexs.decompiler.flash.ecma.NotCompileTime; import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.TranslateStack; import java.util.List; @@ -40,7 +41,10 @@ public class IncLocalIIns extends InstructionDefinition { public boolean execute(LocalDataArea lda, AVM2ConstantPool constants, AVM2Instruction ins) { int locRegIndex = ins.getParamAsLong(constants, 0).intValue(); Object obj = lda.localRegisters.get(locRegIndex); - lda.localRegisters.put(locRegIndex, EcmaScript.toInt32(obj) + 1); + if (obj != NotCompileTime.INSTANCE) { + lda.localRegisters.put(locRegIndex, EcmaScript.toInt32(obj) + 1); + } + return true; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/IncLocalIns.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/IncLocalIns.java index 7561452c6..4a8265561 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/IncLocalIns.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/IncLocalIns.java @@ -26,6 +26,7 @@ import com.jpexs.decompiler.flash.abc.avm2.model.IncLocalAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.IntegerValueAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.operations.AddAVM2Item; import com.jpexs.decompiler.flash.ecma.EcmaScript; +import com.jpexs.decompiler.flash.ecma.NotCompileTime; import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.TranslateStack; import java.util.List; @@ -40,7 +41,10 @@ public class IncLocalIns extends InstructionDefinition { public boolean execute(LocalDataArea lda, AVM2ConstantPool constants, AVM2Instruction ins) { int locRegIndex = ins.getParamAsLong(constants, 0).intValue(); Object obj = lda.localRegisters.get(locRegIndex); - lda.localRegisters.put(locRegIndex, EcmaScript.toNumber(obj) - 1); + if (obj != NotCompileTime.INSTANCE) { + lda.localRegisters.put(locRegIndex, EcmaScript.toNumber(obj) - 1); + } + return true; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/other/DeletePropertyIns.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/other/DeletePropertyIns.java index 599e257f5..4cb5ab5be 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/other/DeletePropertyIns.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/other/DeletePropertyIns.java @@ -42,7 +42,7 @@ public class DeletePropertyIns extends InstructionDefinition { //pop(name) pop(ns) Object obj = lda.operandStack.pop(); //push true if removed*/ - lda.executionException = "Cannot remove property"; + //lda.executionException = "Cannot remove property"; return false; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/other/FindPropertyIns.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/other/FindPropertyIns.java index 5589f7d22..2fb6ef24b 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/other/FindPropertyIns.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/other/FindPropertyIns.java @@ -25,6 +25,7 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction; import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition; import com.jpexs.decompiler.flash.abc.avm2.model.FindPropertyAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.FullMultinameAVM2Item; +import com.jpexs.decompiler.flash.ecma.NotCompileTime; import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.TranslateStack; import java.util.List; @@ -35,12 +36,19 @@ public class FindPropertyIns extends InstructionDefinition { super(0x5e, "findproperty", new int[]{AVM2Code.DAT_MULTINAME_INDEX}, true); } + @Override + public boolean isNotCompileTimeSupported() { + return true; + } + @Override public boolean execute(LocalDataArea lda, AVM2ConstantPool constants, AVM2Instruction ins) { - //int multiIndex = ins.getParamAsLong(constants, 0).intValue(); + int multinameIndex = ins.operands[0]; //if is runtime //pop(name), pop(ns) - lda.executionException = "Cannot find property"; + resolveMultiname(lda, constants, multinameIndex); + lda.operandStack.push(NotCompileTime.INSTANCE); + //lda.executionException = "Cannot find property"; return false; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/other/FindPropertyStrictIns.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/other/FindPropertyStrictIns.java index d890b1275..8f9ed0805 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/other/FindPropertyStrictIns.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/other/FindPropertyStrictIns.java @@ -25,6 +25,7 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction; import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition; import com.jpexs.decompiler.flash.abc.avm2.model.FindPropertyAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.FullMultinameAVM2Item; +import com.jpexs.decompiler.flash.ecma.NotCompileTime; import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.TranslateStack; import java.util.List; @@ -35,13 +36,20 @@ public class FindPropertyStrictIns extends InstructionDefinition { super(0x5d, "findpropstrict", new int[]{AVM2Code.DAT_MULTINAME_INDEX}, true); } + @Override + public boolean isNotCompileTimeSupported() { + return true; + } + @Override public boolean execute(LocalDataArea lda, AVM2ConstantPool constants, AVM2Instruction ins) { - //int multiIndex = ins.getParamAsLong(constants, 0).intValue(); + int multinameIndex = ins.operands[0]; //if is runtime //pop(name), pop(ns) - lda.executionException = "Cannot find property"; - return false; + resolveMultiname(lda, constants, multinameIndex); + lda.operandStack.push(NotCompileTime.INSTANCE); + //lda.executionException = "Cannot find property"; + return true; } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/stack/PushScopeIns.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/stack/PushScopeIns.java index 9c2c489bc..503f57128 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/stack/PushScopeIns.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/stack/PushScopeIns.java @@ -32,6 +32,11 @@ public class PushScopeIns extends InstructionDefinition { super(0x30, "pushscope", new int[]{}, false); } + @Override + public boolean isNotCompileTimeSupported() { + return true; + } + @Override public boolean execute(LocalDataArea lda, AVM2ConstantPool constants, AVM2Instruction ins) { lda.scopeStack.push(lda.operandStack.pop()); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/types/AsTypeIns.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/types/AsTypeIns.java index dae265348..41c6ebecb 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/types/AsTypeIns.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/types/AsTypeIns.java @@ -25,6 +25,7 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction; import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition; import com.jpexs.decompiler.flash.abc.avm2.model.FullMultinameAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.operations.AsTypeAVM2Item; +import com.jpexs.decompiler.flash.ecma.NotCompileTime; import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.TranslateStack; import java.util.List; @@ -40,8 +41,9 @@ public class AsTypeIns extends InstructionDefinition { //Long typeIndex = ins.getParamAsLong(constants, 0); Object obj = lda.operandStack.pop(); //if multiname[typeIndex]==obj - lda.operandStack.push(obj); + //lda.operandStack.push(obj); //else push null + lda.operandStack.push(NotCompileTime.INSTANCE); return true; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/types/AsTypeLateIns.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/types/AsTypeLateIns.java index 4d13bf533..9a955c3c7 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/types/AsTypeLateIns.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/types/AsTypeLateIns.java @@ -23,6 +23,7 @@ import com.jpexs.decompiler.flash.abc.avm2.LocalDataArea; import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction; import com.jpexs.decompiler.flash.abc.avm2.instructions.InstructionDefinition; import com.jpexs.decompiler.flash.abc.avm2.model.operations.AsTypeAVM2Item; +import com.jpexs.decompiler.flash.ecma.NotCompileTime; import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.TranslateStack; import java.util.List; @@ -38,8 +39,9 @@ public class AsTypeLateIns extends InstructionDefinition { //Object objClass = lda.operandStack.pop(); Object obj = lda.operandStack.pop(); //if obj.class=objClass - lda.operandStack.push(obj); + //lda.operandStack.push(obj); //else push null + lda.operandStack.push(NotCompileTime.INSTANCE); return true; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/FullMultinameAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/FullMultinameAVM2Item.java index 1de76957d..060bb248c 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/FullMultinameAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/FullMultinameAVM2Item.java @@ -17,12 +17,11 @@ package com.jpexs.decompiler.flash.abc.avm2.model; import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool; -import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction; import com.jpexs.decompiler.flash.abc.types.Namespace; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; import com.jpexs.decompiler.graph.DottedChain; +import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.GraphSourceItem; -import com.jpexs.decompiler.graph.GraphTargetItem;import com.jpexs.decompiler.graph.GraphSourceItem; import com.jpexs.decompiler.graph.TypeItem; import com.jpexs.decompiler.graph.model.LocalData; import java.util.ArrayList; 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 c54925330..d5e4d9d32 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 @@ -17,9 +17,6 @@ package com.jpexs.decompiler.flash.action.deobfuscation; import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.abc.ABC; -import com.jpexs.decompiler.flash.abc.types.MethodBody; -import com.jpexs.decompiler.flash.abc.types.traits.Trait; import com.jpexs.decompiler.flash.action.Action; import com.jpexs.decompiler.flash.action.ActionList; import com.jpexs.decompiler.flash.action.ActionListReader; @@ -78,7 +75,8 @@ import com.jpexs.decompiler.flash.action.swf5.ActionTypeOf; import com.jpexs.decompiler.flash.action.swf6.ActionGreater; 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.flash.helpers.SWFDecompilerAdapter; +import com.jpexs.decompiler.flash.helpers.collections.FixItemCounterStack; import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.model.FalseItem; import com.jpexs.decompiler.graph.model.PushItem; @@ -95,7 +93,7 @@ import java.util.Stack; * * @author JPEXS */ -public class ActionDeobfuscator implements SWFDecompilerListener { +public class ActionDeobfuscator extends SWFDecompilerAdapter { private final int executionLimit = 5000; @@ -665,27 +663,6 @@ public class ActionDeobfuscator implements SWFDecompilerListener { } } - @Override - public byte[] proxyFileCatched(byte[] data) { - return null; - } - - @Override - public void swfParsed(SWF swf) { - } - - @Override - public void abcParsed(ABC abc, SWF swf) { - } - - @Override - public void methodBodyParsed(MethodBody body, SWF swf) { - } - - @Override - public void avm2CodeRemoveTraps(String path, int classIndex, boolean isStatic, int scriptIndex, ABC abc, Trait trait, int methodInfo, MethodBody body) throws InterruptedException { - } - class ExecutionResult { public ActionItem item; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/UnknownJumpException.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/ecma/NotCompileTime.java similarity index 58% rename from libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/UnknownJumpException.java rename to libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/ecma/NotCompileTime.java index 7856894a7..c1b60ccbb 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/UnknownJumpException.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/ecma/NotCompileTime.java @@ -14,28 +14,19 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library. */ -package com.jpexs.decompiler.flash.abc.avm2; +package com.jpexs.decompiler.flash.ecma; -import com.jpexs.decompiler.graph.GraphTargetItem; -import com.jpexs.decompiler.graph.TranslateStack; -import java.util.List; +import java.io.Serializable; -public class UnknownJumpException extends RuntimeException { +public class NotCompileTime implements Serializable { - public TranslateStack stack; + public static NotCompileTime INSTANCE = new NotCompileTime(); - public int ip; - - public List output; - - public UnknownJumpException(TranslateStack stack, int ip, List output) { - this.stack = stack; - this.ip = ip; - this.output = output; + private NotCompileTime() { } @Override public String toString() { - return "Unknown jump to " + ip; + return "not_compile_time"; } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/SWFDecompilerAdapter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/SWFDecompilerAdapter.java new file mode 100644 index 000000000..287135cdd --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/SWFDecompilerAdapter.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.helpers; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.abc.ABC; +import com.jpexs.decompiler.flash.abc.types.MethodBody; +import com.jpexs.decompiler.flash.abc.types.traits.Trait; +import com.jpexs.decompiler.flash.action.ActionList; +import com.jpexs.decompiler.graph.GraphTargetItem; +import java.util.List; + +/** + * + * @author JPEXS + */ +public class SWFDecompilerAdapter implements SWFDecompilerListener { + + @Override + public byte[] proxyFileCatched(byte[] data) { + return null; + } + + @Override + public void swfParsed(SWF swf) { + } + + @Override + public void actionListParsed(ActionList actions, SWF swf) throws InterruptedException { + } + + @Override + public void actionTreeCreated(List tree, SWF swf) throws InterruptedException { + } + + @Override + public void abcParsed(ABC abc, SWF swf) { + } + + @Override + public void methodBodyParsed(MethodBody body, SWF swf) { + } + + /** + * This method is only called when deobfuscation is enabled and new + * deobfuscation mode is selected + * + * @param path + * @param classIndex + * @param isStatic + * @param scriptIndex + * @param abc + * @param trait + * @param methodInfo + * @param body + * @throws InterruptedException + */ + @Override + public void avm2CodeRemoveTraps(String path, int classIndex, boolean isStatic, int scriptIndex, ABC abc, Trait trait, int methodInfo, MethodBody body) throws InterruptedException { + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/SWFDecompilerListener.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/SWFDecompilerListener.java index faa28a599..f87cbbba4 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/SWFDecompilerListener.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/SWFDecompilerListener.java @@ -42,6 +42,19 @@ public interface SWFDecompilerListener { void methodBodyParsed(MethodBody body, SWF swf); - // this method is only called when deobfuscation is enabled and new deobfuscation mode is selected + /** + * this method is only called when deobfuscation is enabled and new + * deobfuscation mode is selected + * + * @param path + * @param classIndex + * @param isStatic + * @param scriptIndex + * @param abc + * @param trait + * @param methodInfo + * @param body + * @throws InterruptedException + */ void avm2CodeRemoveTraps(String path, int classIndex, boolean isStatic, int scriptIndex, ABC abc, Trait trait, int methodInfo, MethodBody body) throws InterruptedException; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/deobfuscation/FixItemCounterStack.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/collections/FixItemCounterStack.java similarity index 96% rename from libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/deobfuscation/FixItemCounterStack.java rename to libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/collections/FixItemCounterStack.java index 551193696..bd951b00f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/deobfuscation/FixItemCounterStack.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/collections/FixItemCounterStack.java @@ -14,7 +14,7 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library. */ -package com.jpexs.decompiler.flash.action.deobfuscation; +package com.jpexs.decompiler.flash.helpers.collections; import java.util.Stack; diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3DeobfuscatorTest.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3DeobfuscatorTest.java index 3bcf54874..bd2f6bf34 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3DeobfuscatorTest.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/ActionScript3DeobfuscatorTest.java @@ -204,25 +204,25 @@ public class ActionScript3DeobfuscatorTest extends ActionScript2TestBase { + "if(a){" + "trace(\"OK1\");" + "}else{" - + "trace(\"OK2\");" + + "trace(\"FAIL1\");" + "}" + "a = 59;" + "if(b){" - + "trace(\"FAIL1\");" + + "trace(\"FAIL2\");" + "}else{" - + "trace(\"OK3\");" + + "trace(\"OK2\");" + "}"); if (!res.contains("\"OK1\"")) { fail("!OK1:" + res); } + if (res.contains("\"FAIL1\"")) { + fail("FAIL1"); + } if (!res.contains("\"OK2\"")) { fail("!OK2"); } - if (!res.contains("\"OK3\"")) { - fail("!OK3"); - } - if (res.contains("\"FAIL1\"")) { - fail("FAIL1"); + if (res.contains("\"FAIL2\"")) { + fail("FAIL2"); } }