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; }
private boolean executeInstructions( Map<Integer, Object> 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<Long> refs = code.getImportantOffsets(body); boolean modified = false; while (true) { if (idx > endIdx) { break; } if (instructionsProcessed > executionLimit) { break; } AVM2Instruction ins = code.code.get(idx); if (instructionsProcessed > 0 && refs.contains(ins.getOffset())) { break; } modified = modified | code.inlineJumpExit(); InstructionDefinition def = ins.definition; if (inlineIns == ins) { if (def instanceof SetLocalTypeIns) { int regId = ((SetLocalTypeIns) def).getRegisterId(ins); staticRegs.put(regId, localData.localRegisters.get(regId)); code.replaceInstruction( idx, new AVM2Instruction(0, DeobfuscatePopIns.getInstance(), null), body); modified = true; } } if (def instanceof GetLocalTypeIns) { int regId = ((GetLocalTypeIns) def).getRegisterId(ins); if (staticRegs.containsKey(regId)) { AVM2Instruction pushins = abc.constants.makePush(staticRegs.get(regId)); if (pushins == null) { break; } code.replaceInstruction(idx, pushins, body); modified = true; ins = pushins; def = ins.definition; } } if (def instanceof NewFunctionIns && idx + 1 < code.code.size() && code.code.get(idx + 1).definition instanceof PopIns) { code.removeInstruction(idx + 1, body); code.removeInstruction(idx, body); modified = true; continue; } boolean ok = false; // todo: honfika: order by statistics if (def.isNotCompileTimeSupported() || 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 SetLocalTypeIns || def instanceof NewFunctionIns || def instanceof CoerceOrConvertTypeIns) { ok = true; } if (!ok) { break; } if (!(def instanceof NewFunctionIns)) { // 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 ifed = false; if (def instanceof IfTypeIns && !(def instanceof JumpIns)) { long address = ins.getTargetAddress(); 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 (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; code.replaceInstruction(idx, jumpIns, body); jumpIns.operands[0] = (int) (tarIns.getOffset() - jumpIns.getOffset() - jumpIns.getBytesLength()); for (int s = 0; s < stackCount; s++) { code.insertInstruction( idx, new AVM2Instruction(ins.getOffset(), DeobfuscatePopIns.getInstance(), null), true, body); } idx = code.adr2pos(jumpIns.getTargetAddress()); } else { // System.err.println("replacing " + ins + " on " + idx + " with pop"); code.replaceInstruction( idx, new AVM2Instruction(ins.getOffset(), DeobfuscatePopIns.getInstance(), null), body); for (int s = 1 /*first is replaced*/; s < stackCount; s++) { code.insertInstruction( idx, new AVM2Instruction(ins.getOffset(), DeobfuscatePopIns.getInstance(), null), true, body); } // ins.definition = DeobfuscatePopIns.getInstance(); idx++; } modified = true; ifed = true; } 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; } if (localData.jump != null) { idx = code.adr2pos(localData.jump); if (idx == -1) { throw new TranslateException("Jump target not found: " + localData.jump); } } } return modified; }