[
  {
    "path": ".gitignore",
    "content": ".gradle\n.idea\n*.iml\nbuild"
  },
  {
    "path": ".travis.yml",
    "content": "language: java\njdk:\n  - oraclejdk8\n\nafter_success:\n- ./gradlew jacocoTestReport coveralls"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2011 Contra <contra@australia.edu> \n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n"
  },
  {
    "path": "README.md",
    "content": "**JMD is a general purpose Java bytecode deobfuscation tool**\n\n[![Build Status][travis-image]][travis-url] [![Coverage Status][coveralls-image]][coveralls-url]\n\n## Usage\n\n        java -jar JMD.jar <jarfile location> <transformer name> <debug true/false> <transformer specific args>\n\nJMDGUI.exe provides an optional frontend to the command line interface.\n\n## Road map\n   * Actualization transformers\n   * Migrate from BCEL to ASM\n   * Add tests\n\n## Examples\n\n    Remove ZKM obfuscation: java -jar JMD.jar \"C:/Files/Magic.jar\" zkm true\n    Remove Allatori obfuscation: java -jar JMD.jar \"C:/Files/Magic.jar\" allatori true\n    Remove Allatori-Strong obfuscation: java -jar JMD.jar \"C:/Files/Magic.jar\" allatori-strong true\n    Remove JShrink obfuscation: java -jar JMD.jar \"C:/Files/Magic.jar\" jshrink true\n    Remove DashO obfuscation: java -jar JMD.jar \"C:/Files/Magic.jar\" dasho true\n    Remove SmokeScreen obfuscation: java -jar JMD.jar \"C:/Files/Magic.jar\" smokescreen true\n    Remove Generic String obfuscation: java -jar JMD.jar \"C:/Files/Magic.jar\" genericstringdeobfuscator true\n        \n    Find all instances of example.com: java -jar JMD.jar \"C:/Files/Magic.jar\" stringscanner \"example.com\" true\n    Replace all instances of example.com: java -jar JMD.jar \"C:/Files/Magic.jar\" stringreplacer \"example.com\" true \"rscbunlocked.net\"\n    Renamer (currently breaks code): java -jar JMD.jar \"C:/Files/Magic.jar\" renamer true\n    Correct stack issues: java -jar JMD.jar \"C:/Files/Magic.jar\" stackfixer true\n\n## Download\n\nStable releases: https://github.com/Contra/JMD/downloads\n\nLatest release (most likely stable): Get the files from the repo\n\n## Requirements\n\nJMD - Java 6 (hasn't been tested on anything else but should work)\n\nJMDGUI - .NET 4 or higher\n        \n## License\n\nCopyright (c) 2011 Contra <contra@australia.edu>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n[travis-image]: https://travis-ci.org/contra/JMD.svg?branch=master\n[travis-url]: https://travis-ci.org/contra/JMD\n\n[coveralls-image]: https://coveralls.io/repos/github/contra/JMD/badge.svg?branch=master\n[coveralls-url]: https://coveralls.io/github/contra/JMD?branch=master"
  },
  {
    "path": "build.gradle",
    "content": "buildscript {\n    ext {\n        projectVersion = '1.6'\n\n        gradleWrapperVersion = '3.1'\n\n        daggerVersion = '2.6'\n        bcelVersion = '6.0'\n        commonsIoVersion = '2.5'\n        slf4jVersion = '1.7.21'\n        logbackVersion = '1.1.7'\n        testngVersion = '6.9.13.6'\n    }\n\n    repositories {\n        mavenCentral()\n    }\n}\n\nplugins {\n    id \"com.github.kt3k.coveralls\" version '2.6.3'\n}\n\ndescription = 'JMD is a general purpose Java bytecode deobfuscation tool'\n\nsubprojects {\n    apply plugin:  \"java\"\n    apply plugin:  \"findbugs\"\n    apply plugin:  \"pmd\"\n    apply plugin:  \"jacoco\"\n    apply plugin:  \"com.github.kt3k.coveralls\"\n\n    sourceCompatibility = JavaVersion.VERSION_1_8\n    targetCompatibility = JavaVersion.VERSION_1_8\n\n    version = projectVersion\n\n    repositories {\n        mavenCentral()\n    }\n\n    task wrapper(type: Wrapper) {\n        gradleVersion = gradleWrapperVersion\n    }\n\n    findbugs {\n        ignoreFailures = true\n        effort = 'max'\n    }\n\n    pmd {\n        ignoreFailures = true\n        ruleSets = [\n                'java-basic',\n                'java-braces',\n                'java-clone',\n                'java-codesize',\n                'java-comments',\n                'java-controversial',\n                'java-design',\n                'java-empty',\n                'java-finalizers',\n                'java-imports',\n                'java-j2ee',\n                'java-javabeans',\n                'java-junit',\n                'java-logging-jakarta-commons',\n                'java-logging-java',\n                'java-migrating',\n                'java-naming',\n                'java-optimizations',\n                'java-strictexception',\n                'java-strings',\n                'java-sunsecure',\n                'java-typeresolution',\n                'java-unnecessary',\n                'java-unusedcode'\n        ]\n    }\n\n    tasks.withType(Pmd) {\n        reports {\n            xml.enabled = false\n            html.enabled = true\n        }\n    }\n\n    tasks.withType(FindBugs) {\n        reports {\n            xml.enabled = false\n            html.enabled = true\n        }\n    }\n\n    tasks.coveralls {\n        dependsOn 'check'\n    }\n\n    jacocoTestReport {\n        reports {\n            xml.enabled = true\n            html.enabled = false\n        }\n    }\n}\n\nproject(':jmd-cli') {\n\n    dependencies {\n        compile project(':jmd-core')\n    }\n\n    jar {\n        manifest {\n            attributes 'Implementation-Title': 'net.contra.jmd',\n                    'Implementation-Version': version,\n                    'Main-Class': 'net.contra.jmd.Deobfuscator'\n        }\n\n        from {\n            configurations.compile.collect {\n                it.isDirectory() ? it : zipTree(it)\n            }\n        }\n    }\n}\n\nproject(':jmd-core') {\n\n    dependencies {\n        compile group: 'com.google.dagger', name: 'dagger', version: daggerVersion\n        compile group: 'org.apache.bcel', name: 'bcel', version: bcelVersion\n        compile group: 'commons-io', name: 'commons-io', version: commonsIoVersion\n        compile group: 'org.slf4j', name: 'slf4j-api', version: slf4jVersion\n        compile group: 'ch.qos.logback', name: 'logback-classic', version: logbackVersion\n\n        compile group: 'org.testng', name: 'testng', version: testngVersion\n    }\n}\n\nproject(':jmd-gui') {\n}"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "#Tue Nov 08 23:54:47 MSK 2016\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-3.1-bin.zip\n"
  },
  {
    "path": "gradlew",
    "content": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn ( ) {\n    echo \"$*\"\n}\n\ndie ( ) {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules\nfunction splitJvmOpts() {\n    JVM_OPTS=(\"$@\")\n}\neval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\nJVM_OPTS[${#JVM_OPTS[*]}]=\"-Dorg.gradle.appname=$APP_BASE_NAME\"\n\n# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong\nif [[ \"$(uname)\" == \"Darwin\" ]] && [[ \"$HOME\" == \"$PWD\" ]]; then\n  cd \"$(dirname \"$0\")\"\nfi\n\nexec \"$JAVACMD\" \"${JVM_OPTS[@]}\" -classpath \"$CLASSPATH\" org.gradle.wrapper.GradleWrapperMain \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem  Gradle startup script for Windows\n@rem\n@rem ##########################################################################\n\n@rem Set local scope for the variables with windows NT shell\nif \"%OS%\"==\"Windows_NT\" setlocal\n\nset DIRNAME=%~dp0\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\nset APP_BASE_NAME=%~n0\nset APP_HOME=%DIRNAME%\n\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nset DEFAULT_JVM_OPTS=\n\n@rem Find java.exe\nif defined JAVA_HOME goto findJavaFromJavaHome\n\nset JAVA_EXE=java.exe\n%JAVA_EXE% -version >NUL 2>&1\nif \"%ERRORLEVEL%\" == \"0\" goto init\n\necho.\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:findJavaFromJavaHome\nset JAVA_HOME=%JAVA_HOME:\"=%\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\n\nif exist \"%JAVA_EXE%\" goto init\n\necho.\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:init\n@rem Get command-line arguments, handling Windows variants\n\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\n\n:win9xME_args\n@rem Slurp the command line arguments.\nset CMD_LINE_ARGS=\nset _SKIP=2\n\n:win9xME_args_slurp\nif \"x%~1\" == \"x\" goto execute\n\nset CMD_LINE_ARGS=%*\n\n:execute\n@rem Setup the command line\n\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\n\n@rem Execute Gradle\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\n\n:end\n@rem End local scope for the variables with windows NT shell\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\n\n:fail\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\nrem the _cmd.exe /c_ return code!\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\nexit /b 1\n\n:mainEnd\nif \"%OS%\"==\"Windows_NT\" endlocal\n\n:omega\n"
  },
  {
    "path": "jmd-cli/gradle/wrapper/gradle-wrapper.properties",
    "content": "#Tue Nov 08 23:54:48 MSK 2016\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-3.1-bin.zip\n"
  },
  {
    "path": "jmd-cli/gradlew",
    "content": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn ( ) {\n    echo \"$*\"\n}\n\ndie ( ) {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules\nfunction splitJvmOpts() {\n    JVM_OPTS=(\"$@\")\n}\neval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\nJVM_OPTS[${#JVM_OPTS[*]}]=\"-Dorg.gradle.appname=$APP_BASE_NAME\"\n\n# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong\nif [[ \"$(uname)\" == \"Darwin\" ]] && [[ \"$HOME\" == \"$PWD\" ]]; then\n  cd \"$(dirname \"$0\")\"\nfi\n\nexec \"$JAVACMD\" \"${JVM_OPTS[@]}\" -classpath \"$CLASSPATH\" org.gradle.wrapper.GradleWrapperMain \"$@\"\n"
  },
  {
    "path": "jmd-cli/gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem  Gradle startup script for Windows\n@rem\n@rem ##########################################################################\n\n@rem Set local scope for the variables with windows NT shell\nif \"%OS%\"==\"Windows_NT\" setlocal\n\nset DIRNAME=%~dp0\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\nset APP_BASE_NAME=%~n0\nset APP_HOME=%DIRNAME%\n\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nset DEFAULT_JVM_OPTS=\n\n@rem Find java.exe\nif defined JAVA_HOME goto findJavaFromJavaHome\n\nset JAVA_EXE=java.exe\n%JAVA_EXE% -version >NUL 2>&1\nif \"%ERRORLEVEL%\" == \"0\" goto init\n\necho.\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:findJavaFromJavaHome\nset JAVA_HOME=%JAVA_HOME:\"=%\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\n\nif exist \"%JAVA_EXE%\" goto init\n\necho.\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:init\n@rem Get command-line arguments, handling Windows variants\n\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\n\n:win9xME_args\n@rem Slurp the command line arguments.\nset CMD_LINE_ARGS=\nset _SKIP=2\n\n:win9xME_args_slurp\nif \"x%~1\" == \"x\" goto execute\n\nset CMD_LINE_ARGS=%*\n\n:execute\n@rem Setup the command line\n\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\n\n@rem Execute Gradle\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\n\n:end\n@rem End local scope for the variables with windows NT shell\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\n\n:fail\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\nrem the _cmd.exe /c_ return code!\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\nexit /b 1\n\n:mainEnd\nif \"%OS%\"==\"Windows_NT\" endlocal\n\n:omega\n"
  },
  {
    "path": "jmd-cli/src/main/java/net/contra/jmd/Deobfuscator.java",
    "content": "package net.contra.jmd;\n\nimport net.contra.jmd.transformers.allatori.AllatoriTransformer;\nimport net.contra.jmd.transformers.dasho.DashOTransformer;\nimport net.contra.jmd.transformers.generic.*;\nimport net.contra.jmd.transformers.jshrink.JShrinkTransformer;\nimport net.contra.jmd.transformers.smokescreen.SmokeScreenTransformer;\nimport net.contra.jmd.transformers.zkm.ZKMTransformer;\nimport net.contra.jmd.util.LogHandler;\n\nimport java.util.Scanner;\n\n/**\n * Created by IntelliJ IDEA.\n * User: Eric\n * Date: Nov 24, 2010\n * Time: 9:21:10 PM\n */\npublic class Deobfuscator {\n    private static String version = Version.getVersion();\n    private static String credits = \"skoalman, super_, ollie, popcorn89, the prophecy, and saevion\";\n    private static LogHandler logger = new LogHandler(\"Deobfuscator\");\n    //TODO: Load single class files... herpa derp\n\n    public static void main(String[] argv) throws Exception {\n        logger.message(\"Java Multi-Purpose Deobfuscator\");\n        logger.message(\"Version \" + version);\n        logger.message(\"Created by Contra. Please read LICENSE.txt\");\n        logger.message(\"Tons of code from \" + credits);\n        if (!(argv.length >= 3)) {\n            logger.error(\"java -jar JMD.jar <file location> <type> <debug true/false> <optional args>\");\n            logger.error(\"Example ZKM: java -jar JMD.jar \\\"C:/Files/Magic.jar\\\" zkm true\");\n            logger.error(\"Example StringScan: java -jar JMD.jar \\\"C:/Files/Magic.jar\\\" stringscanner \\\"rscheata.net\\\" false\");\n            logger.error(\"Example StringReplace: java -jar JMD.jar \\\"C:/Files/Magic.jar\\\" stringreplacer \\\"rscheata.net\\\" true \\\"rscbunlocked.net\\\"\");\n            return;\n        }\n        if (argv[2].equals(\"true\")) {\n        }\n        if (argv[1].toLowerCase().equals(\"zkm\")) {\n            ZKMTransformer zt = new ZKMTransformer(argv[0]);\n            zt.transform();\n        } else if (argv[1].toLowerCase().equals(\"allatori\")) {\n            AllatoriTransformer at = new AllatoriTransformer(argv[0], false);\n            at.transform();\n        } else if (argv[1].toLowerCase().equals(\"allatori-strong\")) {\n            AllatoriTransformer at = new AllatoriTransformer(argv[0], true);\n            at.transform();\n        } else if (argv[1].toLowerCase().equals(\"jshrink\")) {\n            JShrinkTransformer jt = new JShrinkTransformer(argv[0]);\n            jt.transform();\n        } else if (argv[1].toLowerCase().equals(\"dasho\")) {\n            DashOTransformer dt = new DashOTransformer(argv[0]);\n            dt.transform();\n        } else if (argv[1].toLowerCase().equals(\"smokescreen\")) {\n            SmokeScreenTransformer st = new SmokeScreenTransformer(argv[0]);\n            st.transform();\n        } else if (argv[1].toLowerCase().equals(\"renamer\")) {\n            Renamer re = new Renamer(argv[0]);\n            re.transform();\n        } else if (argv[1].toLowerCase().equals(\"genericstringdeobfuscator\")) {\n            GenericStringDeobfuscator gsd = new GenericStringDeobfuscator(argv[0]);\n            gsd.transform();\n        } else if (argv[1].toLowerCase().equals(\"stringfixer\")) {\n            StringFixer sf = new StringFixer(argv[0]);\n            sf.transform();\n        } else if (argv[1].toLowerCase().equals(\"stackfixer\")) {\n            StackFixer sf = new StackFixer(argv[0]);\n            sf.transform();\n        } else if (argv[1].toLowerCase().equals(\"foreigncallremover\")) {\n            ForeignCallRemover fc = new ForeignCallRemover(argv[0]);\n            fc.transform();\n        } else if (argv[1].toLowerCase().equals(\"stringscanner\")) {\n            StringScanner us = new StringScanner(argv[0], argv[3], false, \"\");\n            us.scan();\n        } else if (argv[1].toLowerCase().equals(\"stringreplacer\")) {\n            StringScanner us = new StringScanner(argv[0], argv[3], true, argv[4]);\n            us.scan();\n        } else {\n            logger.error(\"Types are: ZKM, Allatori, JShrink, DashO, SmokeScreen, StringFixer, StringScanner, \" +\n                    \"\\n ForeignCallRemover, GenericStringDeobfuscator, StackFixer, StringFixer, Renamer, and StringReplacer (not case sensitive)\");\n        }\n        Scanner in = new Scanner(System.in);\n        logger.message(\"Press <Enter> key to exit...\");\n        in.nextLine();\n        in.close();\n    }\n}\n"
  },
  {
    "path": "jmd-cli/src/main/java/net/contra/jmd/Version.java",
    "content": "package net.contra.jmd;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.URL;\nimport java.util.jar.Attributes;\nimport java.util.jar.JarFile;\nimport java.util.jar.Manifest;\n\npublic final class Version {\n\n    private static final String UNKNOWN = \"UNKNOWN\";\n\n    private Version() {\n    }\n\n    public static String getVersion() {\n        final URL url = Version.class.getResource(JarFile.MANIFEST_NAME);\n        if (url == null) {\n            return UNKNOWN;\n        }\n\n        try {\n            final InputStream inputStream = url.openStream();\n            final Manifest manifest = new Manifest(inputStream);\n\n            return manifest.getMainAttributes().getValue(Attributes.Name.IMPLEMENTATION_VERSION);\n        } catch (IOException e) {\n            // empty\n        }\n\n        return UNKNOWN;\n    }\n}\n"
  },
  {
    "path": "jmd-core/gradle/wrapper/gradle-wrapper.properties",
    "content": "#Tue Nov 08 23:54:48 MSK 2016\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-3.1-bin.zip\n"
  },
  {
    "path": "jmd-core/gradlew",
    "content": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn ( ) {\n    echo \"$*\"\n}\n\ndie ( ) {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules\nfunction splitJvmOpts() {\n    JVM_OPTS=(\"$@\")\n}\neval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\nJVM_OPTS[${#JVM_OPTS[*]}]=\"-Dorg.gradle.appname=$APP_BASE_NAME\"\n\n# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong\nif [[ \"$(uname)\" == \"Darwin\" ]] && [[ \"$HOME\" == \"$PWD\" ]]; then\n  cd \"$(dirname \"$0\")\"\nfi\n\nexec \"$JAVACMD\" \"${JVM_OPTS[@]}\" -classpath \"$CLASSPATH\" org.gradle.wrapper.GradleWrapperMain \"$@\"\n"
  },
  {
    "path": "jmd-core/gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem  Gradle startup script for Windows\n@rem\n@rem ##########################################################################\n\n@rem Set local scope for the variables with windows NT shell\nif \"%OS%\"==\"Windows_NT\" setlocal\n\nset DIRNAME=%~dp0\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\nset APP_BASE_NAME=%~n0\nset APP_HOME=%DIRNAME%\n\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nset DEFAULT_JVM_OPTS=\n\n@rem Find java.exe\nif defined JAVA_HOME goto findJavaFromJavaHome\n\nset JAVA_EXE=java.exe\n%JAVA_EXE% -version >NUL 2>&1\nif \"%ERRORLEVEL%\" == \"0\" goto init\n\necho.\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:findJavaFromJavaHome\nset JAVA_HOME=%JAVA_HOME:\"=%\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\n\nif exist \"%JAVA_EXE%\" goto init\n\necho.\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:init\n@rem Get command-line arguments, handling Windows variants\n\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\n\n:win9xME_args\n@rem Slurp the command line arguments.\nset CMD_LINE_ARGS=\nset _SKIP=2\n\n:win9xME_args_slurp\nif \"x%~1\" == \"x\" goto execute\n\nset CMD_LINE_ARGS=%*\n\n:execute\n@rem Setup the command line\n\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\n\n@rem Execute Gradle\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\n\n:end\n@rem End local scope for the variables with windows NT shell\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\n\n:fail\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\nrem the _cmd.exe /c_ return code!\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\nexit /b 1\n\n:mainEnd\nif \"%OS%\"==\"Windows_NT\" endlocal\n\n:omega\n"
  },
  {
    "path": "jmd-core/src/main/java/net/contra/jmd/transformers/Transformer.java",
    "content": "package net.contra.jmd.transformers;\n\nimport org.apache.bcel.generic.TargetLostException;\n\npublic interface Transformer {\n}\n"
  },
  {
    "path": "jmd-core/src/main/java/net/contra/jmd/transformers/allatori/AllatoriTransformer.java",
    "content": "package net.contra.jmd.transformers.allatori;\n\nimport net.contra.jmd.transformers.Transformer;\nimport net.contra.jmd.util.GenericMethods;\nimport net.contra.jmd.util.LogHandler;\nimport net.contra.jmd.util.NonClassEntries;\nimport org.apache.bcel.classfile.ClassParser;\nimport org.apache.bcel.classfile.Method;\nimport org.apache.bcel.generic.*;\n\nimport java.io.File;\nimport java.util.Enumeration;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\n\npublic class AllatoriTransformer implements Transformer {\n    LogHandler logger = new LogHandler(\"AllatoriTransformer\");\n    Map<String, ClassGen> cgs = new HashMap<String, ClassGen>();\n    ClassGen ALLATORI_CLASS;\n    String JAR_NAME;\n    boolean isStrong = false;\n\n    public AllatoriTransformer(String jarfile, boolean strong) throws Exception {\n        logger.log(\"Allatori Deobfuscator\");\n        isStrong = strong;\n        File jar = new File(jarfile);\n        JAR_NAME = jarfile;\n        JarFile jf = new JarFile(jar);\n        Enumeration<JarEntry> entries = jf.entries();\n        while (entries.hasMoreElements()) {\n            JarEntry entry = entries.nextElement();\n            if (entry == null) {\n                break;\n            }\n            if (entry.getName().endsWith(\".class\")) {\n                ClassGen cg = new ClassGen(new ClassParser(jf\n                        .getInputStream(entry), entry.getName()).parse());\n                if (isStringClass(cg) || isStringClassB(cg)) {\n                    ALLATORI_CLASS = cg;\n                    logger.debug(\"Allatori Class: \" + ALLATORI_CLASS.getClassName());\n                }\n                cgs.put(cg.getClassName(), cg);\n            } else {\n                NonClassEntries.add(entry, jf.getInputStream(entry));\n            }\n        }\n        jf.close();\n    }\n\n    private boolean isStringClass(ClassGen cg) {\n        if (cg.getMethods().length == 2 && cg.getMethods()[0].isStatic()\n                && cg.getMethods()[1].isStatic()) {\n            if (cg.getMethods()[0].getReturnType().toString().equals(\n                    \"java.lang.String\")\n                    && cg.getMethods()[1].getReturnType().toString().equals(\n                    \"java.lang.String\")) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    private boolean isStringClassB(ClassGen cg) {\n        if (cg.getMethods().length == 1 && cg.getMethods()[0].isStatic()) {\n            if (cg.getMethods()[0].getReturnType().toString().equals(\"java.lang.String\")) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    public static String decode(String string) {\n        int i = 85;\n        char[] cs = new char[string.length()];\n        int pos = cs.length - 1;\n        int index = pos;\n        int xor = i;\n        while (pos >= 0) {\n            char c = (char) (string.charAt(index) ^ xor);\n            int c1_index = index;\n            xor = (char) ((char) (c1_index ^ xor) & '?');\n            cs[c1_index] = c;\n            if (--index < 0) {\n                break;\n            }\n            char c2 = (char) (string.charAt(index) ^ xor);\n            int c2_index = index;\n            xor = (char) ((char) (c2_index ^ xor) & '?');\n            cs[c2_index] = c2;\n            pos = --index;\n        }\n\n        return new String(cs);\n    }\n   \tpublic static String decodeContext(String encrypted, String callingClass, String callingMethod) {\n\t\tString keyString = callingClass + callingMethod;\n\t\tint lastKeyIndex = keyString.length() - 1;\n\t\tint xor = 85;\n\t\tint keyIndex = lastKeyIndex;\n\t\tint length = encrypted.length();\n\t\tchar[] cs = new char[length];\n\t\tfor (int i = length - 1; i >= 0; i--) {\n\t\t\tif (keyIndex < 0) {\n\t\t\t\tkeyIndex = lastKeyIndex;\n\t\t\t}\n\t\t\tchar keyChar = keyString.charAt(keyIndex--);\n\t\t\tcs[i] = (char) (keyChar ^ (encrypted.charAt(i) ^ xor));\n\t\t\txor = (char) (63 & (xor ^ (i ^ keyChar)));\n\t\t}\n\t\treturn new String(cs);\n\t}\n\n    public void transform() throws TargetLostException {\n        logger.log(\"Starting Encrypted String Removal...\");\n        replaceStrings();\n        logger.log(\"Deobfuscation Finished! Dumping jar...\");\n        GenericMethods.dumpJar(JAR_NAME, cgs.values());\n        logger.log(\"Operation Completed.\");\n    }\n\n    public void replaceStrings() throws TargetLostException {\n        for (ClassGen cg : cgs.values()) {\n            int replaced = 0;\n            for (Method method : cg.getMethods()) {\n                MethodGen mg = new MethodGen(method, cg.getClassName(), cg.getConstantPool());\n                InstructionList list = mg.getInstructionList();\n                if (list == null) {\n                    continue;\n                }\n                InstructionHandle[] handles = list.getInstructionHandles();\n                for (int i = 1; i < handles.length; i++) {\n                    if (handles[i].getInstruction() instanceof INVOKESTATIC && handles[i - 1].getInstruction() instanceof LDC) {\n                            INVOKESTATIC methodCall = (INVOKESTATIC) handles[i].getInstruction();\n                            if (methodCall.getClassName(cg.getConstantPool()).contains(ALLATORI_CLASS.getClassName())) {\n                                LDC encryptedLDC = (LDC) handles[i - 1].getInstruction();\n                                String encryptedString = encryptedLDC.getValue(cg.getConstantPool()).toString();\n                                String decryptedString;\n                                if(isStrong){\n                                    decryptedString = decodeContext(encryptedString, cg.getClassName(), method.getName());\n                                } else {\n                                    decryptedString = decode(encryptedString);\n                                }\n                                logger.debug(encryptedString + \" -> \" + decryptedString + \" in \" + cg.getClassName() + \".\" + method.getName());\n                                int stringRef = cg.getConstantPool().addString(decryptedString);\n                                LDC lc = new LDC(stringRef);\n                                NOP nop = new NOP();\n                                handles[i].setInstruction(lc);\n                                handles[i - 1].setInstruction(nop);\n                                replaced++;\n                            }\n                    }\n                }\n                mg.setInstructionList(list);\n                mg.setMaxLocals();\n                mg.setMaxStack();\n                cg.replaceMethod(method, mg.getMethod());\n            }\n            if (replaced > 0) {\n                logger.debug(\"decrypted \" + replaced + \" strings in class \" + cg.getClassName());\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jmd-core/src/main/java/net/contra/jmd/transformers/dasho/DashOTransformer.java",
    "content": "package net.contra.jmd.transformers.dasho;\n\nimport net.contra.jmd.transformers.Transformer;\nimport net.contra.jmd.util.GenericMethods;\nimport net.contra.jmd.util.LogHandler;\nimport net.contra.jmd.util.NonClassEntries;\nimport org.apache.bcel.classfile.ClassParser;\nimport org.apache.bcel.classfile.Method;\nimport org.apache.bcel.generic.*;\nimport org.apache.commons.io.IOUtils;\n\nimport java.io.*;\nimport java.util.Enumeration;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\nimport java.util.jar.JarInputStream;\nimport java.util.jar.JarOutputStream;\n\npublic class DashOTransformer implements Transformer {\n    private static LogHandler logger = new LogHandler(\"DashOTransformer\");\n    private Map<String, ClassGen> cgs = new HashMap<String, ClassGen>();\n    String JAR_NAME;\n    String decryptor = \"NOTFOUND\";\n    String decryptorclass = \"NOTFOUND\";\n\n    public DashOTransformer(String jarfile) throws Exception {\n        File jar = new File(jarfile);\n        JAR_NAME = jarfile;\n        JarFile jf = new JarFile(jar);\n        Enumeration<JarEntry> entries = jf.entries();\n        while (entries.hasMoreElements()) {\n            JarEntry entry = entries.nextElement();\n            if (entry == null) {\n                break;\n            }\n\n            if (entry.getName().endsWith(\".class\")) {\n                ClassGen cg = new ClassGen(new ClassParser(jf.getInputStream(entry), entry.getName()).parse());\n                cgs.put(cg.getClassName(), cg);\n            } else {\n                NonClassEntries.add(entry, jf.getInputStream(entry));\n            }\n        }\n        jf.close();\n    }\n\n    public static String decrypt(String input) {\n        if (isEmpty(input)) {\n            return input;\n        }\n\n        char[] inputChars = input.toCharArray();\n\n        int length = inputChars.length;\n        char[] inputCharsCopy = new char[length];\n        int j = 0;\n        int i = 0;\n\n        while (j < length) {\n            inputCharsCopy[j] = ((char) (inputChars[j] - '\\1' ^ i));\n\n            i = (char) (i + 1);\n            j++;\n        }\n\n        return new String(inputCharsCopy);\n    }\n\n    private static boolean isEmpty(final CharSequence cs) {\n        return cs == null || cs.length() == 0;\n    }\n\n    public void setDecryptor() {\n        for (ClassGen cg : cgs.values()) {\n            for (Method m : cg.getMethods()) {\n                try {\n                    if (m.isPublic() && m.isStatic() &&\n                            m.getArgumentTypes()[0].toString().equals(\"java.lang.String\")\n                            && m.getReturnType().toString().equals(\"java.lang.String\")) {\n                        String dc = cg.getClassName() + \".\" + m.getName();\n                        decryptor = m.getName();\n                        decryptorclass = cg.getClassName();\n                        logger.debug(\"Found String Decryptor! \" + dc);\n                        return;\n                    }\n                } catch (Exception e) {\n                    continue;\n                }\n            }\n        }\n        logger.error(\"String decrypt not found!\");\n    }\n\n    public void removeStringEncryption() {\n        for (ClassGen cg : cgs.values()) {\n            for (Method m : cg.getMethods()) {\n                MethodGen mg = new MethodGen(m, cg.getClassName(), cg.getConstantPool());\n                InstructionList il = mg.getInstructionList();\n                InstructionHandle[] handles = il.getInstructionHandles();\n                for (int i = 1; i < handles.length; i++) {\n                    if ((handles[i].getInstruction() instanceof LDC)\n                            && (handles[i + 1].getInstruction() instanceof INVOKESTATIC)) {\n                        INVOKESTATIC invoke = (INVOKESTATIC) handles[i + 1].getInstruction();\n                        if (decryptor.equals(\"NOTFOUND\")) {\n                            logger.error(\"String Decryption Method not Set!\");\n                            return;\n                        }\n                        String call = invoke.getClassName(cg.getConstantPool());\n                        String mcall = invoke.getMethodName(cg.getConstantPool());\n                        if (call.equals(decryptorclass) && mcall.equals(decryptor)) {\n                            LDC orig = ((LDC) handles[i].getInstruction());\n                            String enc = (String) orig.getValue(cg.getConstantPool());\n                            int index = cg.getConstantPool().addString(decrypt(enc));\n                            LDC lc = new LDC(index);\n                            handles[i].setInstruction(lc);\n                            handles[i + 1].setInstruction(new NOP());\n                            logger.debug(enc + \" -> \" + decrypt(enc));\n                        }\n                    }\n                }\n                mg.setInstructionList(il);\n                mg.setMaxLocals();\n                mg.setMaxStack();\n                cg.replaceMethod(m, mg.getMethod());\n            }\n        }\n    }\n\n    public void dumpJar(String path) {\n        FileOutputStream os;\n        try {\n            os = new FileOutputStream(new File(path));\n        } catch (FileNotFoundException fnfe) {\n            throw new RuntimeException(\"could not create file \\\"\" + path + \"\\\": \" + fnfe);\n        }\n        JarOutputStream jos;\n\n        try {\n            jos = new JarOutputStream(os);\n            for (JarEntry jbe : NonClassEntries.entries) {\n                JarEntry destEntry = new JarEntry(jbe.getName());\n                byte[] bite = IOUtils.toByteArray(NonClassEntries.ins.get(jbe));\n                jos.putNextEntry(destEntry);\n                jos.write(bite);\n                jos.closeEntry();\n            }\n\n            for (ClassGen classIt : cgs.values()) {\n                jos.putNextEntry(new JarEntry(classIt.getClassName().replace('.', '/') + \".class\"));\n                jos.write(classIt.getJavaClass().getBytes());\n                jos.closeEntry();\n                jos.flush();\n            }\n\n            jos.closeEntry();\n            jos.close();\n        } catch (IOException ioe) {\n        }\n    }\n\n    public void transform() {\n        logger.log(\"DashO Deobfuscator\");\n        logger.log(\"Finding String Decryption Method...\");\n        setDecryptor();\n        logger.log(\"Starting String Encryption Removal...\");\n        removeStringEncryption();\n        //logger.log(\"Starting Unconditional Branch Remover...\");\n        //removeControlFlow();\n        //unconditionalBranchTransformer();\n        //logger.log(\"Starting Exit Flow Corrector...\");\n        //exitFlowTransformer();\n        logger.log(\"Deobfuscation finished! Dumping jar...\");\n        GenericMethods.dumpJar(JAR_NAME, cgs.values());\n        logger.log(\"Operation Completed.\");\n\n    }\n}\n"
  },
  {
    "path": "jmd-core/src/main/java/net/contra/jmd/transformers/generic/ForeignCallRemover.java",
    "content": "package net.contra.jmd.transformers.generic;\n\nimport net.contra.jmd.util.GenericMethods;\nimport net.contra.jmd.util.LogHandler;\nimport net.contra.jmd.util.NonClassEntries;\nimport org.apache.bcel.classfile.ClassParser;\nimport org.apache.bcel.classfile.Method;\nimport org.apache.bcel.generic.*;\nimport org.apache.commons.io.IOUtils;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.util.Enumeration;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\nimport java.util.jar.JarOutputStream;\n\npublic class ForeignCallRemover {\n    private static LogHandler logger = new LogHandler(\"ForeignCallRemover\");\n    private Map<String, ClassGen> cgs = new HashMap<String, ClassGen>();\n    String JAR_NAME;\n    String AuthClass;\n\n    public ForeignCallRemover(String jarfile) throws Exception {\n        File jar = new File(jarfile);\n        JAR_NAME = jarfile;\n        JarFile jf = new JarFile(jar);\n        Enumeration<JarEntry> entries = jf.entries();\n        while (entries.hasMoreElements()) {\n            JarEntry entry = entries.nextElement();\n            if (entry == null) {\n                break;\n            }\n            if (entry.getName().endsWith(\".class\")) {\n                ClassGen cg = new ClassGen(new ClassParser(jf.getInputStream(entry), entry.getName()).parse());\n                if (isAuthClass(cg)) {\n                    logger.debug(\"Found auth class! \" + cg.getClassName());\n                    AuthClass = cg.getClassName();\n                }\n                cgs.put(cg.getClassName(), cg);\n            } else {\n                NonClassEntries.add(entry, jf.getInputStream(entry));\n            }\n        }\n        jf.close();\n    }\n\n    public boolean isAuthClass(ClassGen cg) {\n        if (cg.getMethods().length == 2 && cg.getMethods()[0].getArgumentTypes().length == 1) {\n            if (cg.getMethods()[0].getArgumentTypes()[0].getSignature().contains(\"String\")) {\n                if (cg.getMethods()[0].getReturnType().toString().contains(\"boolean\")) {\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    public void dumpJar(String path) {\n        FileOutputStream os;\n        try {\n            os = new FileOutputStream(new File(path));\n        } catch (FileNotFoundException fnfe) {\n            throw new RuntimeException(\"could not create file \\\"\" + path + \"\\\": \" + fnfe);\n        }\n        JarOutputStream jos;\n\n        try {\n            jos = new JarOutputStream(os);\n            for (ClassGen classIt : cgs.values()) {\n                jos.putNextEntry(new JarEntry(classIt.getClassName().replace('.', '/') + \".class\"));\n                jos.write(classIt.getJavaClass().getBytes());\n                jos.closeEntry();\n                jos.flush();\n            }\n            for (JarEntry jbe : NonClassEntries.entries) {\n                if (!jbe.isDirectory()) {\n                    JarEntry destEntry = new JarEntry(jbe.getName());\n                    byte[] bite = IOUtils.toByteArray(NonClassEntries.ins.get(jbe));\n                    jos.putNextEntry(destEntry);\n                    jos.write(bite);\n                    jos.closeEntry();\n                }\n            }\n            jos.closeEntry();\n            jos.close();\n        } catch (IOException ioe) {\n        }\n    }\n\n    public void RemoveCalls() {\n        for (ClassGen cg : cgs.values()) {\n            int replaced = 0;\n            for (Method method : cg.getMethods()) {\n                //logger.debug(\"in method \" + method.getName());\n                MethodGen mg = new MethodGen(method, cg.getClassName(), cg.getConstantPool());\n                InstructionList list = mg.getInstructionList();\n                if (list == null) {\n                    continue;\n                }\n                InstructionHandle[] handles = list.getInstructionHandles();\n                for (int i = 0; i < handles.length; i++) {\n                    if (GenericMethods.isCall(handles[i].getInstruction())) {\n                        String callClass = GenericMethods.getCallClassName(handles[i].getInstruction(), cg.getConstantPool());\n                        String callMethod = GenericMethods.getCallMethodName(handles[i].getInstruction(), cg.getConstantPool());\n                        if (!callClass.startsWith(\"java\") &&\n                                (!callClass.startsWith(\"org\") || callClass.contains(\"PingBack\"))\n                                && !cgs.containsKey(callClass)) {\n                            if (GenericMethods.getCallArgTypes(handles[i].getInstruction(), cg.getConstantPool()).length == 0) {\n                                handles[i].setInstruction(new NOP());\n                                if (handles[i + 1].getInstruction() instanceof ASTORE) {\n                                    handles[i + 1].setInstruction(new NOP());\n                                }\n                                logger.debug(callClass + \".\" + callMethod + \" invoke had no arguments, so we NOP\");\n                                replaced++;\n                            } else {\n                                //TODO: WRITE SOMETHING TO DETECT MULTIPLE ARGUMENTS\n                                handles[i - 1].setInstruction(new NOP());\n                                handles[i].setInstruction(new NOP());\n                                if (handles[i + 1].getInstruction() instanceof ASTORE) {\n                                    handles[i + 1].setInstruction(new NOP());\n                                }\n                                logger.debug(callClass + \".\" + callMethod + \" invoke had arguments, so we NOP it and the line before\");\n                                replaced++;\n                            }\n                            mg.setInstructionList(list);\n                            mg.removeNOPs();\n                            mg.setMaxLocals();\n                            mg.setMaxStack();\n                            cg.replaceMethod(method, mg.getMethod());\n                        }\n                    }\n\n                    if (handles[i].getInstruction() instanceof NEW) {\n                        String callClass = ((NEW) handles[i].getInstruction()).getLoadClassType(cg.getConstantPool()).getClassName();\n                        //logger.debug(callClass);\n                        if (!callClass.startsWith(\"java\") &&\n                                (!callClass.startsWith(\"org\") || callClass.contains(\"PingBack\"))\n                                && !cgs.containsKey(callClass)) {\n                            handles[i].setInstruction(new NOP());\n                            logger.debug(\"NOPed out NEW \" + callClass);\n                            replaced++;\n                        }\n                        mg.setInstructionList(list);\n                        mg.removeNOPs();\n                        mg.setMaxLocals();\n                        mg.setMaxStack();\n                        cg.replaceMethod(method, mg.getMethod());\n                    }\n                }\n            }\n            if (replaced > 0) {\n                logger.debug(\"Removed \" + replaced + \" foreign calls in \" + cg.getClassName());\n            }\n        }\n    }\n\n    public void replaceCheckMethod() {\n        ClassGen cg = cgs.get(AuthClass);\n        Method method = cg.getMethods()[0];\n        MethodGen mg = new MethodGen(method, cg.getClassName(), cg.getConstantPool());\n\n        InstructionList list = new InstructionList();\n        list.append(new ICONST(1));\n        list.append(new IRETURN());\n\n        mg.removeExceptionHandlers();\n        mg.removeLineNumbers();\n        mg.removeLocalVariables();\n        mg.removeExceptions();\n        mg.setInstructionList(list);\n        mg.setMaxLocals();\n        mg.setMaxStack();\n\n        cg.replaceMethod(method, mg.getMethod());\n    }\n\n    public void fixPOPs() {\n        for (ClassGen cg : cgs.values()) {\n            int replaced = 0;\n            for (Method method : cg.getMethods()) {\n                //logger.debug(\"in method \" + method.getName());\n                MethodGen mg = new MethodGen(method, cg.getClassName(), cg.getConstantPool());\n                InstructionList list = mg.getInstructionList();\n                if (list == null) {\n                    continue;\n                }\n                InstructionHandle[] handles = list.getInstructionHandles();\n                if (handles[0].getInstruction() instanceof DUP || handles[0].getInstruction() instanceof ASTORE\n                        || handles[0].getInstruction() instanceof POP) {\n                    handles[0].setInstruction(new NOP());\n                    replaced++;\n                }\n                mg.setInstructionList(list);\n                mg.removeNOPs();\n                mg.setMaxLocals();\n                mg.setMaxStack();\n                cg.replaceMethod(method, mg.getMethod());\n            }\n            if (replaced > 0) {\n                logger.debug(\"Removed \" + replaced + \" invalid POPs in \" + cg.getClassName());\n            }\n        }\n    }\n\n    public void transform() {\n        //logger.log(\"Removing Exception Handlers...\");\n        //removeExceptions();\n        logger.log(\"Removing Foreign Calls...\");\n        RemoveCalls();\n        logger.log(\"Fixing DUPs...\");\n        fixPOPs();\n        if (AuthClass != null) {\n            logger.log(\"Replacing Authentication System...\");\n            replaceCheckMethod();\n        } else {\n            logger.error(\"Auth class wasn't found so we couldn't remove it!\");\n        }\n        logger.log(\"Deobfuscation finished! Dumping jar...\");\n        dumpJar(JAR_NAME.replace(\".jar\", \"\") + \"-deob.jar\");\n        logger.log(\"Operation Completed.\");\n\n    }\n}\n"
  },
  {
    "path": "jmd-core/src/main/java/net/contra/jmd/transformers/generic/GenericStringDeobfuscator.java",
    "content": "/*\n\tTODO: Write a dynamic string decryptor like the one in SAE; Pattern is LDC INVOKESTATIC,                     \n\tgrab the IL from the invokestatic method and put it in a new methodgen and run the LDC through that and replace it with the result\n\tPlease see http://www.java-tips.org/java-se-tips/java.lang.reflect/invoke-method-using-reflection.html\n\n\tAlso ask somebody how you can trace the stack for stringfixer, foreigncallremover\n\tAND to get the key, check the method arguments. If it is just string pass the string, otherwise grab the integer above it.\n\tIf there is more leave it be or attempt to grab the values\n\t\n\t*/\npackage net.contra.jmd.transformers.generic;\n\nimport net.contra.jmd.util.GenericClassLoader;\nimport net.contra.jmd.util.GenericMethods;\nimport net.contra.jmd.util.LogHandler;\nimport net.contra.jmd.util.NonClassEntries;\nimport org.apache.bcel.classfile.ClassParser;\nimport org.apache.bcel.classfile.Method;\nimport org.apache.bcel.generic.*;\n\nimport java.io.File;\nimport java.util.Enumeration;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\n\npublic class GenericStringDeobfuscator {\n    private static LogHandler logger = new LogHandler(\"GenericStringDeobfuscator\");\n    private Map<String, ClassGen> cgs = new HashMap<String, ClassGen>();\n    String JAR_NAME;\n\n    public GenericStringDeobfuscator(String jarfile) throws Exception {\n        File jar = new File(jarfile);\n        JAR_NAME = jarfile;\n        JarFile jf = new JarFile(jar);\n        Enumeration<JarEntry> entries = jf.entries();\n        while (entries.hasMoreElements()) {\n            JarEntry entry = entries.nextElement();\n            if (entry == null) {\n                break;\n            }\n            if (entry.getName().endsWith(\".class\")) {\n                ClassGen cg = new ClassGen(new ClassParser(jf.getInputStream(entry), entry.getName()).parse());\n                cgs.put(cg.getClassName(), cg);\n            } else {\n                NonClassEntries.add(entry, jf.getInputStream(entry));\n            }\n        }\n        jf.close();\n    }\n\n    public void replaceStrings() {\n        for (ClassGen cg : cgs.values()) {\n            int replaced = 0;\n            for (Method method : cg.getMethods()) {\n                MethodGen mg = new MethodGen(method, cg.getClassName(), cg.getConstantPool());\n                InstructionList list = mg.getInstructionList();\n                if (list == null) {\n                    continue;\n                }\n                InstructionHandle[] handles = list.getInstructionHandles();\n                for (int i = 1; i < handles.length; i++) {\n                    //java.lang.reflect.Method\n                    if (GenericMethods.isCall(handles[i].getInstruction()) && handles[i - 1].getInstruction() instanceof LDC) {\n\n                        String methodCallClass = GenericMethods.getCallClassName(handles[i].getInstruction(), cg.getConstantPool());\n                        String methodCallMethod = GenericMethods.getCallMethodName(handles[i].getInstruction(), cg.getConstantPool());\n                        String methodCallSig = GenericMethods.getCallSignature(handles[i].getInstruction(), cg.getConstantPool());\n                        String methodRetType = GenericMethods.getCallReturnType(handles[i].getInstruction(), cg.getConstantPool());\n\n                        if (GenericMethods.getCallArgTypes(handles[i].getInstruction(), cg.getConstantPool()).length == 1\n                                && methodCallClass != null && methodCallMethod != null && methodRetType.contains(\"String\")) {\n                            //Begin classloader bullshit\n                            GenericClassLoader loader = new GenericClassLoader(GenericStringDeobfuscator.class.getClassLoader());\n                            Class cl;\n                            ClassGen ourCz = cgs.get(methodCallClass);\n                            if (ourCz != null && ourCz.containsMethod(methodCallMethod, methodCallSig) != null) {\n                                byte[] bit = ourCz.getJavaClass().getBytes();\n                                logger.debug(methodCallClass + \" \" + methodCallSig);\n                                logger.debug(ourCz.getClassName());\n                                cl = loader.loadClass(ourCz.getClassName(), bit);\n                            } else {\n                                continue;\n                            }\n                            if (cl == null) {\n                                continue;\n                            }\n                            java.lang.reflect.Method mthd;\n                            try {\n                                mthd = cl.getMethod(methodCallMethod, String.class);\n                                mthd.setAccessible(true);\n                            } catch (NoSuchMethodException e) {\n                                continue;\n                            }\n\n                            LDC encryptedLDC = (LDC) handles[i - 1].getInstruction();\n                            String encryptedString = encryptedLDC.getValue(cg.getConstantPool()).toString();\n                            String decryptedString;\n                            try {\n                                decryptedString = mthd.invoke(null, encryptedString).toString();\n                            } catch (Exception e) {\n                                continue;\n                            }\n                            logger.debug(encryptedString + \" -> \" + decryptedString + \" in \" + cg.getClassName() + \".\" + method.getName());\n                            int stringRef = cg.getConstantPool().addString(decryptedString);\n                            LDC lc = new LDC(stringRef);\n                            NOP nop = new NOP();\n                            handles[i].setInstruction(lc);\n                            handles[i - 1].setInstruction(nop);\n                            replaced++;\n                        } else {\n                            continue;\n                        }\n                    }\n                }\n                mg.setInstructionList(list);\n                mg.setMaxLocals();\n                mg.setMaxStack();\n                cg.replaceMethod(method, mg.getMethod());\n            }\n            if (replaced > 0) {\n                logger.debug(\"decrypted \" + replaced + \" strings in class \" + cg.getClassName());\n            }\n        }\n    }\n\n    public void transform() {\n        logger.log(\"Generic String Deobfuscator\");\n        logger.log(\"Still basic (and very buggy)\");\n        replaceStrings();\n        logger.log(\"Deobfuscation finished! Dumping jar...\");\n        GenericMethods.dumpJar(JAR_NAME, cgs.values());\n        logger.log(\"Operation Completed.\");\n\n    }\n}\n"
  },
  {
    "path": "jmd-core/src/main/java/net/contra/jmd/transformers/generic/Renamer.java",
    "content": "package net.contra.jmd.transformers.generic;\n\nimport net.contra.jmd.util.GenericMethods;\nimport net.contra.jmd.util.LogHandler;\nimport net.contra.jmd.util.NonClassEntries;\nimport org.apache.bcel.classfile.ClassParser;\nimport org.apache.bcel.classfile.Method;\nimport org.apache.bcel.generic.*;\n\nimport java.io.File;\nimport java.util.Enumeration;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\n\npublic class Renamer {\n    private static LogHandler logger = new LogHandler(\"Renamer\");\n    private Map<String, ClassGen> cgs = new HashMap<String, ClassGen>();\n    private Map<String, ClassGen> tempcgs = new HashMap<String, ClassGen>();\n    private Map<String, String> methodNames = new HashMap<String, String>(); //OldName, NewName\n    String JAR_NAME;\n\n    public Renamer(String jarfile) throws Exception {\n        File jar = new File(jarfile);\n        JAR_NAME = jarfile;\n        JarFile jf = new JarFile(jar);\n        Enumeration<JarEntry> entries = jf.entries();\n        //TODO: Make it not rename the main class\n        //TODO: Keep it from renaming like, methods that shouldn't be renamed and shit??\n        //TODO: Rename FIELDS MOTHERFUCKER\n        //Manifest jm = jf.getManifest();\n        //if(jm.getAttributes(\"Main-class\") != null &&\n        //logger.debug(\"Found main class for jar: \" + );\n        while (entries.hasMoreElements()) {\n            JarEntry entry = entries.nextElement();\n            if (entry == null) {\n                break;\n            }\n            if (entry.getName().endsWith(\".class\")) {\n                ClassGen cg = new ClassGen(new ClassParser(jf.getInputStream(entry), entry.getName()).parse());\n                cgs.put(cg.getClassName(), cg);\n            } else {\n                NonClassEntries.add(entry, jf.getInputStream(entry));\n            }\n        }\n        jf.close();\n    }\n\n    public void renameClasses() {\n        int classCount = 1;\n        for (ClassGen cg : cgs.values()) {\n            String className = cg.getClassName();\n            String shortClassName = className.substring(className.lastIndexOf(\".\") + 1, className.length());\n            String newClassName = className.replace(shortClassName, \"Class\" + classCount);\n            cg.setClassName(newClassName);\n            tempcgs.put(newClassName, cg);\n            classCount++;\n        }\n        if (classCount > 1) {\n            logger.debug(\"Renamed \" + classCount + \" classes.\");\n            cgs = tempcgs;\n        }\n    }\n\n    public void replaceMethodRefs() {\n        for (ClassGen cg : cgs.values()) {\n            for (Method m : cg.getMethods()) {\n                int replaced = 0;\n                MethodGen mg = new MethodGen(m, cg.getClassName(), cg.getConstantPool());\n                InstructionList list = mg.getInstructionList();\n                if (list == null) {\n                    continue;\n                }\n                InstructionHandle[] handles = list.getInstructionHandles();\n                for (InstructionHandle handle : handles) {\n                    if (GenericMethods.isCall(handle.getInstruction())) {\n                        String oldClassName = GenericMethods.getCallClassName(handle.getInstruction(), cg.getConstantPool());\n                        String oldMethodName = GenericMethods.getCallMethodName(handle.getInstruction(), cg.getConstantPool());\n                        String oldSignature = GenericMethods.getCallSignature(handle.getInstruction(), cg.getConstantPool());\n                        String mod = oldClassName + \"-\" + oldMethodName + \"-\" + oldSignature;\n                        if (methodNames.containsKey(mod)) {\n                            //logger.debug(\"Accessing \" + methodNames.get(mod));\n                            String[] args = methodNames.get(mod).split(\"-\");\n                            String newClassName = args[0];\n                            String newMethodName = args[1];\n                            String newSignature = args[2];\n                            int newindex = cg.getConstantPool().addMethodref(newClassName, newMethodName, newSignature);\n                            Instruction newInvoke = GenericMethods.getNewInvoke(handle.getInstruction(), newindex);\n                            handle.setInstruction(newInvoke);\n                            replaced++;\n                        }\n                    }\n                }\n                mg.setInstructionList(list);\n                mg.setMaxLocals();\n                mg.setMaxStack();\n                if (replaced > 0) {\n                    logger.debug(\"replaced \" + replaced + \" methodrefs in \" + m.getName());\n                    cg.replaceMethod(m, mg.getMethod());\n                }\n            }\n        }\n    }\n\n    public void renameMethods() {\n        for (ClassGen cg : cgs.values()) {\n            if (cg.isAbstract() || cg.isInterface()) {\n                continue;\n            }\n            int count = 1;\n            for (Method m : cg.getMethods()) {\n                if (m.getName().equalsIgnoreCase(\"<clinit>\")\n                        || m.getName().equalsIgnoreCase(\"<init>\")\n                        || m.getName().equalsIgnoreCase(\"main\")) {\n                    continue;\n                }\n                ConstantPoolGen cpg = cg.getConstantPool();\n                String name = \"\";\n                if (m.isStatic()) {\n                    name += \"static\";\n                }\n                String type = m.getReturnType().toString();\n\n                name += type.substring(type.lastIndexOf(\".\") + 1, type.length());\n                name = name.replace(\"void\", \"\");\n                if (name.contains(\"[]\")) {\n                    name = name.replace(\"[]\", \"Array\");\n                }\n                name += \"Method\" + count;\n                //TODO: Get it to fully change the name (updated methodref name index) and not corrupt the constant pool lol\n                //TODO: Rename classes first, then methods, then fields.\n                MethodGen mg = new MethodGen(m, cg.getClassName(), cpg);\n                mg.setName(name);\n                cg.replaceMethod(m, mg.getMethod());\n                cg.setConstantPool(cpg);\n                //y.pb.methodsig - Class.Method04.MethodSig\n                methodNames.put(cg.getClassName() + \"-\" + m.getName() + \"-\" + m.getSignature(), cg.getClassName() + \"-\" + name + \"-\" + m.getSignature());\n                count++;\n                logger.debug(cg.getClassName() + \".\" + m.getName() + \" -> \" + cg.getClassName() + \".\" + name);\n            }\n        }\n    }\n\n    public void transform() {\n        logger.log(\"Generic Renamer\");\n        renameClasses();\n        renameMethods();\n        replaceMethodRefs();\n        logger.log(\"Deobfuscation finished! Dumping jar...\");\n        GenericMethods.dumpJar(JAR_NAME, cgs.values());\n        logger.log(\"Operation Completed.\");\n\n    }\n}\n"
  },
  {
    "path": "jmd-core/src/main/java/net/contra/jmd/transformers/generic/StackFixer.java",
    "content": "package net.contra.jmd.transformers.generic;\n\nimport net.contra.jmd.util.GenericMethods;\nimport net.contra.jmd.util.LogHandler;\nimport net.contra.jmd.util.NonClassEntries;\nimport org.apache.bcel.classfile.ClassParser;\nimport org.apache.bcel.classfile.Method;\nimport org.apache.bcel.generic.ClassGen;\nimport org.apache.bcel.generic.MethodGen;\n\nimport java.io.File;\nimport java.util.Enumeration;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\n\n/**\n * Created by IntelliJ IDEA.\n * User: Eric\n * Date: Nov 30, 2010\n * Time: 4:52:48 AM\n */\npublic class StackFixer {\n    private static LogHandler logger = new LogHandler(\"StackFixer\");\n    private Map<String, ClassGen> cgs = new HashMap<String, ClassGen>();\n    String JAR_NAME;\n\n    public StackFixer(String jarfile) throws Exception {\n        File jar = new File(jarfile);\n        JAR_NAME = jarfile;\n        JarFile jf = new JarFile(jar);\n        Enumeration<JarEntry> entries = jf.entries();\n        while (entries.hasMoreElements()) {\n            JarEntry entry = entries.nextElement();\n            if (entry == null) {\n                break;\n            }\n\n            if (entry.getName().endsWith(\".class\")) {\n                ClassGen cg = new ClassGen(new ClassParser(jf.getInputStream(entry), entry.getName()).parse());\n                cgs.put(cg.getClassName(), cg);\n            } else {\n                NonClassEntries.add(entry, jf.getInputStream(entry));\n            }\n        }\n        jf.close();\n    }\n\n    public void fixStack() {\n        for (ClassGen cg : cgs.values()) {\n            for (Method method : cg.getMethods()) {\n                MethodGen mg = new MethodGen(method, cg.getClassName(), cg.getConstantPool());\n                mg.removeNOPs();\n                mg.setMaxLocals();\n                mg.setMaxStack();\n                cg.replaceMethod(method, mg.getMethod());\n                logger.debug(String.format(\"Reset MaxStack and MaxLocals in %s.%s\", cg.getClassName(), mg.getName()));\n            }\n        }\n    }\n\n    public void transform() {\n        logger.log(\"Starting StackFixer\");\n        fixStack();\n        logger.log(\"Deobfuscation finished! Dumping jar...\");\n        GenericMethods.dumpJar(JAR_NAME, cgs.values());\n        logger.log(\"Operation Completed.\");\n\n    }\n}\n"
  },
  {
    "path": "jmd-core/src/main/java/net/contra/jmd/transformers/generic/StringFixer.java",
    "content": "package net.contra.jmd.transformers.generic;\n\nimport net.contra.jmd.util.GenericMethods;\nimport net.contra.jmd.util.LogHandler;\nimport net.contra.jmd.util.NonClassEntries;\nimport org.apache.bcel.classfile.ClassParser;\nimport org.apache.bcel.classfile.Method;\nimport org.apache.bcel.generic.*;\nimport org.apache.commons.io.IOUtils;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.util.Enumeration;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\nimport java.util.jar.JarOutputStream;\n\npublic class StringFixer {\n    private static LogHandler logger = new LogHandler(\"StringFixer\");\n    private Map<String, ClassGen> cgs = new HashMap<String, ClassGen>();\n    String JAR_NAME;\n    boolean replacing = false;\n\n    public StringFixer(String jarfile) throws Exception {\n        File jar = new File(jarfile);\n        JAR_NAME = jarfile;\n        JarFile jf = new JarFile(jar);\n        Enumeration<JarEntry> entries = jf.entries();\n        while (entries.hasMoreElements()) {\n            JarEntry entry = entries.nextElement();\n            if (entry == null) {\n                break;\n            }\n\n            if (entry.getName().endsWith(\".class\")) {\n                ClassGen cg = new ClassGen(new ClassParser(jf.getInputStream(entry), entry.getName()).parse());\n                cgs.put(cg.getClassName(), cg);\n            } else {\n                NonClassEntries.add(entry, jf.getInputStream(entry));\n            }\n        }\n        jf.close();\n    }\n\n    public void removeBASA() {\n        for (ClassGen cg : cgs.values()) {\n            for (Method method : cg.getMethods()) {\n                String type = \"\";\n                MethodGen mg = new MethodGen(method, cg.getClassName(), cg.getConstantPool());\n                InstructionList list = mg.getInstructionList();\n                if (list == null) {\n                    continue;\n                }\n                InstructionHandle[] handles = list.getInstructionHandles();\n                int startLoc = -1;\n                int endLoc = -1;\n                int arrayLength = -1;\n                for (int i = 0; i < handles.length; i++) {\n                    if ((handles[i].getInstruction() instanceof NEW)\n                            && (handles[i + 1].getInstruction() instanceof DUP)\n                            && GenericMethods.isNumber(handles[i + 2].getInstruction())\n                            && (handles[i + 3].getInstruction() instanceof NEWARRAY)) {\n                        String newType = ((NEW) handles[i].getInstruction()).getLoadClassType(cg.getConstantPool()).toString();\n                        type = ((NEWARRAY) handles[i + 3].getInstruction()).getType().toString();\n                        logger.debug(\"Found new array conversion pattern: \" + type + \"->\" + newType + \" in \" + cg.getClassName() + \".\" + method.getName());\n\n                        //if(newType.equals(\"java.lang.String\") && (type.equals(\"byte[]\") || type.equals(\"char[]\"))) {\n                        if (newType.equals(\"java.lang.String\") && type.contains(\"[]\")) {\n                            startLoc = i;\n                            arrayLength = GenericMethods.getValueOfNumber(handles[i + 2].getInstruction(), cg.getConstantPool());\n                            //logger.debug(\"Start Location for BASA replacement: \" + startLoc);\n                            //logger.debug(\"Length of Array: \" + arrayLength);\n                        }\n                    }\n                    if (startLoc >= 0 && arrayLength >= 1) {\n                        if (handles.length > (i + 1)) {\n                            if ((handles[i].getInstruction() instanceof BASTORE)\n                                    && GenericMethods.isNumber(handles[i - 1].getInstruction())\n                                    && GenericMethods.isNumber(handles[i - 2].getInstruction())\n                                    && (handles[i - 3].getInstruction() instanceof DUP)) {\n                                /*\n                                                                                    TODO: Also you need to make the endLoc INVOKESTATIC STRING<init> or something because it is leaving a trailing command and fucking up.\n                                                                                */\n                                if (GenericMethods.isCall(handles[i + 1].getInstruction())) {\n                                    if (GenericMethods.getCallArgTypes(handles[i + 1].getInstruction(), cg.getConstantPool()) != null) {\n                                        Type[] tp = GenericMethods.getCallArgTypes(handles[i + 1].getInstruction(), cg.getConstantPool());\n                                        String lasttp = tp[tp.length - 1].toString();\n                                        if (!lasttp.contains(type)) {\n                                            int tendLoc = GenericMethods.getValueOfNumber(handles[i - 2].getInstruction(), cg.getConstantPool());\n                                            if (tendLoc == (arrayLength - 1)) {\n                                                endLoc = i;\n                                                //logger.debug(\"End Location for BASA replacement: \" + endLoc);\n                                            }\n                                        } else {\n                                            logger.debug(\"Can't replace String(\" + type + \"), following method call has argument of same type\");\n                                            startLoc = -1;\n                                            endLoc = -1;\n                                            arrayLength = -1;\n                                            continue;\n                                        }\n                                    }\n                                }\n                            }\n                        }\n                    }\n                    if ((startLoc >= 0) && (endLoc >= 0) && (arrayLength > 1)\n                            && (endLoc < handles.length)) {\n                        byte[] stringBytes = new byte[arrayLength];\n                        int loc = 0;\n                        for (int x = startLoc; x <= endLoc; x++) {\n                            if (GenericMethods.isNumber(handles[x].getInstruction())\n                                    && GenericMethods.isNumber(handles[x + 1].getInstruction())\n                                    && (handles[x + 2].getInstruction() instanceof BASTORE)\n                                    && (GenericMethods.getValueOfNumber(handles[x].getInstruction(), cg.getConstantPool()) == loc)) {\n                                stringBytes[loc] = (byte) GenericMethods.getValueOfNumber(handles[x + 1].getInstruction(), cg.getConstantPool());\n                                loc++;\n                                if (loc == stringBytes.length) {\n                                    if (replacing) {\n                                        int stringRef = cg.getConstantPool().addString(new String(stringBytes));\n                                        LDC lc = new LDC(stringRef);\n                                        handles[startLoc].setInstruction(lc);\n                                        for (int z = startLoc + 1; z <= endLoc; z++) {\n                                            NOP nop = new NOP();\n                                            handles[z].setInstruction(nop);\n                                        }\n                                        logger.debug(\"Replaced conversion with string \" + new String(stringBytes) + \" in \" + cg.getClassName() + \".\" + method.getName());\n                                    } else {\n                                        logger.debug(\"Found conversion, string:\" + new String(stringBytes));\n                                    }\n                                    startLoc = -1;\n                                    endLoc = -1;\n                                    arrayLength = -1;\n                                    type = \"\";\n                                    mg.setInstructionList(list);\n                                    mg.removeNOPs();\n                                    mg.setMaxLocals();\n                                    mg.setMaxStack();\n                                    cg.replaceMethod(method, mg.getMethod());\n                                    continue;\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    public void dumpJar(String path) {\n        FileOutputStream os;\n        try {\n            os = new FileOutputStream(new File(path));\n        } catch (FileNotFoundException fnfe) {\n            throw new RuntimeException(\"could not create file \\\"\" + path + \"\\\": \" + fnfe);\n        }\n        JarOutputStream jos;\n\n        try {\n            jos = new JarOutputStream(os);\n            for (ClassGen classIt : cgs.values()) {\n                jos.putNextEntry(new JarEntry(classIt.getClassName().replace('.', '/') + \".class\"));\n                jos.write(classIt.getJavaClass().getBytes());\n                jos.closeEntry();\n                jos.flush();\n            }\n            for (JarEntry jbe : NonClassEntries.entries) {\n                JarEntry destEntry = new JarEntry(jbe.getName());\n                byte[] bite = IOUtils.toByteArray(NonClassEntries.ins.get(jbe));\n                jos.putNextEntry(destEntry);\n                jos.write(bite);\n                jos.closeEntry();\n            }\n            jos.closeEntry();\n            jos.close();\n        } catch (IOException ioe) {\n        }\n    }\n\n    public void transform() {\n        logger.log(\"Generic String Fixer\");\n        logger.log(\"This hasn't been finished yet.\");\n        logger.log(\"Scanning/Replacing Strings hidden as byte arrays...\");\n        removeBASA();\n        logger.log(\"Deobfuscation finished! Dumping jar...\");\n        dumpJar(JAR_NAME.replace(\".jar\", \"\") + \"-deob.jar\");\n        logger.log(\"Operation Completed.\");\n\n    }\n}\n"
  },
  {
    "path": "jmd-core/src/main/java/net/contra/jmd/transformers/generic/StringScanner.java",
    "content": "package net.contra.jmd.transformers.generic;\n\nimport net.contra.jmd.util.LogHandler;\nimport net.contra.jmd.util.NonClassEntries;\nimport org.apache.bcel.classfile.ClassParser;\nimport org.apache.bcel.classfile.Method;\nimport org.apache.bcel.generic.*;\n\nimport java.io.File;\nimport java.util.Enumeration;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\n\npublic class StringScanner {\n    private static LogHandler logger = new LogHandler(\"StringScanner\");\n    private Map<String, ClassGen> cgs = new HashMap<String, ClassGen>();\n    boolean replaceMode = false;\n    String substitute = \"\";\n    String inputScan = \"\";\n\n    public StringScanner(String jarfile, String scanstring, boolean replace, String replacestring) throws Exception {\n        inputScan = scanstring;\n        replaceMode = replace;\n        substitute = replacestring;\n        File jar = new File(jarfile);\n        JarFile jf = new JarFile(jar);\n        Enumeration<JarEntry> entries = jf.entries();\n        while (entries.hasMoreElements()) {\n            JarEntry entry = entries.nextElement();\n            if (entry == null) {\n                break;\n            }\n\n            if (entry.getName().endsWith(\".class\")) {\n                ClassGen cg = new ClassGen(new ClassParser(jf.getInputStream(entry), entry.getName()).parse());\n                cgs.put(cg.getClassName(), cg);\n            } else {\n                NonClassEntries.add(entry, jf.getInputStream(entry));\n            }\n        }\n        jf.close();\n    }\n\n    public void searchConstantPool() {\n        for (ClassGen cg : cgs.values()) {\n            for (Method m : cg.getMethods()) {\n                MethodGen mg = new MethodGen(m, cg.getClassName(), cg.getConstantPool());\n                InstructionList list = mg.getInstructionList();\n                InstructionHandle[] handles;\n                if (list != null && list.size() > 0) {\n                    handles = list.getInstructionHandles();\n                } else {\n                    break;\n                }\n                for (InstructionHandle handle : handles) {\n                    if (handle.getInstruction() instanceof LDC) {\n                        LDC newldc = (LDC) handle.getInstruction();\n                        String val = newldc.getValue(cg.getConstantPool()).toString();\n                        if (val.contains(inputScan)) {\n                            if (!replaceMode) {\n                                logger.log(val + \" in \" + cg.getClassName() + \".\" + m.getName());\n                            } else {\n                                String newz = val.replace(inputScan, substitute);\n                                int stringRef = cg.getConstantPool().addString(newz);\n                                handle.setInstruction(new LDC(stringRef));\n                                logger.log(val + \"->\" + newz + \" in \" + cg.getClassName() + \".\" + m.getName());\n                            }\n                        }\n                    }\n                }\n                if (replaceMode) {\n                    list.setPositions();\n                    mg.setMaxLocals();\n                    mg.setMaxStack();\n                    cg.replaceMethod(m, mg.getMethod());\n                }\n            }\n        }\n\n    }\n\n    public void scan() {\n        logger.log(\"Generic URL Scanner/Replacer\");\n        if (!replaceMode) {\n            logger.log(\"Scanning for Strings containing \" + inputScan);\n        } else {\n            logger.log(\"Replacing \" + inputScan + \" with \" + substitute);\n        }\n        searchConstantPool();\n        logger.log(\"Operation Completed.\");\n    }\n}\n"
  },
  {
    "path": "jmd-core/src/main/java/net/contra/jmd/transformers/generic/TransformerTemplate.java",
    "content": "package net.contra.jmd.transformers.generic;\n\nimport net.contra.jmd.util.GenericMethods;\nimport net.contra.jmd.util.LogHandler;\nimport org.apache.bcel.generic.ClassGen;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic class TransformerTemplate {\n    private static LogHandler logger = new LogHandler(\"StringFixer\");\n    private Map<String, ClassGen> cgs = new HashMap<String, ClassGen>();\n    String JAR_NAME;\n\n    public void transform() {\n        logger.log(\"Generic Transformer\");\n\n        logger.log(\"Deobfuscation finished! Dumping jar...\");\n        GenericMethods.dumpJar(JAR_NAME, cgs.values());\n        logger.log(\"Operation Completed.\");\n\n    }\n}\n"
  },
  {
    "path": "jmd-core/src/main/java/net/contra/jmd/transformers/jshrink/JShrinkTransformer.java",
    "content": "package net.contra.jmd.transformers.jshrink;\n\nimport net.contra.jmd.transformers.Transformer;\nimport net.contra.jmd.util.GenericMethods;\nimport net.contra.jmd.util.LogHandler;\nimport net.contra.jmd.util.NonClassEntries;\nimport org.apache.bcel.classfile.ClassParser;\nimport org.apache.bcel.classfile.Method;\nimport org.apache.bcel.generic.*;\n\nimport java.io.File;\nimport java.util.Enumeration;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\n\npublic class JShrinkTransformer implements Transformer {\n    private static LogHandler logger = new LogHandler(\"JShrinkTransformer\");\n    private Map<String, ClassGen> cgs = new HashMap<String, ClassGen>();\n    String JAR_NAME;\n    ClassGen LoaderClass = null;\n\n    public JShrinkTransformer(String jarfile) throws Exception {\n        File jar = new File(jarfile);\n        JAR_NAME = jarfile;\n        JarFile jf = new JarFile(jar);\n        Enumeration<JarEntry> entries = jf.entries();\n        while (entries.hasMoreElements()) {\n            JarEntry entry = entries.nextElement();\n            if (entry == null) {\n                break;\n            }\n            if (entry.getName().endsWith(\".class\")) {\n                ClassGen cg = new ClassGen(new ClassParser(jf.getInputStream(entry), entry.getName()).parse());\n                String className = entry.getName().replace(\".class\", \"\").replace(\"\\\\\", \"/\").replace(\"/\", \".\");\n                if (isLoader(cg) && LoaderClass == null) {\n                    logger.debug(\"Found JShrink Loader! \" + cg.getClassName());\n                    LoaderClass = cg;\n                } else {\n                    cgs.put(className, cg);\n                }\n            } else {\n                if (!entry.isDirectory()) {\n                    NonClassEntries.add(entry, jf.getInputStream(entry));\n                }\n            }\n        }\n        logger.debug(\"Classes loaded from JAR\");\n        if (LoaderClass == null) {\n            logger.error(\"Loader class not found! Class not using JShrink\");\n        }\n        jf.close();\n    }\n\n    public boolean isLoader(ClassGen cg) {\n\n\n        return cg.getMethods().length == 3 && cg.getMethods()[1].isStatic()\n                && cg.getMethods()[1].isFinal()\n                && cg.getMethods()[1].isPublic()\n                && cg.getMethods()[1].isSynchronized()\n                && cg.getMethods()[1].getReturnType().toString().equals(\"java.lang.String\");\n    }\n\n    public void replaceStrings() throws TargetLostException {\n        for (ClassGen cg : cgs.values()) {\n            int replaced = 0;\n            for (Method method : cg.getMethods()) {\n                MethodGen mg = new MethodGen(method, cg.getClassName(), cg.getConstantPool());\n                InstructionList list = mg.getInstructionList();\n                if (list == null) {\n                    continue;\n                }\n                InstructionHandle[] handles = list.getInstructionHandles();\n                for (int i = 1; i < handles.length; i++) {\n                    if (handles[i].getInstruction() instanceof INVOKESTATIC && GenericMethods.isNumber(handles[i - 1].getInstruction())) {\n                        INVOKESTATIC methodCall = (INVOKESTATIC) handles[i].getInstruction();\n                        if (methodCall.getClassName(cg.getConstantPool()).contains(LoaderClass.getClassName())) {\n                            int push = GenericMethods.getValueOfNumber(handles[i - 1].getInstruction(), cg.getConstantPool());\n                            String decryptedString = StoreHandler.I(push);\n                            if (decryptedString != null) {\n                                int stringRef = cg.getConstantPool().addString(decryptedString);\n                                LDC lc = new LDC(stringRef);\n                                NOP nop = new NOP();\n                                handles[i].setInstruction(lc);\n                                handles[i - 1].setInstruction(nop);\n                                replaced++;\n                            }\n                        }\n                    }\n                }\n                mg.setInstructionList(list);\n                mg.removeNOPs();\n                mg.setMaxLocals();\n                mg.setMaxStack();\n                cg.replaceMethod(method, mg.getMethod());\n            }\n            if (replaced > 0) {\n                logger.debug(\"replaced \" + replaced + \" calls in class \" + cg.getClassName());\n            }\n        }\n    }\n\n\n    public void transform() {\n        try {\n            logger.log(\"Starting String Replacer...\");\n            replaceStrings();\n        } catch (TargetLostException e) {\n            e.printStackTrace();\n        }\n        logger.log(\"Deobfuscation Finished! Dumping jar...\");\n        GenericMethods.dumpJar(JAR_NAME, cgs.values());\n        logger.log(\"Operation Completed.\");\n    }\n}\n"
  },
  {
    "path": "jmd-core/src/main/java/net/contra/jmd/transformers/jshrink/StoreHandler.java",
    "content": "package net.contra.jmd.transformers.jshrink;\n\nimport net.contra.jmd.util.NonClassEntries;\n\nimport java.io.InputStream;\n\n/**\n * Created by IntelliJ IDEA.\n * User: Eric\n * Date: Nov 29, 2010\n * Time: 10:25:20 PM\n */\npublic class StoreHandler {\n    static byte[] WSVZ;\n    static String[] append = new String[256];\n    static int[] close = new int[256];\n\n    public static synchronized String I(int paramInt) {\n        int i = paramInt & 0xFF;\n        if (close[i] != paramInt) {\n            close[i] = paramInt;\n            if (paramInt < 0) {\n                paramInt &= 65535;\n            }\n            String str = new String(WSVZ, paramInt, WSVZ[(paramInt - 1)] & 0xFF).intern();\n            append[i] = str;\n        }\n        return append[i];\n    }\n\n    static {\n        try {\n            InputStream localInputStream = NonClassEntries.ins.get(NonClassEntries.getByName(\"I/I.gif\"));\n            if (localInputStream != null) {\n                int i = localInputStream.read() << 16 | localInputStream.read() << 8 | localInputStream.read();\n                WSVZ = new byte[i];\n                int j = 0;\n                int k = (byte) i;\n                byte[] arrayOfByte = WSVZ;\n                while (i != 0) {\n                    int m = localInputStream.read(arrayOfByte, j, i);\n                    if (m == -1) {\n                        break;\n                    }\n                    i -= m;\n                    m += j;\n                    while (j < m) {\n                        int int2 = j;\n                        arrayOfByte[int2] = (byte) (arrayOfByte[int2] ^ k);\n                        j++;\n                    }\n                }\n                localInputStream.reset();\n                localInputStream.close();\n            }\n        } catch (Exception localException) {\n        }\n    }\n}\n"
  },
  {
    "path": "jmd-core/src/main/java/net/contra/jmd/transformers/smokescreen/SmokeScreenTransformer.java",
    "content": "package net.contra.jmd.transformers.smokescreen;\n\nimport net.contra.jmd.transformers.Transformer;\nimport net.contra.jmd.util.GenericMethods;\nimport net.contra.jmd.util.LogHandler;\nimport net.contra.jmd.util.NonClassEntries;\nimport org.apache.bcel.classfile.ClassParser;\nimport org.apache.bcel.classfile.Method;\nimport org.apache.bcel.generic.*;\nimport org.apache.bcel.util.InstructionFinder;\n\nimport java.io.File;\nimport java.util.Enumeration;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\n\npublic class SmokeScreenTransformer implements Transformer {\n    private static LogHandler logger = new LogHandler(\"SmokeScreenTransformer\");\n    private Map<String, ClassGen> cgs;\n    private Map<String, String> ssStrings = new HashMap<String, String>();\n    String JAR_NAME;\n\n    public String getActualString(String className, int i1, int i2) {\n        return ssStrings.get(className).substring(i1, i2);\n    }\n\n    public void replaceStrings() {\n        for (ClassGen cg : cgs.values()) {\n            int replaced = 0;\n            for (Method m : cg.getMethods()) {\n                MethodGen mg = new MethodGen(m, cg.getClassName(), cg.getConstantPool());\n                InstructionList list = mg.getInstructionList();\n                if (list == null) {\n                    return;\n                }\n                InstructionHandle[] handles = list.getInstructionHandles();\n                for (int x = 0; x < handles.length; x++) {\n                    if (x + 3 < handles.length) {\n                        if (handles[x].getInstruction() instanceof GETSTATIC\n                                && GenericMethods.isNumber(handles[x + 1].getInstruction())\n                                && GenericMethods.isNumber(handles[x + 2].getInstruction())\n                                && GenericMethods.isCall(handles[x + 3].getInstruction())) {\n                            if (GenericMethods.getCallMethodName(handles[x + 3].getInstruction(), cg.getConstantPool()).contains(\"substring\")) {\n                                int con1 = GenericMethods.getValueOfNumber(handles[x + 1].getInstruction(), cg.getConstantPool());\n                                int con2 = GenericMethods.getValueOfNumber(handles[x + 2].getInstruction(), cg.getConstantPool());\n                                NOP nop = new NOP();\n                                int stringRef = cg.getConstantPool().addString(getActualString(cg.getClassName(), con1, con2));\n                                LDC data = new LDC(stringRef);\n                                handles[x].setInstruction(data);\n                                handles[x + 1].setInstruction(nop);\n                                handles[x + 2].setInstruction(nop);\n                                handles[x + 3].setInstruction(nop);\n                                replaced++;\n                                mg.setInstructionList(list);\n                                mg.removeNOPs();\n                                mg.setMaxLocals();\n                                mg.setMaxStack();\n                                cg.replaceMethod(m, mg.getMethod());\n                                continue;\n                            }\n                        }\n                    }\n                }\n            }\n            if (replaced > 0) {\n                logger.debug(\"Replaced \" + replaced + \" calls in class \" + cg.getClassName());\n            }\n        }\n    }\n\n    public void grabStrings() {\n        for (ClassGen cg : cgs.values()) {\n            for (Method m : cg.getMethods()) {\n                int key = 0;\n                MethodGen mg = new MethodGen(m, cg.getClassName(), cg.getConstantPool());\n                InstructionList list = mg.getInstructionList();\n                if (list == null) {\n                    return;\n                }\n                InstructionHandle[] handles = list.getInstructionHandles();\n                for (int x = 0; x < handles.length; x++) {\n                    if (x + 3 < handles.length) {\n                        if (handles[x].getInstruction() instanceof LDC\n                                && handles[x + 1].getInstruction() instanceof ASTORE\n                                && GenericMethods.isNumber(handles[x + 2].getInstruction())\n                                && handles[x + 3].getInstruction() instanceof ISTORE) {\n                            key = GenericMethods.getValueOfNumber(handles[x + 2].getInstruction(), cg.getConstantPool());\n                            LDC tx = (LDC) handles[x].getInstruction();\n\n                            String encryptedContent = tx.getValue(cg.getConstantPool()).toString();\n                            String decryptedContent = decrypt(encryptedContent, key);\n                            logger.debug(\"Found key for \" + cg.getClassName() + \": \" + key);\n                            logger.debug(\"Strings for class: \" + decryptedContent);\n                            ssStrings.put(cg.getClassName(), decryptedContent);\n                            continue;\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    public SmokeScreenTransformer(String jarfile) throws Exception {\n        cgs = new HashMap<String, ClassGen>();\n        File jar = new File(jarfile);\n        JAR_NAME = jarfile;\n        JarFile jf = new JarFile(jar);\n        Enumeration<JarEntry> entries = jf.entries();\n        while (entries.hasMoreElements()) {\n            JarEntry entry = entries.nextElement();\n            if (entry == null) {\n                break;\n            }\n            if (entry.getName().endsWith(\".class\")) {\n                ClassGen cg = new ClassGen(new ClassParser(jf.getInputStream(entry), entry.getName()).parse());\n                String className = entry.getName().replace(\".class\", \"\").replace(\"\\\\\", \"/\").replace(\"/\", \".\");\n                cgs.put(className, cg);\n            } else {\n                NonClassEntries.add(entry, jf.getInputStream(entry));\n            }\n        }\n        logger.debug(\"Classes loaded from JAR\");\n        jf.close();\n    }\n\n    public static String decrypt(String encrypted, int myKey) {\n        int key = myKey;\n        char[] encChars = encrypted.toCharArray();\n        char[] tmpChars = new char[encChars.length];\n        for (int j = 0; j < encChars.length; j++) {\n            tmpChars = encChars;\n            tmpChars[j] = (char) (tmpChars[j] ^ key);\n            key = (char) (key + encChars[j] & 0x3E);\n        }\n        return new String(tmpChars);\n    }\n\n    public void transform() {\n        logger.log(\"SmokeScreen Deobfuscator\");\n        logger.log(\"Decrypting Strings...\");\n        grabStrings();\n        logger.log(\"Replacing string calls with LDC\");\n        replaceStrings();\n        logger.log(\"Starting Exit Flow Corrector...\");\n        exitFlowTransformer();\n        logger.log(\"Removing Unconditional Branches...\");\n        unconditionalBranchTransformer();\n        logger.log(\"Deobfuscation finished! Dumping jar...\");\n        GenericMethods.dumpJar(JAR_NAME, cgs.values());\n        logger.log(\"Operation Completed.\");\n\n    }\n\n\n    public void unconditionalBranchTransformer() {\n        for (ClassGen cg : cgs.values()) {\n            for (Method method : cg.getMethods()) {\n                final MethodGen mg = new MethodGen(method, cg.getClassName(), cg.getConstantPool());\n                if (method.isAbstract() || method.isNative()) {\n                    return;\n                }\n                final InstructionList list = mg.getInstructionList();\n                InstructionFinder finder = new InstructionFinder(list);\n                final ConstantPoolGen cpg = cg.getConstantPool();\n                int branchesSimplified = 0;\n                Iterator<InstructionHandle[]> matches = finder.search(\"IfInstruction\");\n                while (matches.hasNext()) {\n                    InstructionHandle ifHandle = matches.next()[0];\n                    InstructionHandle target = ((BranchHandle) ifHandle).getTarget();\n                    if (target.getInstruction() instanceof GOTO) {\n                        branchesSimplified++;\n                        ((BranchHandle) ifHandle).setTarget(((BranchHandle) target).getTarget());\n                    }\n                }\n                matches = finder.search(\"GOTO GOTO\");\n                while (matches.hasNext()) {\n                    InstructionHandle[] match = matches.next();\n                    try {\n                        list.delete(match[0]);\n                    } catch (TargetLostException tlex) {\n                        for (InstructionHandle target : tlex.getTargets()) {\n                            for (InstructionTargeter targeter : target.getTargeters()) {\n                                targeter.updateTarget(target, match[1]);\n                            }\n                        }\n                    }\n                }\n                mg.setInstructionList(list);\n                mg.setMaxLocals();\n                mg.setMaxStack();\n                if (branchesSimplified > 0) {\n                    logger.debug(\"simplified \" + branchesSimplified + \" unconditional branches\");\n                    cg.replaceMethod(method, mg.getMethod());\n                }\n            }\n        }\n    }\n\n    public void exitFlowTransformer() {\n        for (ClassGen cg : cgs.values()) {\n            int correct = 0;\n            for (Method method : cg.getMethods()) {\n                final MethodGen mgen = new MethodGen(method, cg.getClassName(), cg.getConstantPool());\n                if (!method.isAbstract() && !method.isNative()) {\n                    InstructionList list = mgen.getInstructionList();\n                    InstructionFinder finder = new InstructionFinder(list);\n                    CodeExceptionGen[] exceptionGens = mgen.getExceptionHandlers();\n                    for (Iterator<InstructionHandle[]> matches = finder.search(\n                            \"ASTORE ALOAD (NEW DUP (PushInstruction InvokeInstruction)+ (ALOAD IfInstruction LDC GOTO LDC \" +\n                                    \"INVOKEVIRTUAL)? (PushInstruction InvokeInstruction)* InvokeInstruction+)?\");\n                         matches.hasNext();) {\n                        /* thanks to popcorn89 */\n                        InstructionHandle[] match = matches.next();\n                        if (!(match[match.length - 1].getInstruction() instanceof ATHROW)) {\n                            continue;\n                        }\n                        InstructionHandle astoreInstr = match[0];\n                        InstructionHandle athrowInstr = match[match.length - 1];\n                        InstructionHandle toRedirect = athrowInstr.getNext();\n                        for (CodeExceptionGen exgen : exceptionGens) {\n                            if (exgen.getHandlerPC().equals(astoreInstr)) {\n                                mgen.removeExceptionHandler(exgen);\n                            }\n                        }\n                        try {\n                            list.delete(astoreInstr, athrowInstr);\n                        } catch (TargetLostException tlex) {\n                            if (athrowInstr == list.getEnd()) {\n                                toRedirect = astoreInstr.getPrev();\n                            }\n                            for (InstructionHandle target : tlex.getTargets()) {\n                                for (InstructionTargeter targeter : target.getTargeters()) {\n                                    targeter.updateTarget(target, toRedirect);\n                                }\n                            }\n                        }\n                    }\n                    list.setPositions(true);\n                    InstructionHandle lastInstr = list.getEnd();\n                    InstructionHandle secondToLastInstr = lastInstr.getPrev();\n                    if (secondToLastInstr != null && (lastInstr.getInstruction() instanceof RETURN)\n                            && (secondToLastInstr.getInstruction() instanceof RETURN)) {\n                        try {\n                            list.delete(secondToLastInstr);\n                        } catch (TargetLostException tlex) {\n                            for (InstructionHandle target : tlex.getTargets()) {\n                                for (InstructionTargeter targeter : target.getTargeters()) {\n                                    targeter.updateTarget(target, lastInstr);\n                                }\n                            }\n                        }\n                    }\n                    if (mgen.getMethod() != method) {\n                        correct++;\n                        //logger.debug(\"corrected exit flow in \" + cg.getClassName() + \".\" + mgen.getName() + mgen.getSignature());\n                        mgen.setInstructionList(list);\n                        mgen.setMaxLocals();\n                        mgen.setMaxStack();\n                        cg.replaceMethod(method, mgen.getMethod());\n                    }\n                }\n            }\n            logger.debug(\"Corrected exit flow \" + correct + \" times in \" + cg.getClassName());\n        }\n    }\n}\n"
  },
  {
    "path": "jmd-core/src/main/java/net/contra/jmd/transformers/zkm/ZKMTransformer.java",
    "content": "package net.contra.jmd.transformers.zkm;\n\nimport net.contra.jmd.transformers.Transformer;\nimport net.contra.jmd.util.GenericMethods;\nimport net.contra.jmd.util.LogHandler;\nimport net.contra.jmd.util.NonClassEntries;\nimport org.apache.bcel.classfile.*;\nimport org.apache.bcel.generic.*;\nimport org.apache.bcel.util.*;\n\nimport java.io.File;\nimport java.util.*;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\n\npublic class ZKMTransformer implements Transformer {\n    private static LogHandler logger = new LogHandler(\"ZKMTransformer\");\n    private Map<String, ClassGen> cgs = new HashMap<String, ClassGen>();\n    private Map<String, ArrayList<String>> zkStrings = new HashMap<String, ArrayList<String>>();\n    String JAR_NAME;\n    private List<Field> flowObstructors = new LinkedList<Field>();\n    private Field controlField = null;\n    private String controlClass = \"\";\n\n    public String getZKMString(String className, int index) {\n        return zkStrings.get(className).get(index);\n    }\n\n    public ZKMTransformer(String jarfile) throws Exception {\n        File jar = new File(jarfile);\n        JAR_NAME = jarfile;\n        JarFile jf = new JarFile(jar);\n        Enumeration<JarEntry> entries = jf.entries();\n        while (entries.hasMoreElements()) {\n            JarEntry entry = entries.nextElement();\n            if (entry == null) {\n                break;\n            }\n            if (entry.getName().endsWith(\".class\")) {\n                ClassGen cg = new ClassGen(new ClassParser(jf.getInputStream(entry), entry.getName()).parse());\n                String className = entry.getName().replace(\".class\", \"\").replace(\"\\\\\", \"/\").replace(\"/\", \".\");\n                cgs.put(className, cg);\n            } else {\n                NonClassEntries.add(entry, jf.getInputStream(entry));\n            }\n        }\n        logger.debug(\"Classes loaded from JAR\");\n        jf.close();\n    }\n\n    public static boolean typeA(ClassGen cg) {\n        for (Method m : cg.getMethods()) {\n            if (m.getArgumentTypes().length == 1 && m.getArgumentTypes()[0].equals(Type.getType(char[].class))) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    public static char[] findKeyC(ClassGen cg) {\n        for (Method m : cg.getMethods()) {\n            if (m.getName().contains(\"clinit\")) {\n                MethodGen mg = new MethodGen(m, cg.getClassName(), cg.getConstantPool());\n                InstructionHandle[] handles = mg.getInstructionList().getInstructionHandles();\n                char[] keyAsChars = new char[5];\n                int found = 0;\n                for (int i = handles.length - 1; i > 0; i--) {\n                    if (found < 5) {\n                        //TODO: FIX THIS, THE LAST TWO CHARS FOR THE KEY ARE BEING FOUND PROPERLY BUT SAVED TO THE ARRAY WRONG\n                        if ((handles[i - 1].getInstruction() instanceof BIPUSH)\n                                && ((handles[i].getInstruction() instanceof GOTO && ((GOTO) handles[i].getInstruction()).getTarget().getInstruction() instanceof IXOR)\n                                || handles[i].getInstruction() instanceof IXOR)) {\n                            keyAsChars[found] = (char) ((BIPUSH) handles[i - 1].getInstruction()).getValue().intValue();\n                            logger.debug(found + \" found key char: \" + (int) keyAsChars[found] + \" line: \" + i);\n                            found++;\n                        } else if ((handles[i - 1].getInstruction() instanceof ICONST)\n                                && ((handles[i].getInstruction() instanceof GOTO && ((GOTO) handles[i].getInstruction()).getTarget().getInstruction() instanceof IXOR)\n                                || handles[i].getInstruction() instanceof IXOR)) {\n                            keyAsChars[found] = (char) ((ICONST) handles[i - 1].getInstruction()).getValue().intValue();\n                            logger.debug(found + \" found key char: \" + (int) keyAsChars[found] + \" line: \" + i);\n                            found++;\n                        }\n                    } else {\n                        break;\n                    }\n                }\n                char[] right = new char[5];\n                right[0] = keyAsChars[4];\n                right[1] = keyAsChars[3];\n                right[2] = keyAsChars[2];\n                right[3] = keyAsChars[1];\n                right[4] = keyAsChars[0];\n                for (char c : right) {\n                    logger.debug(\"KeyChar: \" + (int) c);\n                }\n                if (keyAsChars == new char[5]) {\n                    logger.error(\"ZKM Key Method C Failed, please send in this file to be analyzed.\");\n                    return null;\n                } else {\n                    logger.debug(\"ZKM Key = \" + String.valueOf(right));\n                    return right;\n                }\n            }\n\n        }\n        return null;\n    }\n\n    public static char[] findKeyB(ClassGen cg) {\n        return findKeyC(cg);\n        /*\n\t\tfor(Method m : cg.getMethods()) {\n\t\t\tif(m.getName().contains(\"clinit\")) {\n\t\t\t\tMethodGen mg = new MethodGen(m, cg.getClassName(), cg.getConstantPool());\n\t\t\t\tInstructionHandle[] handles = mg.getInstructionList().getInstructionHandles();\n\t\t\t\tchar[] keyAsChars = new char[5];\n\t\t\t\tint found = 0;\n                int ixor = -1;\n                for(int i = handles.length - 1; i < handles.length; i--){\n                   if(handles[i].getInstruction() instanceof IXOR){\n                       ixor = i;\n                       break;\n                   }\n                }\n                if(ixor == -1){\n                    logger.error(\"ZKM Key Method B Failed, attempting method C\");\n\t\t\t\t\treturn findKeyC(cg);\n                }\n\t\t\t\tfor(int i = ixor; i > 0; i--) {\n\t\t\t\t\tif(found < 5) {\n\t\t\t\t\t\tif((handles[i - 1].getInstruction() instanceof BIPUSH)\n\t\t\t\t\t\t\t\t&& (handles[i].getInstruction() instanceof GOTO || handles[i].getInstruction() instanceof IXOR)) {\n\t\t\t\t\t\t\tkeyAsChars[found] = (char) ((BIPUSH) handles[i - 1].getInstruction()).getValue().intValue();\n\t\t\t\t\t\t\tlogger.debug(\"found key char: \" + (char) found);\n\t\t\t\t\t\t\tfound++;\n\t\t\t\t\t\t} else if((handles[i - 1].getInstruction() instanceof ICONST)\n\t\t\t\t\t\t\t\t&& (handles[i].getInstruction() instanceof GOTO || handles[i].getInstruction() instanceof IXOR)) {\n\t\t\t\t\t\t\tkeyAsChars[found] = (char) ((ICONST) handles[i - 1].getInstruction()).getValue().intValue();\n\t\t\t\t\t\t\tfound++;\n\t\t\t\t\t\t\tlogger.debug(\"found key char: \" + (char) found);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n                char[] right = keyAsChars;\n\t\t\t\tright[0] = keyAsChars[4];\n\t\t\t\tright[1] = keyAsChars[3];\n\t\t\t\tright[2] = keyAsChars[2];\n\t\t\t\tright[3] = keyAsChars[1];\n\t\t\t\tright[4] = keyAsChars[0];\n\t\t\t\tif(keyAsChars == new char[5]) {\n\t\t\t\t\tlogger.error(\"ZKM Key Method B Failed, please send in this file to be analyzed.\");\n\t\t\t\t\treturn null;\n\t\t\t\t} else {\n\t\t\t\t\tlogger.debug(\"ZKM Key = \" + String.valueOf(right));\n\t\t\t\t\treturn right;\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\t\treturn null;       */\n    }\n\n    public static char[] findKey(ClassGen cg) {\n        if (typeA(cg)) {\n            System.out.println(\"Type A Found!\");\n            for (Method m : cg.getMethods()) {\n                if (m.getArgumentTypes().length == 1 && m.getArgumentTypes()[0].equals(Type.getType(char[].class))) {\n                    MethodGen mg = new MethodGen(m, cg.getClassName(), cg.getConstantPool());\n                    InstructionHandle[] handles = mg.getInstructionList().getInstructionHandles();\n                    char[] keyAsChars = new char[5];\n                    for (InstructionHandle handle : handles) {\n                        if (handle.getInstruction() instanceof TABLESWITCH) {\n                            TABLESWITCH xor = (TABLESWITCH) handle.getInstruction();\n                            for (int a = 0; a < xor.getTargets().length; a++) {\n                                Instruction target = xor.getTargets()[a].getInstruction();\n                                if (target instanceof BIPUSH) {\n                                    keyAsChars[a] = (char) ((BIPUSH) target).getValue().intValue();\n                                } else {\n                                    keyAsChars[a] = (char) ((ICONST) target).getValue().intValue();\n                                }\n                            }\n                            Instruction target = xor.getTarget().getInstruction();\n                            if (target instanceof BIPUSH) {\n                                keyAsChars[4] = (char) ((BIPUSH) target).getValue().intValue();\n                            } else {\n                                keyAsChars[4] = (char) ((ICONST) target).getValue().intValue();\n                            }\n                        }\n                    }\n                    return keyAsChars;\n                }\n            }\n        } else {\n            for (Method m : cg.getMethods()) {\n                if (m.getName().contains(\"clinit\")) {\n                    MethodGen mg = new MethodGen(m, cg.getClassName(), cg.getConstantPool());\n                    InstructionHandle[] handles = mg.getInstructionList().getInstructionHandles();\n                    char[] keyAsChars;\n                    for (InstructionHandle handle : handles) {\n                        if (handle.getInstruction() instanceof TABLESWITCH) {\n                            TABLESWITCH xor = (TABLESWITCH) handle.getInstruction();\n                            keyAsChars = getKeyFromSwitch(xor, cg);\n                            if (keyAsChars != null) {\n                                return keyAsChars;\n                            }\n                        }\n                    }\n                    return findKeyB(cg);\n                }\n            }\n        }\n\n        return null;\n    }\n\n    private static char[] getKeyFromSwitch(TABLESWITCH xor, ClassGen cg) {\n        char[] keyAsChars = new char[5];\n        for (int a = 0; a < xor.getTargets().length; a++) {\n            Instruction target = xor.getTargets()[a].getInstruction();\n            if (GenericMethods.isNumber(target)) {\n                keyAsChars[a] = (char) GenericMethods.getValueOfNumber(target, cg.getConstantPool());\n            } else {\n                return null;\n            }\n        }\n        Instruction target = xor.getTarget().getInstruction();\n        if (target instanceof BIPUSH) {\n            keyAsChars[4] = (char) ((BIPUSH) target).getValue().intValue();\n        } else if (target instanceof ICONST) {\n            keyAsChars[4] = (char) ((ICONST) target).getValue().intValue();\n        } else {\n            return null;\n        }\n        return keyAsChars;\n    }\n\n    public static String decrypt(String encrypted, char[] key) {\n        char[] plainText = encrypted.toCharArray();\n        int plainTextLength = plainText.length;\n        int keyLength = key.length;\n        //\n        // encryption\n        char[] cryptoText = new char[plainTextLength];\n        for (int i = 0; i < plainTextLength; i++) {\n            cryptoText[i] = (char) (plainText[i] ^ key[i % keyLength]);\n        }\n\n        // finishing\n        return new String(cryptoText);\n    }\n\n    public void replaceStrings() throws TargetLostException {\n        for (ClassGen cg : cgs.values()) {\n\n            int replaced = 0;\n            for (Method method : cg.getMethods()) {\n                MethodGen mg = new MethodGen(method, cg.getClassName(), cg.getConstantPool());\n                InstructionList list = mg.getInstructionList();\n                if (list == null)\n                    continue;\n                InstructionHandle[] handles = list.getInstructionHandles();\n                //if (!typeA(cg)) {\n                for (int i = 0; i < handles.length; i++) {\n                    if ((handles[i].getInstruction() instanceof GETSTATIC)\n                            && ((handles[i + 1].getInstruction() instanceof BIPUSH)\n                            || (handles[i + 1].getInstruction() instanceof SIPUSH)\n                            || (handles[i + 1].getInstruction() instanceof ICONST))\n                            && (handles[i + 2].getInstruction() instanceof AALOAD)) {\n                        int push;\n                        if (handles[i + 1].getInstruction() instanceof BIPUSH) {\n                            push = ((BIPUSH) handles[i + 1].getInstruction()).getValue().intValue();\n                        } else if (handles[i + 1].getInstruction() instanceof SIPUSH) {\n                            push = ((SIPUSH) handles[i + 1].getInstruction()).getValue().intValue();\n                        } else {\n                            push = ((ICONST) handles[i + 1].getInstruction()).getValue().intValue();\n                        }\n\n                        String decryptedString = getZKMString(cg.getClassName(), push);\n                        int stringRef = cg.getConstantPool().addString(decryptedString);\n                        LDC lc = new LDC(stringRef);\n                        NOP nop = new NOP();\n                        handles[i].setInstruction(lc);\n                        handles[i + 1].setInstruction(nop);\n                        handles[i + 2].setInstruction(nop);\n                        replaced++;\n                    }\n                }\n                mg.setInstructionList(list);\n                mg.setMaxLocals();\n                mg.setMaxStack();\n                cg.replaceMethod(method, mg.getMethod());\n                /*\n                                    } else {\n                                        logger.error(\"This type of ZKM is not currently supported for string deob!\");\n                                    }        */\n            }\n            if (replaced > 0) {\n                logger.debug(\"replaced \" + replaced + \" calls in class \" + cg.getClassName());\n            }\n        }\n    }\n\n    public void removeOriginStrings() {\n        for (ClassGen cg : cgs.values()) {\n            for (Method method : cg.getMethods()) {\n                if (method.getName().contains(\"clinit\")) {\n                    MethodGen mg = new MethodGen(method, cg.getClassName(), cg.getConstantPool());\n                    InstructionList list = mg.getInstructionList();\n                    InstructionHandle[] handles = list.getInstructionHandles();\n                    int startLoc = -1;\n                    int endLoc = -1;\n                    for (int i = 0; i < handles.length; i++) {\n                        if (((handles[i].getInstruction() instanceof BIPUSH) || (handles[i].getInstruction() instanceof SIPUSH) || (handles[i].getInstruction() instanceof ICONST))\n                                && (handles[i + 1].getInstruction() instanceof ANEWARRAY)) {\n                            ANEWARRAY an = (ANEWARRAY) handles[i + 1].getInstruction();\n                            ObjectType ty = an.getLoadClassType(cg.getConstantPool());\n                            if (ty == null) continue;\n                            String type = ty.toString();\n                            if (type.equals(\"java.lang.String\")) {\n                                startLoc = i;\n                                logger.debug(\"Start Location for <clinit> removal: \" + startLoc);\n                            }\n                        }\n                        if (startLoc >= 0) {\n                            if (handles.length > (i + 2)) {\n                                if (handles[i].getInstruction() instanceof POP\n                                        && handles[i + 1].getInstruction() instanceof SWAP\n                                        && handles[i + 2].getInstruction() instanceof TABLESWITCH) {\n                                    endLoc = i + 2;\n                                    logger.debug(\"End Location for <clinit> removal: \" + endLoc);\n                                    break;\n                                }\n                            }\n                        }\n                    }\n                    if ((startLoc >= 0) && (endLoc >= 0)) {\n                        try {\n                            list.delete(handles[startLoc], handles[endLoc]);\n                        } catch (TargetLostException e) {\n                            logger.error(\"Control flow obfuscation evident. Couldn't clear clinit\");\n                            //e.printStackTrace();\n                            return;\n                        }\n                        logger.debug(\"NOPed \" + (endLoc - startLoc) + \" instructions from <clinit> in \" + cg.getClassName());\n                        list.setPositions();\n                        mg.setInstructionList(list);\n                        mg.setMaxLocals();\n                        mg.setMaxStack();\n                        cg.replaceMethod(method, mg.getMethod());\n                    }\n                }\n            }\n        }\n    }\n\n    //TODO: It isn't finding the last string sometimes, so shit gets all fucked up and it ends up leaving a call to static{} and extra instructions\n    public void getStringsFromZKM() {\n        for (ClassGen cg : cgs.values()) {\n            char[] key = findKey(cg);\n            for (Method method : cg.getMethods()) {\n                MethodGen mg = new MethodGen(method, cg.getClassName(), cg.getConstantPool());\n                InstructionList list = mg.getInstructionList();\n                if (list == null) {\n                    continue;\n                }\n                InstructionHandle[] handles = list.getInstructionHandles();\n                ArrayList<String> all = new ArrayList<String>();\n                if (method.getName().contains(\"clinit\")) {\n                    for (int i = 0; i < handles.length; i++) {\n                        if (handles[i].getInstruction() instanceof LDC) {\n                            LDC orig = ((LDC) handles[i].getInstruction());\n                            if (!orig.getType(cg.getConstantPool()).getSignature().contains(\"String\")) continue;\n                            String enc = orig.getValue(cg.getConstantPool()).toString();\n                            String dec = decrypt(enc, key);\n                            all.add(dec);\n                            logger.debug(cg.getClassName() + \" -> \" + dec);\n                        }\n                    }\n                    zkStrings.put(cg.getClassName(), all);\n                    logger.debug(\"Decrypted and stored \" + all.size() + \" strings from \" + cg.getClassName());\n                }\n            }\n        }\n    }\n\n    private void locateObstructors() {\n        for (ClassGen cg : cgs.values()) {\n            for (Method method : cg.getMethods()) {\n                if (method.isAbstract() || method.isNative()) {\n                    continue;\n                }\n                MethodGen mGen = new MethodGen(method, cg.getClassName(), cg.getConstantPool());\n                InstructionFinder finder = new InstructionFinder(mGen.getInstructionList());\n                Iterator<InstructionHandle[]> matches = finder.search(\n                        \"GETSTATIC IFEQ ((ILOAD IFEQ ICONST GOTO ICONST)|(IINC ILOAD)) PUTSTATIC\"\n                );\n                if (matches.hasNext()) {\n                    InstructionHandle[] match = matches.next();\n                    GETSTATIC gstatCtrlField = (GETSTATIC) match[0].getInstruction();\n                    controlClass = gstatCtrlField.getName(cg.getConstantPool());\n                    String fieldName = gstatCtrlField.getFieldName(cg.getConstantPool());\n                    ClassGen ctrlClazz = cgs.get(controlClass);\n                    controlField = ctrlClazz.containsField(fieldName);\n                }\n            }\n        }\n        if (controlField == null) {\n            logger.error(\"Couldn't Locate Control Field!\");\n            return;\n        }\n        flowObstructors.add(controlField);\n        logger.debug(\"control field: \" + controlClass + \".\" + controlField.getName() + \" \" + controlField.getSignature());\n        for (ClassGen cg : cgs.values()) {\n            final ConstantPoolGen cpg = cg.getConstantPool();\n            for (Method method : cg.getMethods()) {\n                if (method.isAbstract() || method.isNative()) {\n                    continue;\n                }\n                MethodGen mGen = new MethodGen(method, cg.getClassName(), cpg);\n                InstructionFinder finder = new InstructionFinder(mGen.getInstructionList());\n                Iterator<InstructionHandle[]> matches = finder.search(\n                        \"(GETSTATIC|ILOAD) IFEQ (((ILOAD|GETSTATIC) IFEQ ICONST GOTO ICONST)|(IINC ILOAD)) PUTSTATIC\",\n                        new InstructionFinder.CodeConstraint() {\n\n                            public boolean checkCode(InstructionHandle[] code) {\n                                FieldInstruction ctrlFieldInstr = null;\n                                if (code[0].getInstruction() instanceof GETSTATIC) {\n                                    ctrlFieldInstr = (FieldInstruction) code[0].getInstruction();\n                                } else {\n                                    ctrlFieldInstr = (FieldInstruction) code[code.length - 2].getInstruction();\n                                }\n                                String className = ctrlFieldInstr.getName(cpg);\n                                String fieldName = ctrlFieldInstr.getFieldName(cpg);\n                                return className.equals(controlClass) && fieldName.equals(controlField.getName());\n                            }\n                        });\n                while (matches.hasNext()) {\n                    InstructionHandle[] match = matches.next();\n                    Instruction first = match[0].getInstruction();\n                    ClassGen ctrlClazz;\n                    Field flowObstructor = null;\n                    if (first instanceof GETSTATIC) {\n                        PUTSTATIC pstatCtrlField = (PUTSTATIC) match[match.length - 2].getInstruction();\n                        String className = pstatCtrlField.getName(cg.getConstantPool());\n                        String fieldName = pstatCtrlField.getFieldName(cg.getConstantPool());\n                        ctrlClazz = cgs.get(className);\n                        flowObstructor = ctrlClazz.containsField(fieldName);\n                    } else {\n                        ILOAD iLoad = (ILOAD) first;\n                        int idx = iLoad.getIndex();\n                        InstructionHandle iStoreHandle = finder.getInstructionList().getInstructionHandles()[1];\n                        ISTORE iStore = (ISTORE) iStoreHandle.getInstruction();\n                        assert idx == iStore.getIndex() && idx == mGen.getMaxLocals() - 1 : \"expected \" + idx\n                                + \" found \" + iStore.getIndex();\n                        GETSTATIC gstatCtrlField = (GETSTATIC) iStoreHandle.getPrev().getInstruction();\n                        String className = gstatCtrlField.getName(cg.getConstantPool());\n                        String fieldName = gstatCtrlField.getFieldName(cg.getConstantPool());\n                        ctrlClazz = cgs.get(className);\n                        flowObstructor = ctrlClazz.containsField(fieldName);\n                    }\n                    if (!flowObstructors.contains(flowObstructor)) {\n                        logger.debug(\"flow obstructor: \" + ctrlClazz.getClassName() + \".\" + flowObstructor.getName()\n                                + \" \" + flowObstructor.getSignature());\n                        flowObstructors.add(flowObstructor);\n                    }\n                }\n            }\n        }\n    }\n\n    public void transform() {\n        logger.log(\"ZKM Deobfuscator\");\n        logger.log(\"Starting Opaque Predicate Remover...\");\n        locateObstructors();\n        opaqueTransformer();\n        logger.log(\"Starting String Encryption Removal...\");\n        try {\n            logger.log(\"Starting ZKM String Grabber...\");\n            getStringsFromZKM();\n            logger.log(\"Starting ZKM String Replacer...\");\n            replaceStrings();\n        } catch (TargetLostException e) {\n            e.printStackTrace();\n        }\n        logger.log(\"Starting String Origin Removal...\");\n        removeOriginStrings();\n        logger.log(\"Starting Unconditional Branch Remover...\");\n        unconditionalBranchTransformer();\n        logger.log(\"Starting Exit Flow Corrector...\");\n        exitFlowTransformer();\n        logger.log(\"Deobfuscation finished! Dumping jar...\");\n        GenericMethods.dumpJar(JAR_NAME, cgs.values());\n        logger.log(\"Operation Completed.\");\n    }\n\n    private InstructionHandle findIStore(InstructionHandle start, int idx) {\n        InstructionHandle ih = start;\n        while (ih != null) {\n            if (ih.getInstruction() instanceof ISTORE) {\n                if (((ISTORE) ih.getInstruction()).getIndex() == idx) {\n                    return ih;\n                }\n            }\n            ih = ih.getNext();\n        }\n        return null;\n    }\n\n    public void unconditionalBranchTransformer() {\n        for (ClassGen cg : cgs.values()) {\n            for (Method method : cg.getMethods()) {\n                final MethodGen mg = new MethodGen(method, cg.getClassName(), cg.getConstantPool());\n                if (method.isAbstract() || method.isNative()) {\n                    return;\n                }\n                final InstructionList list = mg.getInstructionList();\n                InstructionFinder finder = new InstructionFinder(list);\n                final ConstantPoolGen cpg = cg.getConstantPool();\n                int branchesSimplified = 0;\n                Iterator<InstructionHandle[]> matches = finder.search(\"IfInstruction\");\n                while (matches.hasNext()) {\n                    InstructionHandle ifHandle = matches.next()[0];\n                    InstructionHandle target = ((BranchHandle) ifHandle).getTarget();\n                    if (target.getInstruction() instanceof GOTO) {\n                        branchesSimplified++;\n                        ((BranchHandle) ifHandle).setTarget(((BranchHandle) target).getTarget());\n                    }\n                }\n                matches = finder.search(\"GOTO GOTO\");\n                while (matches.hasNext()) {\n                    InstructionHandle[] match = matches.next();\n                    try {\n                        list.delete(match[0]);\n                    } catch (TargetLostException tlex) {\n                        for (InstructionHandle target : tlex.getTargets()) {\n                            for (InstructionTargeter targeter : target.getTargeters()) {\n                                targeter.updateTarget(target, match[1]);\n                            }\n                        }\n                    }\n                }\n                mg.setInstructionList(list);\n                mg.setMaxLocals();\n                mg.setMaxStack();\n                if (branchesSimplified > 0) {\n                    logger.debug(\"simplified \" + branchesSimplified + \" unconditional branches\");\n                    cg.replaceMethod(method, mg.getMethod());\n                }\n            }\n        }\n    }\n\n    public void exitFlowTransformer() {\n        for (ClassGen cg : cgs.values()) {\n            int correct = 0;\n            for (Method method : cg.getMethods()) {\n                final MethodGen mgen = new MethodGen(method, cg.getClassName(), cg.getConstantPool());\n                if (!method.isAbstract() && !method.isNative()) {\n                    InstructionList list = mgen.getInstructionList();\n                    InstructionFinder finder = new InstructionFinder(list);\n                    CodeExceptionGen[] exceptionGens = mgen.getExceptionHandlers();\n                    for (Iterator<InstructionHandle[]> matches = finder.search(\n                            \"ASTORE ALOAD (NEW DUP (PushInstruction InvokeInstruction)+ (ALOAD IfInstruction LDC GOTO LDC \" +\n                                    \"INVOKEVIRTUAL)? (PushInstruction InvokeInstruction)* InvokeInstruction+)?\");\n                         matches.hasNext();) {\n                        /* thanks to popcorn89 */\n                        InstructionHandle[] match = matches.next();\n                        if (!(match[match.length - 1].getInstruction() instanceof ATHROW)) {\n                            continue;\n                        }\n                        InstructionHandle astoreInstr = match[0];\n                        InstructionHandle athrowInstr = match[match.length - 1];\n                        InstructionHandle toRedirect = athrowInstr.getNext();\n                        for (CodeExceptionGen exgen : exceptionGens) {\n                            if (exgen.getHandlerPC().equals(astoreInstr)) {\n                                mgen.removeExceptionHandler(exgen);\n                            }\n                        }\n                        try {\n                            list.delete(astoreInstr, athrowInstr);\n                        } catch (TargetLostException tlex) {\n                            if (athrowInstr == list.getEnd()) {\n                                toRedirect = astoreInstr.getPrev();\n                            }\n                            if (toRedirect != null) {\n                                for (InstructionHandle target : tlex.getTargets()) {\n                                    for (InstructionTargeter targeter : target.getTargeters()) {\n                                        targeter.updateTarget(target, toRedirect);\n                                    }\n                                }\n                            }\n                        }\n                    }\n                    list.setPositions(true);\n                    InstructionHandle lastInstr = list.getEnd();\n                    InstructionHandle secondToLastInstr = lastInstr.getPrev();\n                    if (secondToLastInstr != null && (lastInstr.getInstruction() instanceof RETURN)\n                            && (secondToLastInstr.getInstruction() instanceof RETURN)) {\n                        try {\n                            list.delete(secondToLastInstr);\n                        } catch (TargetLostException tlex) {\n                            for (InstructionHandle target : tlex.getTargets()) {\n                                for (InstructionTargeter targeter : target.getTargeters()) {\n                                    targeter.updateTarget(target, lastInstr);\n                                }\n                            }\n                        }\n                    }\n                    if (mgen.getMethod() != method) {\n                        correct++;\n                        logger.debug(\"corrected exit flow in \" + cg.getClassName() + \".\" + mgen.getName() + mgen.getSignature());\n                        mgen.setInstructionList(list);\n                        mgen.setMaxLocals();\n                        mgen.setMaxStack();\n                        cg.replaceMethod(method, mgen.getMethod());\n                    }\n                }\n            }\n            logger.debug(\"Corrected exit flow \" + correct + \" times in \" + cg.getClassName());\n        }\n    }\n\n    public void opaqueTransformer() {\n        for (ClassGen cg : cgs.values()) {\n            for (Method method : cg.getMethods()) {\n                final MethodGen mg = new MethodGen(method, cg.getClassName(), cg.getConstantPool());\n                if (method.isAbstract() || method.isNative()) {\n                    return;\n                }\n                final InstructionList list = mg.getInstructionList();\n                InstructionFinder finder = new InstructionFinder(list);\n                final ConstantPoolGen cpg = cg.getConstantPool();\n                int stripped = 0;\n\n                Iterator<InstructionHandle[]> matches = finder.search(\n                        \"(ILOAD|GETSTATIC) ((ISTORE)|(IFNE|IFEQ)) (((IINC ILOAD)|((ILOAD IFEQ)? ICONST GOTO ICONST)) PUTSTATIC)?\",\n                        code -> {\n                            InstructionHandle ih = code[0];\n                            if (code.length <= 3) {\n                                if (ih.getInstruction() instanceof GETSTATIC) {\n                                    GETSTATIC gstat = (GETSTATIC) ih.getInstruction();\n                                    return flowObstructors.contains(cgs.get(gstat.getName(cpg))\n                                            .containsField(gstat.getFieldName(cpg)));\n                                } else {\n                                    ILOAD iLoad = (ILOAD) ih.getInstruction();\n                                    int idx = iLoad.getIndex();\n                                    if (idx < mg.getArgumentTypes().length + (mg.isStatic() ? 0 : 1)) {\n                                        return false;\n                                    }\n                                    InstructionHandle storeHandle = findIStore(list.getStart(), idx);\n                                    if (storeHandle == null || !(storeHandle.getPrev().getInstruction() instanceof GETSTATIC)) {\n                                        return false;\n                                    }\n                                    GETSTATIC gstat = (GETSTATIC) storeHandle.getPrev().getInstruction();\n                                    return flowObstructors.contains(cgs.get(gstat.getName(cpg))\n                                            .containsField(gstat.getFieldName(cpg)));\n                                }\n                            } else {\n                                GETSTATIC gstat = (GETSTATIC) ih.getInstruction();\n                                ClassGen cp = cgs.get(gstat.getName(cpg));\n                                Field fz = cp.containsField(gstat.getFieldName(cpg));\n                                return cp != null && fz != null && controlField != null && controlField.equals(fz);\n                            }\n                        });\n\n                while (matches.hasNext()) {\n                    List<InstructionHandle> toDelete = new LinkedList<InstructionHandle>();\n                    InstructionHandle[] match = matches.next();\n                    InstructionHandle ih = match[0];\n                    InstructionHandle theBranch = match[1];\n                    InstructionHandle lastInstr = match[match.length - 2];\n                    InstructionHandle toRedirect = lastInstr.getNext();\n                    if (toRedirect == null) {\n                        break;\n                    }\n                    if (theBranch.getInstruction() instanceof IFEQ && match.length <= 3) {\n                        toDelete.add(ih);\n                        theBranch.setInstruction(new GOTO(((BranchHandle) theBranch).getTarget()));\n                    } else {\n                        try {\n                            list.delete(ih, lastInstr);\n                        } catch (TargetLostException tlex) {\n                            for (InstructionHandle target : tlex.getTargets()) {\n                                for (InstructionTargeter targeter : target.getTargeters()) {\n                                    logger.debug(\"redirected \" + target + \" to \" + toRedirect + \" in \" + cg.getClassName() + \".\" + mg.getName() + mg.getSignature());\n                                    targeter.updateTarget(target, toRedirect);\n                                }\n                            }\n                        }\n                    }\n                    stripped++;\n                    for (InstructionHandle del : toDelete) {\n                        try {\n                            list.delete(del);\n                        } catch (TargetLostException tlex) {\n                            for (InstructionHandle target : tlex.getTargets()) {\n                                for (InstructionTargeter targeter : target.getTargeters()) {\n                                    logger.debug(\"redirected \" + target + \" to \" + (theBranch.getInstruction() instanceof IFEQ ? lastInstr : toRedirect) + \" in \" + cg.getClassName() + \".\" + mg.getName() + mg.getSignature());\n                                    targeter.updateTarget(target, theBranch.getInstruction() instanceof IFEQ ?\n                                            lastInstr : toRedirect);\n                                }\n                            }\n                        }\n                    }\n                }\n                if (stripped > 0) {\n                    logger.debug(\"stripped \" + stripped + \" opaque predicates from \" + cg.getClassName() + \".\" + mg.getName() + mg.getSignature());\n                    mg.setInstructionList(list);\n                    mg.setMaxStack();\n                    mg.setMaxLocals();\n                    cg.replaceMethod(method, mg.getMethod());\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jmd-core/src/main/java/net/contra/jmd/util/GenericClassLoader.java",
    "content": "package net.contra.jmd.util;\n\n/**\n * Created by IntelliJ IDEA.\n * User: Eric\n * Date: Dec 9, 2010\n * Time: 4:23:08 AM\n */\npublic class GenericClassLoader extends ClassLoader {\n    public GenericClassLoader(ClassLoader parent) {\n        super(parent);\n    }\n\n    public Class<?> loadClass(String name, byte[] crap) {\n        //name = name.substring(0, name.lastIndexOf('.'));\n        Class c = null;\n        try {\n            //c = super.defineClass(crap, 0, crap.length);\n            c = super.defineClass(name, crap, 0, crap.length);\n        } catch (Exception e) {\n            return c;\n        }\n        super.resolveClass(c);\n        return c;\n    }\n}\n"
  },
  {
    "path": "jmd-core/src/main/java/net/contra/jmd/util/GenericMethods.java",
    "content": "package net.contra.jmd.util;\n\nimport org.apache.bcel.generic.*;\nimport org.apache.commons.io.IOUtils;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.util.Collection;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarOutputStream;\n\npublic class GenericMethods {\n    //TODO: Get LDC_W into isInt and getValueOfInt\n    public static boolean isNumber(Instruction ins) {\n        return ins instanceof BIPUSH\n                || ins instanceof SIPUSH\n                || ins instanceof ICONST\n                || ins instanceof LDC_W;\n    }\n\n    public static int getValueOfNumber(Instruction ins, ConstantPoolGen cpg) {\n        if (ins instanceof BIPUSH) {\n            return ((BIPUSH) ins).getValue().intValue();\n        } else if (ins instanceof SIPUSH) {\n            return ((SIPUSH) ins).getValue().intValue();\n        } else if (ins instanceof ICONST) {\n            return ((ICONST) ins).getValue().intValue();\n        } else if (ins instanceof LDC_W) {\n            LDC_W ldcw = (LDC_W) ins;\n            return Integer.valueOf(ldcw.getValue(cpg).toString());\n        } else {\n            return -1;\n        }\n    }\n\n    public static String getCallSignature(Instruction ins, ConstantPoolGen cp) {\n        if (ins instanceof INVOKESTATIC) {\n            INVOKESTATIC invst = (INVOKESTATIC) ins;\n            return invst.getSignature(cp);\n        } else if (ins instanceof INVOKEVIRTUAL) {\n            INVOKEVIRTUAL invst = (INVOKEVIRTUAL) ins;\n            return invst.getSignature(cp);\n        } else if (ins instanceof INVOKEINTERFACE) {\n            INVOKEINTERFACE invst = (INVOKEINTERFACE) ins;\n            return invst.getSignature(cp);\n        } else if (ins instanceof INVOKESPECIAL) {\n            INVOKESPECIAL invst = (INVOKESPECIAL) ins;\n            return invst.getSignature(cp);\n        } else {\n            return null;\n        }\n    }\n\n    public static Instruction getNewInvoke(Instruction ins, int index) {\n        if (ins instanceof INVOKESTATIC) {\n            INVOKESTATIC invst = (INVOKESTATIC) ins;\n            invst.setIndex(index);\n            return invst;\n        } else if (ins instanceof INVOKEVIRTUAL) {\n            INVOKEVIRTUAL invst = (INVOKEVIRTUAL) ins;\n            invst.setIndex(index);\n            return invst;\n        } else if (ins instanceof INVOKEINTERFACE) {\n            INVOKEINTERFACE invst = (INVOKEINTERFACE) ins;\n            invst.setIndex(index);\n            return invst;\n        } else if (ins instanceof INVOKESPECIAL) {\n            INVOKESPECIAL invst = (INVOKESPECIAL) ins;\n            invst.setIndex(index);\n            return invst;\n        } else {\n            return null;\n        }\n    }\n\n    public static String getCallReturnType(Instruction ins, ConstantPoolGen cp) {\n        if (ins instanceof INVOKESTATIC) {\n            INVOKESTATIC invst = (INVOKESTATIC) ins;\n            return invst.getReturnType(cp).toString();\n        } else if (ins instanceof INVOKEVIRTUAL) {\n            INVOKEVIRTUAL invst = (INVOKEVIRTUAL) ins;\n            return invst.getReturnType(cp).toString();\n        } else if (ins instanceof INVOKEINTERFACE) {\n            INVOKEINTERFACE invst = (INVOKEINTERFACE) ins;\n            return invst.getReturnType(cp).toString();\n        } else if (ins instanceof INVOKESPECIAL) {\n            INVOKESPECIAL invst = (INVOKESPECIAL) ins;\n            return invst.getReturnType(cp).toString();\n        } else {\n            return null;\n        }\n    }\n\n    public static String getCallClassName(Instruction ins, ConstantPoolGen cp) {\n        if (ins instanceof INVOKESTATIC) {\n            INVOKESTATIC invst = (INVOKESTATIC) ins;\n            return invst.getClassName(cp);\n        } else if (ins instanceof INVOKEVIRTUAL) {\n            INVOKEVIRTUAL invst = (INVOKEVIRTUAL) ins;\n            return invst.getClassName(cp);\n        } else if (ins instanceof INVOKEINTERFACE) {\n            INVOKEINTERFACE invst = (INVOKEINTERFACE) ins;\n            return invst.getClassName(cp);\n        } else if (ins instanceof INVOKESPECIAL) {\n            INVOKESPECIAL invst = (INVOKESPECIAL) ins;\n            return invst.getClassName(cp);\n        } else {\n            return null;\n        }\n    }\n\n    public static void dumpJar(String path, Collection<ClassGen> cgs) {\n        FileOutputStream os;\n        path = path.replace(\".jar\", \"\") + \"-deob.jar\";\n        try {\n            os = new FileOutputStream(new File(path));\n        } catch (FileNotFoundException fnfe) {\n            throw new RuntimeException(\"could not create file \\\"\" + path + \"\\\": \" + fnfe);\n        }\n        JarOutputStream jos;\n\n        try {\n            jos = new JarOutputStream(os);\n\n            for (JarEntry jbe : NonClassEntries.entries) {\n                JarEntry destEntry = new JarEntry(jbe.getName());\n                byte[] bite = IOUtils.toByteArray(NonClassEntries.ins.get(jbe));\n                jos.putNextEntry(destEntry);\n                jos.write(bite);\n                jos.closeEntry();\n            }\n\n            for (ClassGen classIt : cgs) {\n                JarEntry classEntry = new JarEntry(classIt.getClassName().replace('.', '/') + \".class\");\n                jos.putNextEntry(classEntry);\n                jos.write(classIt.getJavaClass().getBytes());\n                jos.closeEntry();\n            }\n            jos.closeEntry();\n            jos.close();\n        } catch (IOException ignored) {\n        }\n    }\n\n    public static String getCallMethodName(Instruction ins, ConstantPoolGen cp) {\n        if (ins instanceof INVOKESTATIC) {\n            INVOKESTATIC invst = (INVOKESTATIC) ins;\n            return invst.getMethodName(cp);\n        } else if (ins instanceof INVOKEVIRTUAL) {\n            INVOKEVIRTUAL invst = (INVOKEVIRTUAL) ins;\n            return invst.getMethodName(cp);\n        } else if (ins instanceof INVOKEINTERFACE) {\n            INVOKEINTERFACE invst = (INVOKEINTERFACE) ins;\n            return invst.getMethodName(cp);\n        } else if (ins instanceof INVOKESPECIAL) {\n            INVOKESPECIAL invst = (INVOKESPECIAL) ins;\n            return invst.getMethodName(cp);\n        } else {\n            return null;\n        }\n    }\n\n    public static Type[] getCallArgTypes(Instruction ins, ConstantPoolGen cp) {\n        if (ins instanceof INVOKESTATIC) {\n            INVOKESTATIC invst = (INVOKESTATIC) ins;\n            return invst.getArgumentTypes(cp);\n        } else if (ins instanceof INVOKEVIRTUAL) {\n            INVOKEVIRTUAL invst = (INVOKEVIRTUAL) ins;\n            return invst.getArgumentTypes(cp);\n        } else if (ins instanceof INVOKEINTERFACE) {\n            INVOKEINTERFACE invst = (INVOKEINTERFACE) ins;\n            return invst.getArgumentTypes(cp);\n        } else if (ins instanceof INVOKESPECIAL) {\n            INVOKESPECIAL invst = (INVOKESPECIAL) ins;\n            return invst.getArgumentTypes(cp);\n        } else {\n            return null;\n        }\n    }\n\n    public static boolean isCall(Instruction ins) {\n        return ins instanceof INVOKESTATIC\n                || ins instanceof INVOKEVIRTUAL\n                || ins instanceof INVOKEINTERFACE\n                || ins instanceof INVOKESPECIAL;\n    }\n}\n"
  },
  {
    "path": "jmd-core/src/main/java/net/contra/jmd/util/HandleSearcher.java",
    "content": "package net.contra.jmd.util;\n\nimport org.apache.bcel.generic.ConstantPoolGen;\nimport org.apache.bcel.generic.INVOKESTATIC;\nimport org.apache.bcel.generic.InstructionHandle;\nimport org.apache.bcel.generic.LDC;\n\n/**\n * Created by IntelliJ IDEA.\n * User: Eric\n * Date: Nov 25, 2010\n * Time: 10:16:26 PM\n */\npublic class HandleSearcher {\n    InstructionHandle[] handles;\n    ConstantPoolGen cpg;\n    public int index;\n\n    public void setPosition(int index) {\n        this.index = index;\n    }\n\n    public LDC previousLDC() {\n        for (; index >= 0; index--) {\n\n            if (handles[index].getInstruction() instanceof LDC) {\n                return (LDC) handles[index].getInstruction();\n            }\n\n        }\n\n        return null;\n    }\n\n    public INVOKESTATIC nextInvokeStatic(String className) {\n        for (; index < handles.length; index++) {\n            if (index > -1) {\n                if (handles[index].getInstruction() instanceof INVOKESTATIC) {\n\n                    INVOKESTATIC methodCall = (INVOKESTATIC) handles[index].getInstruction();\n\n                    if (methodCall.getClassName(cpg).equals(className)) {\n                        return methodCall;\n                    }\n\n                }\n            }\n\n        }\n\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "jmd-core/src/main/java/net/contra/jmd/util/LogHandler.java",
    "content": "package net.contra.jmd.util;\n\npublic class LogHandler {\n    private String _className = \"NoClass\";\n\n    public LogHandler(String className) {\n        _className = className;\n    }\n\n    public void message(String msg) {\n        System.out.println(msg);\n    }\n\n    public void log(String msg) {\n        System.out.println(\"[\" + _className + \"]\" + msg);\n    }\n\n    public void debug(String msg) {\n            System.out.println(\"[\" + _className + \"]\" + \"[DEBUG]\" + msg);\n    }\n\n    public void error(String msg) {\n        System.out.println(\"[\" + _className + \"]\" + \"[ERROR]\" + msg);\n    }\n}\n"
  },
  {
    "path": "jmd-core/src/main/java/net/contra/jmd/util/NonClassEntries.java",
    "content": "package net.contra.jmd.util;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.jar.JarEntry;\n\npublic final class NonClassEntries {\n    public static ArrayList<JarEntry> entries = new ArrayList<JarEntry>();\n    public static Map<JarEntry, InputStream> ins = new HashMap<JarEntry, InputStream>();\n\n    private NonClassEntries() {\n    }\n\n    public static JarEntry getByName(String name) {\n        for (JarEntry e : entries) {\n            if (e.getName().equals(name)) {\n                return e;\n            }\n        }\n        return null;\n    }\n\n    public static void add(JarEntry entry, InputStream inputStream) {\n        entries.add(entry);\n        ins.put(entry, inputStream);\n    }\n\n}\n"
  },
  {
    "path": "jmd-core/src/test/java/net/contra/jmd/transformers/dasho/DashOTransformerTest.java",
    "content": "package net.contra.jmd.transformers.dasho;\n\nimport org.testng.annotations.DataProvider;\nimport org.testng.annotations.Test;\n\nimport static org.testng.Assert.*;\n\npublic class DashOTransformerTest {\n\n    @Test(dataProvider = \"inputData\")\n    public void testDecrypt(String input, String outputExpected) throws Exception {\n        final String outputActual = DashOTransformer.decrypt(input);\n        assertEquals(outputActual, outputExpected);\n    }\n\n\n    @DataProvider\n    public Object[][] inputData() {\n        return new Object[][]{\n                {null, null},\n                {\"<\", \";\"},\n                {\"\", \"\"}\n                };\n\n    }\n}"
  },
  {
    "path": "jmd-gui/gradle/wrapper/gradle-wrapper.properties",
    "content": "#Tue Nov 08 23:54:48 MSK 2016\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-3.1-bin.zip\n"
  },
  {
    "path": "jmd-gui/gradlew",
    "content": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn ( ) {\n    echo \"$*\"\n}\n\ndie ( ) {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules\nfunction splitJvmOpts() {\n    JVM_OPTS=(\"$@\")\n}\neval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\nJVM_OPTS[${#JVM_OPTS[*]}]=\"-Dorg.gradle.appname=$APP_BASE_NAME\"\n\n# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong\nif [[ \"$(uname)\" == \"Darwin\" ]] && [[ \"$HOME\" == \"$PWD\" ]]; then\n  cd \"$(dirname \"$0\")\"\nfi\n\nexec \"$JAVACMD\" \"${JVM_OPTS[@]}\" -classpath \"$CLASSPATH\" org.gradle.wrapper.GradleWrapperMain \"$@\"\n"
  },
  {
    "path": "jmd-gui/gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem  Gradle startup script for Windows\n@rem\n@rem ##########################################################################\n\n@rem Set local scope for the variables with windows NT shell\nif \"%OS%\"==\"Windows_NT\" setlocal\n\nset DIRNAME=%~dp0\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\nset APP_BASE_NAME=%~n0\nset APP_HOME=%DIRNAME%\n\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nset DEFAULT_JVM_OPTS=\n\n@rem Find java.exe\nif defined JAVA_HOME goto findJavaFromJavaHome\n\nset JAVA_EXE=java.exe\n%JAVA_EXE% -version >NUL 2>&1\nif \"%ERRORLEVEL%\" == \"0\" goto init\n\necho.\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:findJavaFromJavaHome\nset JAVA_HOME=%JAVA_HOME:\"=%\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\n\nif exist \"%JAVA_EXE%\" goto init\n\necho.\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:init\n@rem Get command-line arguments, handling Windows variants\n\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\n\n:win9xME_args\n@rem Slurp the command line arguments.\nset CMD_LINE_ARGS=\nset _SKIP=2\n\n:win9xME_args_slurp\nif \"x%~1\" == \"x\" goto execute\n\nset CMD_LINE_ARGS=%*\n\n:execute\n@rem Setup the command line\n\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\n\n@rem Execute Gradle\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\n\n:end\n@rem End local scope for the variables with windows NT shell\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\n\n:fail\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\nrem the _cmd.exe /c_ return code!\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\nexit /b 1\n\n:mainEnd\nif \"%OS%\"==\"Windows_NT\" endlocal\n\n:omega\n"
  },
  {
    "path": "jmd-gui/src/main/java/net/contra/jmd/ConfigureApp.java",
    "content": "package net.contra.jmd;\n\nimport javafx.application.Application;\nimport javafx.fxml.FXMLLoader;\nimport javafx.scene.Scene;\nimport javafx.scene.layout.Pane;\nimport javafx.stage.Stage;\n\nimport java.io.IOException;\n\n\npublic class ConfigureApp extends Application {\n\n    public static void main(String[] args) {\n        launch(args);\n    }\n\n    @Override\n    public void start(Stage primaryStage) {\n        primaryStage.setTitle(\"JMD-GUI\");\n\n        try {\n            FXMLLoader loader = new FXMLLoader();\n            loader.setLocation(ConfigureApp.class.getResource(\"/view/configure.fxml\"));\n            Pane rootLayout = loader.load();\n\n            Scene scene = new Scene(rootLayout);\n            primaryStage.setScene(scene);\n            primaryStage.show();\n        } catch (IOException e) {\n            // empty\n        }\n    }\n}"
  },
  {
    "path": "jmd-gui/src/main/resources/view/configure.fxml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<?import javafx.scene.*?>\n<?import javafx.scene.control.*?>\n<?import java.lang.*?>\n<?import javafx.scene.layout.*?>\n\n\n<AnchorPane maxHeight=\"-Infinity\" maxWidth=\"-Infinity\" minHeight=\"-Infinity\" minWidth=\"-Infinity\" prefHeight=\"125.0\"\n            prefWidth=\"325.0\" xmlns=\"http://javafx.com/javafx/8\" xmlns:fx=\"http://javafx.com/fxml/1\">\n   <ComboBox layoutX=\"81.0\" layoutY=\"54.0\" prefWidth=\"150.0\"/>\n   <CheckBox layoutX=\"249.0\" layoutY=\"58.0\" mnemonicParsing=\"false\" text=\"Debug?\"/>\n   <Label layoutX=\"7.0\" layoutY=\"58.0\" text=\"Transformer:\"/>\n   <TextField layoutX=\"82.0\" layoutY=\"14.0\"/>\n   <Label layoutX=\"21.0\" layoutY=\"18.0\" text=\"Input JAR:\"/>\n   <Button layoutX=\"249.0\" layoutY=\"14.0\" mnemonicParsing=\"false\" text=\"Choose...\"/>\n   <Button layoutX=\"130.0\" layoutY=\"87.0\" mnemonicParsing=\"false\" text=\"Run\"/>\n</AnchorPane>\n"
  },
  {
    "path": "settings.gradle",
    "content": "rootProject.name = 'jmd'\n\ninclude ':jmd-cli', ':jmd-core', ':jmd-gui'"
  }
]