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 ed1462254..5e3f64ae2 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 @@ -777,6 +777,8 @@ public class AVM2Code implements Cloneable { Map codeMap = new TreeMap<>(); DumpInfo diParent = ais.dumpInfo; List addresses = new ArrayList<>(); + //Do not add new jumps when processing these addresses (unreachable code,etc.) + List unAdresses = new ArrayList<>(); //Handle lookupswitches at the end - they can be invalid. Handle other instruction first so we can decide lookupswitch to be invalid based on other instructions inside it //Flashplayer does not check casecount in lookupswitch instruction so the instruction can "be" long and over other instructions List switchAddresses = new ArrayList<>(); @@ -789,14 +791,18 @@ public class AVM2Code implements Cloneable { addresses.add(startPos); loopaddr: - while (!addresses.isEmpty() || !switchAddresses.isEmpty()) { + while (!addresses.isEmpty() || !switchAddresses.isEmpty() || !unAdresses.isEmpty()) { long address; boolean isSwitch = false; + boolean handleJumps = true; if (!addresses.isEmpty()) { address = addresses.remove(0); - } else { + } else if (!switchAddresses.isEmpty()) { address = switchAddresses.remove(0); isSwitch = true; + } else { + address = unAdresses.remove(0); + handleJumps = false; } if (codeMap.containsKey(address) && !(codeMap.get(address).definition instanceof NopIns)) { continue; @@ -805,6 +811,7 @@ public class AVM2Code implements Cloneable { { continue; } + boolean afterExit = false; try { ais.seek(address); while (ais.available() > 0) { @@ -847,7 +854,6 @@ public class AVM2Code implements Cloneable { if (afterCasePos > totalBytes) { invalidSwitch = true; } - if (invalidSwitch) { continue loopaddr; } else { @@ -889,28 +895,33 @@ public class AVM2Code implements Cloneable { ais.endDumpLevel(instr.instructionCode); - if ((instr instanceof IfTypeIns)) { - long target = ais.getPosition() + actualOperands[0]; - addresses.add(target); - //addresses.add(ais.getPosition()); + if (handleJumps) { + if ((instr instanceof IfTypeIns)) { + long target = ais.getPosition() + actualOperands[0]; + addresses.add(target); + //addresses.add(ais.getPosition()); + } + + if (instr instanceof JumpIns) { + long target = ais.getPosition() + actualOperands[0]; + addresses.add(target); + unAdresses.add(ais.getPosition()); + continue loopaddr; + } + + if (instr.isExitInstruction()) { //do not process jumps if there is return/throw instruction + unAdresses.add(ais.getPosition()); + continue loopaddr; + } + if (instr instanceof LookupSwitchIns) { + addresses.add(beforeSwitchPos + actualOperands[0]); + + for (int c = 2; c < actualOperands.length; c++) { + addresses.add(beforeSwitchPos + actualOperands[c]); + } + continue loopaddr; + } } - /*if (instr instanceof JumpIns) { - long target = ais.getPosition() + actualOperands[0]; - addresses.add(target); - continue loopaddr; - } - - if (instr.isExitInstruction()) { //do not process jumps if there is return/throw instruction - continue loopaddr; - } - if (instr instanceof LookupSwitchIns) { - addresses.add(beforeSwitchPos + actualOperands[0]); - - for (int c = 2; c < actualOperands.length; c++) { - addresses.add(beforeSwitchPos + actualOperands[c]); - } - continue loopaddr; - }*/ } else { ais.endDumpLevel(); break; // Unknown instructions are ignored (Some of the obfuscators add unknown instructions) 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 812d5d58c..f0cd601d0 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 @@ -367,6 +367,8 @@ public class AVM2DeobfuscatorSimple implements SWFDecompilerListener { long address = action.offset + action.getBytesLength() + action.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 = -action.definition.getStackDelta(action, abc); if (EcmaScript.toBoolean(res)) { //System.err.println("replacing " + action + " on " + idx + " with jump"); @@ -374,13 +376,17 @@ public class AVM2DeobfuscatorSimple implements SWFDecompilerListener { //jumpIns.operands[0] = action.operands[0] /*- action.getBytes().length*/ + jumpIns.getBytes().length; code.replaceInstruction(idx, jumpIns, body); jumpIns.operands[0] = (int) (tarIns.offset - jumpIns.offset - jumpIns.getBytesLength()); - - code.insertInstruction(idx, new AVM2Instruction(action.offset, new DeobfuscatePopIns(), new int[]{}), true, body); + for (int s = 0; s < stackCount; s++) { + code.insertInstruction(idx, new AVM2Instruction(action.offset, new DeobfuscatePopIns(), new int[]{}), true, body); + } idx = code.adr2pos(jumpIns.offset + jumpIns.getBytesLength() + jumpIns.operands[0]); } else { //System.err.println("replacing " + action + " on " + idx + " with pop"); code.replaceInstruction(idx, new AVM2Instruction(action.offset, new DeobfuscatePopIns(), new int[]{}), body); + for (int s = 1 /*first is replaced*/; s < stackCount; s++) { + code.insertInstruction(idx, new AVM2Instruction(action.offset, new DeobfuscatePopIns(), new int[]{}), true, body); + } //action.definition = new DeobfuscatePopIns(); idx++; } 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 a4b3b91a2..edb0a65b0 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 @@ -93,7 +93,7 @@ public class InstructionDefinition implements Serializable { protected FullMultinameAVM2Item resolveMultiname(TranslateStack stack, AVM2ConstantPool constants, int multinameIndex, AVM2Instruction ins) { GraphTargetItem ns = null; GraphTargetItem name = null; - if (multinameIndex < constants.constant_multiname.size()) { + if (multinameIndex > 0 && multinameIndex < constants.constant_multiname.size()) { if (constants.getMultiname(multinameIndex).needsName()) { name = stack.pop(); } 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 ec7b79927..c2e640778 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 @@ -96,7 +96,11 @@ public class FullMultinameAVM2Item extends AVM2Item { } else { AVM2ConstantPool constants = localData.constantsAvm2; List fullyQualifiedNames = localData.fullyQualifiedNames; - writer.append(constants.getMultiname(multinameIndex).getName(constants, fullyQualifiedNames, false)); + if (multinameIndex > 0 && multinameIndex < constants.constant_multiname.size()) { + writer.append(constants.getMultiname(multinameIndex).getName(constants, fullyQualifiedNames, false)); + } else { + writer.append("§§unknown_multiname"); + } } return writer; }