|
| 1 | +/* |
| 2 | + * Copyright 2018 Sam Sun <[email protected]> |
| 3 | + * |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | + * you may not use this file except in compliance with the License. |
| 6 | + * You may obtain a copy of the License at |
| 7 | + * |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | + * |
| 10 | + * Unless required by applicable law or agreed to in writing, software |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | + * See the License for the specific language governing permissions and |
| 14 | + * limitations under the License. |
| 15 | + */ |
| 16 | + |
| 17 | +package com.javadeobfuscator.deobfuscator.transformers.special; |
| 18 | + |
| 19 | +import java.util.Collections; |
| 20 | +import java.util.HashMap; |
| 21 | +import java.util.Map; |
| 22 | +import java.util.Map.Entry; |
| 23 | +import java.util.concurrent.atomic.AtomicInteger; |
| 24 | + |
| 25 | +import org.objectweb.asm.Opcodes; |
| 26 | +import org.objectweb.asm.tree.ClassNode; |
| 27 | +import org.objectweb.asm.tree.InsnNode; |
| 28 | +import org.objectweb.asm.tree.MethodInsnNode; |
| 29 | +import org.objectweb.asm.tree.MethodNode; |
| 30 | +import org.objectweb.asm.tree.VarInsnNode; |
| 31 | + |
| 32 | +import com.javadeobfuscator.deobfuscator.config.*; |
| 33 | +import com.javadeobfuscator.deobfuscator.exceptions.*; |
| 34 | +import com.javadeobfuscator.deobfuscator.transformers.*; |
| 35 | +import com.javadeobfuscator.deobfuscator.utils.TransformerHelper; |
| 36 | +import com.javadeobfuscator.javavm.MethodExecution; |
| 37 | +import com.javadeobfuscator.javavm.VirtualMachine; |
| 38 | +import com.javadeobfuscator.javavm.mirrors.JavaClass; |
| 39 | +import com.javadeobfuscator.javavm.utils.ArrayConversionHelper; |
| 40 | +import com.javadeobfuscator.javavm.values.JavaWrapper; |
| 41 | + |
| 42 | +public class BisGuardTransformer extends Transformer<TransformerConfig> |
| 43 | +{ |
| 44 | + @Override |
| 45 | + public boolean transform() throws WrongTransformerException |
| 46 | + { |
| 47 | + VirtualMachine vm = TransformerHelper.newVirtualMachine(this); |
| 48 | + AtomicInteger count = new AtomicInteger(); |
| 49 | + System.out.println("[Special] [BisGuardTransformer] Starting"); |
| 50 | + ClassNode loader = classNodes().stream().filter(c -> c.name.equals("JavaPreloader")).findFirst().orElse(null); |
| 51 | + MethodNode getCipher = loader == null ? null : loader.methods.stream().filter(m -> m.name.equals("getCipher") |
| 52 | + && m.desc.equals("([B)LJavaPreloader$Cipher;")).findFirst().orElse(null); |
| 53 | + ClassNode cipher = classNodes().stream().filter(c -> c.name.equals("JavaPreloader$Cipher")).findFirst().orElse(null); |
| 54 | + MethodNode decrypt = cipher == null ? null : cipher.methods.stream().filter(m -> m.name.equals("decrypt") |
| 55 | + && m.desc.equals("([B)V")).findFirst().orElse(null); |
| 56 | + if(getCipher != null && decrypt != null) |
| 57 | + { |
| 58 | + MethodNode init = new MethodNode(Opcodes.ACC_PUBLIC, "<init>", "(I)V", null, null); |
| 59 | + init.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); |
| 60 | + init.instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false)); |
| 61 | + init.instructions.add(new InsnNode(Opcodes.RETURN)); |
| 62 | + loader.methods.add(init); |
| 63 | + JavaWrapper instance = vm.newInstance(JavaClass.forName(vm, "JavaPreloader"), "(I)V", vm.newInt(0)); |
| 64 | + loader.methods.remove(init); |
| 65 | + MethodExecution cipherInstance = vm.execute(loader, getCipher, instance, Collections.<JavaWrapper>singletonList( |
| 66 | + vm.getNull())); |
| 67 | + boolean contains = getDeobfuscator().getInputPassthrough().containsKey("JavaSerialNo.class"); |
| 68 | + byte[] decryptionKey = null; |
| 69 | + if(contains) |
| 70 | + { |
| 71 | + byte[] data = getDeobfuscator().getInputPassthrough().get("JavaSerialNo.class"); |
| 72 | + JavaWrapper byteArr = ArrayConversionHelper.convertByteArray(vm, data); |
| 73 | + vm.execute(cipher, decrypt, cipherInstance.getReturnValue(), Collections.<JavaWrapper>singletonList(byteArr)); |
| 74 | + byte[] b = ArrayConversionHelper.convertByteArray(byteArr.asArray()); |
| 75 | + getDeobfuscator().getInputPassthrough().remove("JavaSerialNo.class"); |
| 76 | + getDeobfuscator().loadInput("JavaSerialNo.class", b); |
| 77 | + ClassNode cn = classNodes().stream().filter(c -> c.name.equals("JavaSerialNo")).findFirst().orElse(null); |
| 78 | + MethodNode serialBytes = cn.methods.stream().filter(m -> m.name.equals("toSerialNoBytes")).findFirst().orElse(null); |
| 79 | + MethodExecution execution = vm.execute(cn, serialBytes); |
| 80 | + String res = vm.convertJavaObjectToString(execution.getReturnValue()); |
| 81 | + //Convert to decryption key |
| 82 | + MethodNode hex2Bytes = loader.methods.stream().filter(m -> m.name.equals("hexToBytes")).findFirst().orElse(null); |
| 83 | + MethodExecution execution2 = vm.execute(loader, hex2Bytes, instance, Collections.<JavaWrapper>singletonList( |
| 84 | + vm.getString(res))); |
| 85 | + cipherInstance = vm.execute(loader, getCipher, instance, Collections.<JavaWrapper>singletonList( |
| 86 | + vm.getNull())); |
| 87 | + decryptionKey = ArrayConversionHelper.convertByteArray(execution2.getReturnValue().asArray()); |
| 88 | + JavaWrapper byteArr1 = ArrayConversionHelper.convertByteArray(vm, decryptionKey); |
| 89 | + vm.execute(cipher, decrypt, cipherInstance.getReturnValue(), Collections.<JavaWrapper>singletonList(byteArr1)); |
| 90 | + decryptionKey = ArrayConversionHelper.convertByteArray(byteArr1.asArray()); |
| 91 | + cipherInstance = vm.execute(loader, getCipher, instance, Collections.<JavaWrapper>singletonList( |
| 92 | + ArrayConversionHelper.convertByteArray(vm, decryptionKey))); |
| 93 | + } |
| 94 | + Map<String, byte[]> decrypted = new HashMap<>(); |
| 95 | + for(Entry<String, byte[]> passthrough : getDeobfuscator().getInputPassthrough().entrySet()) |
| 96 | + if(passthrough.getKey().endsWith(".class")) |
| 97 | + { |
| 98 | + byte[] data = passthrough.getValue(); |
| 99 | + if(data[0] != -54 || data[1] != -2 || data[2] != -70 || data[3] != -66) |
| 100 | + { |
| 101 | + cipherInstance = vm.execute(loader, getCipher, instance, Collections.<JavaWrapper>singletonList( |
| 102 | + decryptionKey == null ? vm.getNull() : ArrayConversionHelper.convertByteArray(vm, decryptionKey))); |
| 103 | + JavaWrapper byteArr = ArrayConversionHelper.convertByteArray(vm, data); |
| 104 | + vm.execute(cipher, decrypt, cipherInstance.getReturnValue(), Collections.<JavaWrapper>singletonList(byteArr)); |
| 105 | + byte[] b = ArrayConversionHelper.convertByteArray(byteArr.asArray()); |
| 106 | + decrypted.put(passthrough.getKey(), b); |
| 107 | + count.getAndIncrement(); |
| 108 | + } |
| 109 | + } |
| 110 | + for(Entry<String, byte[]> entry : decrypted.entrySet()) |
| 111 | + { |
| 112 | + getDeobfuscator().getInputPassthrough().remove(entry.getKey()); |
| 113 | + getDeobfuscator().loadInput(entry.getKey(), entry.getValue()); |
| 114 | + } |
| 115 | + //Delete all class files related to encryption |
| 116 | + classNodes().removeIf(c -> c.name.equals("JavaPreloader$1") || c.name.equals("JavaPreloader$2") |
| 117 | + || c.name.equals("JavaPreloader$3") || c.name.equals("JavaPreloader$Cipher") |
| 118 | + || c.name.equals("JavaPreloader$KlassLoader") || c.name.equals("JavaPreloader$Loader") |
| 119 | + || c.name.equals("JavaPreloader$Protected") || c.name.equals("JavaPreloader") |
| 120 | + || c.name.equals("JavaSerialNo") || c.name.equals("SerialNoClass") |
| 121 | + || c.name.equals("com/bisguard/utils/Authenticator")); |
| 122 | + //Set Main-Class to Subordinate-Class |
| 123 | + String realMain = null; |
| 124 | + int index = -1; |
| 125 | + String[] lines = new String(getDeobfuscator().getInputPassthrough().get("META-INF/MANIFEST.MF")).split("\n"); |
| 126 | + for(int i = 0; i < lines.length; i++) |
| 127 | + { |
| 128 | + String line = lines[i]; |
| 129 | + if(line.startsWith("Subordinate-Class: ")) |
| 130 | + realMain = line.replace("Subordinate-Class: ", ""); |
| 131 | + else if(line.startsWith("Main-Class: ")) |
| 132 | + index = i; |
| 133 | + } |
| 134 | + lines[index] = "Main-Class: " + realMain; |
| 135 | + String res = ""; |
| 136 | + for(String line : lines) |
| 137 | + res += line + "\n"; |
| 138 | + res = res.substring(0, res.length() - 2); |
| 139 | + getDeobfuscator().getInputPassthrough().put("META-INF/MANIFEST.MF", res.getBytes()); |
| 140 | + } |
| 141 | + System.out.println("[Special] [BisGuardTransformer] Decrypted " + count.get() + " classes"); |
| 142 | + System.out.println("[Special] [BisGuardTransformer] Done"); |
| 143 | + return count.get() > 0; |
| 144 | + } |
| 145 | +} |
0 commit comments