Repository: alpheratzteam/obfuscator Branch: master Commit: a03cc48293a7 Files: 42 Total size: 89.6 KB Directory structure: gitextract_o39oe31y/ ├── .gitignore ├── .idea/ │ └── .gitignore ├── LICENSE ├── README.md ├── build.gradle.kts ├── gradle/ │ └── wrapper/ │ └── gradle-wrapper.properties ├── gradle.properties ├── gradlew ├── gradlew.bat ├── settings.gradle.kts └── src/ └── main/ └── kotlin/ └── pl/ └── alpheratzteam/ └── obfuscator/ ├── Obfuscator.kt ├── api/ │ ├── number/ │ │ ├── NumberData.kt │ │ └── NumberType.kt │ └── transformer/ │ └── Transformer.kt ├── main.kt ├── transformer/ │ ├── AntiDebugTransformer.kt │ ├── BadAnnotationTransformer.kt │ ├── BooleanObfuscationTransformer.kt │ ├── DebugInfoRemoverTransformer.kt │ ├── FakeInstructionsTransformer.kt │ ├── FlowTransformer.kt │ ├── FullAccessTransformer.kt │ ├── HideCodeTransformer.kt │ ├── LocalVariableTransformer.kt │ ├── MarkerTransformer.kt │ ├── NumberTransformer.kt │ ├── ShuffleMemberTransformer.kt │ ├── SignatureTransformer.kt │ ├── SourceFileTransformer.kt │ ├── ThrowableTransformer.kt │ ├── TrashCodeTransformer.kt │ ├── TrashExceptionTransformer.kt │ └── optimizer/ │ ├── FieldAccessTransformer.kt │ ├── GotoInlinerTransformer.kt │ └── NopRemoverTransformer.kt └── util/ ├── AsmUtil.kt ├── ConditionUtil.kt ├── InsnBuilder.kt ├── JarUtil.kt ├── RandomUtil.kt ├── StringUtil.kt └── Util.kt ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # Compiled class file *.class # Log file *.log # BlueJ files *.ctxt # Mobile Tools for Java (J2ME) .mtj.tmp/ # Package Files # *.jar *.war *.nar *.ear *.zip *.tar.gz *.rar # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* ================================================ FILE: .idea/.gitignore ================================================ # Default ignored files /shelf/ /workspace.xml # Datasource local storage ignored files /../../../../../../:\Users\Unix\IdeaProjects\Obfuscator\.idea/dataSources/ /dataSources.local.xml # Editor-based HTTP Client requests /httpRequests/ ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2019 AlpheratzTeam Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # Java Obfuscator Java Obfuscator for protecting your Java applications. You can find further instruction on compilation and usage below. [![Discord Badge](https://discordapp.com/api/guilds/615439391132876850/widget.png)](https://discord.gg/Teh8Sqb) *** ## Getting Started todo *** ### TODO - ~~boolean obf~~ - new string encryption - ~~java -> kotlin~~ - ~~insn builder~~ - ~~number obf~~ - ~~crc32 error~~ - class/method/field renamer - decompilators crasher - website (?) - gui (c++, jni) - configuration toml/json *** ================================================ FILE: build.gradle.kts ================================================ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { kotlin("jvm") version "1.4.10" application } group = "pl.alpheratzteam" version = "1.0-SNAPSHOT" repositories { mavenCentral() maven("http://oss.sonatype.org/content/groups/public/") } dependencies { implementation("org.ow2.asm:asm:9.0") implementation("org.ow2.asm:asm-tree:9.0") implementation("org.ow2.asm:asm-commons:9.0") implementation("org.ow2.asm:asm-util:9.0") testImplementation(kotlin("test-junit")) implementation(kotlin("reflect")) } tasks.test { useJUnit() } tasks.withType { kotlinOptions.jvmTarget = "1.8" } application { mainClassName = "pl.alpheratzteam.obfuscator.MainKt" } ================================================ FILE: gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: gradle.properties ================================================ kotlin.code.style=official ================================================ FILE: gradlew ================================================ #!/usr/bin/env sh # # Copyright 2015 the original author or authors. # # 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 # # https://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. # ############################################################################## ## ## Gradle start up script for UN*X ## ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link PRG="$0" # Need this for relative symlinks. while [ -h "$PRG" ] ; do ls=`ls -ld "$PRG"` link=`expr "$ls" : '.*-> \(.*\)$'` if expr "$link" : '/.*' > /dev/null; then PRG="$link" else PRG=`dirname "$PRG"`"/$link" fi done SAVED="`pwd`" cd "`dirname \"$PRG\"`/" >/dev/null APP_HOME="`pwd -P`" cd "$SAVED" >/dev/null APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" warn () { echo "$*" } die () { echo echo "$*" echo exit 1 } # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "`uname`" in CYGWIN* ) cygwin=true ;; Darwin* ) darwin=true ;; MINGW* ) msys=true ;; NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD="$JAVA_HOME/jre/sh/java" else JAVACMD="$JAVA_HOME/bin/java" fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD="java" which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi # Increase the maximum file descriptors if we can. if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then MAX_FD="$MAX_FD_LIMIT" fi ulimit -n $MAX_FD if [ $? -ne 0 ] ; then warn "Could not set maximum file descriptor limit: $MAX_FD" fi else warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" fi fi # For Darwin, add options to specify how the application appears in the dock if $darwin; then GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi # For Cygwin or MSYS, switch paths to Windows format before running java if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` SEP="" for dir in $ROOTDIRSRAW ; do ROOTDIRS="$ROOTDIRS$SEP$dir" SEP="|" done OURCYGPATTERN="(^($ROOTDIRS))" # Add a user-defined pattern to the cygpath arguments if [ "$GRADLE_CYGPATTERN" != "" ] ; then OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" fi # Now convert the arguments - kludge to limit ourselves to /bin/sh i=0 for arg in "$@" ; do CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` else eval `echo args$i`="\"$arg\"" fi i=`expr $i + 1` done case $i in 0) set -- ;; 1) set -- "$args0" ;; 2) set -- "$args0" "$args1" ;; 3) set -- "$args0" "$args1" "$args2" ;; 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi # Escape application args save () { for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done echo " " } APP_ARGS=`save "$@"` # Collect all arguments for the java command, following the shell quoting and substitution rules eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" exec "$JAVACMD" "$@" ================================================ FILE: gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if "%ERRORLEVEL%"=="0" goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 exit /b 1 :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: settings.gradle.kts ================================================ rootProject.name = "Obfuscator" ================================================ FILE: src/main/kotlin/pl/alpheratzteam/obfuscator/Obfuscator.kt ================================================ package pl.alpheratzteam.obfuscator import org.objectweb.asm.tree.ClassNode import pl.alpheratzteam.obfuscator.transformer.* import pl.alpheratzteam.obfuscator.util.JarUtil import java.io.File /** * @author Unix * @since 16.12.2020 */ class Obfuscator { private val dataFolder = File("obfuscator") // base folder val classes = mutableMapOf() // classes from jar val assets = mutableMapOf() // assets from jar /** * The main startup method of the obfuscator. */ fun onStart() { val jarFile = File(dataFolder, "jars").apply { // create files dataFolder.mkdir() mkdir() } JarUtil.loadJar(File(jarFile, "input.jar")).apply { // load classes, assets from jar println("Loading jar...") }.run { println("Loaded jar!") println("Starting transformers...") classes.putAll(first) assets.putAll(second) } val transformers = mutableListOf(ThrowableTransformer()) // modifiers transformers.forEach { val name = it.javaClass.simpleName var time = System.currentTimeMillis() println("Running $name transformer...") it.transform(this) // modify classes time = System.currentTimeMillis() - time println("Finished running $name transformer. [$time ms]") println("---------------------------------------") } JarUtil.saveJar(File(jarFile, "output.jar"), Pair(classes, assets)).apply { // save output println("Saving jar...") }.run { println("Saved jar!") } } } ================================================ FILE: src/main/kotlin/pl/alpheratzteam/obfuscator/api/number/NumberData.kt ================================================ package pl.alpheratzteam.obfuscator.api.number import org.objectweb.asm.Opcodes.* import org.objectweb.asm.tree.FieldNode /** * @author Unix * @since 03.04.2021 */ class NumberData(val fieldName: String, val numberType: NumberType) { val numbers = mutableMapOf() var size = 0 fun addNumber(id: Int, number: T) { numbers[id] = number } fun getFieldNode() : FieldNode { return FieldNode(ACC_STATIC + ACC_PRIVATE, fieldName, numberType.descriptor, null, null) } } //class NumberData(val fieldName: String, val numberType: NumberType, val opcodes: Array) { // // val numbers = mutableMapOf() // var size = 0 // // fun addNumber(id: Int, number: Any) { // numbers[id] = number as T // } // // fun getFieldNode() : FieldNode { // return FieldNode(ACC_STATIC + ACC_PRIVATE, fieldName, numberType.descriptor, null, null) // } // // fun isNumber(abstractInsnNode: AbstractInsnNode) : Boolean { // return when(numberType) { // NumberType.INTEGER -> ASMUtil.isIntInsn(abstractInsnNode) // NumberType.DOUBLE -> ASMUtil.isDoubleInsn(abstractInsnNode) // NumberType.FLOAT -> ASMUtil.isFloatInsn(abstractInsnNode) // NumberType.LONG -> ASMUtil.isLongInsn(abstractInsnNode) // } // } // // fun getNumber(abstractInsnNode: AbstractInsnNode) : Number { // return when(numberType) { // NumberType.INTEGER -> ASMUtil.getIntFromInsn(abstractInsnNode) // NumberType.DOUBLE -> ASMUtil.getDoubleFromInsn(abstractInsnNode) // NumberType.FLOAT -> ASMUtil.getFloatFromInsn(abstractInsnNode) // NumberType.LONG -> ASMUtil.getLongFromInsn(abstractInsnNode) // } // } // //} ================================================ FILE: src/main/kotlin/pl/alpheratzteam/obfuscator/api/number/NumberType.kt ================================================ package pl.alpheratzteam.obfuscator.api.number import org.objectweb.asm.Opcodes.* import org.objectweb.asm.tree.InsnNode /** * @author Unix * @since 03.04.2021 */ enum class NumberType(val store: Int, val opcode: Int, val descriptor: String) { INTEGER(IASTORE, T_INT, "[I"), DOUBLE(DASTORE, T_DOUBLE, "[D"), FLOAT(FASTORE, T_FLOAT, "[F"), LONG(LASTORE, T_LONG, "[J") } ================================================ FILE: src/main/kotlin/pl/alpheratzteam/obfuscator/api/transformer/Transformer.kt ================================================ package pl.alpheratzteam.obfuscator.api.transformer import pl.alpheratzteam.obfuscator.Obfuscator /** * @author Unix * @since 16.12.2020 */ interface Transformer { /** * This method transform some classes by obfuscator. * @param obfuscator as instance of obfuscator. * @see [ClassNode] class to transform. */ fun transform(obfuscator: Obfuscator) } ================================================ FILE: src/main/kotlin/pl/alpheratzteam/obfuscator/main.kt ================================================ import pl.alpheratzteam.obfuscator.Obfuscator /** * @author Unix * @since 16.12.2020 */ /** * This method starts the obfuscator. * @see [Obfuscator] obfuscator class. */ fun main() { Obfuscator().onStart() // start application } ================================================ FILE: src/main/kotlin/pl/alpheratzteam/obfuscator/transformer/AntiDebugTransformer.kt ================================================ package pl.alpheratzteam.obfuscator.transformer import org.objectweb.asm.Opcodes.* import pl.alpheratzteam.obfuscator.Obfuscator import pl.alpheratzteam.obfuscator.api.transformer.Transformer import pl.alpheratzteam.obfuscator.util.insnBuilder import org.objectweb.asm.tree.LabelNode import org.objectweb.asm.tree.MethodInsnNode import org.objectweb.asm.tree.MethodNode import pl.alpheratzteam.obfuscator.util.StringUtil /** * @author Unix * @since 17.12.2020 */ class AntiDebugTransformer : Transformer { private val debugTypes = arrayOf("-Xbootclasspath", "-Xdebug", "-agentlib", "-Xrunjdwp:", "-verbose") override fun transform(obfuscator: Obfuscator) { obfuscator.classes.values.forEach { classNode -> classNode.methods.find { it.name.equals("") }.also { val methodNode = makeMethod() it?.instructions?.insertBefore(it.instructions.last, MethodInsnNode(INVOKESTATIC, classNode.name, methodNode.name, methodNode.desc, false)) classNode.methods.add(methodNode) } } } private fun makeMethod(): MethodNode { val method = MethodNode() with(method) { access = ACC_PRIVATE or ACC_STATIC name = StringUtil.generateString(8) desc = "()V" signature = null exceptions = null maxStack = 2 instructions = insnBuilder { invokestatic("java/lang/management/ManagementFactory", "getRuntimeMXBean", "()Ljava/lang/management/RuntimeMXBean;", false) invokeinterface("java/lang/management/RuntimeMXBean", "getInputArguments", "()Ljava/util/List;", true) invokeinterface("java/util/List", "iterator", "()Ljava/util/Iterator;", true) astore(1) val label1 = LabelNode() +label1 frame(F_APPEND, 1, arrayOf("java/util/Iterator"), 0, null) aload(1) invokeinterface("java/util/Iterator", "hasNext", "()Z", true) val label2 = LabelNode() ifeq(label2) aload(1) invokeinterface("java/util/Iterator", "next", "()Ljava/lang/Object;", true) checkcast("java/lang/String") astore(2) +LabelNode() aload(2) ldc("-javaagent:") invokevirtual("java/lang/String", "startsWith", "(Ljava/lang/String;)Z", false) val label4 = LabelNode() debugTypes.forEach { ifne(label4) aload(2) ldc(it) invokevirtual("java/lang/String", "startsWith", "(Ljava/lang/String;)Z", false) } val label5 = LabelNode() ifeq(label5) +label4 frame(F_APPEND, 1, arrayOf("java/lang/String"), 0, null) insn(ICONST_0) invokestatic("java/lang/System", "exit", "(I)V", false) +label5 frame(F_CHOP, 1, null, 0, null) goto(label1) +label2 frame(F_CHOP, 1, null, 0, null) _return() } } return method } } ================================================ FILE: src/main/kotlin/pl/alpheratzteam/obfuscator/transformer/BadAnnotationTransformer.kt ================================================ package pl.alpheratzteam.obfuscator.transformer import org.objectweb.asm.tree.AnnotationNode import pl.alpheratzteam.obfuscator.Obfuscator import pl.alpheratzteam.obfuscator.api.transformer.Transformer import pl.alpheratzteam.obfuscator.util.RandomUtil import pl.alpheratzteam.obfuscator.util.StringUtil import java.util.Objects /** * @author Unix * @since 17.12.2020 */ class BadAnnotationTransformer : Transformer { private val annotations: MutableList = mutableListOf() init { val string = StringUtil.generateString(RandomUtil.int(10, 64)) repeat((0..RandomUtil.int(1, 10)).count()) { annotations.add(AnnotationNode("L$string;")) } repeat((0..RandomUtil.int(1, 10)).count()) { annotations.add(AnnotationNode(string)) } repeat((0..RandomUtil.int(1, 10)).count()) { annotations.add(AnnotationNode("@$string")) } } override fun transform(obfuscator: Obfuscator) { obfuscator.classes.values.forEach { it.run { if (Objects.isNull(visibleAnnotations)) { visibleAnnotations = mutableListOf() } if (Objects.isNull(invisibleAnnotations)) { invisibleAnnotations = mutableListOf() } val pair = change(visibleAnnotations, invisibleAnnotations) visibleAnnotations = pair.first invisibleAnnotations = pair.second } it.methods.forEach { it.run { if (Objects.isNull(visibleAnnotations)) { visibleAnnotations = mutableListOf() } if (Objects.isNull(invisibleAnnotations)) { invisibleAnnotations = mutableListOf() } val pair = change(visibleAnnotations, invisibleAnnotations) visibleAnnotations = pair.first invisibleAnnotations = pair.second } } it.fields.forEach { it.run { if (Objects.isNull(visibleAnnotations)) { visibleAnnotations = mutableListOf() } if (Objects.isNull(invisibleAnnotations)) { invisibleAnnotations = mutableListOf() } val pair = change(visibleAnnotations, invisibleAnnotations) visibleAnnotations = pair.first invisibleAnnotations = pair.second } } } } fun change(visibleAnnotations: MutableList, invisibleAnnotations: MutableList): Pair, List> { visibleAnnotations.addAll(annotations) invisibleAnnotations.addAll(annotations) return Pair(visibleAnnotations, invisibleAnnotations) } } ================================================ FILE: src/main/kotlin/pl/alpheratzteam/obfuscator/transformer/BooleanObfuscationTransformer.kt ================================================ package pl.alpheratzteam.obfuscator.transformer import org.objectweb.asm.Opcodes.* import org.objectweb.asm.tree.* import pl.alpheratzteam.obfuscator.Obfuscator import pl.alpheratzteam.obfuscator.api.transformer.Transformer import pl.alpheratzteam.obfuscator.util.RandomUtil import pl.alpheratzteam.obfuscator.util.StringUtil import pl.alpheratzteam.obfuscator.util.insnBuilder import java.util.concurrent.atomic.AtomicInteger /** * @author Unix * @since 07.04.2021 */ class BooleanObfuscationTransformer : Transformer { override fun transform(obfuscator: Obfuscator) { obfuscator.classes.values.forEach { classNode -> val fieldName = StringUtil.generateString(8) val ints = mutableListOf() classNode.fields.add(FieldNode(ACC_STATIC + ACC_PRIVATE, fieldName, "[I", null, null)) classNode.methods.forEach { methodNode -> methodNode.instructions.forEach { if (it.previous is InsnNode && it is VarInsnNode) { val value = RandomUtil.int(10, 2000) val insnNode = it.previous as InsnNode if (insnNode.opcode == 4 || insnNode.opcode == 3) { methodNode.instructions.insertBefore(it, makeInsn(classNode, fieldName, ints.size, ints.size + 1)) methodNode.instructions.remove(it.previous) ints.add(value) when (insnNode.opcode) { 4 -> ints.add(value) 3 -> ints.add(value + RandomUtil.int(10, 2000)) } } } } } classNode.methods.filter { it.name.equals("") }.forEach { it.instructions = makeClinit(it, classNode.name, fieldName, ints) } } } private fun makeClinit(methodNode: MethodNode, className: String, fieldName: String, ints: List): InsnList { val insnNode = methodNode.instructions return insnBuilder { ldc(ints.size) newintarray() putstatic(className, fieldName, "[I") val size = AtomicInteger() ints.forEach { getstatic(className, fieldName, "[I") ldc(size.getAndIncrement()) ldc(it) iastore() } +insnNode _return() } } fun makeInsn(classNode: ClassNode, fieldName: String, first: Int, second: Int) : InsnList { return insnBuilder { getstatic(classNode.name, fieldName, "[I") ldc(first) iaload() getstatic(classNode.name, fieldName, "[I") ldc(second) iaload() val labelNode = LabelNode() if_icmpne(labelNode) insn(ICONST_1) val labelNode2 = LabelNode() goto(labelNode2) +labelNode frame(F_SAME, 0, null, 0, null) insn(ICONST_0) +labelNode2 frame(F_SAME1, 0, null, 1, arrayOf(INTEGER)) istore(0) } } } ================================================ FILE: src/main/kotlin/pl/alpheratzteam/obfuscator/transformer/DebugInfoRemoverTransformer.kt ================================================ package pl.alpheratzteam.obfuscator.transformer import org.objectweb.asm.ClassReader import org.objectweb.asm.ClassWriter import org.objectweb.asm.tree.ClassNode import pl.alpheratzteam.obfuscator.Obfuscator import pl.alpheratzteam.obfuscator.api.transformer.Transformer /** * @author Unix * @since 18.12.2020 */ class DebugInfoRemoverTransformer : Transformer { override fun transform(obfuscator: Obfuscator) { val classes = mutableMapOf() obfuscator.classes.values.forEach { val classWriter = ClassWriter(ClassWriter.COMPUTE_MAXS or ClassWriter.COMPUTE_FRAMES) it.accept(classWriter) val newClassNode = ClassNode() ClassReader(classWriter.toByteArray()).accept(newClassNode, ClassReader.SKIP_DEBUG) classes[newClassNode.name] = newClassNode } obfuscator.classes.clear() obfuscator.classes.putAll(classes) } } ================================================ FILE: src/main/kotlin/pl/alpheratzteam/obfuscator/transformer/FakeInstructionsTransformer.kt ================================================ package pl.alpheratzteam.obfuscator.transformer import org.objectweb.asm.Opcodes.* import pl.alpheratzteam.obfuscator.Obfuscator import pl.alpheratzteam.obfuscator.api.transformer.Transformer import pl.alpheratzteam.obfuscator.util.ASMUtil import org.objectweb.asm.tree.InsnNode import org.objectweb.asm.tree.IntInsnNode import org.objectweb.asm.tree.LdcInsnNode import pl.alpheratzteam.obfuscator.util.RandomUtil import java.util.concurrent.atomic.AtomicInteger /** * @author Unix * @since 16.04.2021 */ class FakeInstructionsTransformer : Transformer { // https://github.com/sim0n/Caesium/blob/master/src/main/java/dev/sim0n/caesium/mutator/impl/PolymorphMutator.java override fun transform(obfuscator: Obfuscator) { obfuscator.classes.values.forEach { it.methods.filter { ASMUtil.hasInstructions(it) }.forEach { val index = AtomicInteger() val instructions = it.instructions it.instructions.forEach { if (it is LdcInsnNode) { if (RandomUtil.boolean()) { instructions.insertBefore( it, IntInsnNode(BIPUSH, RandomUtil.int(-64, 64)) ) instructions.insertBefore(it, InsnNode(POP)) } } else if (index.getAndIncrement() % 6 == 0) { if (RandomUtil.float() > 0.6) { instructions.insertBefore( it, IntInsnNode(BIPUSH, RandomUtil.int(-27, 37)) ) instructions.insertBefore(it, InsnNode(POP)) } else { instructions.insertBefore(it, InsnNode(NOP)) } } } } } } } ================================================ FILE: src/main/kotlin/pl/alpheratzteam/obfuscator/transformer/FlowTransformer.kt ================================================ package pl.alpheratzteam.obfuscator.transformer import org.objectweb.asm.Opcodes.* import org.objectweb.asm.tree.FieldInsnNode import org.objectweb.asm.tree.FieldNode import pl.alpheratzteam.obfuscator.Obfuscator import pl.alpheratzteam.obfuscator.api.transformer.Transformer import pl.alpheratzteam.obfuscator.util.StringUtil import org.objectweb.asm.tree.InsnNode import org.objectweb.asm.tree.JumpInsnNode import pl.alpheratzteam.obfuscator.util.ConditionUtil /** * @author Unix * @since 18.12.2020 */ class FlowTransformer : Transformer { override fun transform(obfuscator: Obfuscator) { obfuscator.classes.values.forEach { classNode -> var hasField = false val fieldName = StringUtil.generateString(8) classNode.methods.forEach { methodNode -> methodNode.instructions.filter { it.opcode == GOTO }.forEach { hasField = true with(methodNode) { instructions.insertBefore(it, FieldInsnNode(GETSTATIC, classNode.name, fieldName, "Z")) instructions.insert(it, InsnNode(ATHROW)) instructions.insert(it, InsnNode(ACONST_NULL)) instructions.set(it, JumpInsnNode(IFEQ, (it as JumpInsnNode).label)) } } } ConditionUtil.checkCondition(hasField) { classNode.fields.add(FieldNode(ACC_PUBLIC + ACC_STATIC + ACC_FINAL, fieldName, "Z", null, null)) } } } } ================================================ FILE: src/main/kotlin/pl/alpheratzteam/obfuscator/transformer/FullAccessTransformer.kt ================================================ package pl.alpheratzteam.obfuscator.transformer import org.objectweb.asm.Opcodes.* import pl.alpheratzteam.obfuscator.Obfuscator import pl.alpheratzteam.obfuscator.api.transformer.Transformer /** * @author Unix * @since 18.12.2020 */ class FullAccessTransformer : Transformer { private val accesses = intArrayOf(ACC_ANNOTATION, ACC_FINAL, ACC_ENUM, ACC_INTERFACE, ACC_MANDATED, ACC_MODULE, ACC_OPEN, ACC_STRICT, ACC_SYNCHRONIZED, ACC_SYNTHETIC, ACC_TRANSIENT, ACC_TRANSITIVE, ACC_VARARGS, ACC_DEPRECATED ) // separate (enum): class, method, field override fun transform(obfuscator: Obfuscator) { obfuscator.classes.values.forEach { with (it) { // access = changeAccess(access) // change classNode methods.filter { !it.name.startsWith("<") }.forEach { it.access = changeAccess(it.access) } // change methodNode fields.forEach { it.access = changeAccess(it.access) } // change fieldNode } } } private fun changeAccess(access: Int): Int { var newAccess: Int = access accesses.filter { access and it == 0 }.forEach { newAccess = newAccess or it } return newAccess } } ================================================ FILE: src/main/kotlin/pl/alpheratzteam/obfuscator/transformer/HideCodeTransformer.kt ================================================ package pl.alpheratzteam.obfuscator.transformer import org.objectweb.asm.Opcodes.* import pl.alpheratzteam.obfuscator.Obfuscator import pl.alpheratzteam.obfuscator.api.transformer.Transformer import pl.alpheratzteam.obfuscator.util.ASMUtil import pl.alpheratzteam.obfuscator.util.ConditionUtil import java.util.Objects /** * @author Unix * @since 18.12.2020 */ class HideCodeTransformer : Transformer { override fun transform(obfuscator: Obfuscator) { obfuscator.classes.values.forEach { ConditionUtil.checkCondition(!(ASMUtil.isSynthetic(it.access) && Objects.isNull(it.visibleAnnotations))) { it.access = it.access or ACC_SYNTHETIC } it.methods.forEach { ConditionUtil.checkCondition(!ASMUtil.isSynthetic(it.access)) { it.access = it.access or ACC_SYNTHETIC } ConditionUtil.checkCondition(!it.name.startsWith("<") && ASMUtil.isBridge(it.access)) { it.access = it.access or ACC_BRIDGE } } it.fields.filter { ASMUtil.isStatic(it.access) }.forEach { it.access = it.access or ACC_SYNTHETIC } } } } ================================================ FILE: src/main/kotlin/pl/alpheratzteam/obfuscator/transformer/LocalVariableTransformer.kt ================================================ package pl.alpheratzteam.obfuscator.transformer import pl.alpheratzteam.obfuscator.Obfuscator import pl.alpheratzteam.obfuscator.api.transformer.Transformer import pl.alpheratzteam.obfuscator.util.StringUtil import java.util.* /** * @author Unix * @since 18.12.2020 */ class LocalVariableTransformer : Transformer { override fun transform(obfuscator: Obfuscator) { obfuscator.classes.flatMap { it.value.methods } .filter { Objects.nonNull(it.localVariables) } .flatMap { it.localVariables } .forEach { it.name = StringUtil.generateString(16) } } } ================================================ FILE: src/main/kotlin/pl/alpheratzteam/obfuscator/transformer/MarkerTransformer.kt ================================================ package pl.alpheratzteam.obfuscator.transformer import org.objectweb.asm.Opcodes.* import org.objectweb.asm.tree.MethodNode import pl.alpheratzteam.obfuscator.Obfuscator import pl.alpheratzteam.obfuscator.api.transformer.Transformer import pl.alpheratzteam.obfuscator.util.insnBuilder /** * @author Unix * @since 18.12.2020 */ class MarkerTransformer : Transformer { private val methodName = "hello" private val text = "your text here" override fun transform(obfuscator: Obfuscator) { val methodNode = makeMethod() obfuscator.classes.values.forEach { it.methods.add(methodNode) } } private fun makeMethod(): MethodNode { val method = MethodNode() with(method) { access = ACC_PRIVATE or ACC_STATIC name = methodName desc = "()V" signature = null exceptions = null instructions = insnBuilder { getstatic("java/lang/System", "out", "Ljava/io/PrintStream;") ldc(text) invokevirtual("java/io/PrintStream", "println", "(Ljava/lang/String;)V", false) _return() } } return method } } ================================================ FILE: src/main/kotlin/pl/alpheratzteam/obfuscator/transformer/NumberTransformer.kt ================================================ package pl.alpheratzteam.obfuscator.transformer import org.objectweb.asm.tree.InsnList import org.objectweb.asm.tree.MethodNode import pl.alpheratzteam.obfuscator.Obfuscator import pl.alpheratzteam.obfuscator.api.number.NumberData import pl.alpheratzteam.obfuscator.api.number.NumberType.DOUBLE import pl.alpheratzteam.obfuscator.api.number.NumberType.FLOAT import pl.alpheratzteam.obfuscator.api.number.NumberType.LONG import pl.alpheratzteam.obfuscator.api.number.NumberType.INTEGER import pl.alpheratzteam.obfuscator.api.transformer.Transformer import pl.alpheratzteam.obfuscator.util.* /** * @author Unix * @since 17.12.2020 */ class NumberTransformer : Transformer { // TODO: 04.04.2021 cleanup code, static initialization override fun transform(obfuscator: Obfuscator) { obfuscator.classes.values.forEach { classNode -> val intNumbers = NumberData(StringUtil.generateString(8), INTEGER) val doubleNumbers = NumberData(StringUtil.generateString(8), DOUBLE) val floatNumbers = NumberData(StringUtil.generateString(8), FLOAT) val longNumbers = NumberData(StringUtil.generateString(8), LONG) classNode.fields.add(intNumbers.getFieldNode()) classNode.fields.add(doubleNumbers.getFieldNode()) classNode.fields.add(floatNumbers.getFieldNode()) classNode.fields.add(longNumbers.getFieldNode()) classNode.methods.forEach { methodNode -> methodNode.instructions.forEach { ConditionUtil.checkCondition(ASMUtil.isIntInsn(it)) { // int val fieldNumber = RandomUtil.int(10, 3000) val originalNumber = ASMUtil.getIntFromInsn(it) val fakeNumber = RandomUtil.int(10, 3000) val calcNumber = originalNumber xor fakeNumber * fieldNumber intNumbers.addNumber(intNumbers.size, fieldNumber) methodNode.instructions.insertBefore(it, insnBuilder { ldc(calcNumber) ldc(fakeNumber) getstatic(classNode.name, intNumbers.fieldName, intNumbers.numberType.descriptor) ldc(intNumbers.size) iaload() imul() ixor() }) methodNode.instructions.remove(it) ++intNumbers.size } ConditionUtil.checkCondition(ASMUtil.isDoubleInsn(it)) { // double val fieldNumber = RandomUtil.int(10, 3000).toDouble() val originalNumber = ASMUtil.getDoubleFromInsn(it) val fakeNumber = RandomUtil.int(10, 3000).toDouble() val calcNumber = originalNumber * fakeNumber * fieldNumber doubleNumbers.addNumber(doubleNumbers.size, fieldNumber) methodNode.instructions.insertBefore(it, insnBuilder { ldc(calcNumber) ldc(fakeNumber) getstatic(classNode.name, doubleNumbers.fieldName, doubleNumbers.numberType.descriptor) ldc(doubleNumbers.size) daload() dmul() ddiv() }) methodNode.instructions.remove(it) ++doubleNumbers.size } ConditionUtil.checkCondition(ASMUtil.isFloatInsn(it)) { // float val fieldNumber = RandomUtil.int(10, 3000).toFloat() val originalNumber = ASMUtil.getFloatFromInsn(it) val fakeNumber = RandomUtil.int(10, 3000).toFloat() val calcNumber = originalNumber * fakeNumber * fieldNumber floatNumbers.addNumber(floatNumbers.size, fieldNumber) methodNode.instructions.insertBefore(it, insnBuilder { ldc(calcNumber) ldc(fakeNumber) getstatic(classNode.name, floatNumbers.fieldName, floatNumbers.numberType.descriptor) ldc(floatNumbers.size) faload() fmul() fdiv() }) methodNode.instructions.remove(it) ++floatNumbers.size } ConditionUtil.checkCondition(ASMUtil.isLongInsn(it)) { // long val fieldNumber = RandomUtil.int(10, 3000).toLong() val originalNumber = ASMUtil.getLongFromInsn(it) val fakeNumber = RandomUtil.int(10, 3000).toLong() val calcNumber = originalNumber xor fakeNumber * fieldNumber longNumbers.addNumber(longNumbers.size, fieldNumber) methodNode.instructions.insertBefore(it, insnBuilder { ldc(calcNumber) ldc(fakeNumber) getstatic(classNode.name, longNumbers.fieldName, longNumbers.numberType.descriptor) ldc(longNumbers.size) laload() lmul() lxor() }) methodNode.instructions.remove(it) ++longNumbers.size } } } with (classNode) { methods.filter { it.name.equals("") }.forEach { it.instructions = makeClinit(it, classNode.name, intNumbers) it.instructions = makeClinit(it, classNode.name, doubleNumbers) it.instructions = makeClinit(it, classNode.name, floatNumbers) it.instructions = makeClinit(it, classNode.name, longNumbers) } } } } private fun makeClinit(methodNode: MethodNode, className: String, numberData: NumberData): InsnList { val insnNode = methodNode.instructions return insnBuilder { ldc(numberData.size) newarray(numberData.numberType.opcode) putstatic(className, numberData.fieldName, numberData.numberType.descriptor) numberData.numbers.forEach { (key, value) -> getstatic(className, numberData.fieldName, numberData.numberType.descriptor) ldc(key) when (numberData.numberType) { INTEGER -> ldc(value as Int) LONG -> ldc(value as Long) DOUBLE -> ldc(value as Double) FLOAT -> ldc(value as Float) } insn(numberData.numberType.store) } +insnNode _return() } } } // FIXME: 07.04.2021 V error - Exception in thread "main" java.lang.NegativeArraySizeException: -1 //class NumberTransformer : Transformer { // // // TODO: 04.04.2021 static initialization, unique string generator // // override fun transform(obfuscator: Obfuscator) { // obfuscator.classes.values.forEach { classNode -> // val numberDatas = listOf(NumberData(StringUtil.generateString(8), INTEGER, arrayOf(IALOAD, IMUL, IXOR)), NumberData(StringUtil.generateString(8), LONG, arrayOf(LALOAD, LMUL, LXOR)), // NumberData(StringUtil.generateString(8), DOUBLE, arrayOf(DALOAD, DMUL, DDIV)), NumberData(StringUtil.generateString(8), FLOAT, arrayOf(FALOAD, FMUL, FDIV))) // // numberDatas.forEach { classNode.fields.add(it.getFieldNode()) } // // classNode.methods.forEach { methodNode -> // numberDatas.forEach { numberData -> // methodNode.instructions.forEach { abstractInsnNode -> // ConditionUtil.checkCondition(numberData.isNumber(abstractInsnNode)) { // val fieldNumber = RandomUtil.int(10, 3000) // val originalNumber = numberData.getNumber(abstractInsnNode) // val fakeNumber = RandomUtil.int(10, 3000) // methodNode.instructions.insertBefore(abstractInsnNode, insnBuilder { // when (numberData.numberType) { // INTEGER -> { // numberData.addNumber(numberData.size, fieldNumber) // ldc((originalNumber.toInt() xor fakeNumber * fieldNumber)) // } // DOUBLE -> { // numberData.addNumber(numberData.size, fieldNumber.toDouble()) // ldc((originalNumber.toDouble() * fakeNumber * fieldNumber)) // } // FLOAT -> { // numberData.addNumber(numberData.size, fieldNumber.toFloat()) // ldc((originalNumber.toFloat() * fakeNumber * fieldNumber)) // } // LONG -> { // numberData.addNumber(numberData.size, fieldNumber.toLong()) // ldc((originalNumber.toLong() xor fakeNumber.toLong() * fieldNumber)) // } // } // // ldc(fakeNumber) // getstatic(classNode.name, numberData.fieldName, numberData.numberType.descriptor) // ldc(numberData.size) // numberData.opcodes.forEach { insn(it) } // }) // // methodNode.instructions.remove(abstractInsnNode) // ++numberData.size // } // } // } // } // // with (classNode) { // methods.filter { it.name.equals("") }.forEach { methodNode -> // val insnList = InsnList() // numberDatas.forEach { insnList.add(makeClinit(classNode.name, it)) } // // if (Objects.isNull(methodNode.instructions)) { // methodNode.instructions = InsnList() // } // // val cachedInsnNode = methodNode.instructions // methodNode.instructions.clear() // methodNode.instructions.add(insnBuilder { // +insnList // +cachedInsnNode // _return() // }) // } // } // } // } // // private fun makeClinit(className: String, numberData: NumberData): InsnList { // return insnBuilder { // ldc(numberData.size) // newarray(numberData.numberType.opcode) // putstatic(className, numberData.fieldName, numberData.numberType.descriptor) // numberData.numbers.forEach { (key, value) -> // getstatic(className, numberData.fieldName, numberData.numberType.descriptor) // ldc(key) // when (numberData.numberType) { // INTEGER -> ldc(value as Int) // LONG -> ldc(value as Long) // DOUBLE -> ldc(value as Double) // FLOAT -> ldc(value as Float) // } // insn(numberData.numberType.store) // } // } // } // //} ================================================ FILE: src/main/kotlin/pl/alpheratzteam/obfuscator/transformer/ShuffleMemberTransformer.kt ================================================ package pl.alpheratzteam.obfuscator.transformer import pl.alpheratzteam.obfuscator.Obfuscator import pl.alpheratzteam.obfuscator.api.transformer.Transformer /** * @author Unix * @since 18.12.2020 */ class ShuffleMemberTransformer : Transformer { override fun transform(obfuscator: Obfuscator) { obfuscator.classes.values.forEach { it.attrs?.shuffle() it.methods?.shuffle() it.methods?.forEach { it.localVariables?.shuffle() it.parameters?.shuffle() it.attrs?.shuffle() } it.fields?.shuffle() it.fields?.forEach { it.attrs?.shuffle() } } } } ================================================ FILE: src/main/kotlin/pl/alpheratzteam/obfuscator/transformer/SignatureTransformer.kt ================================================ package pl.alpheratzteam.obfuscator.transformer import pl.alpheratzteam.obfuscator.Obfuscator import pl.alpheratzteam.obfuscator.api.transformer.Transformer import pl.alpheratzteam.obfuscator.util.StringUtil /** * @author Unix * @since 16.12.2020 */ class SignatureTransformer : Transformer { override fun transform(obfuscator: Obfuscator) = obfuscator.classes.values.forEach { it.signature = StringUtil.makeUnreadable(StringUtil.generateString(4)) } } ================================================ FILE: src/main/kotlin/pl/alpheratzteam/obfuscator/transformer/SourceFileTransformer.kt ================================================ package pl.alpheratzteam.obfuscator.transformer import pl.alpheratzteam.obfuscator.Obfuscator import pl.alpheratzteam.obfuscator.api.transformer.Transformer import pl.alpheratzteam.obfuscator.util.StringUtil /** * @author Unix * @since 18.12.2020 */ class SourceFileTransformer : Transformer { override fun transform(obfuscator: Obfuscator) = obfuscator.classes.values.forEach { it.sourceFile = StringUtil.generateString(Byte.MAX_VALUE.toInt()) } } ================================================ FILE: src/main/kotlin/pl/alpheratzteam/obfuscator/transformer/ThrowableTransformer.kt ================================================ package pl.alpheratzteam.obfuscator.transformer import org.objectweb.asm.Opcodes.F_SAME import org.objectweb.asm.tree.* import pl.alpheratzteam.obfuscator.Obfuscator import pl.alpheratzteam.obfuscator.api.transformer.Transformer import pl.alpheratzteam.obfuscator.util.ASMUtil import pl.alpheratzteam.obfuscator.util.RandomUtil import pl.alpheratzteam.obfuscator.util.StringUtil import pl.alpheratzteam.obfuscator.util.insnBuilder import java.io.IOException import java.lang.annotation.AnnotationTypeMismatchException import java.nio.BufferUnderflowException import java.util.* import kotlin.reflect.KClass /** * @author Unix * @since 03.04.2021 */ class ThrowableTransformer : Transformer { private val exceptions = listOf(get(Exception::class), get(IOException::class), get(BufferUnderflowException::class), get(ExceptionInInitializerError::class), get(ArrayIndexOutOfBoundsException::class), get(ArrayStoreException::class), get(AnnotationTypeMismatchException::class)) override fun transform(obfuscator: Obfuscator) { obfuscator.classes.values.forEach { it.methods.filter { !it.name.startsWith("<") }.forEach { methodNode -> methodNode.instructions .asSequence() .filter { ASMUtil.isInstruction(it) && !Objects.isNull(it.next) } .forEach { methodNode.instructions.insertBefore(it.next, makeInsn()) } } } } fun makeInsn() : InsnList { return insnBuilder { +LabelNode() val bool = RandomUtil.boolean() val type = RandomUtil.int(1, 3) when (type) { 1 -> { val string = StringUtil.generateString(2) ldc(string) when { bool -> { ldc(string + StringUtil.generateString(2)) } else -> { ldc(string) } } invokevirtual("java/lang/String", "equals", "(Ljava/lang/Object;)Z", false) } 2 -> { when (RandomUtil.int(1, 3)) { 1 -> { ldc(RandomUtil.float(1.0, 200.0)) when (RandomUtil.int(1, 3)) { 1 -> invokestatic("java/lang/Float", "isInfinite", "(F)Z", false) 2 -> invokestatic("java/lang/Float", "isNaN", "(F)Z", false) } } 2 -> { ldc(RandomUtil.double(1.0, 200.0)) when (RandomUtil.int(1, 3)) { 1 -> invokestatic("java/lang/Double", "isInfinite", "(D)Z", false) 2 -> invokestatic("java/lang/Double", "isNaN", "(D)Z", false) } } } } } // val string = StringUtil.generateString(2) // ldc(string) // ldc(string + StringUtil.generateString(2)) // invokevirtual("java/lang/String", "equals", "(Ljava/lang/Object;)Z", false) val labelNode = LabelNode() when (type) { 1 -> { when { bool -> { ifeq(labelNode) } else -> { ifne(labelNode) } } } else -> ifeq(labelNode) } val labelNode1 = LabelNode() +labelNode1 when (RandomUtil.int(1, 3)) { 1 -> { val exception: String? = exceptions[RandomUtil.int(exceptions.size)] exception?.let { new(it) dup() invokespecial(it, "", "()V", false) } } else -> aconst_null() } athrow() +labelNode frame(F_SAME, 0, null, 0, null) +LabelNode() } } fun get(any: KClass) = any.qualifiedName?.replace(".", "/") } ================================================ FILE: src/main/kotlin/pl/alpheratzteam/obfuscator/transformer/TrashCodeTransformer.kt ================================================ package pl.alpheratzteam.obfuscator.transformer import org.objectweb.asm.Opcodes.* import org.objectweb.asm.tree.LabelNode import org.objectweb.asm.tree.MethodInsnNode import pl.alpheratzteam.obfuscator.Obfuscator import pl.alpheratzteam.obfuscator.api.transformer.Transformer import pl.alpheratzteam.obfuscator.util.StringUtil import pl.alpheratzteam.obfuscator.util.insnBuilder import pl.alpheratzteam.obfuscator.util.RandomUtil import pl.alpheratzteam.obfuscator.util.printlnAsm /** * @author Unix * @since 18.12.2020 */ class TrashCodeTransformer : Transformer { override fun transform(obfuscator: Obfuscator) { obfuscator.classes.values.forEach { it.methods.filter { !it.name.startsWith("<") }.forEach { methodNode -> methodNode.instructions.filter { it is MethodInsnNode }.map { it as MethodInsnNode } .filter { !it.owner.startsWith("\u0000") }.forEach { methodNode.instructions.insertBefore(it.next, insnBuilder { val bool = RandomUtil.boolean() +LabelNode() // TODO: 17.04.2021 code cleanup. val type = RandomUtil.int(1, 3) when (type) { 1 -> { val string = StringUtil.generateString(2) ldc(string) when { bool -> { ldc(string + StringUtil.generateString(2)) } else -> { ldc(string) } } invokevirtual("java/lang/String", "equals", "(Ljava/lang/Object;)Z", false) } 2 -> { when (RandomUtil.int(1, 3)) { 1 -> { ldc(RandomUtil.float(1.0, 200.0)) when (RandomUtil.int(1, 3)) { 1 -> invokestatic("java/lang/Float", "isInfinite", "(F)Z", false) 2 -> invokestatic("java/lang/Float", "isNaN", "(F)Z", false) } } 2 -> { ldc(RandomUtil.double(1.0, 200.0)) when (RandomUtil.int(1, 3)) { 1 -> invokestatic("java/lang/Double", "isInfinite", "(D)Z", false) 2 -> invokestatic("java/lang/Double", "isNaN", "(D)Z", false) } } } } 3 -> { } } val labelNode = LabelNode() when (type) { 1 -> { when { bool -> { ifeq(labelNode) } else -> { ifne(labelNode) } } } else -> ifeq(labelNode) } val labelNode1 = LabelNode() +labelNode1 // start // todo make switch with shit code. when(RandomUtil.int(1, 3)) { 1 -> { val size = RandomUtil.int(1, 30) val stringBuilder = StringBuilder() stringBuilder.append("(") repeat((1..size).count()) { stringBuilder.append("Ljava/lang/String;") } stringBuilder.append(")V") repeat((1..RandomUtil.int(3, 10)).count()) { +LabelNode() val className = '\u0000' + StringUtil.getStringWithJavaKeywords(6) new(className) repeat((1..size).count()) { ldc(StringUtil.generateString(6)) } invokespecial( className, "", stringBuilder.toString(), false ) +LabelNode() } } 2 -> { val list = mutableListOf>() repeat((0..RandomUtil.int(10, 30)).count()) { list.add(Pair(LabelNode(), it))} val label3 = LabelNode() val labels = mutableListOf() val ints = mutableListOf() list.forEach { labels.add(it.first) ints.add(it.second) } labels.add(label3) ints.add(100) +LabelNode() ldc(RandomUtil.int(10, 2000)) ldc(RandomUtil.int(10, 2000)) ixor() lookupswitch(label3, Pair(ints.toIntArray(), labels.toTypedArray())) +label3 frame(F_SAME, 0, null, 0, null) goto(label3) labels.remove(label3) labels.forEach { +it frame(F_SAME, 0, null, 0, null) when(RandomUtil.int(1, 6)) { 1 -> { new("java/lang/NullPointerException") dup() ldc("AlpheratzObfuscator") invokespecial( "java/lang/NullPointerException", "", "(Ljava/lang/String;)V", false ) athrow() } 2 -> { val size = RandomUtil.int(1, 30) val stringBuilder = StringBuilder() stringBuilder.append("(") repeat((1..size).count()) { stringBuilder.append("Ljava/lang/String;") } stringBuilder.append(")V") repeat((1..RandomUtil.int(3, 10)).count()) { +LabelNode() val className = '\u0000' + StringUtil.getStringWithJavaKeywords(6) new(className) repeat((1..size).count()) { ldc(StringUtil.generateString(6)) } invokespecial( className, "", stringBuilder.toString(), false ) +LabelNode() } } 3 -> { ldc("AlpheratzObfuscator - https://github.com/alpheratzteam/obfuscator") printlnAsm() } 4 -> { aconst_null() athrow() } else -> goto(label3) } } +LabelNode() } } // shit code // end +labelNode frame(F_SAME, 0, null, 0, null) // +LabelNode() }) } } } } } ================================================ FILE: src/main/kotlin/pl/alpheratzteam/obfuscator/transformer/TrashExceptionTransformer.kt ================================================ package pl.alpheratzteam.obfuscator.transformer import pl.alpheratzteam.obfuscator.Obfuscator import pl.alpheratzteam.obfuscator.api.transformer.Transformer import java.io.IOException import java.lang.annotation.AnnotationTypeMismatchException import java.nio.BufferUnderflowException import kotlin.reflect.KClass /** * @author Unix * @since 04.04.2021 */ class TrashExceptionTransformer : Transformer { // TODO: 04.04.2021 get automatic all exceptions from package java/util private val exceptions = listOf(get(Exception::class), get(IOException::class), get(BufferUnderflowException::class), get(ExceptionInInitializerError::class), get(ArrayIndexOutOfBoundsException::class), get(ArrayStoreException::class), get(AnnotationTypeMismatchException::class)) override fun transform(obfuscator: Obfuscator) = obfuscator.classes.values.forEach { it.methods.forEach { it.exceptions.addAll(exceptions) } } fun get(any: KClass) = any.qualifiedName?.replace(".", "/") // fun gets(classes: List>) : List { // val list = mutableListOf() // classes.forEach { get(it)?.let { list.add(it) } } // // return list // } } ================================================ FILE: src/main/kotlin/pl/alpheratzteam/obfuscator/transformer/optimizer/FieldAccessTransformer.kt ================================================ package pl.alpheratzteam.obfuscator.transformer.optimizer import org.objectweb.asm.Opcodes.ACC_FINAL import pl.alpheratzteam.obfuscator.Obfuscator import pl.alpheratzteam.obfuscator.api.transformer.Transformer import pl.alpheratzteam.obfuscator.util.ASMUtil /** * @author Unix * @since 07.04.2021 */ class FieldAccessTransformer : Transformer { override fun transform(obfuscator: Obfuscator) { obfuscator.classes.values.stream() .flatMap { it.fields.stream() } .filter { ASMUtil.isFinal(it.access) } .forEach { it.access -= ACC_FINAL } } } ================================================ FILE: src/main/kotlin/pl/alpheratzteam/obfuscator/transformer/optimizer/GotoInlinerTransformer.kt ================================================ package pl.alpheratzteam.obfuscator.transformer.optimizer import org.objectweb.asm.Opcodes.GOTO import org.objectweb.asm.tree.JumpInsnNode import pl.alpheratzteam.obfuscator.Obfuscator import pl.alpheratzteam.obfuscator.api.transformer.Transformer import pl.alpheratzteam.obfuscator.util.ConditionUtil import java.util.* /** * @author Unix * @since 18.12.2020 */ class GotoInlinerTransformer : Transformer { override fun transform(obfuscator: Obfuscator) { obfuscator.classes.values.forEach { it.methods.forEach { it.instructions.filter { it.opcode == GOTO }.forEach { val gotoJump = it as JumpInsnNode val insnAfterTarget = gotoJump.label.next ConditionUtil.checkCondition(Objects.nonNull(insnAfterTarget)) { when (insnAfterTarget.opcode) { GOTO -> gotoJump.label = (insnAfterTarget as JumpInsnNode).label } } } } } } } ================================================ FILE: src/main/kotlin/pl/alpheratzteam/obfuscator/transformer/optimizer/NopRemoverTransformer.kt ================================================ package pl.alpheratzteam.obfuscator.transformer.optimizer import org.objectweb.asm.Opcodes.NOP import pl.alpheratzteam.obfuscator.Obfuscator import pl.alpheratzteam.obfuscator.api.transformer.Transformer /** * @author Unix * @since 18.12.2020 */ class NopRemoverTransformer : Transformer { override fun transform(obfuscator: Obfuscator) = obfuscator.classes.values.forEach { it.methods.forEach { methodNode -> methodNode.instructions.filter { it.opcode == NOP }.forEach { methodNode.instructions.remove(it) } } } } ================================================ FILE: src/main/kotlin/pl/alpheratzteam/obfuscator/util/AsmUtil.kt ================================================ package pl.alpheratzteam.obfuscator.util import org.objectweb.asm.Opcodes.* import org.objectweb.asm.commons.CodeSizeEvaluator import org.objectweb.asm.tree.* import java.util.* import kotlin.collections.HashMap import kotlin.collections.any import kotlin.collections.filterIndexed import kotlin.collections.forEachIndexed import kotlin.collections.set // https://github.com/ByteZ1337/Vetric/blob/master/src/main/kotlin/xyz/xenondevs/obfuscator/utils/asm/ASMUtils.kt object ASMUtil { /* ------------------ Constants ------------------ */ const val OBJECT_TYPE = "java/lang/Object" /* ------------------ Access Checks ------------------ */ fun isPublic(access: Int) = access and ACC_PUBLIC != 0 fun isPrivate(access: Int) = access and ACC_PRIVATE != 0 fun isProtected(access: Int) = access and ACC_PROTECTED != 0 fun isStatic(access: Int) = access and ACC_STATIC != 0 fun isFinal(access: Int) = access and ACC_FINAL != 0 fun isAbstract(access: Int) = access and ACC_ABSTRACT != 0 fun isNative(access: Int) = access and ACC_NATIVE != 0 fun isEnum(access: Int) = access and ACC_ENUM != 0 fun isInterface(access: Int) = access and ACC_INTERFACE != 0 fun isAnnotation(access: Int) = access and ACC_ANNOTATION != 0 fun isBridge(access: Int) = access and ACC_BRIDGE != 0 fun isMandated(access: Int) = access and ACC_MANDATED != 0 fun isModule(access: Int) = access and ACC_MODULE != 0 fun isOpen(access: Int) = access and ACC_OPEN != 0 fun isStaticPhase(access: Int) = access and ACC_STATIC_PHASE != 0 fun isSuper(access: Int) = access and ACC_SUPER != 0 fun isSynchronized(access: Int) = access and ACC_SYNCHRONIZED != 0 fun isSynthetic(access: Int) = access and ACC_SYNTHETIC != 0 fun isTransient(access: Int) = access and ACC_TRANSIENT != 0 fun isTransitive(access: Int) = access and ACC_TRANSITIVE != 0 fun isVolatile(access: Int) = access and ACC_VOLATILE != 0 fun isVarargs(access: Int) = access and ACC_VARARGS != 0 fun isDeprecated(access: Int) = access and ACC_DEPRECATED != 0 fun isStrict(access: Int) = access and ACC_STRICT != 0 fun AnnotationNode.toHashMap(): HashMap { val map = HashMap() values.filterIndexed { index, _ -> index % 2 == 0 }.forEachIndexed { index, any -> map[any.toString()] = values[index * 2 + 1] } return map } fun hasMethod(name: String, desc: String, clazz: ClassNode) = clazz.methods != null && clazz.methods.any { it.desc == desc && it.name == name } fun getIntInsn(value: Int) = when (value) { in -1..5 -> InsnNode(value + 3) in Byte.MIN_VALUE..Byte.MAX_VALUE -> IntInsnNode(BIPUSH, value) in Short.MIN_VALUE..Short.MAX_VALUE -> IntInsnNode(SIPUSH, value) else -> LdcInsnNode(value) } fun getLongInsn(value: Long) = when (value) { in 0..1 -> InsnNode((value + 9).toInt()) else -> LdcInsnNode(value) } fun getFloatInsn(value: Float) = when { value % 1 == 0f && value in 0f..2f -> InsnNode((value + 11).toInt()) else -> LdcInsnNode(value) } fun getDoubleInsn(value: Double) = when { value % 1 == 0.0 && value in 0.0..1.0 -> InsnNode((value + 14).toInt()) else -> LdcInsnNode(value) } fun isIntInsn(insn: AbstractInsnNode): Boolean { return when { Objects.isNull(insn) -> false else -> { val opcode = insn.opcode (opcode in ICONST_M1..ICONST_5 || opcode == BIPUSH || opcode == SIPUSH || (insn is LdcInsnNode && insn.cst is Int)) } } } fun isLongInsn(insn: AbstractInsnNode): Boolean = insn.opcode == LCONST_0 || insn.opcode == LCONST_1 || (insn is LdcInsnNode && insn.cst is Long) fun isFloatInsn(insn: AbstractInsnNode): Boolean = (insn.opcode in FCONST_0..FCONST_2 || insn is LdcInsnNode && insn.cst is Float) fun isDoubleInsn(insn: AbstractInsnNode): Boolean = (insn.opcode in DCONST_0..DCONST_1 || insn is LdcInsnNode && insn.cst is Double) // https://github.com/ItzSomebody/radon/blob/master/src/main/java/me/itzsomebody/radon/utils/ASMUtils.java fun getIntFromInsn(insn: AbstractInsnNode): Int { val opcode = insn.opcode return when { opcode in ICONST_M1..ICONST_5 -> opcode - 3 insn is IntInsnNode && insn.opcode !== NEWARRAY -> insn.operand insn is LdcInsnNode && insn.cst is Int -> insn.cst as Int else -> throw UnsupportedOperationException() } } fun getLongFromInsn(insn: AbstractInsnNode): Long { val opcode = insn.opcode return when { opcode in LCONST_0..LCONST_1 -> (opcode - 9).toLong() insn is LdcInsnNode && insn.cst is Long -> insn.cst as Long else -> 0L } } fun getFloatFromInsn(insn: AbstractInsnNode): Float { val opcode = insn.opcode return when { opcode in FCONST_0..FCONST_2 -> (opcode - 11).toFloat() insn is LdcInsnNode && insn.cst is Float -> insn.cst as Float else -> .0f } } fun getDoubleFromInsn(insn: AbstractInsnNode): Double { val opcode = insn.opcode return when { opcode in DCONST_0..DCONST_1 -> (opcode - 14).toDouble() insn is LdcInsnNode && insn.cst is Double -> insn.cst as Double else -> .0 } } fun isInstruction(insn: AbstractInsnNode?) = insn !is FrameNode && insn !is LineNumberNode && insn !is LabelNode fun getMaxSize(methodNode: MethodNode): Int { val codeSizeEvaluator = CodeSizeEvaluator(null) methodNode.accept(codeSizeEvaluator) return codeSizeEvaluator.getMaxSize() } fun hasInstructions(methodNode: MethodNode) = Objects.nonNull(methodNode.instructions) && methodNode.instructions.size() > 0 } ================================================ FILE: src/main/kotlin/pl/alpheratzteam/obfuscator/util/ConditionUtil.kt ================================================ package pl.alpheratzteam.obfuscator.util /** * @author Unix * @since 30.03.2021 */ object ConditionUtil { /** * Checks some conditions. * if **true**, runs [Runnable]. * @param condition as conditions to check. * @param runnable as runnable to run. * @see [Runnable] */ fun checkCondition(condition: Boolean, runnable: Runnable) { if (!condition) { return } runnable.run() } } ================================================ FILE: src/main/kotlin/pl/alpheratzteam/obfuscator/util/InsnBuilder.kt ================================================ package pl.alpheratzteam.obfuscator.util import org.objectweb.asm.Handle import org.objectweb.asm.Opcodes.* import org.objectweb.asm.Type import org.objectweb.asm.tree.* /** * @author cookiedragon234, ByteZ */ class InsnBuilder { val list = InsnList() operator fun InsnList.unaryPlus() = list.add(this) operator fun AbstractInsnNode.unaryPlus() = list.add(this) fun Int.insn() = InsnNode(this) fun insn(opcode: Int) = +InsnNode(opcode) fun nop() = insn(NOP) /* Loading constant values */ fun aconst_null() = insn(ACONST_NULL) fun ldc(int: Int) = +ASMUtil.getIntInsn(int) fun ldc(long: Long) = +ASMUtil.getLongInsn(long) fun ldc(float: Float) = +ASMUtil.getFloatInsn(float) fun ldc(double: Double) = +ASMUtil.getDoubleInsn(double) fun ldc(string: String) = +LdcInsnNode(string) fun ldc(type: Type) = +LdcInsnNode(type) fun ldc(handle: Handle) = +LdcInsnNode(handle) /* Locals */ fun istore(`var`: Int) = +VarInsnNode(ISTORE, `var`) fun iload(`var`: Int) = +VarInsnNode(ILOAD, `var`) fun lstore(`var`: Int) = +VarInsnNode(LSTORE, `var`) fun lload(`var`: Int) = +VarInsnNode(LLOAD, `var`) fun fstore(`var`: Int) = +VarInsnNode(FSTORE, `var`) fun fload(`var`: Int) = +VarInsnNode(FLOAD, `var`) fun dstore(`var`: Int) = +VarInsnNode(DSTORE, `var`) fun dload(`var`: Int) = +VarInsnNode(DLOAD, `var`) fun astore(`var`: Int) = +VarInsnNode(ASTORE, `var`) fun aload(`var`: Int) = +VarInsnNode(ALOAD, `var`) /* Array storing & loading */ fun iastore() = insn(IASTORE) fun iaload() = insn(IALOAD) fun lastore() = insn(LASTORE) fun laload() = insn(LALOAD) fun fastore() = insn(FASTORE) fun faload() = insn(FALOAD) fun dastore() = insn(DASTORE) fun daload() = insn(DALOAD) fun aastore() = insn(AASTORE) fun aaload() = insn(AALOAD) fun bastore() = insn(BASTORE) fun baload() = insn(BALOAD) fun castore() = insn(CASTORE) fun caload() = insn(CALOAD) fun sastore() = insn(SASTORE) fun saload() = insn(SALOAD) /* Stack manipulation */ fun pop() = insn(POP) fun pop2() = insn(POP2) fun dup() = insn(DUP) fun dup_x1() = insn(DUP_X1) fun dup_x2() = insn(DUP_X2) fun dup2() = insn(DUP2) fun dup2_x1() = insn(DUP2_X1) fun dup2_x2() = insn(DUP2_X2) fun swap() = insn(SWAP) /* Arithmetic & Bitwise */ fun iadd() = insn(IADD) fun isub() = insn(ISUB) fun imul() = insn(IMUL) fun idiv() = insn(IDIV) fun irem() = insn(IREM) fun ineg() = insn(INEG) fun ishl() = insn(ISHL) fun ishr() = insn(ISHR) fun iushr() = insn(IUSHR) fun iand() = insn(IAND) fun ior() = insn(IOR) fun ixor() = insn(IXOR) fun iinc(`var`: Int, incr: Int) = +IincInsnNode(`var`, incr) fun ladd() = insn(LADD) fun lsub() = insn(LSUB) fun lmul() = insn(LMUL) fun ldiv() = insn(LDIV) fun lrem() = insn(LREM) fun lneg() = insn(LNEG) fun lshl() = insn(LSHL) fun lshr() = insn(LSHR) fun lushr() = insn(LUSHR) fun lor() = insn(LOR) fun land() = insn(LAND) fun lxor() = insn(LXOR) fun fadd() = insn(FADD) fun fsub() = insn(FSUB) fun fmul() = insn(FMUL) fun fdiv() = insn(FDIV) fun frem() = insn(FREM) fun fneg() = insn(FNEG) fun dadd() = insn(DADD) fun dsub() = insn(DSUB) fun dmul() = insn(DMUL) fun ddiv() = insn(DDIV) fun drem() = insn(DREM) fun dneg() = insn(DNEG) /* Primitive type conversion */ fun i2l() = insn(I2L) fun i2f() = insn(I2F) fun i2d() = insn(I2D) fun i2b() = insn(I2B) fun i2c() = insn(I2C) fun i2s() = insn(I2S) fun l2i() = insn(L2I) fun l2f() = insn(L2F) fun l2d() = insn(L2D) fun f2i() = insn(F2I) fun f2l() = insn(F2L) fun f2d() = insn(F2D) fun d2i() = insn(D2I) fun d2l() = insn(D2L) fun d2f() = insn(D2F) /* Number comparisons */ fun lcmp() = insn(LCMP) fun fcmpl() = insn(FCMPL) fun fcmpg() = insn(FCMPG) fun dcmpl() = insn(DCMPL) fun dcmpg() = insn(DCMPG) /* Jumping */ fun goto(label: LabelNode) = +JumpInsnNode(GOTO, label) fun jsr(label: LabelNode) = +JumpInsnNode(JSR, label) fun ifeq(label: LabelNode) = +JumpInsnNode(IFEQ, label) fun ifne(label: LabelNode) = +JumpInsnNode(IFNE, label) fun iflt(label: LabelNode) = +JumpInsnNode(IFLT, label) fun ifle(label: LabelNode) = +JumpInsnNode(IFLE, label) fun ifge(label: LabelNode) = +JumpInsnNode(IFGE, label) fun ifgt(label: LabelNode) = +JumpInsnNode(IFGT, label) fun if_icmplt(label: LabelNode) = +JumpInsnNode(IF_ICMPLT, label) fun if_icmple(label: LabelNode) = +JumpInsnNode(IF_ICMPLE, label) fun if_icmpge(label: LabelNode) = +JumpInsnNode(IF_ICMPGE, label) fun if_icmpgt(label: LabelNode) = +JumpInsnNode(IF_ICMPGT, label) fun if_icmpeq(label: LabelNode) = +JumpInsnNode(IF_ICMPEQ, label) fun if_icmpne(label: LabelNode) = +JumpInsnNode(IF_ICMPNE, label) fun if_acmpeq(label: LabelNode) = +JumpInsnNode(IF_ACMPEQ, label) fun ifnull(label: LabelNode) = +JumpInsnNode(IFNULL, label) fun ifnonnull(label: LabelNode) = +JumpInsnNode(IFNONNULL, label) // fun tableswitch(baseNumber: Int, dflt: LabelNode, vararg targets: LabelNode) = +constructTableSwitch(baseNumber, dflt, *targets) fun lookupswitch(defaultLabel: LabelNode, lookup: Pair>) = +LookupSwitchInsnNode(defaultLabel, lookup.first, lookup.second) /* Fields */ fun getstatic(owner: String, name: String, desc: String) = +FieldInsnNode(GETSTATIC, owner, name, desc) fun putstatic(owner: String, name: String, desc: String) = +FieldInsnNode(PUTSTATIC, owner, name, desc) fun getfield(owner: String, name: String, desc: String) = +FieldInsnNode(GETFIELD, owner, name, desc) fun putfield(owner: String, name: String, desc: String) = +FieldInsnNode(PUTFIELD, owner, name, desc) /* Method invocation */ fun invokevirtual(owner: String, name: String, desc: String, `interface`: Boolean = false) = +MethodInsnNode(INVOKEVIRTUAL, owner, name, desc, `interface`) fun invokespecial(owner: String, name: String, desc: String, `interface`: Boolean = false) = +MethodInsnNode(INVOKESPECIAL, owner, name, desc, `interface`) fun invokestatic(owner: String, name: String, desc: String, `interface`: Boolean = false) = +MethodInsnNode(INVOKESTATIC, owner, name, desc, `interface`) fun invokeinterface(owner: String, name: String, desc: String, `interface`: Boolean = false) = +MethodInsnNode(INVOKEINTERFACE, owner, name, desc, `interface`) /* Creating new instances */ fun new(type: String) = +TypeInsnNode(NEW, type) fun newarray(type: Int) = +IntInsnNode(NEWARRAY, type) fun anewarray(desc: String) = +TypeInsnNode(ANEWARRAY, desc) fun newboolarray() = newarray(T_BOOLEAN) fun newchararray() = newarray(T_CHAR) fun newbytearray() = newarray(T_BYTE) fun newshortarray() = newarray(T_SHORT) fun newintarray() = newarray(T_INT) fun newlongarray() = newarray(T_LONG) fun newfloatarray() = newarray(T_FLOAT) fun newdoublearray() = newarray(T_DOUBLE) /* Array information */ fun arraylength() = insn(ARRAYLENGTH) /* Throwing exceptions */ fun athrow() = insn(ATHROW) /* Type checks and casts */ fun checkcast(descriptor: String) = +TypeInsnNode(CHECKCAST, descriptor) fun instanceof(descriptor: String) = +TypeInsnNode(INSTANCEOF, descriptor) /* Returns */ fun ireturn() = insn(IRETURN) fun lreturn() = insn(LRETURN) fun freturn() = insn(FRETURN) fun dreturn() = insn(DRETURN) fun areturn() = insn(ARETURN) fun _return() = insn(RETURN) /* Frames */ fun frame(type: Int, numLocal: Int, local: Array?, numStack: Int, stack: Array?) = +FrameNode(type, numLocal, local, numStack, stack) } fun insnBuilder(builder: InsnBuilder.() -> Unit) = InsnBuilder().also(builder).list ================================================ FILE: src/main/kotlin/pl/alpheratzteam/obfuscator/util/JarUtil.kt ================================================ package pl.alpheratzteam.obfuscator.util import org.objectweb.asm.ClassReader import org.objectweb.asm.ClassWriter import org.objectweb.asm.tree.ClassNode import java.io.* import java.lang.Exception import java.util.jar.JarEntry import java.util.jar.JarFile import java.util.jar.JarOutputStream import java.util.zip.CRC32 import java.util.zip.ZipOutputStream /** * @author Unix * @since 16.12.2020 */ object JarUtil { /** * Loads jar file as [Pair]. * @param file input file. * @return [Pair] as readed content from the file. */ fun loadJar(file: File): Pair, MutableMap> { val classes = mutableMapOf() val assets = mutableMapOf() JarFile(file).use { val entries = it.entries() while (entries.hasMoreElements()) { val jarEntry = entries.nextElement() try { val bytes = asByteArray(it.getInputStream(jarEntry)) if (!jarEntry.name.endsWith(".class")) { assets[jarEntry.name] = bytes continue } val classNode = ClassNode() val classReader = ClassReader(bytes) classReader.accept(classNode, ClassReader.EXPAND_FRAMES) classes[classNode.name] = classNode } catch (ex: Exception) { ex.printStackTrace() } } } return Pair(classes, assets) } /** * Saves contents to jar file. * @param file output file. * @param pair content to save. * @throws [IOException] thrown when error is occurred. */ @Throws(IOException::class) fun saveJar(file: File, pair: Pair, MutableMap>) { JarOutputStream(FileOutputStream(file)).use { corrupt(it) // TODO: 04.04.2021 add this to configuration pair.first.values.forEach { classNode -> val classWriter = ClassWriter(ClassWriter.COMPUTE_MAXS or ClassWriter.COMPUTE_FRAMES) it.putNextEntry(JarEntry(classNode.name + ".class")) classNode.accept(classWriter) it.write(classWriter.toByteArray()) it.closeEntry() } pair.second.forEach { (key, value) -> run { it.putNextEntry(JarEntry(key)) it.write(value) it.closeEntry() } } } } /** * This methods reads content from [InputStream] to [ByteArray]. * @param inputStream stream to read. * @return [ByteArray] readed data. */ private fun asByteArray(inputStream: InputStream): ByteArray { return try { val out = ByteArrayOutputStream() var readed: Int while (inputStream.read().also { readed = it } != -1) { out.write(readed) } inputStream.close() out.toByteArray() } catch (ex: Exception) { ex.printStackTrace() ByteArray(0) } } /** * Corrupts the contents of the zip file. * @param outputStream stream to corrupt * @see [ZipOutputStream] */ private fun corrupt(outputStream: ZipOutputStream) { val field = ZipOutputStream::class.java.getDeclaredField("crc") field.isAccessible = true field[outputStream] = object : CRC32() { override fun getValue() = RandomUtil.int(Int.MAX_VALUE).toLong() } } } ================================================ FILE: src/main/kotlin/pl/alpheratzteam/obfuscator/util/RandomUtil.kt ================================================ package pl.alpheratzteam.obfuscator.util import java.util.concurrent.ThreadLocalRandom /** * @author Unix * @since 17.12.2020 */ object RandomUtil { private val random = ThreadLocalRandom.current() /** * Randomizes a number. * @param max as max int range. * @return [Int] randomized int value. */ fun int(max: Int) = random.nextInt(max) /** * Randomizes a number. * @return [Int] randomized int value. */ fun int() = random.nextInt() /** * Randomizes a number. * @return [Double] randomized double value. */ fun double() = random.nextDouble() /** * Randomizes a number. * @return [Float] randomized float value. */ fun float() = random.nextFloat() /** * Randomizes a number. * @param min as min value to randomize. * @param max as max value to randomize. * @return [Int] randomized int value. */ fun int(min: Int, max: Int) = random.nextInt(min, max) /** * Randomizes a number. * @param [min] as min value to randomize. * @param [max] as max value to randomize. * @return [Double] randomized double value. */ fun double(min: Double, max: Double) = random.nextDouble(min, max) /** * Randomizes a number. * @param [min] as min value to randomize. * @param [max] as max value to randomize. * @return [Float] randomized float value. */ fun float(min: Double, max: Double) = double(min, max).toFloat() /** * Randomizes the chance. * @param chance as chance to check. * @return [Boolean], if `true` chance is right. */ fun chance(chance: Double) = Math.random() * 100.0 <= chance /** * Randomizes a boolean. * @return [Boolean] randomized boolean value. */ fun boolean() = random.nextBoolean() } ================================================ FILE: src/main/kotlin/pl/alpheratzteam/obfuscator/util/StringUtil.kt ================================================ package pl.alpheratzteam.obfuscator.util import java.lang.StringBuilder import java.util.stream.Collectors import java.util.stream.IntStream import java.util.concurrent.ThreadLocalRandom /** * @author Unix * @since 17.12.2020 */ object StringUtil { private val chars = "abcdefghijklmnopqrstuvwxyz1234567890".toCharArray() private val javaKeywords = mutableListOf( "abstract", "boolean", "break", "byte", "case", "catch", "char", "class", "continue", "default", "do", "while", "for", "if", "\u0000", "\u0001", "\u0002", "\u0004", "double", "else", "new", "null", "return", "short", "super", "static", "switch", "try", "void", "while", "volatile" ) /** * Generates custom string. * @param length length of the generated string. * @return [String] as generated string. */ fun generateString(length: Int): String { return IntStream.range(0, length) .mapToObj { Character.toString( chars[RandomUtil.int(chars.size)] ) }.collect(Collectors.joining()) } /** * Generates unreadable string. * @param string string to be encoded. * @return [String] as unreadable generated string. */ fun makeUnreadable(string: String): String { // generate unreadable string val stringBuilder = StringBuilder() string.toCharArray().forEach { stringBuilder.append((it + '\u7159'.toInt())) } return stringBuilder.toString() } /** * Generates java keyword string. * @param length length of the generated string. * @return [String] as java keyword generated string. */ fun getStringWithJavaKeywords(length: Int): String { val stringBuilder = StringBuilder() for (index in 0..length) { val keyword = javaKeywords[ThreadLocalRandom.current().nextInt(0, javaKeywords.size)] when { index != 24 -> { stringBuilder.append(keyword).append(" ") } else -> { stringBuilder.append(keyword) } } } return stringBuilder.toString() } } ================================================ FILE: src/main/kotlin/pl/alpheratzteam/obfuscator/util/Util.kt ================================================ package pl.alpheratzteam.obfuscator.util import org.objectweb.asm.Type import org.objectweb.asm.Opcodes.* import org.objectweb.asm.tree.* import java.io.PrintStream import kotlin.reflect.KClass import kotlin.reflect.KFunction /** * @author cookiedragon234 23/Apr/2020 */ inline fun Any?.cast(type: KClass): T = this as T inline fun Any?.cast(type: Class): T = this as T val KClass.internalName: String get() = Type.getInternalName(this.java) inline val KFunction<*>.descriptor: String inline get() { val params = parameters.map { Type.getType(it.type.classifier.cast(KClass::class).java) } val returnType = Type.getType(returnType.classifier.cast(KClass::class).java) return Type.getMethodDescriptor(returnType, *params.toTypedArray()) } fun InsnList.add(opcode: Int) = add(InsnNode(opcode)) fun ldcInt(int: Int): AbstractInsnNode { return if (int == -1) { InsnNode(ICONST_M1) } else if (int == 0) { InsnNode(ICONST_0) } else if (int == 1) { InsnNode(ICONST_1) } else if (int == 2) { InsnNode(ICONST_2) } else if (int == 3) { InsnNode(ICONST_3) } else if (int == 4) { InsnNode(ICONST_4) } else if (int == 5) { InsnNode(ICONST_5) } else if (int >= -128 && int <= 127) { IntInsnNode(BIPUSH, int) } else if (int >= -32768 && int <= 32767) { IntInsnNode(SIPUSH, int) } else { LdcInsnNode(int) } } fun ldcLong(long: Long): AbstractInsnNode { return when (long) { 0L -> InsnNode(LCONST_0) 1L -> InsnNode(LCONST_1) else -> LdcInsnNode(long) } } fun ldcDouble(double: Double): AbstractInsnNode { return when (double) { 0.0 -> InsnNode(DCONST_0) 1.0 -> InsnNode(DCONST_1) else -> LdcInsnNode(double) } } fun ldcFloat(float: Float): AbstractInsnNode { return when (float) { 0f -> InsnNode(FCONST_0) 1f -> InsnNode(FCONST_1) 2f -> InsnNode(FCONST_2) else -> LdcInsnNode(float) } } inline fun constructTableSwitch( baseNumber: Int, defaultLabel: LabelNode, vararg targetLabels: LabelNode ): TableSwitchInsnNode { return TableSwitchInsnNode( baseNumber, baseNumber + targetLabels.size - 1, defaultLabel, *targetLabels ) } inline fun constructLookupSwitch( defaultLabel: LabelNode, lookup: Array> ): LookupSwitchInsnNode { lookup.sortWith { a, b -> a.first.compareTo(b.first) } val keys = lookup.map { it.first }.toIntArray() val values = lookup.map { it.second }.toTypedArray() return LookupSwitchInsnNode( defaultLabel, keys, values ) } fun InsnList.printlnAsm() { add(FieldInsnNode(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;")) add(SWAP) add(MethodInsnNode(INVOKEVIRTUAL, PrintStream::class.internalName, "println", "(Ljava/lang/Object;)V", false)) } fun InsnBuilder.printlnAsm() { +FieldInsnNode(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;") +SWAP.insn() +MethodInsnNode(INVOKEVIRTUAL, PrintStream::class.internalName, "println", "(Ljava/lang/Object;)V", false) } fun InsnList.printlnIntAsm() { add(FieldInsnNode(GETSTATIC, System::class.internalName, "out", "Ljava/io/PrintStream;")) add(InsnNode(SWAP)) add(MethodInsnNode(INVOKEVIRTUAL, PrintStream::class.internalName, "println", "(I)V", false)) } fun InsnBuilder.printlnIntAsm() { +FieldInsnNode(GETSTATIC, System::class.internalName, "out", "Ljava/io/PrintStream;") +SWAP.insn() +MethodInsnNode(INVOKEVIRTUAL, PrintStream::class.internalName, "println", "(I)V", false) } inline fun InsnList.forEach(op: (insn: AbstractInsnNode) -> Unit) = this.iterator().forEach(op)