mirror of
https://github.com/JessSystemV/zProtect.git
synced 2024-12-22 14:25:41 +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