@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 getFirstRegisterSetter( Reference<AVM2Instruction> assignment, int classIndex, boolean isStatic, int scriptIndex, ABC abc, MethodBody body, Set<Integer> ignoredRegisters, Set<Integer> ignoredGets) throws InterruptedException { AVM2Code code = body.getCode(); if (code.code.isEmpty()) { return -1; } return visitCode( assignment, new HashSet<>(), new TranslateStack("deo"), classIndex, isStatic, body, scriptIndex, abc, code, 0, code.code.size() - 1, ignoredRegisters, ignoredGets); }
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; }
@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); }
@Override public void avm2CodeRemoveTraps( String path, int classIndex, boolean isStatic, int scriptIndex, ABC abc, Trait trait, int methodInfo, MethodBody body) throws InterruptedException { // System.err.println("regdeo:" + path); MethodBody originalBody = body; body.getCode().removeDeadCode(body); Set<Integer> ignoredRegs = new HashSet<>(); int localReservedCount = body.getLocalReservedCount(); for (int i = 0; i < localReservedCount; i++) { ignoredRegs.add(i); } int setReg = 0; List<Integer> listedRegs = new ArrayList<>(); List<MethodBody> listedLastBodies = new ArrayList<>(); Set<Integer> ignoredRegGets = new HashSet<>(); Reference<AVM2Instruction> assignmentRef = new Reference<>(null); while (setReg > -1) { if (Thread.currentThread().isInterrupted()) { throw new InterruptedException(); } MethodBody bodybefore = body; body = bodybefore.clone(); setReg = getFirstRegisterSetter( assignmentRef, classIndex, isStatic, scriptIndex, abc, body, ignoredRegs, ignoredRegGets); // System.err.println("setreg " + setReg + " ass:" + assignmentRef.getVal()); if (setReg < 0) { break; } // if there is second assignment if (listedRegs.contains(setReg)) { // System.err.println("second assignment of loc" + setReg + ", ignoring"); int lindex = listedRegs.indexOf(setReg); body = listedLastBodies.get(lindex); // switch to body before ignoredRegs.add(setReg); // this is not obfuscated for (int i = listedRegs.size() - 1; i >= lindex; i--) { int r = listedRegs.get(i); listedRegs.remove(i); listedLastBodies.remove(i); ignoredRegGets.remove(r); } continue; } AVM2Instruction assignment = assignmentRef.getVal(); InstructionDefinition def = assignment.definition; if ((def instanceof SetLocalTypeIns) || (def instanceof GetLocalTypeIns /*First usage -> value undefined*/)) { super.removeObfuscationIfs( classIndex, isStatic, scriptIndex, abc, body, Arrays.asList(assignment)); } if (def instanceof GetLocalTypeIns) { ignoredRegGets.add(setReg); } listedRegs.add(setReg); listedLastBodies.add(bodybefore); } body.getCode().removeDeadCode(body); originalBody.exceptions = body.exceptions; originalBody.setCode(body.getCode()); }
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 void addTraitButtonActionPerformed(ActionEvent evt) { int class_index = decompiledTextArea.getClassIndex(); if (class_index < 0) { return; } if (newTraitDialog == null) { newTraitDialog = new NewTraitDialog(); } int void_type = abc.constants.getPublicQnameId( "void", true); // abc.constants.forceGetMultinameId(new Multiname(Multiname.QNAME, // abc.constants.forceGetStringId("void"), abc.constants.forceGetNamespaceId(new // Namespace(Namespace.KIND_PACKAGE, abc.constants.forceGetStringId("")), 0), -1, // -1, new ArrayList<Integer>())); int int_type = abc.constants.getPublicQnameId( "int", true); // abc.constants.forceGetMultinameId(new Multiname(Multiname.QNAME, // abc.constants.forceGetStringId("int"), abc.constants.forceGetNamespaceId(new // Namespace(Namespace.KIND_PACKAGE, abc.constants.forceGetStringId("")), 0), -1, // -1, new ArrayList<Integer>())); Trait t = null; int kind; int nskind; String name = null; boolean isStatic; Multiname m; boolean again = false; loopm: do { if (again) { View.showMessageDialog( null, AppStrings.translate("error.trait.exists").replace("%name%", name), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE); } again = false; if (newTraitDialog.showDialog() != AppDialog.OK_OPTION) { return; } kind = newTraitDialog.getTraitType(); nskind = newTraitDialog.getNamespaceKind(); name = newTraitDialog.getTraitName(); isStatic = newTraitDialog.getStatic(); m = new Multiname( Multiname.QNAME, abc.constants.getStringId(name, true), abc.constants.getNamespaceId( new Namespace(nskind, abc.constants.getStringId("", true)), 0, true), 0, 0, new ArrayList<>()); int mid = abc.constants.getMultinameId(m); if (mid == 0) { break; } for (Trait tr : abc.class_info.get(class_index).static_traits.traits) { if (tr.name_index == mid) { again = true; break; } } for (Trait tr : abc.instance_info.get(class_index).instance_traits.traits) { if (tr.name_index == mid) { again = true; break; } } } while (again); switch (kind) { case Trait.TRAIT_GETTER: case Trait.TRAIT_SETTER: case Trait.TRAIT_METHOD: TraitMethodGetterSetter tm = new TraitMethodGetterSetter(); MethodInfo mi = new MethodInfo( new int[0], void_type, abc.constants.getStringId(name, true), 0, new ValueKind[0], new int[0]); int method_info = abc.addMethodInfo(mi); tm.method_info = method_info; MethodBody body = new MethodBody(); body.method_info = method_info; body.init_scope_depth = 1; body.max_regs = 1; body.max_scope_depth = 1; body.max_stack = 1; body.exceptions = new ABCException[0]; AVM2Code code = new AVM2Code(); code.code.add(new AVM2Instruction(0, new GetLocal0Ins(), new int[0])); code.code.add(new AVM2Instruction(0, new PushScopeIns(), new int[0])); code.code.add(new AVM2Instruction(0, new ReturnVoidIns(), new int[0])); body.setCode(code); Traits traits = new Traits(); traits.traits = new ArrayList<>(); body.traits = traits; abc.addMethodBody(body); mi.setBody(body); t = tm; break; case Trait.TRAIT_SLOT: case Trait.TRAIT_CONST: TraitSlotConst ts = new TraitSlotConst(); ts.type_index = int_type; ts.value_kind = ValueKind.CONSTANT_Int; ts.value_index = abc.constants.getIntId(0, true); t = ts; break; } if (t != null) { t.kindType = kind; t.name_index = abc.constants.getMultinameId(m, true); int traitId; if (isStatic) { traitId = abc.class_info.get(class_index).static_traits.addTrait(t); } else { traitId = abc.class_info.get(class_index).static_traits.traits.size() + abc.instance_info.get(class_index).instance_traits.addTrait(t); } reload(); decompiledTextArea.gotoTrait(traitId); } }