package net.contra.obfuscator.trans.ob; import com.sun.org.apache.bcel.internal.Constants; import com.sun.org.apache.bcel.internal.classfile.Method; import com.sun.org.apache.bcel.internal.generic.*; import net.contra.obfuscator.ITransformer; import net.contra.obfuscator.Settings; import net.contra.obfuscator.util.bcel.JarLoader; import net.contra.obfuscator.util.misc.LogHandler; public class StringObfuscator implements ITransformer { private final LogHandler Logger = new LogHandler("StringObfuscator"); private String Location = ""; private JarLoader LoadedJar; public StringObfuscator(String loc) { Location = loc; } public void load() { LoadedJar = new JarLoader(Location); } public void transform() { for (int i = 0; i < Settings.CIPHER_KEYS.length; i++) { for (ClassGen cg : LoadedJar.ClassEntries.values()) { MethodGen cryptor = getDecryptor(cg, i); for (Method method : cg.getMethods()) { MethodGen mg = new MethodGen(method, cg.getClassName(), cg.getConstantPool()); InstructionList list = mg.getInstructionList(); if (list == null) continue; Logger.log("Obfuscating Strings -> Class: " + cg.getClassName() + " Method: " + method.getName()); InstructionHandle[] handles = list.getInstructionHandles(); for (InstructionHandle handle : handles) { if (handle.getInstruction() instanceof LDC) { try { String orig = ((LDC) handle.getInstruction()).getValue(cg.getConstantPool()).toString(); int index = cg.getConstantPool().addString(getCiphered(orig, Settings.CIPHER_KEYS[i])); handle.setInstruction(new LDC(index)); list.append(handle, new INVOKESTATIC(cg.getConstantPool().addMethodref(cryptor))); } catch (Exception e) { Logger.debug("Caught error, skipping instruction."); } } } list.setPositions(); mg.setInstructionList(list); mg.setMaxLocals(); mg.setMaxStack(); cg.replaceMethod(method, mg.getMethod()); } if (cg.containsMethod(cryptor.getName(), cryptor.getSignature()) == null) { Logger.log("Injecting Cipher Method -> Class: " + cg.getClassName()); cg.addMethod(cryptor.getMethod()); } else { Logger.error("Cipher Method Already Exists! -> Class: " + cg.getClassName()); } } } } public void save() { String loc = Location.replace(".jar", Settings.FILE_TAG + ".jar"); LoadedJar.saveJar(loc); } String getCiphered(String input, int key) { char[] inputChars = input.toCharArray(); for (int i = 0; i < inputChars.length; i++) { inputChars[i] = (char) (inputChars[i] ^ key); } return new String(inputChars); } MethodGen getDecryptor(ClassGen cg, int i) { InstructionList il = new InstructionList(); InstructionFactory fa = new InstructionFactory(cg); il.append(new ALOAD(0)); il.append(fa.createInvoke("java.lang.String", "toCharArray", new ArrayType(Type.CHAR, 1), Type.NO_ARGS, Constants.INVOKEVIRTUAL)); il.append(new ASTORE(2)); il.append(new ICONST(0)); il.append(new ISTORE(3)); il.append(new ILOAD(3)); il.append(new ALOAD(2)); il.append(new ARRAYLENGTH()); il.append(new IF_ICMPGE(il.getInstructionHandles()[0]));//Placeholder, to be replaced il.append(new ALOAD(2)); il.append(new ILOAD(3)); il.append(new ALOAD(2)); il.append(new ILOAD(3)); il.append(new CALOAD()); il.append(new BIPUSH((byte) Settings.CIPHER_KEYS[i])); il.append(new IXOR()); il.append(new I2C()); il.append(new CASTORE()); il.append(new IINC(3, 1)); il.append(new GOTO(il.getInstructionHandles()[5])); il.append(fa.createNew(ObjectType.STRING)); il.append(new DUP()); il.append(new ALOAD(2)); il.append(fa.createInvoke("java.lang.String", "<init>", Type.VOID, new Type[]{new ArrayType(Type.CHAR, 1)}, Constants.INVOKESPECIAL)); il.append(new ARETURN()); il.getInstructionHandles()[8].setInstruction(new IF_ICMPGE(il.getInstructionHandles()[20])); il.setPositions(); MethodGen mg = new MethodGen(Constants.ACC_STATIC | Constants.ACC_PUBLIC, Type.STRING, new Type[]{Type.STRING}, new String[]{Settings.CIPHER_ARG}, Settings.CIPHER_NAME + i, cg.getClassName(), il, cg.getConstantPool()); mg.setMaxLocals(); mg.setMaxStack(); return mg; } }