diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java index 2579f75ab..d509e83dc 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java @@ -2341,7 +2341,7 @@ public final class SWF implements SWFContainerItem, Timelined { public static ActionList getCachedActionList(ASMSource src, final List listeners) throws InterruptedException { synchronized (src) { SWF swf = src.getSwf(); - int deobfuscationMode = Configuration.autoDeobfuscate.get() ? (Configuration.deobfuscationOldMode.get() ? 0 : 1) : -1; + int deobfuscationMode = Configuration.autoDeobfuscate.get() ? 1 : 0; if (swf != null && swf.as2PcodeCache.contains(src)) { ActionList result = swf.as2PcodeCache.get(src); if (result.deobfuscationMode == deobfuscationMode) { 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 d03294918..5ce4573b1 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 @@ -19,7 +19,6 @@ package com.jpexs.decompiler.flash.abc.avm2; import com.jpexs.decompiler.flash.EndOfStreamException; import com.jpexs.decompiler.flash.abc.ABC; import com.jpexs.decompiler.flash.abc.ABCInputStream; -import com.jpexs.decompiler.flash.abc.AVM2LocalData; import com.jpexs.decompiler.flash.abc.CopyOutputStream; import com.jpexs.decompiler.flash.abc.avm2.deobfuscation.AVM2DeobfuscatorGetSet; import com.jpexs.decompiler.flash.abc.avm2.deobfuscation.AVM2DeobfuscatorJumps; @@ -31,7 +30,6 @@ import com.jpexs.decompiler.flash.abc.avm2.graph.AVM2Graph; import com.jpexs.decompiler.flash.abc.avm2.graph.AVM2GraphSource; 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.UnknownInstruction; @@ -245,9 +243,7 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.xml.DXNSIns; import com.jpexs.decompiler.flash.abc.avm2.instructions.xml.DXNSLateIns; import com.jpexs.decompiler.flash.abc.avm2.instructions.xml.EscXAttrIns; import com.jpexs.decompiler.flash.abc.avm2.instructions.xml.EscXElemIns; -import com.jpexs.decompiler.flash.abc.avm2.model.BooleanAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.FullMultinameAVM2Item; -import com.jpexs.decompiler.flash.abc.avm2.model.HasNextAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.InitPropertyAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.LocalRegAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.NewFunctionAVM2Item; @@ -278,7 +274,6 @@ import com.jpexs.decompiler.flash.abc.types.traits.TraitSlotConst; import com.jpexs.decompiler.flash.abc.types.traits.Traits; import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.dumpview.DumpInfo; -import com.jpexs.decompiler.flash.ecma.EcmaScript; import com.jpexs.decompiler.flash.ecma.Undefined; import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; @@ -287,13 +282,10 @@ import com.jpexs.decompiler.flash.helpers.SWFDecompilerPlugin; import com.jpexs.decompiler.flash.helpers.hilight.HighlightSpecialType; import com.jpexs.decompiler.graph.Block; import com.jpexs.decompiler.graph.DottedChain; -import com.jpexs.decompiler.graph.Graph; import com.jpexs.decompiler.graph.GraphPart; import com.jpexs.decompiler.graph.GraphSourceItem; 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.TypeItem; import com.jpexs.decompiler.graph.model.ExitItem; @@ -1053,6 +1045,14 @@ public class AVM2Code implements Cloneable { } } + public void markMappedOffsets() { + int ofs = 0; + for (int i = 0; i < code.size(); i++) { + code.get(i).mappedOffset = ofs; + ofs += code.get(i).getBytesLength(); + } + } + @Override public String toString() { StringBuilder s = new StringBuilder(); @@ -1290,26 +1290,13 @@ public class AVM2Code implements Cloneable { if (markOffsets) { writer.append("", ins.mappedOffset > -1 ? ins.mappedOffset : ofs); } - int fixBranch = ins.getFixBranch(); - if (fixBranch > -1) { - if (ins.definition instanceof IfTypeIns) { - for (int i = 0; i < -ins.definition.getStackDelta(ins, null/*IfTypeIns do not require ABCs*/); i++) { - writer.appendNoHilight(DeobfuscatePopIns.NAME).newLine(); - } - if (fixBranch == 0) { // jump - writer.appendNoHilight(JumpIns.NAME + " ofs" + Helper.formatAddress(ofs + ins.getBytesLength() + ins.operands[0])); - } else { - // nojump, ignore - } - } - // TODO: lookupswitch ? + + if (ins.changeJumpTo > -1) { + writer.appendNoHilight(ins.definition.instructionName + " ofs" + Helper.formatAddress(pos2adr(ins.changeJumpTo))); } else { - if (ins.changeJumpTo > -1) { - writer.appendNoHilight(ins.definition.instructionName + " ofs" + Helper.formatAddress(pos2adr(ins.changeJumpTo))); - } else { - writer.appendNoHilight(ins.toStringNoAddress(constants, new ArrayList<>())); - } + writer.appendNoHilight(ins.toStringNoAddress(constants, new ArrayList<>())); } + writer.newLine(); outputMap.add(ip); } @@ -2288,71 +2275,21 @@ public class AVM2Code implements Cloneable { //checkValidOffsets(body); } - @SuppressWarnings("unchecked") - private static AVM2LocalData prepareBranchLocalData(AVM2LocalData localData) { - AVM2LocalData ret = new AVM2LocalData(); - ret.isStatic = localData.isStatic; - ret.classIndex = localData.classIndex; - ret.localRegs = new HashMap<>(localData.localRegs); - ret.scopeStack = (ScopeStack) (localData.scopeStack).clone(); - ret.methodBody = localData.methodBody; - ret.abc = localData.abc; - ret.localRegNames = localData.localRegNames; - ret.fullyQualifiedNames = localData.fullyQualifiedNames; - ret.parsedExceptions = localData.parsedExceptions; - ret.finallyJumps = localData.finallyJumps; - ret.ignoredSwitches = localData.ignoredSwitches; - ret.ignoredSwitches2 = localData.ignoredSwitches2; - ret.scriptIndex = localData.scriptIndex; - ret.localRegAssignmentIps = localData.localRegAssignmentIps; - ret.ip = localData.ip; - ret.refs = localData.refs; - ret.code = localData.code; - return ret; - } - - private int removeTrapsOld(Trait trait, int methodInfo, MethodBody body, ABC abc, int scriptIndex, int classIndex, boolean isStatic, String path) throws InterruptedException { - removeDeadCode(body); - AVM2LocalData localData = new AVM2LocalData(); - localData.isStatic = isStatic; - localData.classIndex = classIndex; - localData.localRegs = new HashMap<>(); - localData.scopeStack = new ScopeStack(); - localData.methodBody = body; - localData.abc = abc; - localData.localRegNames = body.getLocalRegNames(abc); - localData.scriptIndex = scriptIndex; - localData.ip = 0; - HashMap> refs = visitCode(body); - localData.refs = refs; - localData.code = this; - int ret = 0; - ret += removeTrapsOld(trait, methodInfo, body, localData, new AVM2GraphSource(this, false, -1, -1, new HashMap<>(), new ScopeStack(), abc, body, new HashMap<>(), new ArrayList<>(), new HashMap<>(), refs), 0, path, refs); - removeIgnored(body); - removeDeadCode(body); - - return ret; - } - public int removeTraps(Trait trait, int methodInfo, MethodBody body, ABC abc, int scriptIndex, int classIndex, boolean isStatic, String path) throws InterruptedException { - if (Configuration.deobfuscationOldMode.get()) { - return removeTrapsOld(trait, methodInfo, body, abc, scriptIndex, classIndex, isStatic, path); - } else { - SWFDecompilerPlugin.fireAvm2CodeRemoveTraps(path, classIndex, isStatic, scriptIndex, abc, trait, methodInfo, body); - try (Statistics s = new Statistics("AVM2DeobfuscatorGetSet")) { - new AVM2DeobfuscatorGetSet().avm2CodeRemoveTraps(path, classIndex, isStatic, scriptIndex, abc, trait, methodInfo, body); - } - try (Statistics s = new Statistics("AVM2DeobfuscatorSimple")) { - new AVM2DeobfuscatorSimpleOld().avm2CodeRemoveTraps(path, classIndex, isStatic, scriptIndex, abc, trait, methodInfo, body); - } - try (Statistics s = new Statistics("AVM2DeobfuscatorRegisters")) { - new AVM2DeobfuscatorRegistersOld().avm2CodeRemoveTraps(path, classIndex, isStatic, scriptIndex, abc, trait, methodInfo, body); - } - try (Statistics s = new Statistics("AVM2DeobfuscatorJumps")) { - new AVM2DeobfuscatorJumps().avm2CodeRemoveTraps(path, classIndex, isStatic, scriptIndex, abc, trait, methodInfo, body); - } - return 1; + SWFDecompilerPlugin.fireAvm2CodeRemoveTraps(path, classIndex, isStatic, scriptIndex, abc, trait, methodInfo, body); + try (Statistics s = new Statistics("AVM2DeobfuscatorGetSet")) { + new AVM2DeobfuscatorGetSet().avm2CodeRemoveTraps(path, classIndex, isStatic, scriptIndex, abc, trait, methodInfo, body); } + try (Statistics s = new Statistics("AVM2DeobfuscatorSimple")) { + new AVM2DeobfuscatorSimpleOld().avm2CodeRemoveTraps(path, classIndex, isStatic, scriptIndex, abc, trait, methodInfo, body); + } + try (Statistics s = new Statistics("AVM2DeobfuscatorRegisters")) { + new AVM2DeobfuscatorRegistersOld().avm2CodeRemoveTraps(path, classIndex, isStatic, scriptIndex, abc, trait, methodInfo, body); + } + try (Statistics s = new Statistics("AVM2DeobfuscatorJumps")) { + new AVM2DeobfuscatorJumps().avm2CodeRemoveTraps(path, classIndex, isStatic, scriptIndex, abc, trait, methodInfo, body); + } + return 1; } private void handleRegister(CodeStats stats, int reg) { @@ -2495,10 +2432,11 @@ public class AVM2Code implements Cloneable { nextIp = adr2pos(pos2adr(nextIp) + code.get(maxIp).operands[0]); } if (nextIp < stats.instructionStats.length) { - int origScopePos = stats.instructionStats[nextIp].scopepos; - int origStackPos = stats.instructionStats[nextIp].stackpos; + InstructionStats nextIpStat = stats.instructionStats[nextIp]; + int origScopePos = nextIpStat.scopepos; + int origStackPos = nextIpStat.stackpos; - if (prevStart == ex.start && ex.isFinally() && !code.get(nextIp).isExit() && stats.instructionStats[nextIp].seen) { + if (prevStart == ex.start && ex.isFinally() && !code.get(nextIp).isExit() && nextIpStat.seen) { for (int i = 0; i < stats.instructionStats.length; i++) { stats.instructionStats[i].seen = false; } @@ -2612,7 +2550,7 @@ public class AVM2Code implements Cloneable { } } - public void restoreControlFlow(int ip, HashMap> refs, int[] visited2, HashMap> appended) throws ConvertException { + private void restoreControlFlow(int ip, HashMap> refs, int[] visited2, HashMap> appended) throws ConvertException { List buf = new ArrayList<>(); boolean cont = false; int continueip; @@ -2832,25 +2770,6 @@ public class AVM2Code implements Cloneable { return modified; } - public void markMappedOffsets() { - int ofs = 0; - for (int i = 0; i < code.size(); i++) { - code.get(i).mappedOffset = ofs; - ofs += code.get(i).getBytesLength(); - } - } - - private static class Decision { - - public boolean jumpUsed = false; - - public boolean skipUsed = false; - - public Set casesUsed = new HashSet<>(); - - HashMap registers = new HashMap<>(); - } - private static int getMostCommonIp(AVM2GraphSource code, List branches) { List> reachable = new ArrayList<>(); for (int i = 0; i < branches.size(); i++) { @@ -2994,294 +2913,6 @@ public class AVM2Code implements Cloneable { return true; } - @SuppressWarnings("unchecked") - private static int removeTrapsOld(HashMap> refs, boolean secondPass, boolean indeterminate, AVM2LocalData localData, TranslateStack stack, List output, AVM2GraphSource code, int ip, HashMap visited, HashMap> visitedStates, HashMap decisions, String path, int recursionLevel) throws InterruptedException { - if (Thread.currentThread().isInterrupted()) { - throw new InterruptedException(); - } - if (recursionLevel > code.size() + 1) { - throw new TranslateException("removeTraps max recursion level reached."); - } - boolean debugMode = false; - int ret = 0; - iploop: - while ((ip > -1) && ip < code.size()) { - - if (false) { //useVisited) { - if (visited.containsKey(ip)) { - break; - } - if (!visited.containsKey(ip)) { - visited.put(ip, 0); - } else { - visited.put(ip, visited.get(ip) + 1); - } - } else { - HashMap currentState = localData.localRegs; - - if (visitedStates.containsKey(ip)) { - HashMap lastState = visitedStates.get(ip); - if (lastState.equals(currentState)) { - break; - } - } - visitedStates.put(ip, (HashMap) currentState.clone()); - - } - - int curVisited; - if (!visited.containsKey(ip)) { - curVisited = 1; - } else { - curVisited = visited.get(ip) + 1; - } - visited.put(ip, curVisited); - - List r = refs.get(ip); - /*if (r != null) { - if (r.size() > 1) { - if (!stack.isEmpty()) { - GraphTargetItem it = stack.pop(); - stack.push(new NotCompileTimeAVM2Item(null, it)); - } - } - }*/ - - AVM2Instruction ins = code.get(ip); - // Errorneous code inserted by some obfuscators - if (ins.definition instanceof NewObjectIns) { - if (ins.operands[0] > stack.size()) { - ins.setIgnored(true, 0); - } - } - if (ins.definition instanceof NewArrayIns) { - if (ins.operands[0] > stack.size()) { - ins.setIgnored(true, 0); - } - } - - if (ins.isIgnored()) { - ip++; - continue; - } - - if (debugMode) { - System.out.println((indeterminate ? "useV " : "") + (secondPass ? "secondPass " : "") + "Visit " + ip + ": " + ins + " stack:" + stack.toString()); - HashMap registers = localData.localRegs; - System.out.print("Registers:"); - for (int reg : registers.keySet()) { - try { - System.out.print(" r" + reg + ": " + registers.get(reg).getResult()); - } catch (NullPointerException npe) { - System.out.print(" r" + reg + ": " + "null"); - } - } - System.out.println(""); - } - if (secondPass) { - /*if ((ins instanceof AVM2Instruction) && (((AVM2Instruction) ins).definition instanceof PopIns)) { - GraphTargetItem top = stack.peek(); - for (GraphSourceItemPos p : top.getNeededSources()) { - if (p == null) { - continue; - } - if (p.item == null) { - continue; - } - if (p.item.isIgnored()) { - ins.setIgnored(true, 0); - break; - } - } - }*/ - } - - if (ins.definition instanceof NewFunctionIns) { - stack.push(new BooleanAVM2Item(null, null, true)); - } else { - localData.ip = ip; - ins.translate(localData, stack, output, Graph.SOP_USE_STATIC, path); - } - - if (ins.definition instanceof SetLocalTypeIns) { - SetLocalTypeIns slt = (SetLocalTypeIns) ins.definition; - int regId = slt.getRegisterId(ins); - if (indeterminate) { - HashMap registers = localData.localRegs; - GraphTargetItem regVal = registers.get(regId); - if (regVal.isCompileTime()) { - registers.put(regId, new NotCompileTimeItem(null, null, regVal)); - } - } - } - - if (ins.isExit()) { - break; - } - - if (ins.isBranch() || ins.isJump()) { - List branches = ins.getBranches(code); - if (ins.definition instanceof IfTypeIns - && (!(ins.definition instanceof JumpIns)) - && (!stack.isEmpty()) - && (stack.peek().isCompileTime()) - && (!stack.peek().hasSideEffect())) { - boolean condition = EcmaScript.toBoolean(stack.peek().getResult()); - if (debugMode) { - if (condition) { - System.out.println("JUMP"); - } else { - System.out.println("SKIP"); - } - } - Decision dec = new Decision(); - if (decisions.containsKey(ins)) { - dec = decisions.get(ins); - } else { - decisions.put(ins, dec); - } - if (condition) { - dec.jumpUsed = true; - } else { - dec.skipUsed = true; - } - - if (branches.size() > 1) { - if (secondPass) { - if (condition && (dec.jumpUsed) && (!dec.skipUsed)) { - ins.setFixBranch(0); - //ins.definition = AVM2Code.instructionSet[AVM2Instructions.Jump]; - } - if ((!condition) && (!dec.jumpUsed) && (dec.skipUsed)) { - ins.setFixBranch(1); - //ins.setIgnored(true, 0); - } - } - } - GraphTargetItem tar = stack.pop(); - /*if (secondPass && (dec.jumpUsed != dec.skipUsed)) { - for (GraphSourceItemPos pos : tar.getNeededSources()) { - if (pos.item instanceof AVM2Instruction) { - if (((AVM2Instruction) pos.item).definition instanceof DupIns) { - pos.item.setIgnored(true, 0); - break; - } - } - if (pos.item != ins) { - pos.item.setIgnored(true, 0); - } - } - - }*/ - if (branches.size() == 1) { - ip = branches.get(0); - } else { - ip = condition ? branches.get(0) : branches.get(1); - } - continue; - } else { - if (ins.isBranch() && (!ins.isJump())) { - GraphTargetItem top = stack.pop(); - - Decision dec = new Decision(); - if (decisions.containsKey(ins)) { - dec = decisions.get(ins); - } else { - decisions.put(ins, dec); - } - HashMap registers = localData.localRegs; - boolean regChanged = false; - if (!dec.registers.isEmpty()) { - if (dec.registers.size() != registers.size()) { - regChanged = true; - } else { - for (int reg : registers.keySet()) { - if (!dec.registers.containsKey(reg)) { - regChanged = true; - break; - } - if (!registers.get(reg).isCompileTime() && dec.registers.get(reg).isCompileTime()) { - regChanged = true; - break; - } - } - } - } - dec.registers.putAll(registers); - dec.jumpUsed = true; - dec.skipUsed = true; - - if (!regChanged && ((!(top instanceof HasNextAVM2Item) && curVisited > 1) || (curVisited > 2))) { - for (int b : branches) { - int visc = 0; - if (visited.containsKey(b)) { - visc = visited.get(b); - } - if (visc == 0) {//= 0) { //useVisited || (!ins.isJump()) - ret += removeTrapsOld(refs, secondPass, indeterminate, prepareBranchLocalData(localData), brStack, output, code, b, visited, visitedStates, decisions, path, recursionLevel + 1); - } else { - if (debugMode) { - System.out.println("Negative branch:" + b); - } - } - } - } - break; - } - ip++; - } - if (ip < 0 && debugMode) { - System.out.println("Visited Negative: " + ip); - } - return ret; - } - - public static int removeTrapsOld(Trait trait, int methodInfo, MethodBody body, AVM2LocalData localData, AVM2GraphSource code, int addr, String path, HashMap> refs) throws InterruptedException { - HashMap decisions = new HashMap<>(); - removeTrapsOld(refs, false, false, localData, new TranslateStack(path), new ArrayList<>(), code, code.adr2pos(addr), new HashMap<>(), new HashMap<>(), decisions, path, 0); - int cnt = 0; - for (AVM2Instruction src : decisions.keySet()) { - Decision dec = decisions.get(src); - if (dec != null) { - if (src.definition instanceof LookupSwitchIns) { - if (dec.casesUsed.size() == 1) { - for (int c : dec.casesUsed) { - src.setFixBranch(c); - cnt++; - } - } - } else { - if (dec.jumpUsed && !dec.skipUsed) { - src.setFixBranch(0); - cnt++; - } - if (!dec.jumpUsed && dec.skipUsed) { - src.setFixBranch(1); - cnt++; - } - } - } - } - code.getCode().removeIgnored(body); - return cnt; - } - /*public static int removeTraps(AVM2LocalData localData, AVM2GraphSource code, int addr) { - AVM2Graph.translateViaGraph(localData, "", code, new ArrayList(), Graph.SOP_REMOVE_STATIC); - return 1; - }*/ - @Override public AVM2Code clone() { try { 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 c999dc1da..925fb9a29 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 @@ -57,6 +57,8 @@ public class AVM2Instruction implements Cloneable, GraphSourceItem { public int changeJumpTo = -1; + public List replaceWith; + private int line; private String file; @@ -329,8 +331,6 @@ public class AVM2Instruction implements Cloneable, GraphSourceItem { return s; } - public List replaceWith; - @Override public void translate(BaseLocalData localData, TranslateStack stack, List output, int staticOperation, String path) throws InterruptedException { AVM2LocalData aLocalData = (AVM2LocalData) localData; @@ -363,14 +363,11 @@ public class AVM2Instruction implements Cloneable, GraphSourceItem { @Override public boolean isJump() { - return (definition instanceof JumpIns) || (fixedBranch > -1); + return definition instanceof JumpIns; } @Override public boolean isBranch() { - if (fixedBranch > -1) { - return false; - } return (definition instanceof IfTypeIns) || (definition instanceof LookupSwitchIns); } @@ -389,23 +386,15 @@ public class AVM2Instruction implements Cloneable, GraphSourceItem { List ret = new ArrayList<>(); if (definition instanceof IfTypeIns) { - if (fixedBranch == -1 || fixedBranch == 0) { - ret.add(code.adr2pos(offset + getBytesLength() + operands[0])); - } + ret.add(code.adr2pos(offset + getBytesLength() + operands[0])); if (!(definition instanceof JumpIns)) { - if (fixedBranch == -1 || fixedBranch == 1) { - ret.add(code.adr2pos(offset + getBytesLength())); - } + ret.add(code.adr2pos(offset + getBytesLength())); } } if (definition instanceof LookupSwitchIns) { - if (fixedBranch == -1 || fixedBranch == 0) { - ret.add(code.adr2pos(offset + operands[0])); - } + ret.add(code.adr2pos(offset + operands[0])); for (int k = 2; k < operands.length; k++) { - if (fixedBranch == -1 || fixedBranch == k - 1) { - ret.add(code.adr2pos(offset + operands[k])); - } + ret.add(code.adr2pos(offset + operands[k])); } } return ret; @@ -421,16 +410,6 @@ public class AVM2Instruction implements Cloneable, GraphSourceItem { this.ignored = ignored; } - public void setFixBranch(int pos) { - this.fixedBranch = pos; - } - - private int fixedBranch = -1; - - public int getFixBranch() { - return fixedBranch; - } - @Override public boolean isDeobfuscatePop() { return definition instanceof DeobfuscatePopIns; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/ConvertData.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/ConvertData.java index 59f7f8d3f..9eba72b81 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/ConvertData.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/ConvertData.java @@ -32,6 +32,6 @@ public class ConvertData { public Map assignedValues = new HashMap<>(); public ConvertData() { - deobfuscationMode = Configuration.autoDeobfuscate.get() ? (Configuration.deobfuscationOldMode.get() ? 0 : 1) : -1; + deobfuscationMode = Configuration.autoDeobfuscate.get() ? 1 : 0; } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java index 03ce1a3e3..fe6964673 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/MethodBody.java @@ -384,7 +384,7 @@ public final class MethodBody implements Cloneable { code.markMappedOffsets(); code.fixJumps(path, body); - if (convertData.deobfuscationMode != -1) { + if (convertData.deobfuscationMode != 0) { try { code.removeTraps(trait, method_info, body, abc, scriptIndex, classIndex, isStatic, path); } catch (ThreadDeath | InterruptedException ex) { @@ -405,7 +405,7 @@ public final class MethodBody implements Cloneable { public String toSource() { ConvertData convertData = new ConvertData(); - convertData.deobfuscationMode = -1; + convertData.deobfuscationMode = 0; try { convert(convertData, "", ScriptExportMode.AS, false, method_info, 0, 0, abc, null, new ScopeStack(), 0, new NulWriter(), new ArrayList<>(), new ArrayList<>(), true); HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), false); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/Action.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/Action.java index 30aed124c..4cb80f780 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/Action.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/Action.java @@ -838,8 +838,7 @@ public abstract class Action implements GraphSourceItem { int staticOperation = Graph.SOP_USE_STATIC; //(Boolean) Configuration.getConfig("autoDeobfuscate", true) ? Graph.SOP_SKIP_STATIC : Graph.SOP_USE_STATIC; List tree = actionsToTree(new HashMap<>(), new HashMap<>(), new HashMap<>(), actions, version, staticOperation, path); SWFDecompilerPlugin.fireActionTreeCreated(tree, swf); - int deobfuscationMode = Configuration.autoDeobfuscate.get() ? (Configuration.deobfuscationOldMode.get() ? 0 : 1) : -1; - if (deobfuscationMode == 1) { + if (Configuration.autoDeobfuscate.get()) { new ActionDeobfuscator().actionTreeCreated(tree, swf); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionListReader.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionListReader.java index 0dabf6967..54d259fed 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionListReader.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionListReader.java @@ -20,45 +20,26 @@ import com.jpexs.decompiler.flash.DisassemblyListener; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.action.deobfuscation.ActionDeobfuscator; import com.jpexs.decompiler.flash.action.model.ConstantPool; -import com.jpexs.decompiler.flash.action.model.DirectValueActionItem; import com.jpexs.decompiler.flash.action.special.ActionDeobfuscateJump; import com.jpexs.decompiler.flash.action.special.ActionEnd; import com.jpexs.decompiler.flash.action.special.ActionNop; import com.jpexs.decompiler.flash.action.special.ActionStore; -import com.jpexs.decompiler.flash.action.swf4.ActionEquals; import com.jpexs.decompiler.flash.action.swf4.ActionIf; import com.jpexs.decompiler.flash.action.swf4.ActionJump; import com.jpexs.decompiler.flash.action.swf4.ActionPush; import com.jpexs.decompiler.flash.action.swf5.ActionConstantPool; -import com.jpexs.decompiler.flash.action.swf5.ActionDefineFunction; -import com.jpexs.decompiler.flash.action.swf5.ActionEquals2; -import com.jpexs.decompiler.flash.action.swf5.ActionStoreRegister; -import com.jpexs.decompiler.flash.action.swf7.ActionDefineFunction2; import com.jpexs.decompiler.flash.configuration.Configuration; -import com.jpexs.decompiler.flash.ecma.EcmaScript; -import com.jpexs.decompiler.flash.ecma.Null; -import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; import com.jpexs.decompiler.flash.helpers.SWFDecompilerPlugin; -import com.jpexs.decompiler.graph.Graph; -import com.jpexs.decompiler.graph.GraphSourceItem; import com.jpexs.decompiler.graph.GraphSourceItemContainer; -import com.jpexs.decompiler.graph.GraphTargetItem; -import com.jpexs.decompiler.graph.NotCompileTimeItem; -import com.jpexs.decompiler.graph.TranslateException; -import com.jpexs.decompiler.graph.TranslateStack; -import com.jpexs.decompiler.graph.model.LocalData; import com.jpexs.helpers.CancellableWorker; -import com.jpexs.helpers.Helper; import com.jpexs.helpers.stat.Statistics; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; -import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Queue; -import java.util.Scanner; import java.util.TreeMap; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; @@ -169,17 +150,9 @@ public class ActionListReader { actions = fixActionList(actions, null); } - if (deobfuscationMode == 0) { + if (deobfuscationMode == 1) { try { - actions = deobfuscateActionListOld(listeners, actions, version, 0, path); - updateActionLengths(actions); - } catch (OutOfMemoryError | StackOverflowError | TranslateException ex) { - // keep orignal (not deobfuscated) actions - logger.log(Level.SEVERE, null, ex); - } - } else if (deobfuscationMode == 1) { - try { - try (Statistics s = new Statistics("ActionDeobfuscatorSimpleFast")) { + try (Statistics s = new Statistics("ActionDeobfuscator")) { new ActionDeobfuscator().actionListParsed(actions, sis.getSwf()); } } catch (ThreadDeath | InterruptedException ex) { @@ -249,81 +222,6 @@ public class ActionListReader { return new ArrayList<>(actionMap.values()); } - /** - * Reads list of actions from the stream. Reading ends with - * ActionEndFlag(=0) or end of the stream. - * - * @param listeners - * @param actions - * @param version - * @param ip - * @param path - * @return List of actions - * @throws IOException - * @throws java.lang.InterruptedException - */ - private static ActionList deobfuscateActionListOld(List listeners, ActionList actions, int version, int ip, String path) throws IOException, InterruptedException { - if (actions.isEmpty()) { - return actions; - } - - Action lastAction = actions.get(actions.size() - 1); - int endIp = (int) lastAction.getAddress(); - - List retMap = new ArrayList<>(endIp); - for (int i = 0; i < endIp; i++) { - retMap.add(null); - } - List actionMap = new ArrayList<>(endIp + 1); - for (int i = 0; i <= endIp; i++) { - actionMap.add(null); - } - for (Action a : actions) { - actionMap.set((int) a.getAddress(), a); - } - - int maxRecursionLevel = 0; - for (int i = 0; i < actions.size(); i++) { - Action a = actions.get(i); - if (a instanceof ActionIf || a instanceof GraphSourceItemContainer) { - maxRecursionLevel++; - } - if (a instanceof ActionIf) { - ActionIf aif = (ActionIf) a; - aif.ignoreUsed = false; - aif.jumpUsed = false; - } - } - - deobfustaceActionListAtPosRecursiveOld(listeners, - new ArrayList<>(), - new HashMap<>(), - new ActionLocalData(), - new TranslateStack(path), - new ConstantPool(), - actionMap, ip, retMap, ip, endIp, path, - new HashMap<>(), false, - new HashMap<>(), - version, 0, maxRecursionLevel); - - ActionList ret = new ActionList(); - Action last = null; - for (Action a : retMap) { - if (a != last && a != null) { - ret.add(a); - } - last = a; - } - ret.removeNops(); - ActionList reta = new ActionList(); - for (Object o : ret) { - if (o instanceof Action) { - reta.add((Action) o); - } - } - return reta; - } - private static long getNearAddress(ActionList actions, long address, boolean next) { int min = 0; int max = actions.size() - 1; @@ -997,252 +895,4 @@ public class ActionListReader { return ret; } - - private static void deobfustaceActionListAtPosRecursiveOld(List listeners, List output, HashMap> containers, ActionLocalData localData, TranslateStack stack, ConstantPool cpool, List actions, int ip, List ret, int startIp, int endip, String path, Map visited, boolean indeterminate, Map> decisionStates, int version, int recursionLevel, int maxRecursionLevel) throws IOException, InterruptedException { - boolean debugMode = false; - boolean decideBranch = false; - - if (recursionLevel > maxRecursionLevel + 1) { - throw new TranslateException("deobfustaceActionListAtPosRecursive max recursion level reached."); - } - - Action a; - Scanner sc = null; - loopip: - while (((endip == -1) || (endip > ip)) && (a = actions.get(ip)) != null) { - if (Thread.currentThread().isInterrupted()) { - throw new InterruptedException(); - } - - int actionLen = a.getTotalActionLength(); - if (!visited.containsKey(ip)) { - visited.put(ip, 0); - } - int curVisited = visited.get(ip); - curVisited++; - visited.put(ip, curVisited); - for (int i = 0; i < listeners.size(); i++) { - listeners.get(i).progressDeobfuscating(ip, actions.size()); - } - int info = a.getTotalActionLength(); - - if (a instanceof ActionPush) { - if (cpool != null) { - ((ActionPush) a).constantPool = cpool.constants; - } - } - - if (debugMode) { - String atos = a.getASMSource(new ActionList(), new HashSet<>(), ScriptExportMode.PCODE); - if (a instanceof GraphSourceItemContainer) { - atos = a.toString(); - } - System.err.println("readActionListAtPos ip: " + (ip - startIp) + " (0x" + Helper.formatAddress(ip - startIp) + ") " + " action(len " + a.actionLength + "): " + atos + (a.isIgnored() ? " (ignored)" : "") + " stack:" + Helper.stackToString(stack, LocalData.create(cpool)) + " " + Helper.byteArrToString(a.getBytes(version))); - System.err.print("variables: "); - for (Map.Entry v : localData.variables.entrySet()) { - System.err.print("'" + v + "' = " + v.getValue().toString(LocalData.create(cpool)) + ", "); - } - System.err.println(); - String add = ""; - if (a instanceof ActionIf) { - add = " change: " + ((ActionIf) a).getJumpOffset(); - } - if (a instanceof ActionJump) { - add = " change: " + ((ActionJump) a).getJumpOffset(); - } - System.err.println(add); - } - - int newip = -1; - - if (a instanceof ActionConstantPool) { - if (cpool == null) { - cpool = new ConstantPool(); - } - cpool.setNew(((ActionConstantPool) a).constantPool); - } - ActionIf aif = null; - boolean goaif = false; - if (!a.isIgnored()) { - String varname = null; - if (a instanceof StoreTypeAction) { - StoreTypeAction sta = (StoreTypeAction) a; - varname = sta.getVariableName(stack, cpool); - } - - try { - if (a instanceof ActionIf) { - aif = (ActionIf) a; - - GraphTargetItem top = stack.pop(); - int nip = ip + actionLen + aif.getJumpOffset(); - - if (decideBranch) { - System.out.print("newip " + nip + ", "); - System.out.print("Action: jump(j),ignore(i),compute(c)?"); - if (sc == null) { - sc = new Scanner(System.in); - } - String next = sc.next(); - switch (next) { - case "j": - newip = nip; - break; - case "i": - break; - case "c": - goaif = true; - break; - } - } else if (top.isCompileTime() && (!top.hasSideEffect())) { - if (debugMode) { - System.err.print("is compiletime -> "); - } - if (EcmaScript.toBoolean(top.getResult())) { - newip = nip; - aif.jumpUsed = true; - if (debugMode) { - System.err.println("jump"); - } - } else { - aif.ignoreUsed = true; - if (debugMode) { - System.err.println("ignore"); - } - } - } else { - if (debugMode) { - System.err.println("goaif"); - } - goaif = true; - } - } else if (a instanceof ActionJump) { - newip = ip + actionLen + ((ActionJump) a).getJumpOffset(); - } else if (!(a instanceof GraphSourceItemContainer)) { - //return in for..in, TODO:Handle this better way - if (((a instanceof ActionEquals) || (a instanceof ActionEquals2)) && (stack.size() == 1) && (stack.peek() instanceof DirectValueActionItem)) { - stack.push(new DirectValueActionItem(null, null, 0, Null.INSTANCE, new ArrayList<>())); - } - if ((a instanceof ActionStoreRegister) && stack.isEmpty()) { - stack.push(new DirectValueActionItem(null, null, 0, Null.INSTANCE, new ArrayList<>())); - } - a.translate(localData, stack, output, Graph.SOP_USE_STATIC/*Graph.SOP_SKIP_STATIC*/, path); - } - } catch (RuntimeException ex) { - logger.log(Level.SEVERE, "Disassembly exception", ex); - break; - } - - HashMap vars = localData.variables; - if (varname != null) { - GraphTargetItem varval = vars.get(varname); - if (varval != null && varval.isCompileTime() && indeterminate) { - vars.put(varname, new NotCompileTimeItem(null, null, varval)); - } - } - } - for (int i = 0; i < actionLen; i++) { - ret.set(ip + i, a); - } - - if (a instanceof GraphSourceItemContainer) { - GraphSourceItemContainer cnt = (GraphSourceItemContainer) a; - if (a instanceof Action) { - long endAddr = a.getAddress() + cnt.getHeaderSize(); - String cntName = cnt.getName(); - List> output2s = new ArrayList<>(); - for (long size : cnt.getContainerSizes()) { - if (size == 0) { - output2s.add(new ArrayList<>()); - continue; - } - ActionLocalData localData2; - List output2 = new ArrayList<>(); - if ((cnt instanceof ActionDefineFunction) || (cnt instanceof ActionDefineFunction2)) { - localData2 = new ActionLocalData(); - } else { - localData2 = localData; - } - deobfustaceActionListAtPosRecursiveOld(listeners, output2, containers, localData2, new TranslateStack(path), cpool, actions, (int) endAddr, ret, startIp, (int) (endAddr + size), path + (cntName == null ? "" : "/" + cntName), visited, indeterminate, decisionStates, version, recursionLevel + 1, maxRecursionLevel); - output2s.add(output2); - endAddr += size; - } - GraphSourceItem lineStartItem = null; - if (cnt instanceof GraphSourceItem) { - lineStartItem = (GraphSourceItem) cnt; - } - cnt.translateContainer(output2s, lineStartItem, stack, output, localData.regNames, localData.variables, localData.functions); - ip = (int) endAddr; - continue; - } - } - - if (a instanceof ActionEnd) { - break; - } - if (goaif && aif != null) { - aif.ignoreUsed = true; - aif.jumpUsed = true; - indeterminate = true; - - HashMap vars = localData.variables; - boolean stateChanged = false; - if (decisionStates.containsKey(ip)) { - HashMap oldstate = decisionStates.get(ip); - if (oldstate.size() != vars.size()) { - stateChanged = true; - } else { - for (String k : vars.keySet()) { - if (!oldstate.containsKey(k)) { - stateChanged = true; - break; - } - if (!vars.get(k).isCompileTime() && oldstate.get(k).isCompileTime()) { - stateChanged = true; - break; - } - } - } - } - HashMap curstate = new HashMap<>(); - curstate.putAll(vars); - decisionStates.put(ip, curstate); - - if ((!stateChanged) && curVisited > 1) { - List branches = new ArrayList<>(); - branches.add(ip + actionLen + aif.getJumpOffset()); - branches.add(ip + actionLen); - for (int br : branches) { - int visc = 0; - if (visited.containsKey(br)) { - visc = visited.get(br); - } - if (visc == 0) {//(localData.regNames), - new HashMap<>(localData.variables), new HashMap<>(localData.functions)); - deobfustaceActionListAtPosRecursiveOld(listeners, output, containers, subLocalData, subStack, cpool, actions, ip + actionLen + aif.getJumpOffset(), ret, startIp, endip, path, visited, indeterminate, decisionStates, version, recursionLevel + 1, maxRecursionLevel); - } - - if (newip > -1) { - ip = newip; - } else { - ip += info; - } - - if (a.isExit()) { - break; - } - } - for (DisassemblyListener listener : listeners) { - listener.progressDeobfuscating(ip, actions.size()); - } - } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf4/ActionPush.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf4/ActionPush.java index 64fc253ff..d875277e9 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf4/ActionPush.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf4/ActionPush.java @@ -37,7 +37,6 @@ import com.jpexs.decompiler.flash.helpers.GraphTextWriter; import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter; import com.jpexs.decompiler.flash.types.annotations.SWFVersion; import com.jpexs.decompiler.graph.GraphSourceItem; -import com.jpexs.decompiler.graph.GraphSourceItem; import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.TranslateStack; import com.jpexs.decompiler.graph.model.FalseItem; @@ -60,31 +59,6 @@ public class ActionPush extends Action { public List constantPool; - public List ignoredParts = new ArrayList<>(); - - @Override - public boolean isIgnored() { - return ignoredParts.size() == values.size(); - } - - @Override - public void setIgnored(boolean ignored, int pos) { - if (ignored) { - if (!ignoredParts.contains(pos)) { - ignoredParts.add(pos); - if (ignoredParts.size() == values.size()) { - super.setIgnored(ignored, 0); - } - } - } else { - if (ignoredParts.contains(pos)) { - ignoredParts.remove(pos); - super.setIgnored(false, 0); - } - } - - } - public ActionPush(int actionLength, SWFInputStream sis, int version) throws IOException { super(0x96, actionLength); int type; @@ -360,9 +334,6 @@ public class ActionPush extends Action { public GraphTextWriter paramsToString(GraphTextWriter writer) { int pos = 0; for (int i = 0; i < values.size(); i++) { - if (ignoredParts.contains(i)) { - continue; - } if (pos > 0) { writer.appendNoHilight(" "); } @@ -404,10 +375,6 @@ public class ActionPush extends Action { public void translate(GraphSourceItem lineStartAction, TranslateStack stack, List output, HashMap regNames, HashMap variables, HashMap functions, int staticOperation, String path) { int pos = 0; for (Object o : values) { - if (ignoredParts.contains(pos)) { - pos++; - continue; - } if (o instanceof ConstantIndex) { if ((constantPool == null) || (((ConstantIndex) o).index >= constantPool.size())) { o = "§§constant" + ((ConstantIndex) o).index; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java index 90a93254a..7f1444791 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java @@ -92,10 +92,6 @@ public class Configuration { @ConfigurationCategory("script") public static final ConfigurationItem autoDeobfuscate = null; - @ConfigurationDefaultBoolean(false) - @ConfigurationCategory("") - public static final ConfigurationItem deobfuscationOldMode = null; - @ConfigurationDefaultBoolean(false) @ConfigurationCategory("") public static final ConfigurationItem cacheOnDisk = null; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java index f72207f65..1a9e633eb 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java @@ -18,7 +18,6 @@ package com.jpexs.decompiler.graph; import com.jpexs.decompiler.flash.BaseLocalData; import com.jpexs.decompiler.flash.FinalProcessLocalData; -import com.jpexs.decompiler.flash.abc.avm2.parser.script.Reference; import com.jpexs.decompiler.flash.action.Action; import com.jpexs.decompiler.flash.action.model.FunctionActionItem; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; @@ -298,11 +297,9 @@ public class Graph { getReachableParts(part, ret, loops, true); } - /** - * Non recursive version of getReachablePartsOld - */ private void getReachableParts(GraphPart part, LinkedHashSet ret, List loops, boolean first) { + // todo: honfika: why call with first = true parameter always? Stack stack = new Stack<>(); GraphPartQueue queue = new GraphPartQueue(); queue.add(part); @@ -386,77 +383,6 @@ public class Graph { } } - private void getReachablePartsOld(GraphPart part, LinkedHashSet ret, List loops, boolean first) { - - // todo: honfika: why call with first = true parameter always? - if (first) { - for (Loop l : loops) { - l.reachableMark = 0; - } - } - - Loop currentLoop = null; - for (Loop l : loops) { - if ((l.phase == 1) || (l.reachableMark == 1)) { - if (l.loopContinue == part) { - return; - } - if (l.loopBreak == part) { - return; - } - if (l.loopPreContinue == part) { - return; - } - } - if (l.reachableMark == 0) { - if (l.loopContinue == part) { - l.reachableMark = 1; - currentLoop = l; - } - } - } - - List newparts = new ArrayList<>(); - loopnext: - for (GraphPart next : part.nextParts) { - for (Loop l : loops) { - if ((l.phase == 1) || (l.reachableMark == 1)) { - if (l.loopContinue == next) { - continue loopnext; - } - if (l.loopBreak == next) { - continue loopnext; - } - if (l.loopPreContinue == next) { - continue loopnext; - } - } - - } - if (!ret.contains(next)) { - newparts.add(next); - } - } - - ret.addAll(newparts); - for (GraphPart next : newparts) { - getReachableParts(next, ret, loops, true); - } - - if (currentLoop != null) { - if (currentLoop.loopBreak != null) { - if (!ret.contains(currentLoop.loopBreak)) { - ret.add(currentLoop.loopBreak); - currentLoop.reachableMark = 2; - getReachableParts(currentLoop.loopBreak, ret, loops, true); - } - } - } - } - - /* public GraphPart getNextCommonPart(GraphPart part, List loops) { - return getNextCommonPart(part, new ArrayList(),loops); - }*/ public GraphPart getNextCommonPart(BaseLocalData localData, GraphPart part, List loops) throws InterruptedException { return getCommonPart(localData, part.nextParts, loops); }