protected boolean isRegisterCompileTime( int regId, int ip, HashMap<Integer, List<Integer>> refs, AVM2Code code) { Set<Integer> previous = new HashSet<>(); AVM2Code.getPreviousReachableIps(ip, refs, previous, new HashSet<>()); for (int p : previous) { if (p < 0) { continue; } if (p >= code.code.size()) { continue; } AVM2Instruction sins = code.code.get(p); if (code.code.get(p).definition instanceof SetLocalTypeIns) { SetLocalTypeIns sl = (SetLocalTypeIns) sins.definition; if (sl.getRegisterId(sins) == regId) { if (!AVM2Code.isDirectAncestor(ip, p, refs)) { return false; } } } if ((code.code.get(p).definition instanceof IncLocalIns) || (code.code.get(p).definition instanceof IncLocalIIns) || (code.code.get(p).definition instanceof DecLocalIns) || (code.code.get(p).definition instanceof DecLocalIIns)) { if (sins.operands[0] == regId) { if (!AVM2Code.isDirectAncestor(ip, p, refs)) { return false; } } } } return true; }
@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, null); removeZeroJumps(code, body); }
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<Integer, Object> 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; } 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.clear(); initLocalRegs(localData, localReservedCount, body.max_regs, i == 0); if (executeInstructions( staticRegs, body, abc, code, localData, i, code.code.size() - 1, null, inlineIns)) { code.removeDeadCode(body); i--; } } 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; }
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; }