mirror of
https://github.com/JessSystemV/zProtect.git
synced 2024-12-22 09:25:33 +00:00
Initial commit
This commit is contained in:
commit
a45ffb98c8
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
34
.github/workflows/build.yml
vendored
Normal file
34
.github/workflows/build.yml
vendored
Normal file
|
@ -0,0 +1,34 @@
|
|||
name: Build
|
||||
|
||||
on: [ pull_request, push ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
java: [ '8', '17' ]
|
||||
name: Java ${{ matrix.Java }} build
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v2
|
||||
- name: Ensure genuine gradle
|
||||
uses: gradle/wrapper-validation-action@v1
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v2
|
||||
with:
|
||||
distribution: 'zulu'
|
||||
java-version: ${{ matrix.java }}
|
||||
name: Gradle Build
|
||||
check-latest: true
|
||||
- name: Make gradle wrapper executable
|
||||
run: chmod +x ./gradlew
|
||||
- name: Run "clean" task
|
||||
run: ./gradlew clean
|
||||
- name: Run "build" task
|
||||
run: ./gradlew build --no-daemon
|
||||
- name: Capture artifacts
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: zProtect Internal Preview (Java ${{ matrix.java }})
|
||||
path: build/libs/*
|
22
.gitignore
vendored
Normal file
22
.gitignore
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
# Eclipse
|
||||
bin
|
||||
*.launch
|
||||
.settings
|
||||
.metadata
|
||||
.classpath
|
||||
.project
|
||||
|
||||
# IDEA
|
||||
out
|
||||
*.ipr
|
||||
*.iws
|
||||
*.iml
|
||||
.idea
|
||||
|
||||
# Gradle
|
||||
build
|
||||
.gradle
|
||||
|
||||
# Other
|
||||
eclipse
|
||||
run
|
69
.onedev-buildspec.yml
Normal file
69
.onedev-buildspec.yml
Normal file
|
@ -0,0 +1,69 @@
|
|||
version: 15
|
||||
jobs:
|
||||
- name: Build
|
||||
steps:
|
||||
- !CheckoutStep
|
||||
name: Checkout
|
||||
cloneCredential: !DefaultCredential {}
|
||||
withLfs: false
|
||||
withSubmodules: false
|
||||
condition: ALL_PREVIOUS_STEPS_WERE_SUCCESSFUL
|
||||
- !CommandStep
|
||||
name: Detect Version
|
||||
runInContainer: true
|
||||
image: '@script:builtin:gradle:determine-docker-image@'
|
||||
interpreter: !DefaultInterpreter
|
||||
commands:
|
||||
- echo "Detecting project version (may require some time while downloading gradle
|
||||
dependencies)..."
|
||||
- 'echo $(gradle properties | grep ^version: | grep -v unspecified | cut -c10-)
|
||||
> buildVersion'
|
||||
useTTY: false
|
||||
condition: ALL_PREVIOUS_STEPS_WERE_SUCCESSFUL
|
||||
- !SetBuildVersionStep
|
||||
name: Set Version
|
||||
buildVersion: '@file:buildVersion@'
|
||||
condition: ALL_PREVIOUS_STEPS_WERE_SUCCESSFUL
|
||||
- !CommandStep
|
||||
name: Post Webhook
|
||||
runInContainer: true
|
||||
image: prontotools/alpine-git-curl
|
||||
interpreter: !DefaultInterpreter
|
||||
commands:
|
||||
- user=$(git log --format=%an -n 1 @commit_hash@)
|
||||
- commit_hash=@commit_hash@
|
||||
- commit_message=$(git log --format=%B -n 1 @commit_hash@)
|
||||
- 'curl -H ''Content-Type: application/json'' \'
|
||||
- "\t-d \"{\\\"avatar_url\\\": \\\"https://test.it-snek.com/static/media/logo.c0ab911818705a32c78c.png\\\
|
||||
\", \\\"username\\\": \\\"zGitBot\\\", \\\"embeds\\\": [{\\\"author\\\": {\\\
|
||||
\"name\\\": \\\"${user}\\\"},\\\"title\\\": \\\"@project_name@/@branch@\\\"\
|
||||
, \\\"description\\\": \\\"${commit_hash:0:7}: ${commit_message}\\\"}]}\"\
|
||||
\ \\"
|
||||
- "\t'https://discord.com/api/webhooks/904058376504348702/v7Otrf48So0S8g67YkH8Xnh6g7EN9T8grSuvY3IHGksjhP6V7AYb5FG0zKr33mtZSFmq'"
|
||||
useTTY: false
|
||||
condition: ALWAYS
|
||||
- !CommandStep
|
||||
name: Gradle Build
|
||||
runInContainer: true
|
||||
image: '@script:builtin:gradle:determine-docker-image@'
|
||||
interpreter: !DefaultInterpreter
|
||||
commands:
|
||||
- gradle build --no-daemon
|
||||
useTTY: false
|
||||
condition: ALL_PREVIOUS_STEPS_WERE_SUCCESSFUL
|
||||
- !PublishArtifactStep
|
||||
name: Publish Artifact
|
||||
artifacts: build/libs/*
|
||||
condition: ALL_PREVIOUS_STEPS_WERE_SUCCESSFUL
|
||||
triggers:
|
||||
- !BranchUpdateTrigger {}
|
||||
- !PullRequestUpdateTrigger {}
|
||||
retryCondition: never
|
||||
maxRetries: 3
|
||||
retryDelay: 30
|
||||
cpuRequirement: 500
|
||||
memoryRequirement: 256
|
||||
caches:
|
||||
- key: gradle-cache
|
||||
path: /home/gradle/.gradle
|
||||
timeout: 3600
|
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"java.configuration.updateBuildConfiguration": "automatic"
|
||||
}
|
21
LICENSE
Normal file
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2023 Potato Sus
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
61
build.gradle.kts
Normal file
61
build.gradle.kts
Normal file
|
@ -0,0 +1,61 @@
|
|||
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
|
||||
plugins {
|
||||
java
|
||||
kotlin("jvm") version "1.7.20"
|
||||
kotlin("plugin.serialization") version "1.6.10"
|
||||
id("com.github.johnrengelman.shadow") version "7.1.2"
|
||||
}
|
||||
|
||||
group = "dev.zprotect"
|
||||
version = "0.2"
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven {
|
||||
url = uri("https://oss.sonatype.org/content/groups/public/")
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("org.json:json:20211205")
|
||||
|
||||
implementation("org.ow2.asm:asm:9.2")
|
||||
implementation("org.ow2.asm:asm-tree:9.2")
|
||||
implementation("org.ow2.asm:asm-commons:9.2")
|
||||
implementation("org.ow2.asm:asm-util:9.2")
|
||||
|
||||
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
|
||||
}
|
||||
|
||||
tasks {
|
||||
build {
|
||||
dependsOn(shadowJar)
|
||||
}
|
||||
|
||||
register<Jar>("standaloneJar") {
|
||||
manifest {
|
||||
attributes["Main-Class"] = "dev.zprotect.obfuscator.StandaloneKt"
|
||||
}
|
||||
}
|
||||
|
||||
named<ShadowJar>("shadowJar") {
|
||||
manifest {
|
||||
attributes["Main-Class"] = "dev.zprotect.obfuscator.MainKt"
|
||||
}
|
||||
minimize()
|
||||
}
|
||||
|
||||
withType<Jar> {
|
||||
manifest {
|
||||
attributes["Main-Class"] = "dev.zprotect.obfuscator.MainKt"
|
||||
}
|
||||
}
|
||||
|
||||
withType<KotlinCompile> {
|
||||
kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
}
|
||||
}
|
||||
}
|
1
gradle.properties
Normal file
1
gradle.properties
Normal file
|
@ -0,0 +1 @@
|
|||
kotlin.code.style=official
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
5
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
5
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
185
gradlew
vendored
Normal file
185
gradlew
vendored
Normal file
|
@ -0,0 +1,185 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
# Copyright 2015 the original author or authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=`expr $i + 1`
|
||||
done
|
||||
case $i in
|
||||
0) set -- ;;
|
||||
1) set -- "$args0" ;;
|
||||
2) set -- "$args0" "$args1" ;;
|
||||
3) set -- "$args0" "$args1" "$args2" ;;
|
||||
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=`save "$@"`
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
exec "$JAVACMD" "$@"
|
104
gradlew.bat
vendored
Normal file
104
gradlew.bat
vendored
Normal file
|
@ -0,0 +1,104 @@
|
|||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
1
settings.gradle.kts
Normal file
1
settings.gradle.kts
Normal file
|
@ -0,0 +1 @@
|
|||
rootProject.name = "zProtect"
|
23
src/main/java/dev/zprotect/obfuscator/Extensions.kt
Normal file
23
src/main/java/dev/zprotect/obfuscator/Extensions.kt
Normal file
|
@ -0,0 +1,23 @@
|
|||
/**
|
||||
* Copyright (C) 2022 zProtect
|
||||
*
|
||||
* This software is NOT free software.
|
||||
* You may NOT distribute it or modify it without explicit permission.
|
||||
*
|
||||
* This software has been created in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY. zProtect is NOT liable for ANY damages caused by unlawful distribution
|
||||
* or usage of any zProtect source code or products.
|
||||
*
|
||||
* You should have received a copy of the zProtect PU (Prohibited Usage) License along with this program.
|
||||
*/
|
||||
|
||||
package dev.zprotect.obfuscator
|
||||
|
||||
import org.objectweb.asm.tree.ClassNode
|
||||
import org.objectweb.asm.tree.FieldNode
|
||||
import org.objectweb.asm.tree.MethodNode
|
||||
|
||||
fun ClassNode.hasAccess(access: Int) = this.access and access == 0
|
||||
fun FieldNode.hasAccess(access: Int) = this.access and access == 0
|
||||
fun MethodNode.hasAccess(access: Int) = this.access and access == 0
|
||||
|
31
src/main/java/dev/zprotect/obfuscator/Main.kt
Normal file
31
src/main/java/dev/zprotect/obfuscator/Main.kt
Normal file
|
@ -0,0 +1,31 @@
|
|||
/**
|
||||
* Copyright (C) 2022 zProtect
|
||||
*
|
||||
* This software is NOT free software.
|
||||
* You may NOT distribute it or modify it without explicit permission.
|
||||
*
|
||||
* This software has been created in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY. zProtect is NOT liable for ANY damages caused by unlawful distribution
|
||||
* or usage of any zProtect source code or products.
|
||||
*
|
||||
* You should have received a copy of the zProtect PU (Prohibited Usage) License along with this program.
|
||||
*/
|
||||
|
||||
package dev.zprotect.obfuscator
|
||||
|
||||
import dev.zprotect.obfuscator.Obfuscator.info
|
||||
import java.io.File
|
||||
import kotlin.system.exitProcess
|
||||
import java.util.Collections
|
||||
import java.util.UUID
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
if (args.size != 1) {
|
||||
Obfuscator.info("Missing argument: Config file")
|
||||
exitProcess(-1)
|
||||
}
|
||||
|
||||
Obfuscator.info("Visit https://zprotect.dev for more information.\n")
|
||||
|
||||
Obfuscator.run(File(args[0]))
|
||||
}
|
306
src/main/java/dev/zprotect/obfuscator/Obfuscator.kt
Normal file
306
src/main/java/dev/zprotect/obfuscator/Obfuscator.kt
Normal file
|
@ -0,0 +1,306 @@
|
|||
/**
|
||||
* Copyright (C) 2022 zProtect
|
||||
*
|
||||
* This software is NOT free software.
|
||||
* You may NOT distribute it or modify it without explicit permission.
|
||||
*
|
||||
* This software has been created in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY. zProtect is NOT liable for ANY damages caused by unlawful distribution
|
||||
* or usage of any zProtect source code or products.
|
||||
*
|
||||
* You should have received a copy of the zProtect PU (Prohibited Usage) License along with this program.
|
||||
*/
|
||||
|
||||
package dev.zprotect.obfuscator
|
||||
|
||||
import dev.zprotect.obfuscator.api.ClassPath
|
||||
import dev.zprotect.obfuscator.api.Transformer
|
||||
import dev.zprotect.obfuscator.api.interfaces.IBytecode
|
||||
import dev.zprotect.obfuscator.api.settings.ArrayConfig
|
||||
import dev.zprotect.obfuscator.api.settings.BooleanConfig
|
||||
import dev.zprotect.obfuscator.api.settings.Config
|
||||
import dev.zprotect.obfuscator.api.settings.StringConfig
|
||||
import dev.zprotect.obfuscator.transformers.antitamper.AntiDebug
|
||||
import dev.zprotect.obfuscator.transformers.decompiler.BadAnnotationCrasher
|
||||
import dev.zprotect.obfuscator.transformers.decompiler.DecompilerCrasher
|
||||
import dev.zprotect.obfuscator.transformers.flow.Flow
|
||||
import dev.zprotect.obfuscator.transformers.naming.ClassRenamer
|
||||
import dev.zprotect.obfuscator.transformers.naming.FieldRenamer
|
||||
import dev.zprotect.obfuscator.transformers.naming.LocalVariableRenamer
|
||||
import dev.zprotect.obfuscator.transformers.naming.MethodRenamer
|
||||
import dev.zprotect.obfuscator.transformers.optimization.*
|
||||
import dev.zprotect.obfuscator.transformers.poolers.NumberPooler
|
||||
import dev.zprotect.obfuscator.transformers.shrinking.*
|
||||
import dev.zprotect.obfuscator.transformers.shufflers.ShuffleFields
|
||||
import dev.zprotect.obfuscator.transformers.shufflers.ShuffleMethods
|
||||
import org.objectweb.asm.ClassReader
|
||||
import org.objectweb.asm.Opcodes
|
||||
import org.objectweb.asm.tree.ClassNode
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Paths
|
||||
import java.nio.file.StandardOpenOption
|
||||
import java.time.Instant
|
||||
import java.util.jar.JarEntry
|
||||
import java.util.jar.JarFile
|
||||
import java.util.jar.JarOutputStream
|
||||
import java.util.jar.Manifest
|
||||
import kotlin.random.Random
|
||||
|
||||
|
||||
object Obfuscator {
|
||||
private val inputJar = StringConfig("inputJar")
|
||||
private val outputJar = StringConfig("outputJar")
|
||||
private val exclusions = ArrayConfig("exclusions")
|
||||
private val libraries = ArrayConfig("libraries")
|
||||
|
||||
private val watermark = BooleanConfig("watermark")
|
||||
|
||||
private lateinit var ioMode: IOMode
|
||||
private val files: MutableMap<String, ByteArray> = HashMap()
|
||||
private val classNodes: MutableMap<String, ClassNode> = HashMap()
|
||||
private lateinit var manifest: Manifest
|
||||
|
||||
@JvmStatic
|
||||
fun info(msg: String) {
|
||||
println("[${Instant.now()}] $msg")
|
||||
}
|
||||
|
||||
fun run(config: File) {
|
||||
val startTime = System.currentTimeMillis()
|
||||
|
||||
Config.read(config)
|
||||
|
||||
if (inputJar.value == null || outputJar.value == null) {
|
||||
info("Error: Input file or output file is not specified!")
|
||||
return
|
||||
}
|
||||
|
||||
val inputFile = File(inputJar.value!!)
|
||||
if (!inputFile.exists()) {
|
||||
info("Input file not found!")
|
||||
return
|
||||
}
|
||||
openFile(inputFile)
|
||||
|
||||
ClassPath.load(getLibraries())
|
||||
|
||||
arrayListOf(
|
||||
// Flow
|
||||
Flow,
|
||||
|
||||
// Shrinking
|
||||
RemoveInnerClasses,
|
||||
LocalVariableRemover,
|
||||
LineNumberRemover,
|
||||
SourceDebugRemover,
|
||||
SourceFileRemover,
|
||||
|
||||
// Shuffling
|
||||
ShuffleFields,
|
||||
ShuffleMethods,
|
||||
|
||||
// Number
|
||||
NumberPooler,
|
||||
|
||||
// Optimization
|
||||
KotlinMetadataRemover,
|
||||
HideClassMembers,
|
||||
RemoveSignatures,
|
||||
FinalRemover,
|
||||
InsnRemover,
|
||||
EnumOptimiser,
|
||||
NOPInsnRemover,
|
||||
|
||||
|
||||
// Naming
|
||||
MethodRenamer,
|
||||
FieldRenamer,
|
||||
ClassRenamer,
|
||||
LocalVariableRenamer,
|
||||
|
||||
// Reversing
|
||||
DecompilerCrasher,
|
||||
AntiDebug,
|
||||
BadAnnotationCrasher,
|
||||
).forEach(Transformer::run)
|
||||
|
||||
saveFile()
|
||||
|
||||
info("zProtect has finished obfuscating in " + (System.currentTimeMillis() - startTime) + " milliseconds.")
|
||||
}
|
||||
|
||||
private fun openFile(file: File) {
|
||||
if (file.name.endsWith(".jar")) {
|
||||
ioMode = IOMode.JAR
|
||||
openJar(JarFile(file))
|
||||
} else if (file.name.endsWith(".class")) {
|
||||
ioMode = IOMode.CLASS
|
||||
openClass(file)
|
||||
}
|
||||
}
|
||||
|
||||
private fun openJar(jar: JarFile) {
|
||||
val entries = jar.entries()
|
||||
|
||||
while (entries.hasMoreElements()) {
|
||||
val entry = entries.nextElement()
|
||||
|
||||
val bytes: ByteArray = IBytecode.readBytes(jar.getInputStream(entry))
|
||||
|
||||
if (!entry.name.endsWith(".class")) {
|
||||
files[entry.name] = bytes
|
||||
} else {
|
||||
val classNode = ClassNode()
|
||||
ClassReader(bytes).accept(classNode, ClassReader.EXPAND_FRAMES)
|
||||
classNodes[classNode.name] = classNode
|
||||
ClassPath.get(classNode)
|
||||
}
|
||||
}
|
||||
manifest = jar.manifest
|
||||
}
|
||||
|
||||
private fun openClass(file: File) {
|
||||
val bytes: ByteArray = IBytecode.readBytes(file.inputStream())
|
||||
val classNode = ClassNode()
|
||||
ClassReader(bytes).accept(classNode, ClassReader.EXPAND_FRAMES)
|
||||
classNodes[classNode.name] = classNode
|
||||
}
|
||||
|
||||
private fun saveFile() {
|
||||
when (ioMode) {
|
||||
IOMode.JAR -> saveJar()
|
||||
IOMode.CLASS -> saveClass()
|
||||
}
|
||||
}
|
||||
|
||||
private fun saveJar() {
|
||||
/*
|
||||
not P
|
||||
TODO: Figure out why CRC corrupter doesn't work with JarOutputStream
|
||||
Even when we set ZipOutputStream and use the function it does not work...
|
||||
Here is the function:
|
||||
|
||||
fun corruptCRC32(zipOutputStream: ZipOutputStream?) {
|
||||
try {
|
||||
val field: Field = ZipOutputStream::class.java.getDeclaredField("crc")
|
||||
field.isAccessible = true
|
||||
field.set(zipOutputStream, object : CRC32() {
|
||||
override fun getValue(): Long {
|
||||
return -0x21523f22
|
||||
}
|
||||
})
|
||||
} catch (ignored: NoSuchFieldException) {
|
||||
} catch (ignored: IllegalAccessException) {}
|
||||
}
|
||||
|
||||
FIX THIS PLEASE...
|
||||
*/
|
||||
|
||||
val byteArrayOutputStream = ByteArrayOutputStream()
|
||||
manifest.write(byteArrayOutputStream)
|
||||
files["META-INF/MANIFEST.MF"] = byteArrayOutputStream.toByteArray()
|
||||
|
||||
var location: String = outputJar.value!!
|
||||
if (!location.endsWith(".jar")) location += ".jar"
|
||||
|
||||
val jarPath = Paths.get(location)
|
||||
Files.deleteIfExists(jarPath)
|
||||
|
||||
val outJar = JarOutputStream(
|
||||
Files.newOutputStream(
|
||||
jarPath,
|
||||
StandardOpenOption.CREATE,
|
||||
StandardOpenOption.CREATE_NEW,
|
||||
StandardOpenOption.WRITE
|
||||
)
|
||||
)
|
||||
|
||||
classNodes.values.forEach { classNode ->
|
||||
outJar.putNextEntry(JarEntry(classNode.name + ".class"))
|
||||
outJar.write(IBytecode.writeBytes(classNode))
|
||||
outJar.closeEntry()
|
||||
}
|
||||
|
||||
files.entries.forEach { (key, value) ->
|
||||
outJar.putNextEntry(JarEntry(key))
|
||||
outJar.write(value)
|
||||
outJar.closeEntry()
|
||||
}
|
||||
|
||||
// Our unique identifier so we can check if a program has been obfuscated with zProtect or not.
|
||||
// Set a comment in jar, can be seen once opening a jar in a zip viewer.
|
||||
if (watermark.value == true) {
|
||||
outJar.setComment("보호에 의해 난독화되고 오늘 보호 난독화 장치를 구입하십시오.")
|
||||
|
||||
// Dummy class.
|
||||
val dummy = ClassNode()
|
||||
dummy.visit(
|
||||
Opcodes.V1_5,
|
||||
Opcodes.ACC_PUBLIC,
|
||||
"보호에 의해 난독화되고 오늘 보호 난독화 장치를 구입하십시오.",
|
||||
null,
|
||||
"java/lang/Object",
|
||||
null
|
||||
)
|
||||
dummy.visitMethod(Random.nextInt(100), "\u0001", "(\u0001/)L\u0001/;", null, null)
|
||||
try {
|
||||
outJar.putNextEntry(JarEntry(dummy.name + ".class"))
|
||||
outJar.write(IBytecode.toByteArrayDefault(dummy))
|
||||
info("Applied transformer: Watermark")
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
outJar.close()
|
||||
}
|
||||
|
||||
private fun saveClass() {
|
||||
var location: String = outputJar.value!!
|
||||
if (!location.endsWith(".class")) location += ".class"
|
||||
|
||||
val classPath = Paths.get(location)
|
||||
Files.deleteIfExists(classPath)
|
||||
|
||||
val outputStream = Files.newOutputStream(
|
||||
classPath,
|
||||
StandardOpenOption.CREATE,
|
||||
StandardOpenOption.CREATE_NEW,
|
||||
StandardOpenOption.WRITE
|
||||
)
|
||||
outputStream.write(IBytecode.writeBytes(classNodes.entries.iterator().next().value))
|
||||
outputStream.close()
|
||||
}
|
||||
|
||||
fun getClassNodes(): MutableMap<String, ClassNode> {
|
||||
return classNodes
|
||||
}
|
||||
|
||||
fun getFiles(): MutableMap<String, ByteArray> {
|
||||
return files
|
||||
}
|
||||
|
||||
fun getManifest(): Manifest {
|
||||
return manifest
|
||||
}
|
||||
|
||||
fun getExclusions(): List<String> { // TODO: Caching for faster performance.
|
||||
val exclusionsCache: MutableList<String> = mutableListOf()
|
||||
if (exclusions.value == null) return exclusionsCache
|
||||
for (i in 0 until exclusions.value!!.length()) exclusionsCache.add(exclusions.value!!.getString(i))
|
||||
return exclusionsCache
|
||||
}
|
||||
|
||||
fun getLibraries(): List<String> { // TODO: Caching for faster performance.
|
||||
val librariesCache: MutableList<String> = mutableListOf()
|
||||
if (libraries.value == null) return librariesCache
|
||||
for (i in 0 until libraries.value!!.length()) librariesCache.add(libraries.value!!.getString(i))
|
||||
return librariesCache
|
||||
}
|
||||
|
||||
enum class IOMode {
|
||||
CLASS, JAR;
|
||||
}
|
||||
}
|
116
src/main/java/dev/zprotect/obfuscator/api/ClassPath.kt
Normal file
116
src/main/java/dev/zprotect/obfuscator/api/ClassPath.kt
Normal file
|
@ -0,0 +1,116 @@
|
|||
/**
|
||||
* Copyright (C) 2022 zProtect
|
||||
*
|
||||
* This software is NOT free software.
|
||||
* You may NOT distribute it or modify it without explicit permission.
|
||||
*
|
||||
* This software has been created in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY. zProtect is NOT liable for ANY damages caused by unlawful distribution
|
||||
* or usage of any zProtect source code or products.
|
||||
*
|
||||
* You should have received a copy of the zProtect PU (Prohibited Usage) License along with this program.
|
||||
*/
|
||||
|
||||
package dev.zprotect.obfuscator.api
|
||||
|
||||
import dev.zprotect.obfuscator.api.interfaces.IBytecode
|
||||
import org.objectweb.asm.ClassReader
|
||||
import org.objectweb.asm.tree.ClassNode
|
||||
import org.objectweb.asm.Type
|
||||
import java.util.jar.JarFile
|
||||
|
||||
object ClassPath : HashMap<String, ClassEntry>() {
|
||||
override fun get(key: String): ClassEntry? = super.get(key) ?: add(get(Class.forName(key.replace("/", "."))))
|
||||
fun get(classNode: ClassNode): ClassEntry = super.get(classNode.name) ?: add(ClassNodeEntry(classNode))
|
||||
fun get(clazz: Class<*>): ClassEntry = super.get(Type.getInternalName(clazz)) ?: add(ReflectionClassEntry(clazz))
|
||||
private fun add(classEntry: ClassEntry): ClassEntry = classEntry.apply { put(classEntry.getName(), classEntry) }
|
||||
|
||||
fun load(paths: List<String>) = paths.forEach { load(it) }
|
||||
fun load(path: String) {
|
||||
val jar = JarFile(path)
|
||||
val entries = jar.entries()
|
||||
|
||||
while (entries.hasMoreElements()) {
|
||||
val entry = entries.nextElement()
|
||||
|
||||
if (entry.name.endsWith(".class")) {
|
||||
val bytes: ByteArray = IBytecode.readBytes(jar.getInputStream(entry))
|
||||
val classNode = ClassNode()
|
||||
ClassReader(bytes).accept(classNode, ClassReader.SKIP_CODE or ClassReader.SKIP_DEBUG)
|
||||
put(classNode.name, ClassNodeEntry(classNode))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract class ClassEntry {
|
||||
abstract fun getName(): String
|
||||
abstract fun getSuper(): String?
|
||||
abstract fun getAccess(): Int
|
||||
abstract fun getInterfaces(): MutableList<String>
|
||||
abstract fun getFields(): MutableList<FieldEntry>
|
||||
abstract fun getMethods(): MutableList<MethodEntry>
|
||||
}
|
||||
|
||||
data class MethodEntry(val owner: ClassEntry, val name: String, val desc: String)
|
||||
data class FieldEntry(val owner: ClassEntry, val name: String, val desc: String)
|
||||
|
||||
class ClassNodeEntry(private val classNode: ClassNode) : ClassEntry() {
|
||||
override fun getName(): String = classNode.name
|
||||
override fun getSuper(): String? = classNode.superName
|
||||
override fun getAccess(): Int = classNode.access
|
||||
override fun getInterfaces(): MutableList<String> = classNode.interfaces
|
||||
|
||||
override fun getFields(): MutableList<FieldEntry> = exploreFields
|
||||
private val exploreFields: MutableList<FieldEntry> by lazy {
|
||||
val list = mutableListOf<FieldEntry>()
|
||||
for (fieldNode in classNode.fields) {
|
||||
list.add(FieldEntry(this, fieldNode.name, fieldNode.desc))
|
||||
}
|
||||
list
|
||||
}
|
||||
|
||||
override fun getMethods(): MutableList<MethodEntry> = exploreMethods
|
||||
private val exploreMethods: MutableList<MethodEntry> by lazy {
|
||||
val list = mutableListOf<MethodEntry>()
|
||||
for (methodNode in classNode.methods) {
|
||||
list.add(MethodEntry(this, methodNode.name, methodNode.desc))
|
||||
}
|
||||
list
|
||||
}
|
||||
}
|
||||
|
||||
class ReflectionClassEntry(private val clazz: Class<*>) : ClassEntry() {
|
||||
override fun getName(): String = Type.getInternalName(clazz)
|
||||
override fun getSuper(): String? = if (clazz.superclass == null) null else Type.getInternalName(clazz.superclass)
|
||||
?: if (getName() != "java/lang/Object") "java/lang/Object" else null
|
||||
|
||||
override fun getAccess(): Int = clazz.modifiers
|
||||
|
||||
override fun getInterfaces(): MutableList<String> = exploreInterfaces
|
||||
private val exploreInterfaces: MutableList<String> by lazy {
|
||||
val list = mutableListOf<String>()
|
||||
for (interfaces in clazz.interfaces) {
|
||||
list.add(Type.getInternalName(interfaces))
|
||||
}
|
||||
list
|
||||
}
|
||||
|
||||
override fun getFields(): MutableList<FieldEntry> = exploreFields
|
||||
private val exploreFields: MutableList<FieldEntry> by lazy {
|
||||
val list = mutableListOf<FieldEntry>()
|
||||
for (field in clazz.declaredFields) {
|
||||
list.add(FieldEntry(this, field.name, Type.getDescriptor(field.type)))
|
||||
}
|
||||
list
|
||||
}
|
||||
|
||||
override fun getMethods(): MutableList<MethodEntry> = exploreMethods
|
||||
private val exploreMethods: MutableList<MethodEntry> by lazy {
|
||||
val list = mutableListOf<MethodEntry>()
|
||||
for (method in clazz.declaredMethods) {
|
||||
list.add(MethodEntry(this, method.name, Type.getMethodDescriptor(method)))
|
||||
}
|
||||
list
|
||||
}
|
||||
}
|
101
src/main/java/dev/zprotect/obfuscator/api/Transformer.kt
Normal file
101
src/main/java/dev/zprotect/obfuscator/api/Transformer.kt
Normal file
|
@ -0,0 +1,101 @@
|
|||
/**
|
||||
* Copyright (C) 2022 zProtect
|
||||
*
|
||||
* This software is NOT free software.
|
||||
* You may NOT distribute it or modify it without explicit permission.
|
||||
*
|
||||
* This software has been created in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY. zProtect is NOT liable for ANY damages caused by unlawful distribution
|
||||
* or usage of any zProtect source code or products.
|
||||
*
|
||||
* You should have received a copy of the zProtect PU (Prohibited Usage) License along with this program.
|
||||
*/
|
||||
|
||||
package dev.zprotect.obfuscator.api
|
||||
|
||||
import dev.zprotect.obfuscator.Obfuscator
|
||||
import dev.zprotect.obfuscator.Obfuscator.info
|
||||
import dev.zprotect.obfuscator.api.settings.BooleanConfig
|
||||
import dev.zprotect.obfuscator.api.interfaces.INode
|
||||
import dev.zprotect.obfuscator.api.interfaces.IBytecode
|
||||
import org.objectweb.asm.commons.ClassRemapper
|
||||
import org.objectweb.asm.commons.SimpleRemapper
|
||||
import org.objectweb.asm.tree.ClassNode
|
||||
import java.util.jar.Manifest
|
||||
import java.util.stream.Collectors
|
||||
|
||||
abstract class Transformer(val name: String, val description: String) : IBytecode, INode {
|
||||
private val setting = BooleanConfig(name)
|
||||
|
||||
val classMap: MutableMap<String, ClassNode>
|
||||
get() = Obfuscator.getClassNodes()
|
||||
|
||||
val classes: List<ClassNode>
|
||||
get() = ArrayList(classMap.values)
|
||||
|
||||
val filesMap: MutableMap<String, ByteArray>
|
||||
get() = Obfuscator.getFiles()
|
||||
|
||||
val files: List<String>
|
||||
get() = ArrayList(filesMap.keys)
|
||||
|
||||
val manifest: Manifest
|
||||
get() = Obfuscator.getManifest()
|
||||
|
||||
fun run() {
|
||||
if (setting.value != null && setting.value!!) {
|
||||
obfuscate()
|
||||
info("Applied transformer: $name")
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract fun obfuscate()
|
||||
|
||||
fun applyRemap(remap: Map<String?, String?>?) {
|
||||
val remapper = SimpleRemapper(remap)
|
||||
for (node in classes) {
|
||||
val copy = ClassNode()
|
||||
val adapter = ClassRemapper(copy, remapper)
|
||||
node.accept(adapter)
|
||||
classMap.remove(node.name)
|
||||
classMap[node.name] = copy
|
||||
}
|
||||
}
|
||||
|
||||
fun getImplementations(target: ClassNode): List<ClassNode> {
|
||||
return classes.stream().filter { cn -> cn.interfaces.contains(target.name) }.collect(Collectors.toList())
|
||||
}
|
||||
|
||||
fun getExtensions(target: ClassNode): List<ClassNode> {
|
||||
val extensions: MutableList<ClassNode> = mutableListOf()
|
||||
|
||||
classes.stream()
|
||||
.filter { classNode -> classNode.superName == target.name }
|
||||
.forEach { classNode ->
|
||||
extensions.add(classNode)
|
||||
extensions.addAll(getExtensions(classNode))
|
||||
}
|
||||
|
||||
return extensions
|
||||
}
|
||||
|
||||
fun getImplementations(target: ClassEntry): List<ClassEntry> {
|
||||
val implementations = mutableListOf<ClassEntry>()
|
||||
for (classNode in classes.stream().filter { classNode -> classNode.interfaces.contains(target.getName()) }) {
|
||||
implementations.add(ClassPath.get(classNode))
|
||||
implementations.addAll(getImplementations(ClassPath.get(classNode)))
|
||||
}
|
||||
return implementations
|
||||
}
|
||||
|
||||
fun getExtensions(target: ClassEntry): List<ClassEntry> {
|
||||
val extensions = mutableListOf<ClassEntry>()
|
||||
classes.stream()
|
||||
.filter { classNode -> classNode.superName == target.getName() }
|
||||
.forEach { classNode ->
|
||||
extensions.add(ClassPath.get(classNode))
|
||||
extensions.addAll(getExtensions(ClassPath.get(classNode)))
|
||||
}
|
||||
return extensions
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
/**
|
||||
* Copyright (C) 2022 zProtect
|
||||
*
|
||||
* This software is NOT free software.
|
||||
* You may NOT distribute it or modify it without explicit permission.
|
||||
*
|
||||
* This software has been created in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY. zProtect is NOT liable for ANY damages caused by unlawful distribution
|
||||
* or usage of any zProtect source code or products.
|
||||
*
|
||||
* You should have received a copy of the zProtect PU (Prohibited Usage) License along with this program.
|
||||
*/
|
||||
|
||||
package dev.zprotect.obfuscator.api
|
||||
|
||||
enum class TransformerPriority {
|
||||
HIGHEST, HIGH, NORMAL, LOW, LOWEST
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/**
|
||||
* Copyright (C) 2022 zProtect
|
||||
*
|
||||
* This software is NOT free software.
|
||||
* You may NOT distribute it or modify it without explicit permission.
|
||||
*
|
||||
* This software has been created in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY. zProtect is NOT liable for ANY damages caused by unlawful distribution
|
||||
* or usage of any zProtect source code or products.
|
||||
*
|
||||
* You should have received a copy of the zProtect PU (Prohibited Usage) License along with this program.
|
||||
*/
|
||||
|
||||
package dev.zprotect.obfuscator.api.encryption
|
||||
|
||||
import java.security.SecureRandom
|
||||
|
||||
object Dictionary {
|
||||
private val RANDOM = SecureRandom()
|
||||
private val ALPHABET = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
|
||||
private var num = 0
|
||||
|
||||
fun getNewName(): String {
|
||||
return getInAlphabet(num++)
|
||||
}
|
||||
|
||||
fun reset() {
|
||||
num = 0
|
||||
}
|
||||
|
||||
private fun getInAlphabet(i: Int): String {
|
||||
return if (i < 0) "" else getInAlphabet(i / 52 - 1) + (toAscii(i % 52)).toChar()
|
||||
}
|
||||
|
||||
private fun toAscii(i: Int): Int {
|
||||
return if (i < 26) i + 97 else i + 39
|
||||
}
|
||||
|
||||
fun genRandomString(): String {
|
||||
val length = RANDOM.nextInt(15 - 5) + 5
|
||||
val stringBuilder = StringBuilder()
|
||||
for (i in 0 until length) {
|
||||
val letter = RANDOM.nextInt(ALPHABET.length)
|
||||
stringBuilder.append(ALPHABET[letter])
|
||||
}
|
||||
return stringBuilder.toString()
|
||||
}
|
||||
|
||||
fun generateString(length: Int): String {
|
||||
val length = length
|
||||
val stringBuilder = StringBuilder()
|
||||
for (i in 0 until length) {
|
||||
val letter = RANDOM.nextInt(ALPHABET.length)
|
||||
stringBuilder.append(ALPHABET[letter])
|
||||
}
|
||||
return stringBuilder.toString()
|
||||
}
|
||||
}
|
243
src/main/java/dev/zprotect/obfuscator/api/insn/InsnBuilder.kt
Normal file
243
src/main/java/dev/zprotect/obfuscator/api/insn/InsnBuilder.kt
Normal file
|
@ -0,0 +1,243 @@
|
|||
/**
|
||||
* Copyright (C) 2022 zProtect
|
||||
*
|
||||
* This software is NOT free software.
|
||||
* You may NOT distribute it or modify it without explicit permission.
|
||||
*
|
||||
* This software has been created in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY. zProtect is NOT liable for ANY damages caused by unlawful distribution
|
||||
* or usage of any zProtect source code or products.
|
||||
*
|
||||
* You should have received a copy of the zProtect PU (Prohibited Usage) License along with this program.
|
||||
*/
|
||||
|
||||
package dev.zprotect.obfuscator.api.insn
|
||||
|
||||
import org.objectweb.asm.Handle
|
||||
import org.objectweb.asm.Opcodes.*
|
||||
import org.objectweb.asm.Type
|
||||
import org.objectweb.asm.tree.*
|
||||
|
||||
class InsnBuilder {
|
||||
|
||||
val insnList = InsnList()
|
||||
|
||||
operator fun InsnList.unaryPlus() = insnList.add(this)
|
||||
operator fun AbstractInsnNode.unaryPlus() = insnList.add(this)
|
||||
fun Int.insn() = InsnNode(this)
|
||||
|
||||
fun insn(opcode: Int) = +InsnNode(opcode)
|
||||
|
||||
fun nop() = insn(NOP)
|
||||
|
||||
fun aconst_null() = insn(ACONST_NULL)
|
||||
fun ldc(int: Int) = +getIntInsn(int)
|
||||
fun ldc(long: Long) = +getLongInsn(long)
|
||||
fun ldc(float: Float) = +getFloatInsn(float)
|
||||
fun ldc(double: Double) = +getDoubleInsn(double)
|
||||
fun ldc(string: String) = +LdcInsnNode(string)
|
||||
fun ldc(type: Type) = +LdcInsnNode(type)
|
||||
fun ldc(handle: Handle) = +LdcInsnNode(handle)
|
||||
|
||||
fun istore(`var`: Int) = +VarInsnNode(ISTORE, `var`)
|
||||
fun iload(`var`: Int) = +VarInsnNode(ILOAD, `var`)
|
||||
fun lstore(`var`: Int) = +VarInsnNode(LSTORE, `var`)
|
||||
fun lload(`var`: Int) = +VarInsnNode(LLOAD, `var`)
|
||||
fun fstore(`var`: Int) = +VarInsnNode(FSTORE, `var`)
|
||||
fun fload(`var`: Int) = +VarInsnNode(FLOAD, `var`)
|
||||
fun dstore(`var`: Int) = +VarInsnNode(DSTORE, `var`)
|
||||
fun dload(`var`: Int) = +VarInsnNode(DLOAD, `var`)
|
||||
fun astore(`var`: Int) = +VarInsnNode(ASTORE, `var`)
|
||||
fun aload(`var`: Int) = +VarInsnNode(ALOAD, `var`)
|
||||
|
||||
fun iastore() = insn(IASTORE)
|
||||
fun iaload() = insn(IALOAD)
|
||||
fun lastore() = insn(LASTORE)
|
||||
fun laload() = insn(LALOAD)
|
||||
fun fastore() = insn(FASTORE)
|
||||
fun faload() = insn(FALOAD)
|
||||
fun dastore() = insn(DASTORE)
|
||||
fun daload() = insn(DALOAD)
|
||||
fun aastore() = insn(AASTORE)
|
||||
fun aaload() = insn(AALOAD)
|
||||
fun bastore() = insn(BASTORE)
|
||||
fun baload() = insn(BALOAD)
|
||||
fun castore() = insn(CASTORE)
|
||||
fun caload() = insn(CALOAD)
|
||||
fun sastore() = insn(SASTORE)
|
||||
fun saload() = insn(SALOAD)
|
||||
|
||||
|
||||
fun pop() = insn(POP)
|
||||
fun pop2() = insn(POP2)
|
||||
fun dup() = insn(DUP)
|
||||
fun dup_x1() = insn(DUP_X1)
|
||||
fun dup_x2() = insn(DUP_X2)
|
||||
fun dup2() = insn(DUP2)
|
||||
fun dup2_x1() = insn(DUP2_X1)
|
||||
fun dup2_x2() = insn(DUP2_X2)
|
||||
fun swap() = insn(SWAP)
|
||||
|
||||
|
||||
fun iadd() = insn(IADD)
|
||||
fun isub() = insn(ISUB)
|
||||
fun imul() = insn(IMUL)
|
||||
fun idiv() = insn(IDIV)
|
||||
fun irem() = insn(IREM)
|
||||
fun ineg() = insn(INEG)
|
||||
fun ishl() = insn(ISHL)
|
||||
fun ishr() = insn(ISHR)
|
||||
fun iushr() = insn(IUSHR)
|
||||
fun iand() = insn(IAND)
|
||||
fun ior() = insn(IOR)
|
||||
fun ixor() = insn(IXOR)
|
||||
fun iinc(`var`: Int, incr: Int) = +IincInsnNode(`var`, incr)
|
||||
|
||||
fun ladd() = insn(LADD)
|
||||
fun lsub() = insn(LSUB)
|
||||
fun lmul() = insn(LMUL)
|
||||
fun ldiv() = insn(LDIV)
|
||||
fun lrem() = insn(LREM)
|
||||
fun lneg() = insn(LNEG)
|
||||
fun lshl() = insn(LSHL)
|
||||
fun lshr() = insn(LSHR)
|
||||
fun lushr() = insn(LUSHR)
|
||||
fun lor() = insn(LOR)
|
||||
fun land() = insn(LAND)
|
||||
fun lxor() = insn(LXOR)
|
||||
|
||||
fun fadd() = insn(FADD)
|
||||
fun fsub() = insn(FSUB)
|
||||
fun fmul() = insn(FMUL)
|
||||
fun fdiv() = insn(FDIV)
|
||||
fun frem() = insn(FREM)
|
||||
fun fneg() = insn(FNEG)
|
||||
|
||||
fun dadd() = insn(DADD)
|
||||
fun dsub() = insn(DSUB)
|
||||
fun dmul() = insn(DMUL)
|
||||
fun ddiv() = insn(DDIV)
|
||||
fun drem() = insn(DREM)
|
||||
fun dneg() = insn(DNEG)
|
||||
|
||||
fun i2l() = insn(I2L)
|
||||
fun i2f() = insn(I2F)
|
||||
fun i2d() = insn(I2D)
|
||||
fun i2b() = insn(I2B)
|
||||
fun i2c() = insn(I2C)
|
||||
fun i2s() = insn(I2S)
|
||||
fun l2i() = insn(L2I)
|
||||
fun l2f() = insn(L2F)
|
||||
fun l2d() = insn(L2D)
|
||||
fun f2i() = insn(F2I)
|
||||
fun f2l() = insn(F2L)
|
||||
fun f2d() = insn(F2D)
|
||||
fun d2i() = insn(D2I)
|
||||
fun d2l() = insn(D2L)
|
||||
fun d2f() = insn(D2F)
|
||||
|
||||
fun lcmp() = insn(LCMP)
|
||||
fun fcmpl() = insn(FCMPL)
|
||||
fun fcmpg() = insn(FCMPG)
|
||||
fun dcmpl() = insn(DCMPL)
|
||||
fun dcmpg() = insn(DCMPG)
|
||||
|
||||
|
||||
fun goto(label: LabelNode) = +JumpInsnNode(GOTO, label)
|
||||
fun jsr(label: LabelNode) = +JumpInsnNode(JSR, label)
|
||||
|
||||
fun ifeq(label: LabelNode) = +JumpInsnNode(IFEQ, label)
|
||||
fun ifne(label: LabelNode) = +JumpInsnNode(IFNE, label)
|
||||
fun iflt(label: LabelNode) = +JumpInsnNode(IFLT, label)
|
||||
fun ifle(label: LabelNode) = +JumpInsnNode(IFLE, label)
|
||||
fun ifge(label: LabelNode) = +JumpInsnNode(IFGE, label)
|
||||
fun ifgt(label: LabelNode) = +JumpInsnNode(IFGT, label)
|
||||
|
||||
fun if_icmplt(label: LabelNode) = +JumpInsnNode(IF_ICMPLT, label)
|
||||
fun if_icmple(label: LabelNode) = +JumpInsnNode(IF_ICMPLE, label)
|
||||
fun if_icmpge(label: LabelNode) = +JumpInsnNode(IF_ICMPGE, label)
|
||||
fun if_icmpgt(label: LabelNode) = +JumpInsnNode(IF_ICMPGT, label)
|
||||
fun if_icmpeq(label: LabelNode) = +JumpInsnNode(IF_ICMPEQ, label)
|
||||
fun if_icmpne(label: LabelNode) = +JumpInsnNode(IF_ICMPNE, label)
|
||||
fun if_acmpeq(label: LabelNode) = +JumpInsnNode(IF_ACMPEQ, label)
|
||||
|
||||
fun ifnull(label: LabelNode) = +JumpInsnNode(IFNULL, label)
|
||||
fun ifnonnull(label: LabelNode) = +JumpInsnNode(IFNONNULL, label)
|
||||
|
||||
fun lookupswitch(defaultLabel: LabelNode, lookup: Pair<IntArray, Array<LabelNode>>) =
|
||||
+LookupSwitchInsnNode(defaultLabel, lookup.first, lookup.second)
|
||||
|
||||
fun getstatic(owner: String, name: String, desc: String) = +FieldInsnNode(GETSTATIC, owner, name, desc)
|
||||
fun putstatic(owner: String, name: String, desc: String) = +FieldInsnNode(PUTSTATIC, owner, name, desc)
|
||||
fun getfield(owner: String, name: String, desc: String) = +FieldInsnNode(GETFIELD, owner, name, desc)
|
||||
fun putfield(owner: String, name: String, desc: String) = +FieldInsnNode(PUTFIELD, owner, name, desc)
|
||||
|
||||
fun invokevirtual(owner: String, name: String, desc: String, `interface`: Boolean = false) =
|
||||
+MethodInsnNode(INVOKEVIRTUAL, owner, name, desc, `interface`)
|
||||
|
||||
fun invokespecial(owner: String, name: String, desc: String, `interface`: Boolean = false) =
|
||||
+MethodInsnNode(INVOKESPECIAL, owner, name, desc, `interface`)
|
||||
|
||||
fun invokestatic(owner: String, name: String, desc: String, `interface`: Boolean = false) =
|
||||
+MethodInsnNode(INVOKESTATIC, owner, name, desc, `interface`)
|
||||
|
||||
fun invokeinterface(owner: String, name: String, desc: String, `interface`: Boolean = false) =
|
||||
+MethodInsnNode(INVOKEINTERFACE, owner, name, desc, `interface`)
|
||||
|
||||
fun new(type: String) = +TypeInsnNode(NEW, type)
|
||||
fun newarray(type: Int) = +IntInsnNode(NEWARRAY, type)
|
||||
fun anewarray(desc: String) = +TypeInsnNode(ANEWARRAY, desc)
|
||||
fun newboolarray() = newarray(T_BOOLEAN)
|
||||
fun newchararray() = newarray(T_CHAR)
|
||||
fun newbytearray() = newarray(T_BYTE)
|
||||
fun newshortarray() = newarray(T_SHORT)
|
||||
fun newintarray() = newarray(T_INT)
|
||||
fun newlongarray() = newarray(T_LONG)
|
||||
fun newfloatarray() = newarray(T_FLOAT)
|
||||
fun newdoublearray() = newarray(T_DOUBLE)
|
||||
|
||||
fun arraylength() = insn(ARRAYLENGTH)
|
||||
|
||||
fun athrow() = insn(ATHROW)
|
||||
|
||||
fun checkcast(descriptor: String) = +TypeInsnNode(CHECKCAST, descriptor)
|
||||
fun instanceof(descriptor: String) = +TypeInsnNode(INSTANCEOF, descriptor)
|
||||
|
||||
fun ireturn() = insn(IRETURN)
|
||||
fun lreturn() = insn(LRETURN)
|
||||
fun freturn() = insn(FRETURN)
|
||||
fun dreturn() = insn(DRETURN)
|
||||
fun areturn() = insn(ARETURN)
|
||||
fun _return() = insn(RETURN)
|
||||
|
||||
fun frame(type: Int, numLocal: Int, local: Array<Any>?, numStack: Int, stack: Array<Any>?) =
|
||||
+FrameNode(type, numLocal, local, numStack, stack)
|
||||
|
||||
fun getIntInsn(value: Int) =
|
||||
when (value) {
|
||||
in -1..5 -> InsnNode(value + 3)
|
||||
in Byte.MIN_VALUE..Byte.MAX_VALUE -> IntInsnNode(BIPUSH, value)
|
||||
in Short.MIN_VALUE..Short.MAX_VALUE -> IntInsnNode(SIPUSH, value)
|
||||
else -> LdcInsnNode(value)
|
||||
}
|
||||
|
||||
fun getLongInsn(value: Long) =
|
||||
when (value) {
|
||||
in 0..1 -> InsnNode((value + 9).toInt())
|
||||
else -> LdcInsnNode(value)
|
||||
}
|
||||
|
||||
fun getFloatInsn(value: Float) =
|
||||
when {
|
||||
value % 1 == 0f && value in 0f..2f -> InsnNode((value + 11).toInt())
|
||||
else -> LdcInsnNode(value)
|
||||
}
|
||||
|
||||
fun getDoubleInsn(value: Double) =
|
||||
when {
|
||||
value % 1 == 0.0 && value in 0.0..1.0 -> InsnNode((value + 14).toInt())
|
||||
else -> LdcInsnNode(value)
|
||||
}
|
||||
}
|
||||
|
||||
fun insnBuilder(builder: InsnBuilder.() -> Unit) = InsnBuilder().also(builder).insnList
|
|
@ -0,0 +1,72 @@
|
|||
/**
|
||||
* Copyright (C) 2022 zProtect
|
||||
*
|
||||
* This software is NOT free software.
|
||||
* You may NOT distribute it or modify it without explicit permission.
|
||||
*
|
||||
* This software has been created in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY. zProtect is NOT liable for ANY damages caused by unlawful distribution
|
||||
* or usage of any zProtect source code or products.
|
||||
*
|
||||
* You should have received a copy of the zProtect PU (Prohibited Usage) License along with this program.
|
||||
*/
|
||||
|
||||
package dev.zprotect.obfuscator.api.interfaces
|
||||
|
||||
import dev.zprotect.obfuscator.Obfuscator
|
||||
import org.objectweb.asm.ClassWriter
|
||||
import org.objectweb.asm.tree.ClassNode
|
||||
import org.objectweb.asm.tree.MethodNode
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.InputStream
|
||||
|
||||
interface IBytecode {
|
||||
companion object : IBytecode
|
||||
|
||||
fun isExcluded(name: String): Boolean {
|
||||
val path = getPath(name)
|
||||
for (exclusion in Obfuscator.getExclusions()) {
|
||||
if (path.contains(exclusion)) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun getPath(name: String): String {
|
||||
if (!name.contains("/")) return ""
|
||||
val reversedString = name.reversed()
|
||||
val path = reversedString.substring(reversedString.indexOf("/"))
|
||||
return path.reversed()
|
||||
}
|
||||
|
||||
fun getMethod(classNode: ClassNode, method: String): MethodNode? {
|
||||
classNode.methods.forEach { methodNode ->
|
||||
if (methodNode.name == method) return methodNode
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
fun readBytes(inputStream: InputStream): ByteArray {
|
||||
val bytes: ByteArray
|
||||
val byteArrayOutputStream = ByteArrayOutputStream()
|
||||
val buf = ByteArray(256)
|
||||
var n: Int
|
||||
while (inputStream.read(buf).also { n = it } != -1) byteArrayOutputStream.write(buf, 0, n)
|
||||
bytes = byteArrayOutputStream.toByteArray()
|
||||
|
||||
return bytes
|
||||
}
|
||||
|
||||
fun writeBytes(classNode: ClassNode): ByteArray {
|
||||
val writer = ClassWriter(ClassWriter.COMPUTE_MAXS)
|
||||
writer.newUTF8("Obfuscated with zProtect, visit https://zprotect.dev for more information.")
|
||||
classNode.accept(writer)
|
||||
return writer.toByteArray()
|
||||
}
|
||||
|
||||
fun toByteArrayDefault(classNode: ClassNode): ByteArray? {
|
||||
val classWriter = ClassWriter(ClassWriter.COMPUTE_MAXS)
|
||||
classNode.accept(classWriter)
|
||||
return classWriter.toByteArray()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/**
|
||||
* Copyright (C) 2022 zProtect
|
||||
*
|
||||
* This software is NOT free software.
|
||||
* You may NOT distribute it or modify it without explicit permission.
|
||||
*
|
||||
* This software has been created in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY. zProtect is NOT liable for ANY damages caused by unlawful distribution
|
||||
* or usage of any zProtect source code or products.
|
||||
*
|
||||
* You should have received a copy of the zProtect PU (Prohibited Usage) License along with this program.
|
||||
*/
|
||||
|
||||
package dev.zprotect.obfuscator.api.interfaces
|
||||
|
||||
import org.objectweb.asm.Opcodes.*
|
||||
import org.objectweb.asm.tree.AbstractInsnNode
|
||||
import org.objectweb.asm.tree.InsnNode
|
||||
import org.objectweb.asm.tree.IntInsnNode
|
||||
import org.objectweb.asm.tree.LdcInsnNode
|
||||
|
||||
interface INode {
|
||||
|
||||
companion object : INode
|
||||
|
||||
fun getLdcInt(int: Int): AbstractInsnNode {
|
||||
if (int <= 32767 && int >= -32768) {
|
||||
return IntInsnNode(SIPUSH, int)
|
||||
} else if (int <= 127 && int >= -128) {
|
||||
return IntInsnNode(BIPUSH, int)
|
||||
}
|
||||
|
||||
return when (int) {
|
||||
-1 -> InsnNode(ICONST_M1)
|
||||
0 -> InsnNode(ICONST_0)
|
||||
1 -> InsnNode(ICONST_1)
|
||||
2 -> InsnNode(ICONST_2)
|
||||
3 -> InsnNode(ICONST_3)
|
||||
4 -> InsnNode(ICONST_4)
|
||||
5 -> InsnNode(ICONST_5)
|
||||
else -> LdcInsnNode(int)
|
||||
}
|
||||
}
|
||||
|
||||
fun getIntFromAin(ain: AbstractInsnNode): Int {
|
||||
return when (ain.opcode) {
|
||||
ICONST_M1 -> -1
|
||||
ICONST_0 -> 0
|
||||
ICONST_1 -> 1
|
||||
ICONST_2 -> 2
|
||||
ICONST_3 -> 3
|
||||
ICONST_4 -> 4
|
||||
ICONST_5 -> 5
|
||||
SIPUSH -> (ain as IntInsnNode).operand
|
||||
BIPUSH -> (ain as IntInsnNode).operand
|
||||
LDC -> (ain as LdcInsnNode).cst as Int
|
||||
else -> -2
|
||||
}
|
||||
}
|
||||
|
||||
fun isReturn(ain: AbstractInsnNode): Boolean {
|
||||
return ain.opcode in IRETURN..RETURN
|
||||
}
|
||||
}
|
62
src/main/java/dev/zprotect/obfuscator/api/settings/Config.kt
Normal file
62
src/main/java/dev/zprotect/obfuscator/api/settings/Config.kt
Normal file
|
@ -0,0 +1,62 @@
|
|||
/**
|
||||
* Copyright (C) 2022 zProtect
|
||||
*
|
||||
* This software is NOT free software.
|
||||
* You may NOT distribute it or modify it without explicit permission.
|
||||
*
|
||||
* This software has been created in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY. zProtect is NOT liable for ANY damages caused by unlawful distribution
|
||||
* or usage of any zProtect source code or products.
|
||||
*
|
||||
* You should have received a copy of the zProtect PU (Prohibited Usage) License along with this program.
|
||||
*/
|
||||
|
||||
package dev.zprotect.obfuscator.api.settings
|
||||
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import org.json.JSONTokener
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
|
||||
open class Config<T>(private val name: String, private val type: Type, private val read: (JSONObject) -> T) {
|
||||
var value: T? = null
|
||||
|
||||
companion object {
|
||||
private lateinit var READ_OBJECT: JSONObject
|
||||
private val TO_READ: ArrayList<Config<*>> = arrayListOf()
|
||||
private val IS_INITIALIZED: Boolean
|
||||
get() = ::READ_OBJECT.isInitialized
|
||||
|
||||
fun read(file: File?) {
|
||||
READ_OBJECT = JSONObject(JSONTokener(FileInputStream(file)))
|
||||
TO_READ.forEach { it.read(READ_OBJECT) }
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
if (IS_INITIALIZED) read(READ_OBJECT)
|
||||
else TO_READ.add(this)
|
||||
}
|
||||
|
||||
private fun read(jsonObject: JSONObject) {
|
||||
value = if (jsonObject.has(name)) read.invoke(jsonObject) else null
|
||||
}
|
||||
|
||||
enum class Type {
|
||||
ARRAY, STRING, BOOLEAN
|
||||
}
|
||||
}
|
||||
|
||||
class ArrayConfig(name: String?) : Config<JSONArray?>(name!!, Type.ARRAY, {
|
||||
it.getJSONArray(name)
|
||||
})
|
||||
|
||||
class StringConfig(name: String?) : Config<String?>(name!!, Type.STRING, {
|
||||
it.getString(name)
|
||||
})
|
||||
|
||||
class BooleanConfig(name: String?) : Config<Boolean?>(name!!, Type.BOOLEAN, {
|
||||
it.getBoolean(name)
|
||||
})
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
/**
|
||||
* Copyright (C) 2022 zProtect
|
||||
*
|
||||
* This software is NOT free software.
|
||||
* You may NOT distribute it or modify it without explicit permission.
|
||||
*
|
||||
* This software has been created in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY. zProtect is NOT liable for ANY damages caused by unlawful distribution
|
||||
* or usage of any zProtect source code or products.
|
||||
*
|
||||
* You should have received a copy of the zProtect PU (Prohibited Usage) License along with this program.
|
||||
*/
|
||||
|
||||
package dev.zprotect.obfuscator.transformers.antitamper
|
||||
|
||||
import dev.zprotect.obfuscator.api.Transformer
|
||||
import dev.zprotect.obfuscator.api.encryption.Dictionary
|
||||
import dev.zprotect.obfuscator.api.insn.insnBuilder
|
||||
import org.objectweb.asm.Opcodes.*
|
||||
import org.objectweb.asm.tree.LabelNode
|
||||
import org.objectweb.asm.tree.MethodInsnNode
|
||||
import org.objectweb.asm.tree.MethodNode
|
||||
|
||||
object AntiDebug : Transformer("AntiDebug", "Blocks debugging options on terminal.") {
|
||||
|
||||
private val debugTypes = arrayOf("-Xbootclasspath", "-Xdebug", "-agentlib", "-Xrunjdwp:", /*"-verbose"*/)
|
||||
|
||||
override fun obfuscate() {
|
||||
// Have fun. :)
|
||||
classes.stream()
|
||||
.filter { classNode -> !isExcluded(classNode.name) }
|
||||
.forEach { classNode ->
|
||||
classNode.methods.find { it.name.equals("<clinit>") }.also {
|
||||
val methodNode = makeMethod()
|
||||
it?.instructions?.insertBefore(
|
||||
it.instructions.last,
|
||||
MethodInsnNode(INVOKESTATIC, classNode.name, methodNode.name, methodNode.desc, false)
|
||||
)
|
||||
classNode.methods.add(methodNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Fix crashing with minecraft... ???
|
||||
private fun makeMethod(): MethodNode {
|
||||
val method = MethodNode()
|
||||
with(method) {
|
||||
access = ACC_PRIVATE or ACC_STATIC
|
||||
name = Dictionary.generateString(8)
|
||||
desc = "()V"
|
||||
signature = null
|
||||
exceptions = null
|
||||
maxStack = 2
|
||||
instructions = insnBuilder {
|
||||
invokestatic(
|
||||
"java/lang/management/ManagementFactory",
|
||||
"getRuntimeMXBean",
|
||||
"()Ljava/lang/management/RuntimeMXBean;",
|
||||
false
|
||||
)
|
||||
invokeinterface("java/lang/management/RuntimeMXBean", "getInputArguments", "()Ljava/util/List;", true)
|
||||
invokeinterface("java/util/List", "iterator", "()Ljava/util/Iterator;", true)
|
||||
astore(1)
|
||||
val label1 = LabelNode()
|
||||
+label1
|
||||
frame(F_APPEND, 1, arrayOf("java/util/Iterator"), 0, null)
|
||||
aload(1)
|
||||
invokeinterface("java/util/Iterator", "hasNext", "()Z", true)
|
||||
val label2 = LabelNode()
|
||||
ifeq(label2)
|
||||
aload(1)
|
||||
invokeinterface("java/util/Iterator", "next", "()Ljava/lang/Object;", true)
|
||||
checkcast("java/lang/String")
|
||||
astore(2)
|
||||
+LabelNode()
|
||||
aload(2)
|
||||
ldc("-javaagent:") // -agentpath when?
|
||||
invokevirtual("java/lang/String", "startsWith", "(Ljava/lang/String;)Z", false)
|
||||
val label4 = LabelNode()
|
||||
debugTypes.forEach {
|
||||
ifne(label4)
|
||||
aload(2)
|
||||
ldc(it)
|
||||
invokevirtual("java/lang/String", "startsWith", "(Ljava/lang/String;)Z", false)
|
||||
}
|
||||
val label5 = LabelNode()
|
||||
ifeq(label5)
|
||||
+label4
|
||||
frame(F_APPEND, 1, arrayOf("java/lang/String"), 0, null)
|
||||
insn(ICONST_0)
|
||||
invokestatic("java/lang/System", "exit", "(I)V", false)
|
||||
+label5
|
||||
frame(F_CHOP, 1, null, 0, null)
|
||||
goto(label1)
|
||||
+label2
|
||||
frame(F_CHOP, 1, null, 0, null)
|
||||
_return()
|
||||
}
|
||||
}
|
||||
return method
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/**
|
||||
* Copyright (C) 2022 zProtect
|
||||
*
|
||||
* This software is NOT free software.
|
||||
* You may NOT distribute it or modify it without explicit permission.
|
||||
*
|
||||
* This software has been created in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY. zProtect is NOT liable for ANY damages caused by unlawful distribution
|
||||
* or usage of any zProtect source code or products.
|
||||
*
|
||||
* You should have received a copy of the zProtect PU (Prohibited Usage) License along with this program.
|
||||
*/
|
||||
|
||||
package dev.zprotect.obfuscator.transformers.decompiler
|
||||
|
||||
import dev.zprotect.obfuscator.api.Transformer
|
||||
import joptsimple.internal.Strings
|
||||
import org.objectweb.asm.tree.AnnotationNode
|
||||
|
||||
|
||||
object BadAnnotationCrasher :
|
||||
Transformer(
|
||||
"BadAnnotationCrasher",
|
||||
"Generates invisible annotations which will cause Procyon to be very slow."
|
||||
) {
|
||||
|
||||
private val string: String = Strings.repeat('\n', 40) // I think making this any higher is a bad idea...
|
||||
|
||||
override fun obfuscate() {
|
||||
classes.stream()
|
||||
.filter { classNode -> !isExcluded(classNode.name) }
|
||||
.forEach { classNode ->
|
||||
if (classNode.invisibleAnnotations == null)
|
||||
classNode.invisibleAnnotations = arrayListOf()
|
||||
|
||||
classNode.invisibleAnnotations.add(getAnnotationNode())
|
||||
|
||||
classNode.fields.forEach { fieldNode ->
|
||||
if (fieldNode.invisibleAnnotations == null) {
|
||||
fieldNode.invisibleAnnotations = arrayListOf()
|
||||
|
||||
fieldNode.invisibleAnnotations.add(getAnnotationNode())
|
||||
}
|
||||
}
|
||||
|
||||
classNode.methods.forEach { methodNode ->
|
||||
if (methodNode.invisibleAnnotations == null) {
|
||||
methodNode.invisibleAnnotations = arrayListOf()
|
||||
|
||||
methodNode.invisibleAnnotations.add(getAnnotationNode())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getAnnotationNode(): AnnotationNode? {
|
||||
return AnnotationNode(string)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
/**
|
||||
* Copyright (C) 2022 zProtect
|
||||
*
|
||||
* This software is NOT free software.
|
||||
* You may NOT distribute it or modify it without explicit permission.
|
||||
*
|
||||
* This software has been created in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY. zProtect is NOT liable for ANY damages caused by unlawful distribution
|
||||
* or usage of any zProtect source code or products.
|
||||
*
|
||||
* You should have received a copy of the zProtect PU (Prohibited Usage) License along with this program.
|
||||
*/
|
||||
|
||||
package dev.zprotect.obfuscator.transformers.decompiler
|
||||
|
||||
import dev.zprotect.obfuscator.api.Transformer
|
||||
import org.objectweb.asm.Handle
|
||||
import org.objectweb.asm.Label
|
||||
import org.objectweb.asm.Opcodes
|
||||
import org.objectweb.asm.tree.*
|
||||
|
||||
/* Use noverify for now, I would suggest not using this transformer and use
|
||||
BadAnnotationCrasher instead even though it's weaker and more stupid.
|
||||
*/
|
||||
|
||||
object DecompilerCrasher : Transformer("DecompilerCrasher", "Fucks the decompiler.") {
|
||||
|
||||
override fun obfuscate() {
|
||||
classes.stream()
|
||||
.filter { classNode -> !isExcluded(classNode.name) }
|
||||
.forEach { classNode ->
|
||||
// Just don't code in minecraft...
|
||||
//if (classNode.name.contains("Mixin")) return@forEach
|
||||
classNode.methods.filterNot { it.name == "<clinit>" }.forEach { method ->
|
||||
if (method.instructions.first != null) {
|
||||
val label = LabelNode(Label())
|
||||
val insnList = InsnList().apply {
|
||||
//add(emitIntPush(0))
|
||||
add(JumpInsnNode(Opcodes.IFNE, label))
|
||||
add(InvokeDynamicInsnNode("i am sad your java got yeeted", "()V", Handle(6, "a", "a", "(IIIIIIIIIIIIIIIIIII)I")))
|
||||
add(InsnNode(Opcodes.ACONST_NULL))
|
||||
add(TypeInsnNode(Opcodes.CHECKCAST, "give up and buy zprotect"))
|
||||
// TODO: Push to stack lol
|
||||
add(InsnNode(Opcodes.LDC)) // prob do trick idk
|
||||
// if you push to stack the bytecode would probably be kinda valid ngl lmao
|
||||
//add(InsnNode(Opcodes.POP)) Causes crash when you run the program...
|
||||
add(label)
|
||||
}
|
||||
|
||||
method.instructions.insertBefore(method.instructions.first, insnList)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/**
|
||||
* Copyright (C) 2022 zProtect
|
||||
*
|
||||
* This software is NOT free software.
|
||||
* You may NOT distribute it or modify it without explicit permission.
|
||||
*
|
||||
* This software has been created in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY. zProtect is NOT liable for ANY damages caused by unlawful distribution
|
||||
* or usage of any zProtect source code or products.
|
||||
*
|
||||
* You should have received a copy of the zProtect PU (Prohibited Usage) License along with this program.
|
||||
*/
|
||||
|
||||
package dev.zprotect.obfuscator.transformers.flow
|
||||
|
||||
import dev.zprotect.obfuscator.api.Transformer
|
||||
import dev.zprotect.obfuscator.api.encryption.Dictionary
|
||||
import org.objectweb.asm.Opcodes.*
|
||||
import org.objectweb.asm.tree.FieldInsnNode
|
||||
import org.objectweb.asm.tree.FieldNode
|
||||
|
||||
import org.objectweb.asm.tree.InsnNode
|
||||
import org.objectweb.asm.tree.JumpInsnNode
|
||||
|
||||
object Flow : Transformer("Flow", "Adds fake jumps, and such to code.") {
|
||||
|
||||
override fun obfuscate() {
|
||||
classes.stream()
|
||||
.filter { classNode -> !isExcluded(classNode.name) }
|
||||
.forEach { classNode ->
|
||||
var hasField = false
|
||||
val fieldName = Dictionary.generateString(8)
|
||||
classNode.methods.forEach { methodNode ->
|
||||
methodNode.instructions.filter { it.opcode == GOTO }.forEach {
|
||||
hasField = true
|
||||
with(methodNode) {
|
||||
instructions.insertBefore(it, FieldInsnNode(GETSTATIC, classNode.name, fieldName, "Z"))
|
||||
instructions.insert(it, InsnNode(ATHROW))
|
||||
instructions.insert(it, InsnNode(ACONST_NULL))
|
||||
instructions.set(it, JumpInsnNode(IFEQ, (it as JumpInsnNode).label))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checkCondition(hasField) {
|
||||
classNode.fields.add(FieldNode(ACC_PUBLIC + ACC_STATIC + ACC_FINAL, fieldName, "Z", null, null))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun checkCondition(condition: Boolean, runnable: Runnable) {
|
||||
if (!condition) {
|
||||
return
|
||||
}
|
||||
runnable.run()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/**
|
||||
* Copyright (C) 2022 zProtect
|
||||
*
|
||||
* This software is NOT free software.
|
||||
* You may NOT distribute it or modify it without explicit permission.
|
||||
*
|
||||
* This software has been created in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY. zProtect is NOT liable for ANY damages caused by unlawful distribution
|
||||
* or usage of any zProtect source code or products.
|
||||
*
|
||||
* You should have received a copy of the zProtect PU (Prohibited Usage) License along with this program.
|
||||
*/
|
||||
|
||||
package dev.zprotect.obfuscator.transformers.naming
|
||||
|
||||
import dev.zprotect.obfuscator.api.Transformer
|
||||
import dev.zprotect.obfuscator.api.encryption.Dictionary
|
||||
import dev.zprotect.obfuscator.api.settings.StringConfig
|
||||
|
||||
object ClassRenamer : Transformer("ClassRenamer", "Renames class names.") {
|
||||
|
||||
private val path = StringConfig("ClassRenamerPath")
|
||||
|
||||
override fun obfuscate() {
|
||||
val remap: MutableMap<String?, String?> = HashMap()
|
||||
|
||||
val prefix = if (path.value == null) "" else path.value
|
||||
|
||||
classes.stream()
|
||||
.filter { classNode -> !isExcluded(classNode.name) }
|
||||
.forEach { classNode ->
|
||||
val name = prefix + Dictionary.getNewName()
|
||||
remap[classNode.name] = name
|
||||
if (classNode.name.replace("/", ".") == manifest.mainAttributes.getValue("Main-Class"))
|
||||
manifest.mainAttributes.putValue("Main-Class", name.replace("/", "."))
|
||||
}
|
||||
|
||||
applyRemap(remap)
|
||||
|
||||
Dictionary.reset()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/**
|
||||
* Copyright (C) 2022 zProtect
|
||||
*
|
||||
* This software is NOT free software.
|
||||
* You may NOT distribute it or modify it without explicit permission.
|
||||
*
|
||||
* This software has been created in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY. zProtect is NOT liable for ANY damages caused by unlawful distribution
|
||||
* or usage of any zProtect source code or products.
|
||||
*
|
||||
* You should have received a copy of the zProtect PU (Prohibited Usage) License along with this program.
|
||||
*/
|
||||
|
||||
package dev.zprotect.obfuscator.transformers.naming
|
||||
|
||||
import dev.zprotect.obfuscator.api.ClassEntry
|
||||
import dev.zprotect.obfuscator.api.ClassPath
|
||||
import dev.zprotect.obfuscator.api.Transformer
|
||||
import dev.zprotect.obfuscator.api.encryption.Dictionary
|
||||
import org.objectweb.asm.tree.FieldNode
|
||||
import java.util.*
|
||||
|
||||
// TODO: Choose if we want to use the regular Dictionary or use another format.
|
||||
|
||||
object FieldRenamer : Transformer("FieldRenamer", "Renames field names.") {
|
||||
|
||||
override fun obfuscate() {
|
||||
val remap: MutableMap<String?, String?> = mutableMapOf()
|
||||
val fieldMap: MutableMap<FieldNode, ClassEntry> = mutableMapOf()
|
||||
|
||||
classes.stream()
|
||||
.filter { classNode -> !isExcluded(classNode.name) }
|
||||
.forEach { classNode ->
|
||||
classNode.fields
|
||||
.forEach { fieldNode -> fieldMap[fieldNode] = ClassPath.get(classNode) }
|
||||
}
|
||||
|
||||
for ((fieldNode, owner) in fieldMap.entries) {
|
||||
val name = Dictionary.getNewName()
|
||||
|
||||
val stack = Stack<ClassEntry>()
|
||||
stack.add(owner)
|
||||
|
||||
while (!stack.empty()) {
|
||||
val classEntry = stack.pop()
|
||||
remap[classEntry.getName() + "." + fieldNode.name] = name
|
||||
|
||||
stack.addAll(getExtensions(classEntry))
|
||||
stack.addAll(getImplementations(classEntry))
|
||||
}
|
||||
}
|
||||
|
||||
applyRemap(remap)
|
||||
|
||||
Dictionary.reset()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/**
|
||||
* Copyright (C) 2022 zProtect
|
||||
*
|
||||
* This software is NOT free software.
|
||||
* You may NOT distribute it or modify it without explicit permission.
|
||||
*
|
||||
* This software has been created in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY. zProtect is NOT liable for ANY damages caused by unlawful distribution
|
||||
* or usage of any zProtect source code or products.
|
||||
*
|
||||
* You should have received a copy of the zProtect PU (Prohibited Usage) License along with this program.
|
||||
*/
|
||||
|
||||
package dev.zprotect.obfuscator.transformers.naming
|
||||
|
||||
import dev.zprotect.obfuscator.api.Transformer
|
||||
import dev.zprotect.obfuscator.api.encryption.Dictionary
|
||||
import org.objectweb.asm.tree.LocalVariableNode
|
||||
|
||||
object LocalVariableRenamer : Transformer("LocalVariableRenamer", "Obfuscates local variables.") {
|
||||
|
||||
var hashMap = HashMap<String, Boolean>()
|
||||
|
||||
override fun obfuscate() {
|
||||
classes.stream()
|
||||
.filter { classNode -> !isExcluded(classNode.name) }
|
||||
.forEach { classNode ->
|
||||
classNode.methods.stream()
|
||||
.forEach { methodNode ->
|
||||
//if (methodNode.localVariables == null) return@forEach
|
||||
for (i in 0 until methodNode.localVariables.size) {
|
||||
val localVariableNode: LocalVariableNode = methodNode.localVariables.get(i)
|
||||
methodNode.localVariables.set(
|
||||
i,
|
||||
LocalVariableNode(
|
||||
Dictionary.getNewName(),
|
||||
localVariableNode.desc,
|
||||
null,
|
||||
localVariableNode.start,
|
||||
localVariableNode.end,
|
||||
i
|
||||
)
|
||||
)
|
||||
hashMap[localVariableNode.desc] = java.lang.Boolean.TRUE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
/**
|
||||
* Copyright (C) 2022 zProtect
|
||||
*
|
||||
* This software is NOT free software.
|
||||
* You may NOT distribute it or modify it without explicit permission.
|
||||
*
|
||||
* This software has been created in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY. zProtect is NOT liable for ANY damages caused by unlawful distribution
|
||||
* or usage of any zProtect source code or products.
|
||||
*
|
||||
* You should have received a copy of the zProtect PU (Prohibited Usage) License along with this program.
|
||||
*/
|
||||
|
||||
package dev.zprotect.obfuscator.transformers.naming
|
||||
|
||||
import dev.zprotect.obfuscator.api.ClassEntry
|
||||
import dev.zprotect.obfuscator.api.ClassPath
|
||||
import dev.zprotect.obfuscator.api.Transformer
|
||||
import dev.zprotect.obfuscator.api.encryption.Dictionary
|
||||
import dev.zprotect.obfuscator.hasAccess
|
||||
import org.objectweb.asm.Opcodes.*
|
||||
import org.objectweb.asm.tree.MethodNode
|
||||
import java.util.*
|
||||
|
||||
object MethodRenamer : Transformer("MethodRenamer", "Renames method names.") {
|
||||
private val badNames = arrayListOf("main")
|
||||
|
||||
override fun obfuscate() {
|
||||
val remap: MutableMap<String?, String?> = mutableMapOf()
|
||||
val methodMap: MutableMap<MethodNode, ClassEntry> = mutableMapOf()
|
||||
|
||||
// bruh classNode.access and ACC_ANNOTATION == 0 && classNode.access and ACC_ENUM == 0 && classNode.access and ACC_ABSTRACT == 0
|
||||
|
||||
classes.stream()
|
||||
.filter { classNode -> !isExcluded(classNode.name) && classNode.hasAccess(ACC_ANNOTATION or ACC_ENUM or ACC_ABSTRACT) }
|
||||
.forEach { classNode ->
|
||||
classNode.methods.stream()
|
||||
.filter { methodNode -> !badNames.contains(methodNode.name) && !methodNode.name.startsWith("<") && methodNode.hasAccess(ACC_NATIVE) }
|
||||
.forEach { methodNode -> methodMap[methodNode] = ClassPath.get(classNode) }
|
||||
}
|
||||
|
||||
methods@
|
||||
for ((methodNode, owner) in methodMap.entries) {
|
||||
val stack = Stack<ClassEntry>()
|
||||
stack.add(owner)
|
||||
|
||||
while (stack.isNotEmpty()) {
|
||||
val classEntry = stack.pop()
|
||||
|
||||
if (classEntry != owner && classEntry.getMethods()
|
||||
.findLast { method -> method.name == methodNode.name && method.desc == methodNode.desc } != null
|
||||
)
|
||||
continue@methods
|
||||
|
||||
val parent = if (classEntry.getSuper() == null) null else ClassPath[classEntry.getSuper()]
|
||||
if (parent != null) stack.push(parent)
|
||||
|
||||
classEntry.getInterfaces().forEach { inter: String ->
|
||||
val interfNode = ClassPath[inter]
|
||||
if (interfNode != null) stack.push(interfNode)
|
||||
}
|
||||
}
|
||||
|
||||
val name = Dictionary.getNewName()
|
||||
stack.add(owner)
|
||||
|
||||
while (stack.isNotEmpty()) {
|
||||
val classEntry = stack.pop()
|
||||
remap[classEntry.getName() + "." + methodNode.name + methodNode.desc] = name
|
||||
|
||||
stack.addAll(getExtensions(classEntry))
|
||||
stack.addAll(getImplementations(classEntry))
|
||||
}
|
||||
}
|
||||
|
||||
applyRemap(remap)
|
||||
|
||||
Dictionary.reset()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/**
|
||||
* Copyright (C) 2022 zProtect
|
||||
*
|
||||
* This software is NOT free software.
|
||||
* You may NOT distribute it or modify it without explicit permission.
|
||||
*
|
||||
* This software has been created in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY. zProtect is NOT liable for ANY damages caused by unlawful distribution
|
||||
* or usage of any zProtect source code or products.
|
||||
*
|
||||
* You should have received a copy of the zProtect PU (Prohibited Usage) License along with this program.
|
||||
*/
|
||||
|
||||
package dev.zprotect.obfuscator.transformers.optimization
|
||||
|
||||
import dev.zprotect.obfuscator.api.Transformer
|
||||
import org.objectweb.asm.Opcodes.*
|
||||
import org.objectweb.asm.tree.MethodInsnNode
|
||||
|
||||
object EnumOptimiser : Transformer("EnumOptimiser", "Removes clone call and return array.") {
|
||||
|
||||
override fun obfuscate() {
|
||||
classes.stream()
|
||||
.filter { classNode -> !isExcluded(classNode.name) }
|
||||
.forEach { classNode ->
|
||||
if (classNode.access.hasAccess(ACC_ENUM)) {
|
||||
val desc = "[L${classNode.name};"
|
||||
|
||||
val valuesMethod = classNode.methods.firstOrNull {
|
||||
it.name == "values"
|
||||
&&
|
||||
it.desc == "()$desc"
|
||||
&&
|
||||
it.instructions.size() >= 4
|
||||
} ?: return@forEach
|
||||
|
||||
for (insnNode in valuesMethod.instructions) {
|
||||
if (insnNode is MethodInsnNode) {
|
||||
if (
|
||||
insnNode.opcode == INVOKEVIRTUAL
|
||||
&&
|
||||
insnNode.name == "clone"
|
||||
) {
|
||||
if (insnNode.next.opcode == CHECKCAST) {
|
||||
valuesMethod.instructions.remove(insnNode.next)
|
||||
}
|
||||
valuesMethod.instructions.remove(insnNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private fun Int.hasAccess(access: Int) = this and access != 0
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/**
|
||||
* Copyright (C) 2022 zProtect
|
||||
*
|
||||
* This software is NOT free software.
|
||||
* You may NOT distribute it or modify it without explicit permission.
|
||||
*
|
||||
* This software has been created in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY. zProtect is NOT liable for ANY damages caused by unlawful distribution
|
||||
* or usage of any zProtect source code or products.
|
||||
*
|
||||
* You should have received a copy of the zProtect PU (Prohibited Usage) License along with this program.
|
||||
*/
|
||||
|
||||
package dev.zprotect.obfuscator.transformers.optimization
|
||||
|
||||
import dev.zprotect.obfuscator.api.Transformer
|
||||
import org.objectweb.asm.Opcodes.ACC_FINAL
|
||||
import org.objectweb.asm.tree.FieldNode
|
||||
|
||||
object FinalRemover : Transformer("FinalRemover", "Removes final.") {
|
||||
|
||||
override fun obfuscate() {
|
||||
classes.stream()
|
||||
.filter { classNode -> !isExcluded(classNode.name) }
|
||||
.forEach { classNode ->
|
||||
for (i in 0 until classNode.fields.size) {
|
||||
val fieldNode: FieldNode = classNode.fields.get(i)
|
||||
if (fieldNode.access or ACC_FINAL !== 0) fieldNode.access = fieldNode.access and ACC_FINAL.inv()
|
||||
classNode.fields.set(i, fieldNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/**
|
||||
* Copyright (C) 2022 zProtect
|
||||
*
|
||||
* This software is NOT free software.
|
||||
* You may NOT distribute it or modify it without explicit permission.
|
||||
*
|
||||
* This software has been created in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY. zProtect is NOT liable for ANY damages caused by unlawful distribution
|
||||
* or usage of any zProtect source code or products.
|
||||
*
|
||||
* You should have received a copy of the zProtect PU (Prohibited Usage) License along with this program.
|
||||
*/
|
||||
|
||||
package dev.zprotect.obfuscator.transformers.optimization
|
||||
|
||||
import dev.zprotect.obfuscator.api.Transformer
|
||||
import org.objectweb.asm.Opcodes
|
||||
|
||||
//private const val ANNOTATION_REF = "java/lang/annotation/Annotation"
|
||||
|
||||
object HideClassMembers : Transformer("HideClassMembers", "Mark classes as synthetic to hide them from bad decompilers.") {
|
||||
|
||||
override fun obfuscate() {
|
||||
classes.stream()
|
||||
.filter { classNode -> !isExcluded(classNode.name) }
|
||||
.forEach { classNode ->
|
||||
|
||||
/*if (!classNode.editable) return
|
||||
classNode.modified = true
|
||||
|
||||
if (!classNode.dependencies.contains(ANNOTATION_REF)) {
|
||||
classNode.access = classNode.access or Opcodes.ACC_SYNTHETIC
|
||||
}*/
|
||||
|
||||
|
||||
classNode.methods.forEach { methodNode ->
|
||||
methodNode.access = methodNode.access or Opcodes.ACC_SYNTHETIC or Opcodes.ACC_BRIDGE
|
||||
}
|
||||
|
||||
classNode.fields.forEach { fieldNode ->
|
||||
fieldNode.access = fieldNode.access or Opcodes.ACC_SYNTHETIC
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
/**
|
||||
* Copyright (C) 2022 zProtect
|
||||
*
|
||||
* This software is NOT free software.
|
||||
* You may NOT distribute it or modify it without explicit permission.
|
||||
*
|
||||
* This software has been created in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY. zProtect is NOT liable for ANY damages caused by unlawful distribution
|
||||
* or usage of any zProtect source code or products.
|
||||
*
|
||||
* You should have received a copy of the zProtect PU (Prohibited Usage) License along with this program.
|
||||
*/
|
||||
|
||||
package dev.zprotect.obfuscator.transformers.optimization
|
||||
|
||||
import dev.zprotect.obfuscator.api.Transformer
|
||||
import org.objectweb.asm.Opcodes
|
||||
import org.objectweb.asm.tree.*
|
||||
|
||||
object InsnRemover : Transformer("InsnRemover", "Removes the instructions const_. and tableswitch.") {
|
||||
|
||||
override fun obfuscate() {
|
||||
classes.stream()
|
||||
.filter { classNode -> !isExcluded(classNode.name) }
|
||||
.forEach { classNode ->
|
||||
classNode.methods.forEach { methodNode ->
|
||||
val newInsnSet = InsnList()
|
||||
insn@ for (abstractInsnNode in methodNode.instructions.toArray()) {
|
||||
if (abstractInsnNode is TableSwitchInsnNode) {
|
||||
|
||||
val labelNodeStart = LabelNode()
|
||||
val clearStack = InsnNode(Opcodes.POP)
|
||||
|
||||
val jumpInsnNodeStart = JumpInsnNode(Opcodes.GOTO, abstractInsnNode.dflt)
|
||||
val labelNodeEnd = LabelNode()
|
||||
val jumpInsnNodeEnd = JumpInsnNode(Opcodes.GOTO, labelNodeEnd)
|
||||
|
||||
newInsnSet.add(jumpInsnNodeEnd)
|
||||
newInsnSet.add(labelNodeStart)
|
||||
newInsnSet.add(clearStack)
|
||||
newInsnSet.add(jumpInsnNodeStart)
|
||||
newInsnSet.add(labelNodeEnd)
|
||||
|
||||
newInsnSet.add(InsnNode(Opcodes.DUP))
|
||||
newInsnSet.add(LdcInsnNode(-abstractInsnNode.min))
|
||||
newInsnSet.add(InsnNode(Opcodes.IADD))
|
||||
newInsnSet.add(JumpInsnNode(Opcodes.IFLT, labelNodeStart))
|
||||
newInsnSet.add(InsnNode(Opcodes.DUP))
|
||||
newInsnSet.add(LdcInsnNode(-abstractInsnNode.max))
|
||||
newInsnSet.add(InsnNode(Opcodes.IADD))
|
||||
newInsnSet.add(JumpInsnNode(Opcodes.IFGT, labelNodeStart))
|
||||
newInsnSet.add(InsnNode(Opcodes.DUP))
|
||||
newInsnSet.add(LdcInsnNode(-abstractInsnNode.min))
|
||||
newInsnSet.add(InsnNode(Opcodes.IADD))
|
||||
var labelIndex = 0
|
||||
for (label in abstractInsnNode.labels) {
|
||||
val nextBranch = LabelNode()
|
||||
newInsnSet.add(InsnNode(Opcodes.DUP))
|
||||
newInsnSet.add(JumpInsnNode(Opcodes.IFNE, nextBranch))
|
||||
newInsnSet.add(InsnNode(Opcodes.POP))
|
||||
newInsnSet.add(InsnNode(Opcodes.POP))
|
||||
newInsnSet.add(JumpInsnNode(Opcodes.GOTO, label))
|
||||
newInsnSet.add(nextBranch)
|
||||
if (labelIndex + 1 != abstractInsnNode.labels.size) {
|
||||
newInsnSet.add(LdcInsnNode(-1))
|
||||
newInsnSet.add(InsnNode(Opcodes.IADD))
|
||||
}
|
||||
labelIndex++
|
||||
}
|
||||
newInsnSet.add(InsnNode(Opcodes.POP))
|
||||
newInsnSet.add(JumpInsnNode(Opcodes.GOTO, labelNodeStart))
|
||||
} else {
|
||||
when (abstractInsnNode.opcode) {
|
||||
Opcodes.ICONST_M1, Opcodes.ICONST_0, Opcodes.ICONST_1, Opcodes.ICONST_2, Opcodes.ICONST_3, Opcodes.ICONST_4, Opcodes.ICONST_5 -> {
|
||||
newInsnSet.add(LdcInsnNode(abstractInsnNode.opcode - 3))
|
||||
continue@insn
|
||||
}
|
||||
Opcodes.LCONST_0, Opcodes.LCONST_1 -> {
|
||||
newInsnSet.add(LdcInsnNode(abstractInsnNode.opcode - 9L))
|
||||
continue@insn
|
||||
}
|
||||
Opcodes.FCONST_0, Opcodes.FCONST_1, Opcodes.FCONST_2 -> {
|
||||
newInsnSet.add(LdcInsnNode(abstractInsnNode.opcode - 11f))
|
||||
continue@insn
|
||||
}
|
||||
Opcodes.DCONST_0, Opcodes.DCONST_1 -> {
|
||||
newInsnSet.add(LdcInsnNode(abstractInsnNode.opcode - 14.0))
|
||||
continue@insn
|
||||
}
|
||||
}
|
||||
}
|
||||
newInsnSet.add(abstractInsnNode)
|
||||
}
|
||||
methodNode.instructions = newInsnSet
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
/**
|
||||
* Copyright (C) 2022 zProtect
|
||||
*
|
||||
* This software is NOT free software.
|
||||
* You may NOT distribute it or modify it without explicit permission.
|
||||
*
|
||||
* This software has been created in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY. zProtect is NOT liable for ANY damages caused by unlawful distribution
|
||||
* or usage of any zProtect source code or products.
|
||||
*
|
||||
* You should have received a copy of the zProtect PU (Prohibited Usage) License along with this program.
|
||||
*/
|
||||
|
||||
package dev.zprotect.obfuscator.transformers.optimization
|
||||
|
||||
import dev.zprotect.obfuscator.api.Transformer
|
||||
|
||||
object KotlinMetadataRemover : Transformer("KotlinMetadataRemover", "Removes Kotlin Metadata.") {
|
||||
|
||||
override fun obfuscate() {
|
||||
|
||||
classes.stream()
|
||||
.filter { classNode -> !isExcluded(classNode.name) }
|
||||
.forEach { classNode ->
|
||||
|
||||
if (classNode.visibleAnnotations != null) {
|
||||
classNode.visibleAnnotations =
|
||||
classNode.visibleAnnotations.filter { it.desc != "Lkotlin/Metadata;" }
|
||||
}
|
||||
|
||||
val annotations = arrayOf(
|
||||
"Lorg/jetbrains/annotations/NotNull;",
|
||||
"Lorg/jetbrains/annotations/JvmName;",
|
||||
"Lorg/jetbrains/annotations/Nullable;"
|
||||
)
|
||||
|
||||
classNode.methods.forEach { method ->
|
||||
if (method.invisibleAnnotations != null) {
|
||||
method.invisibleAnnotations =
|
||||
method.invisibleAnnotations.filterNot { annotations.contains(it.desc) }
|
||||
}
|
||||
|
||||
if (method.visibleAnnotations != null) {
|
||||
method.visibleAnnotations =
|
||||
method.visibleAnnotations.filterNot { annotations.contains(it.desc) }
|
||||
}
|
||||
}
|
||||
|
||||
classNode.fields.forEach { field ->
|
||||
if (field.invisibleAnnotations != null) {
|
||||
field.invisibleAnnotations =
|
||||
field.invisibleAnnotations.filterNot { annotations.contains(it.desc) }
|
||||
}
|
||||
|
||||
if (field.visibleAnnotations != null) {
|
||||
field.visibleAnnotations = field.visibleAnnotations.filterNot { annotations.contains(it.desc) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/**
|
||||
* Copyright (C) 2022 zProtect
|
||||
*
|
||||
* This software is NOT free software.
|
||||
* You may NOT distribute it or modify it without explicit permission.
|
||||
*
|
||||
* This software has been created in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY. zProtect is NOT liable for ANY damages caused by unlawful distribution
|
||||
* or usage of any zProtect source code or products.
|
||||
*
|
||||
* You should have received a copy of the zProtect PU (Prohibited Usage) License along with this program.
|
||||
*/
|
||||
|
||||
package dev.zprotect.obfuscator.transformers.optimization
|
||||
|
||||
import dev.zprotect.obfuscator.api.Transformer
|
||||
import org.objectweb.asm.Opcodes.NOP
|
||||
|
||||
object NOPInsnRemover : Transformer("NOPInsnRemover", "Removes extended type information.") {
|
||||
|
||||
override fun obfuscate() {
|
||||
classes.stream()
|
||||
.filter { cn -> !isExcluded(cn.name) }
|
||||
.forEach { cn ->
|
||||
cn.methods.forEach { mn ->
|
||||
mn.instructions.removeAll { ain -> ain.opcode == NOP }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
/**
|
||||
* Copyright (C) 2022 zProtect
|
||||
*
|
||||
* This software is NOT free software.
|
||||
* You may NOT distribute it or modify it without explicit permission.
|
||||
*
|
||||
* This software has been created in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY. zProtect is NOT liable for ANY damages caused by unlawful distribution
|
||||
* or usage of any zProtect source code or products.
|
||||
*
|
||||
* You should have received a copy of the zProtect PU (Prohibited Usage) License along with this program.
|
||||
*/
|
||||
|
||||
package dev.zprotect.obfuscator.transformers.optimization
|
||||
|
||||
import dev.zprotect.obfuscator.api.Transformer
|
||||
|
||||
object RemoveSignatures : Transformer("RemoveSignatures", "Removes extended type information.") {
|
||||
|
||||
override fun obfuscate() {
|
||||
classes.stream()
|
||||
.filter { classNode -> !isExcluded(classNode.name) }
|
||||
.forEach { classNode ->
|
||||
classNode.signature = null
|
||||
classNode.methods.forEach { methodNode ->
|
||||
methodNode.signature = null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
/**
|
||||
* Copyright (C) 2022 zProtect
|
||||
*
|
||||
* This software is NOT free software.
|
||||
* You may NOT distribute it or modify it without explicit permission.
|
||||
*
|
||||
* This software has been created in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY. zProtect is NOT liable for ANY damages caused by unlawful distribution
|
||||
* or usage of any zProtect source code or products.
|
||||
*
|
||||
* You should have received a copy of the zProtect PU (Prohibited Usage) License along with this program.
|
||||
*/
|
||||
|
||||
package dev.zprotect.obfuscator.transformers.poolers
|
||||
|
||||
import dev.zprotect.obfuscator.api.Transformer
|
||||
import org.objectweb.asm.Opcodes
|
||||
import org.objectweb.asm.tree.*
|
||||
|
||||
object NumberPooler : Transformer("NumberPooler", "Moves numbers into an array.") {
|
||||
|
||||
private const val numberPoolerArray = "¤¶§†!|~ÇüéäçêïîìæÆ¢£¥Pƒáíúñ¿¬½¼¡«»¦ßµ±°•·²€„…‡‰Š‹Œ˜™š›œŸ¨©®¯³´¸¹¾Ð×ØÞãðõ÷øüþ"
|
||||
|
||||
override fun obfuscate() {
|
||||
classes.stream()
|
||||
.filter { classNode -> !isExcluded(classNode.name) }
|
||||
.forEach { classNode ->
|
||||
val numberMap: MutableMap<AbstractInsnNode, MethodNode> = mutableMapOf()
|
||||
classNode.methods.forEach { methodNode ->
|
||||
methodNode.instructions.forEach { abstractInsnNode ->
|
||||
if ((abstractInsnNode is LdcInsnNode && abstractInsnNode.cst is Int) || (abstractInsnNode.opcode == Opcodes.BIPUSH || abstractInsnNode.opcode == Opcodes.SIPUSH)
|
||||
|| (abstractInsnNode.opcode in Opcodes.ICONST_M1..Opcodes.ICONST_5)
|
||||
) {
|
||||
numberMap[abstractInsnNode] = methodNode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (numberMap.isNotEmpty()) {
|
||||
classNode.fields.add(
|
||||
FieldNode(
|
||||
(if (classNode.access and Opcodes.ACC_INTERFACE != 0) Opcodes.ACC_PUBLIC else Opcodes.ACC_PRIVATE) or (if (classNode.version > Opcodes.V1_8) 0 else Opcodes.ACC_FINAL) or Opcodes.ACC_STATIC,
|
||||
numberPoolerArray,
|
||||
"[I",
|
||||
null,
|
||||
null
|
||||
)
|
||||
)
|
||||
|
||||
var clinit = getMethod(classNode, "<clinit>")
|
||||
if (clinit == null) {
|
||||
clinit = MethodNode(Opcodes.ACC_STATIC, "<clinit>", "()V", null, arrayOf<String>())
|
||||
classNode.methods.add(clinit)
|
||||
}
|
||||
if (clinit.instructions == null) clinit.instructions = InsnList()
|
||||
|
||||
val arrayInstructions = InsnList().apply {
|
||||
add(getLdcInt(numberMap.size))
|
||||
add(IntInsnNode(Opcodes.NEWARRAY, Opcodes.T_INT))
|
||||
|
||||
for ((index, abstractInsnNode) in numberMap.keys.withIndex()) {
|
||||
add(InsnNode(Opcodes.DUP))
|
||||
add(getLdcInt(index))
|
||||
add(getLdcInt(getIntFromAin(abstractInsnNode)))
|
||||
add(InsnNode(Opcodes.IASTORE))
|
||||
|
||||
numberMap[abstractInsnNode]!!.instructions.insert(abstractInsnNode, InsnList().apply {
|
||||
add(
|
||||
FieldInsnNode(
|
||||
Opcodes.GETSTATIC,
|
||||
classNode.name,
|
||||
numberPoolerArray,
|
||||
"[I"
|
||||
)
|
||||
)
|
||||
add(getLdcInt(index))
|
||||
add(InsnNode(Opcodes.IALOAD))
|
||||
})
|
||||
numberMap[abstractInsnNode]!!.instructions.remove(abstractInsnNode)
|
||||
}
|
||||
|
||||
add(
|
||||
FieldInsnNode(
|
||||
Opcodes.PUTSTATIC,
|
||||
classNode.name,
|
||||
numberPoolerArray,
|
||||
"[I"
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
if (clinit.instructions == null || clinit.instructions.first == null) {
|
||||
clinit.instructions.add(arrayInstructions)
|
||||
clinit.instructions.add(InsnNode(Opcodes.RETURN))
|
||||
} else {
|
||||
clinit.instructions.insertBefore(clinit.instructions.first, arrayInstructions)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
/**
|
||||
* Copyright (C) 2022 zProtect
|
||||
*
|
||||
* This software is NOT free software.
|
||||
* You may NOT distribute it or modify it without explicit permission.
|
||||
*
|
||||
* This software has been created in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY. zProtect is NOT liable for ANY damages caused by unlawful distribution
|
||||
* or usage of any zProtect source code or products.
|
||||
*
|
||||
* You should have received a copy of the zProtect PU (Prohibited Usage) License along with this program.
|
||||
*/
|
||||
|
||||
package dev.zprotect.obfuscator.transformers.poolers
|
||||
|
||||
import dev.zprotect.obfuscator.api.Transformer
|
||||
import org.objectweb.asm.Opcodes
|
||||
import org.objectweb.asm.tree.*
|
||||
|
||||
object StringPooler : Transformer("StringPooler", "Moves strings into an array.") {
|
||||
|
||||
private const val stringPoolerArray = "¤¶§†!|~ÇüéäçêïîìæÆ¢£¥Pƒáíúñ¿¬½¼¡«»¦ßµ±°•·²€„…‡‰Š‹Œ˜™š›œŸ¨©®¯³´¸¹¾Ð×ØÞãðõ÷øüþp"
|
||||
|
||||
override fun obfuscate() {
|
||||
classes.stream()
|
||||
.filter { classNode -> !isExcluded(classNode.name) }
|
||||
.forEach { classNode ->
|
||||
val ldcInsnNodeMap: MutableMap<LdcInsnNode, MethodNode> = mutableMapOf()
|
||||
classNode.methods.forEach { methodNode ->
|
||||
methodNode.instructions.forEach { abstractInsnNode ->
|
||||
if (abstractInsnNode is LdcInsnNode && abstractInsnNode.cst is String) ldcInsnNodeMap[abstractInsnNode] = methodNode
|
||||
}
|
||||
}
|
||||
|
||||
if (ldcInsnNodeMap.isNotEmpty()) {
|
||||
classNode.fields.add(
|
||||
FieldNode(
|
||||
(if (classNode.access and Opcodes.ACC_INTERFACE != 0) Opcodes.ACC_PUBLIC else Opcodes.ACC_PRIVATE) or (if (classNode.version > Opcodes.V1_8) 0 else Opcodes.ACC_FINAL) or Opcodes.ACC_STATIC,
|
||||
stringPoolerArray,
|
||||
"[Ljava/lang/String;",
|
||||
null,
|
||||
null
|
||||
)
|
||||
)
|
||||
|
||||
var clinit = getMethod(classNode, "<clinit>")
|
||||
if (clinit == null) {
|
||||
clinit = MethodNode(Opcodes.ACC_STATIC, "<clinit>", "()V", null, arrayOf<String>())
|
||||
classNode.methods.add(clinit)
|
||||
}
|
||||
if (clinit.instructions == null) clinit.instructions = InsnList()
|
||||
|
||||
val arrayInstructions = InsnList().apply {
|
||||
add(getLdcInt(ldcInsnNodeMap.size)) // set array length
|
||||
add(TypeInsnNode(Opcodes.ANEWARRAY, "java/lang/String")) // create array
|
||||
|
||||
for ((index, ldc) in ldcInsnNodeMap.keys.withIndex()) {
|
||||
add(InsnNode(Opcodes.DUP))
|
||||
add(getLdcInt(index))
|
||||
add(LdcInsnNode(ldc.cst as String))
|
||||
add(InsnNode(Opcodes.AASTORE))
|
||||
|
||||
ldcInsnNodeMap[ldc]!!.instructions.insert(ldc, InsnList().apply {
|
||||
add(
|
||||
FieldInsnNode(
|
||||
Opcodes.GETSTATIC,
|
||||
classNode.name,
|
||||
stringPoolerArray,
|
||||
"[Ljava/lang/String;"
|
||||
)
|
||||
)
|
||||
add(getLdcInt(index))
|
||||
add(InsnNode(Opcodes.AALOAD))
|
||||
})
|
||||
ldcInsnNodeMap[ldc]!!.instructions.remove(ldc)
|
||||
}
|
||||
|
||||
add(
|
||||
FieldInsnNode(
|
||||
Opcodes.PUTSTATIC,
|
||||
classNode.name,
|
||||
stringPoolerArray,
|
||||
"[Ljava/lang/String;"
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
if (clinit.instructions == null || clinit.instructions.first == null) {
|
||||
clinit.instructions.add(arrayInstructions)
|
||||
clinit.instructions.add(InsnNode(Opcodes.RETURN))
|
||||
} else {
|
||||
clinit.instructions.insertBefore(clinit.instructions.first, arrayInstructions)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/**
|
||||
* Copyright (C) 2022 zProtect
|
||||
*
|
||||
* This software is NOT free software.
|
||||
* You may NOT distribute it or modify it without explicit permission.
|
||||
*
|
||||
* This software has been created in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY. zProtect is NOT liable for ANY damages caused by unlawful distribution
|
||||
* or usage of any zProtect source code or products.
|
||||
*
|
||||
* You should have received a copy of the zProtect PU (Prohibited Usage) License along with this program.
|
||||
*/
|
||||
|
||||
package dev.zprotect.obfuscator.transformers.shrinking
|
||||
|
||||
import dev.zprotect.obfuscator.api.Transformer
|
||||
import org.objectweb.asm.tree.LineNumberNode
|
||||
|
||||
object LineNumberRemover : Transformer("LineNumberRemover", "Removes line numbers so StackTraces show (Unknown) on errors.") {
|
||||
override fun obfuscate() {
|
||||
classes.stream()
|
||||
.filter { classNode -> !isExcluded(classNode.name) }
|
||||
.forEach { classNode ->
|
||||
classNode.methods.forEach { methodNode ->
|
||||
methodNode.instructions.removeAll { abstractInsnNode -> abstractInsnNode is LineNumberNode }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/**
|
||||
* Copyright (C) 2022 zProtect
|
||||
*
|
||||
* This software is NOT free software.
|
||||
* You may NOT distribute it or modify it without explicit permission.
|
||||
*
|
||||
* This software has been created in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY. zProtect is NOT liable for ANY damages caused by unlawful distribution
|
||||
* or usage of any zProtect source code or products.
|
||||
*
|
||||
* You should have received a copy of the zProtect PU (Prohibited Usage) License along with this program.
|
||||
*/
|
||||
|
||||
package dev.zprotect.obfuscator.transformers.shrinking
|
||||
|
||||
import dev.zprotect.obfuscator.api.Transformer
|
||||
|
||||
object LocalVariableRemover : Transformer("LocalVariableRemover", "Removes local variables.") {
|
||||
|
||||
override fun obfuscate() {
|
||||
classes.stream()
|
||||
.filter { classNode -> !isExcluded(classNode.name) }
|
||||
.forEach { classNode ->
|
||||
classNode.methods.forEach { methodNode ->
|
||||
if (methodNode.localVariables != null) {
|
||||
methodNode.localVariables = null
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/**
|
||||
* Copyright (C) 2022 zProtect
|
||||
*
|
||||
* This software is NOT free software.
|
||||
* You may NOT distribute it or modify it without explicit permission.
|
||||
*
|
||||
* This software has been created in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY. zProtect is NOT liable for ANY damages caused by unlawful distribution
|
||||
* or usage of any zProtect source code or products.
|
||||
*
|
||||
* You should have received a copy of the zProtect PU (Prohibited Usage) License along with this program.
|
||||
*/
|
||||
|
||||
package dev.zprotect.obfuscator.transformers.shrinking
|
||||
|
||||
import dev.zprotect.obfuscator.api.Transformer
|
||||
|
||||
object RemoveInnerClasses : Transformer("RemoveInnerClasses", "Removes inner classes.") {
|
||||
|
||||
override fun obfuscate() {
|
||||
classes.stream()
|
||||
.filter { classNode -> !isExcluded(classNode.name) }
|
||||
.forEach { classNode ->
|
||||
classNode.outerClass = null
|
||||
classNode.outerMethod = null
|
||||
classNode.outerMethodDesc = null
|
||||
classNode.innerClasses.clear()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/**
|
||||
* Copyright (C) 2022 zProtect
|
||||
*
|
||||
* This software is NOT free software.
|
||||
* You may NOT distribute it or modify it without explicit permission.
|
||||
*
|
||||
* This software has been created in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY. zProtect is NOT liable for ANY damages caused by unlawful distribution
|
||||
* or usage of any zProtect source code or products.
|
||||
*
|
||||
* You should have received a copy of the zProtect PU (Prohibited Usage) License along with this program.
|
||||
*/
|
||||
|
||||
package dev.zprotect.obfuscator.transformers.shrinking
|
||||
|
||||
import dev.zprotect.obfuscator.api.Transformer
|
||||
|
||||
object SourceDebugRemover : Transformer("SourceDebugRemover", "Removes the SourceDebug attribute.") {
|
||||
|
||||
override fun obfuscate() {
|
||||
classes.stream()
|
||||
.filter { classNode -> !isExcluded(classNode.name) }
|
||||
.forEach { classNode ->
|
||||
classNode.sourceDebug = null
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/**
|
||||
* Copyright (C) 2022 zProtect
|
||||
*
|
||||
* This software is NOT free software.
|
||||
* You may NOT distribute it or modify it without explicit permission.
|
||||
*
|
||||
* This software has been created in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY. zProtect is NOT liable for ANY damages caused by unlawful distribution
|
||||
* or usage of any zProtect source code or products.
|
||||
*
|
||||
* You should have received a copy of the zProtect PU (Prohibited Usage) License along with this program.
|
||||
*/
|
||||
|
||||
package dev.zprotect.obfuscator.transformers.shrinking
|
||||
|
||||
import dev.zprotect.obfuscator.api.Transformer
|
||||
|
||||
object SourceFileRemover : Transformer("SourceFileRemover", "Removes the SourceFile attribute.") {
|
||||
|
||||
override fun obfuscate() {
|
||||
classes.stream()
|
||||
.filter { classNode -> !isExcluded(classNode.name) }
|
||||
.forEach { classNode ->
|
||||
classNode.sourceFile = null
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/**
|
||||
* Copyright (C) 2022 zProtect
|
||||
*
|
||||
* This software is NOT free software.
|
||||
* You may NOT distribute it or modify it without explicit permission.
|
||||
*
|
||||
* This software has been created in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY. zProtect is NOT liable for ANY damages caused by unlawful distribution
|
||||
* or usage of any zProtect source code or products.
|
||||
*
|
||||
* You should have received a copy of the zProtect PU (Prohibited Usage) License along with this program.
|
||||
*/
|
||||
|
||||
package dev.zprotect.obfuscator.transformers.shufflers
|
||||
|
||||
import dev.zprotect.obfuscator.api.Transformer
|
||||
|
||||
object ShuffleFields : Transformer("ShuffleFields", "Shuffles around fields.") {
|
||||
|
||||
override fun obfuscate() {
|
||||
classes.stream()
|
||||
.filter { classNode -> !isExcluded(classNode.name) }
|
||||
.forEach { classNode ->
|
||||
classNode.fields.shuffle()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/**
|
||||
* Copyright (C) 2022 zProtect
|
||||
*
|
||||
* This software is NOT free software.
|
||||
* You may NOT distribute it or modify it without explicit permission.
|
||||
*
|
||||
* This software has been created in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY. zProtect is NOT liable for ANY damages caused by unlawful distribution
|
||||
* or usage of any zProtect source code or products.
|
||||
*
|
||||
* You should have received a copy of the zProtect PU (Prohibited Usage) License along with this program.
|
||||
*/
|
||||
|
||||
package dev.zprotect.obfuscator.transformers.shufflers
|
||||
|
||||
import dev.zprotect.obfuscator.api.Transformer
|
||||
|
||||
object ShuffleMethods : Transformer("ShuffleMethods", "Shuffles around methods.") {
|
||||
|
||||
override fun obfuscate() {
|
||||
classes.stream()
|
||||
.filter { classNode -> !isExcluded(classNode.name) }
|
||||
.forEach { classNode ->
|
||||
classNode.methods.shuffle()
|
||||
}
|
||||
}
|
||||
}
|
118
src/main/java/joptsimple/internal/Strings.java
Normal file
118
src/main/java/joptsimple/internal/Strings.java
Normal file
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2004-2013 Paul R. Holser, Jr.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package joptsimple.internal;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import static java.lang.System.getProperty;
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
/**
|
||||
* @author Paul Holser
|
||||
*/
|
||||
public final class Strings {
|
||||
public static final String EMPTY = "";
|
||||
public static final String SINGLE_QUOTE = "'";
|
||||
public static final String LINE_SEPARATOR = getProperty("line.separator");
|
||||
|
||||
private Strings() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives a string consisting of the given character repeated the given number of times.
|
||||
*
|
||||
* @param ch the character to repeat
|
||||
* @param count how many times to repeat the character
|
||||
* @return the resultant string
|
||||
*/
|
||||
public static String repeat(char ch, int count) {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < count; ++i)
|
||||
buffer.append(ch);
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether the given string is either {@code} or consists solely of whitespace characters.
|
||||
*
|
||||
* @param target string to check
|
||||
* @return {@code true} if the target string is null or empty
|
||||
*/
|
||||
public static boolean isNullOrEmpty(String target) {
|
||||
return target == null || EMPTY.equals(target);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gives a string consisting of a given string prepended and appended with surrounding characters.
|
||||
*
|
||||
* @param target a string
|
||||
* @param begin character to prepend
|
||||
* @param end character to append
|
||||
* @return the surrounded string
|
||||
*/
|
||||
public static String surround(String target, char begin, char end) {
|
||||
return begin + target + end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives a string consisting of the elements of a given array of strings, each separated by a given separator
|
||||
* string.
|
||||
*
|
||||
* @param pieces the strings to join
|
||||
* @param separator the separator
|
||||
* @return the joined string
|
||||
*/
|
||||
public static String join(String[] pieces, String separator) {
|
||||
return join(asList(pieces), separator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives a string consisting of the string representations of the elements of a given array of objects,
|
||||
* each separated by a given separator string.
|
||||
*
|
||||
* @param pieces the elements whose string representations are to be joined
|
||||
* @param separator the separator
|
||||
* @return the joined string
|
||||
*/
|
||||
public static String join(List pieces, String separator) {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
|
||||
for (Iterator iter = pieces.iterator(); iter.hasNext(); ) {
|
||||
buffer.append(iter.next());
|
||||
|
||||
if (iter.hasNext())
|
||||
buffer.append(separator);
|
||||
}
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in a new issue