@Override public void deobfuscate( String path, int classIndex, boolean isStatic, int scriptIndex, ABC abc, AVM2ConstantPool cpool, Trait trait, MethodInfo minfo, MethodBody body) throws InterruptedException { // body.getCode().markMappedOffsets(); // removeUnreachableActions(body.getCode(), cpool, trait, minfo, body); AVM2Code code = body.getCode(); boolean found; do { found = false; Map<Integer, List<Integer>> refs = body.getCode().visitCode(body); loopi: for (int i = 0; i < code.code.size(); i++) { AVM2Instruction ins = code.code.get(i); if (ins.definition instanceof JumpIns) { long targetAddr = ins.offset + ins.operands[0] + ins.getBytesLength(); { for (int r : refs.get(i)) { if (r >= 0) { // Not Exception start/end 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; } } } } } } } } removeUnreachableActions(body.getCode(), cpool, trait, minfo, body); } while (found); }
private int visitCode( Reference<AVM2Instruction> assignment, Set<Integer> visited, TranslateStack stack, int classIndex, boolean isStatic, MethodBody body, int scriptIndex, ABC abc, AVM2Code code, int idx, int endIdx, Set<Integer> ignored, Set<Integer> ignoredGets) throws InterruptedException { List<GraphTargetItem> 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<Integer> toVisit = new ArrayList<>(); toVisit.add(idx); List<TranslateStack> 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 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 if (!(def instanceof KillIns) && !(def instanceof DebugIns)) { // can be inclocal, declocal, hasnext... for (int p = 0; p < ins.definition.operands.length; p++) { int op = ins.definition.operands[p]; if (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<Integer> 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<GraphTargetItem> 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; }
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; }