From ad1e6e16ad881321c1ab47d981d5d6a13ae24c05 Mon Sep 17 00:00:00 2001 From: Michael Rozumyanskiy Date: Fri, 23 Feb 2018 00:23:17 +0300 Subject: [PATCH] Generate a unique Deobfuscator class per project #14 --- .../paranoid/plugin/ParanoidTransform.kt | 5 +-- .../paranoid/processor/Generator.kt | 14 +++++--- .../paranoid/processor/ParanoidProcessor.kt | 32 ++++++++++++++++--- .../paranoid/processor/Patcher.kt | 6 ++-- .../processor/StringLiteralsClassPatcher.kt | 7 ++-- .../paranoid/processor/StringRegistry.kt | 7 +--- .../paranoid/processor/model/Deobfuscator.kt | 25 +++++++++++++++ 7 files changed, 75 insertions(+), 21 deletions(-) create mode 100644 processor/src/main/kotlin/io/michaelrocks/paranoid/processor/model/Deobfuscator.kt diff --git a/gradle-plugin/src/main/java/io/michaelrocks/paranoid/plugin/ParanoidTransform.kt b/gradle-plugin/src/main/java/io/michaelrocks/paranoid/plugin/ParanoidTransform.kt index fe6d122..8db4d47 100644 --- a/gradle-plugin/src/main/java/io/michaelrocks/paranoid/plugin/ParanoidTransform.kt +++ b/gradle-plugin/src/main/java/io/michaelrocks/paranoid/plugin/ParanoidTransform.kt @@ -1,5 +1,5 @@ /* - * Copyright 2017 Michael Rozumyanskiy + * Copyright 2018 Michael Rozumyanskiy * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -54,7 +54,8 @@ class ParanoidTransform(private val android: BaseExtension) : Transform() { classpath = invocation.referencedInputs.flatMap { it.jarInputs.map { it.file } + it.directoryInputs.map { it.file } }, - bootClasspath = android.bootClasspath + bootClasspath = android.bootClasspath, + projectName = invocation.context.path.replace(":transformClassesWithParanoidFor", ":").replace(':', '$') ) try { diff --git a/processor/src/main/kotlin/io/michaelrocks/paranoid/processor/Generator.kt b/processor/src/main/kotlin/io/michaelrocks/paranoid/processor/Generator.kt index 2a2a968..829bc9f 100644 --- a/processor/src/main/kotlin/io/michaelrocks/paranoid/processor/Generator.kt +++ b/processor/src/main/kotlin/io/michaelrocks/paranoid/processor/Generator.kt @@ -1,5 +1,5 @@ /* - * Copyright 2017 Michael Rozumyanskiy + * Copyright 2018 Michael Rozumyanskiy * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ package io.michaelrocks.paranoid.processor import io.michaelrocks.paranoid.processor.logging.getLogger +import io.michaelrocks.paranoid.processor.model.Deobfuscator import java.io.File import java.util.Collections import java.util.HashSet @@ -25,7 +26,10 @@ import javax.tools.JavaFileObject import javax.tools.StandardLocation import javax.tools.ToolProvider -class Generator(private val stringRegistry: StringRegistry) { +class Generator( + private val deobfuscator: Deobfuscator, + private val stringRegistry: StringRegistry +) { private val logger = getLogger() fun generateDeobfuscator( @@ -35,7 +39,7 @@ class Generator(private val stringRegistry: StringRegistry) { bootClasspath: Collection ) { val sourceCode = generateDeobfuscatorSourceCode() - val sourceFile = File(sourcePath, "${DEOBFUSCATOR_TYPE.internalName}.java") + val sourceFile = File(sourcePath, "${deobfuscator.type.internalName}.java") sourceFile.parentFile.mkdirs() genPath.mkdirs() @@ -107,7 +111,7 @@ class Generator(private val stringRegistry: StringRegistry) { val locationChunkCount = (stringCount + chunkSize - 1) / chunkSize return buildString { - val internalName = DEOBFUSCATOR_TYPE.internalName + val internalName = deobfuscator.type.internalName val packageName = internalName.substringBeforeLast('/').replace('/', '.') val className = internalName.substringAfterLast('/') appendln("package $packageName;") @@ -169,7 +173,7 @@ class Generator(private val stringRegistry: StringRegistry) { } appendln() - appendln(" public static String ${DEOBFUSCATION_METHOD.name}(final int id) {") + appendln(" public static String ${deobfuscator.deobfuscationMethod.name}(final int id) {") appendln(" final int offset = locations[id * 2];") appendln(" final int length = locations[id * 2 + 1];") appendln(" final char[] stringChars = new char[length];") diff --git a/processor/src/main/kotlin/io/michaelrocks/paranoid/processor/ParanoidProcessor.kt b/processor/src/main/kotlin/io/michaelrocks/paranoid/processor/ParanoidProcessor.kt index aa46ba2..7fc8b1f 100644 --- a/processor/src/main/kotlin/io/michaelrocks/paranoid/processor/ParanoidProcessor.kt +++ b/processor/src/main/kotlin/io/michaelrocks/paranoid/processor/ParanoidProcessor.kt @@ -1,5 +1,5 @@ /* - * Copyright 2017 Michael Rozumyanskiy + * Copyright 2018 Michael Rozumyanskiy * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,7 +18,11 @@ package io.michaelrocks.paranoid.processor import io.michaelrocks.grip.Grip import io.michaelrocks.grip.GripFactory +import io.michaelrocks.grip.mirrors.getObjectTypeByInternalName import io.michaelrocks.paranoid.processor.logging.getLogger +import io.michaelrocks.paranoid.processor.model.Deobfuscator +import org.objectweb.asm.Type +import org.objectweb.asm.commons.Method import java.io.File class ParanoidProcessor( @@ -27,7 +31,8 @@ class ParanoidProcessor( private val sourcePath: File, private val genPath: File, private val classpath: Collection, - private val bootClasspath: Collection + private val bootClasspath: Collection, + private val projectName: String ) { private val logger = getLogger() @@ -41,8 +46,11 @@ class ParanoidProcessor( val analysisResult = Analyzer(grip).analyze(inputs) analysisResult.dump() - Patcher(stringRegistry, grip.classRegistry).copyAndPatchClasses(inputs, outputs, analysisResult) - Generator(stringRegistry).generateDeobfuscator(sourcePath, genPath, outputs + classpath, bootClasspath) + + val deobfuscator = createDeobfuscator() + logger.info("Prepare to generate {}", deobfuscator) + Patcher(deobfuscator, stringRegistry, grip.classRegistry).copyAndPatchClasses(inputs, outputs, analysisResult) + Generator(deobfuscator, stringRegistry).generateDeobfuscator(sourcePath, genPath, outputs + classpath, bootClasspath) } private fun AnalysisResult.dump() { @@ -60,4 +68,20 @@ class ParanoidProcessor( } } } + + private fun createDeobfuscator(): Deobfuscator { + val deobfuscatorInternalName = "io/michaelrocks/paranoid/Deobfuscator${composeDeobfuscatorNameSuffix()}" + val deobfuscatorType = getObjectTypeByInternalName(deobfuscatorInternalName) + val deobfuscationMethod = Method("getString", Type.getType(String::class.java), arrayOf(Type.INT_TYPE)) + return Deobfuscator(deobfuscatorType, deobfuscationMethod) + } + + private fun composeDeobfuscatorNameSuffix(): String { + val normalizedProjectName = projectName.filter { it.isLetterOrDigit() || it == '_' || it == '$' } + return if (normalizedProjectName.isEmpty() || normalizedProjectName.startsWith('$')) { + normalizedProjectName + } else { + '$' + normalizedProjectName + } + } } diff --git a/processor/src/main/kotlin/io/michaelrocks/paranoid/processor/Patcher.kt b/processor/src/main/kotlin/io/michaelrocks/paranoid/processor/Patcher.kt index 076869e..8b38d0c 100644 --- a/processor/src/main/kotlin/io/michaelrocks/paranoid/processor/Patcher.kt +++ b/processor/src/main/kotlin/io/michaelrocks/paranoid/processor/Patcher.kt @@ -1,5 +1,5 @@ /* - * Copyright 2017 Michael Rozumyanskiy + * Copyright 2018 Michael Rozumyanskiy * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,11 +20,13 @@ import io.michaelrocks.grip.ClassRegistry import io.michaelrocks.grip.mirrors.Type import io.michaelrocks.grip.mirrors.getObjectTypeByInternalName import io.michaelrocks.paranoid.processor.logging.getLogger +import io.michaelrocks.paranoid.processor.model.Deobfuscator import org.objectweb.asm.ClassReader import org.objectweb.asm.ClassWriter import java.io.File class Patcher( + private val deobfuscator: Deobfuscator, private val stringRegistry: StringRegistry, private val classRegistry: ClassRegistry ) { @@ -73,7 +75,7 @@ class Patcher( logger.debug(" Target: {}", targetFile) val reader = ClassReader(sourceFile.readBytes()) val writer = StandaloneClassWriter(reader, ClassWriter.COMPUTE_MAXS or ClassWriter.COMPUTE_FRAMES, classRegistry) - val stringLiteralsPatcher = StringLiteralsClassPatcher(stringRegistry, writer) + val stringLiteralsPatcher = StringLiteralsClassPatcher(deobfuscator, stringRegistry, writer) val stringConstantsPatcher = StringConstantsClassPatcher(configuration, stringLiteralsPatcher) reader.accept(stringConstantsPatcher, ClassReader.SKIP_FRAMES) targetFile.parentFile.mkdirs() diff --git a/processor/src/main/kotlin/io/michaelrocks/paranoid/processor/StringLiteralsClassPatcher.kt b/processor/src/main/kotlin/io/michaelrocks/paranoid/processor/StringLiteralsClassPatcher.kt index 526f5c1..4d12d18 100644 --- a/processor/src/main/kotlin/io/michaelrocks/paranoid/processor/StringLiteralsClassPatcher.kt +++ b/processor/src/main/kotlin/io/michaelrocks/paranoid/processor/StringLiteralsClassPatcher.kt @@ -1,5 +1,5 @@ /* - * Copyright 2017 Michael Rozumyanskiy + * Copyright 2018 Michael Rozumyanskiy * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,16 @@ package io.michaelrocks.paranoid.processor +import io.michaelrocks.grip.mirrors.toAsmType import io.michaelrocks.paranoid.processor.logging.getLogger +import io.michaelrocks.paranoid.processor.model.Deobfuscator import org.objectweb.asm.ClassVisitor import org.objectweb.asm.MethodVisitor import org.objectweb.asm.Opcodes.ASM5 import org.objectweb.asm.commons.GeneratorAdapter class StringLiteralsClassPatcher( + private val deobfuscator: Deobfuscator, private val stringRegistry: StringRegistry, delegate: ClassVisitor ) : ClassVisitor(ASM5, delegate) { @@ -65,7 +68,7 @@ class StringLiteralsClassPatcher( logger.info(" Obfuscating string literal: \"{}\"", string) val stringId = stringRegistry.registerString(string) push(stringId) - invokeStatic(DEOBFUSCATOR_TYPE, DEOBFUSCATION_METHOD) + invokeStatic(deobfuscator.type.toAsmType(), deobfuscator.deobfuscationMethod) } } } diff --git a/processor/src/main/kotlin/io/michaelrocks/paranoid/processor/StringRegistry.kt b/processor/src/main/kotlin/io/michaelrocks/paranoid/processor/StringRegistry.kt index 7eb3297..c22b95f 100644 --- a/processor/src/main/kotlin/io/michaelrocks/paranoid/processor/StringRegistry.kt +++ b/processor/src/main/kotlin/io/michaelrocks/paranoid/processor/StringRegistry.kt @@ -1,5 +1,5 @@ /* - * Copyright 2017 Michael Rozumyanskiy + * Copyright 2018 Michael Rozumyanskiy * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,8 @@ package io.michaelrocks.paranoid.processor -import org.objectweb.asm.Type -import org.objectweb.asm.commons.Method import java.util.HashMap -val DEOBFUSCATOR_TYPE = Type.getObjectType("io/michaelrocks/paranoid/Deobfuscator") -val DEOBFUSCATION_METHOD: Method = Method("getString", Type.getType(String::class.java), arrayOf(Type.INT_TYPE)) - interface StringRegistry { fun registerString(string: String): Int fun getAllIds(): Collection diff --git a/processor/src/main/kotlin/io/michaelrocks/paranoid/processor/model/Deobfuscator.kt b/processor/src/main/kotlin/io/michaelrocks/paranoid/processor/model/Deobfuscator.kt new file mode 100644 index 0000000..666063b --- /dev/null +++ b/processor/src/main/kotlin/io/michaelrocks/paranoid/processor/model/Deobfuscator.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2018 Michael Rozumyanskiy + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.michaelrocks.paranoid.processor.model + +import io.michaelrocks.grip.mirrors.Type +import org.objectweb.asm.commons.Method + +data class Deobfuscator( + val type: Type.Object, + val deobfuscationMethod: Method +)