package net.contra.obfuscator.trans.deob; import com.sun.org.apache.bcel.internal.classfile.Method; import com.sun.org.apache.bcel.internal.generic.*; import net.contra.obfuscator.Application; import net.contra.obfuscator.ITransformer; import net.contra.obfuscator.Settings; import net.contra.obfuscator.util.bcel.BCELMethods; import net.contra.obfuscator.util.bcel.JarLoader; import net.contra.obfuscator.util.misc.LogHandler; public class AllatoriDeobfuscator implements ITransformer { private final LogHandler Logger = new LogHandler("AllatoriDeobfuscator"); private String Location = ""; private JarLoader LoadedJar; private boolean isHeavy = false; private boolean isLight = false; public AllatoriDeobfuscator(String loc) { Location = loc; } public void load() { LoadedJar = new JarLoader(Location); } private String cipher(String string) { int i = 85; char[] cs = new char[string.length()]; int pos = cs.length - 1; int index = pos; int xor = i; while (pos >= 0) { char c = (char) (string.charAt(index) ^ xor); int c1_index = index; xor = (char) ((char) (c1_index ^ xor) & '?'); cs[c1_index] = c; if (--index < 0) { break; } char c2 = (char) (string.charAt(index) ^ xor); int c2_index = index; xor = (char) ((char) (c2_index ^ xor) & '?'); cs[c2_index] = c2; pos = --index; } return new String(cs); } private String cipherContext(String encrypted, String callingClass, String callingMethod) { String keyString = callingClass + callingMethod; int lastKeyIndex = keyString.length() - 1; int xor = 85; int keyIndex = lastKeyIndex; int length = encrypted.length(); char[] cs = new char[length]; for (int i = length - 1; i >= 0; i--) { if (keyIndex < 0) { keyIndex = lastKeyIndex; } char keyChar = keyString.charAt(keyIndex--); cs[i] = (char) (keyChar ^ (encrypted.charAt(i) ^ xor)); xor = (char) (63 & (xor ^ (i ^ keyChar))); } return new String(cs); } private ClassGen getAllatoriClassGen(JarLoader jr) { for (ClassGen cg : jr.ClassEntries.values()) { if (cg.getMethods().length == 2 && cg.getMethods()[0].isStatic() && cg.getMethods()[1].isStatic()) { if (cg.getMethods()[0].getReturnType().toString().equals("java.lang.String") && cg.getMethods()[1].getReturnType().toString().equals("java.lang.String")) { return cg; } } } return null; } public void transform() { ClassGen hashClass = getAllatoriClassGen(LoadedJar); if (hashClass == null) { Logger.error("Could not locate Allatori cipher class."); Logger.error("This is not obfuscated with Allatori."); Application.close(); } else { Logger.debug("Allatori Class: " + hashClass.getClassName()); } for (ClassGen cg : LoadedJar.ClassEntries.values()) { for (Method method : cg.getMethods()) { MethodGen mg = new MethodGen(method, cg.getClassName(), cg.getConstantPool()); InstructionList list = mg.getInstructionList(); if (list == null) continue; Logger.debug("Stripping Allatori Calls -> Class: " + cg.getClassName() + " Method: " + method.getName()); InstructionHandle[] handles = list.getInstructionHandles(); for (InstructionHandle handle : handles) { if (handle.getNext() == null) continue; if (handle.getInstruction() instanceof LDC && handle.getNext().getInstruction() instanceof INVOKESTATIC) { INVOKESTATIC invs = (INVOKESTATIC) handle.getNext().getInstruction(); assert hashClass != null; if (!BCELMethods.getInvokeClassName(invs, cg.getConstantPool()).equals(hashClass.getClassName())) continue; if (!isLight && !isHeavy) { if (!BCELMethods.getInvokeSignature(invs, cg.getConstantPool()).equals(hashClass.getMethods()[0].getSignature())) { isLight = true; Logger.log("Light string obfuscation detected!"); } else { isHeavy = true; Logger.log("Heavy string obfuscation detected!"); } } String original = (String) ((LDC) handle.getInstruction()).getValue(cg.getConstantPool()); String deciphered; if (isHeavy) { deciphered = cipherContext(original, cg.getClassName(), mg.getName()); } else { deciphered = cipher(original); } int idx = cg.getConstantPool().addString(deciphered); //Add our new string handle.getNext().setInstruction(new NOP()); //Get rid of the invoke handle.setInstruction(new LDC(idx)); //Replace old LDC with new LDC Logger.debug("\"" + original + "\" -> \"" + deciphered + "\""); } } list.setPositions(); mg.setInstructionList(list); mg.setMaxLocals(); mg.setMaxStack(); cg.replaceMethod(method, mg.getMethod()); } } } public void save() { String loc = Location.replace(".jar", Settings.FILE_TAG + ".jar"); LoadedJar.saveJar(loc); } }