YumeCloud Protection Plus is a Java bytecode-protection workspace. It contains the YCP obfuscator, a native-code translation pipeline, annotation APIs, local authorization-server implementations, and administration clients.
The native pipeline is experimental. Use it only on software you are authorized to protect, keep original artifacts, and validate every protected build in an environment that matches production.
- Highlights
- Repository layout
- Requirements
- Build and run
- Configuration
- Native backends
- Authorization services and admin UI
- Verification
- Limitations
- Contributing and license
- Bytecode transformations for strings, numeric expressions, control flow, calls, renaming, and
invokedynamicaccording to the configured selectors. - Native translation selected per class or method with
@Native. - The established J2C generator and the experimental J2LL generator can be used in the same protected JAR.
- J2LL builds a backend-independent JVM semantic IR, lowers it to LLVM IR, validates LLVM input when a compatible tool is available, then links it with the JNI runtime and the J2C output.
- JNI method registration uses method name plus descriptor, so overloads and mixed backends share one native library.
- Python and Go form-based authorization-service implementations, plus a separate React/Spring administration application.
| Path | Purpose |
|---|---|
obfuscator/ |
Core transformer, J2C implementation, shared IR, J2LL backend, JNI runtime, and bundled configuration templates. |
annotations/ |
Compile-time annotation API used by applications being protected. |
obfuscatorgui/ |
Legacy Swing launcher. The supported workflow is the configuration-file CLI below. |
adminpanel/ |
Legacy Swing authorization administration client. |
obfuscatorsdk/ |
SDK artifact that packages the annotation API. |
server_python/ |
Flask and SQLite authorization service. |
server_go/ |
Gin and SQLite authorization service. |
admin-web/ |
Separate React + Spring Boot key-management application. |
tests/ |
Authorization-service checks and J2LL differential fixtures. |
- A JDK that can run Gradle 8.6 and compile Java 8 source compatibility targets. Java 8+ is required for protected applications.
- Windows x86_64 is the currently documented native build target. The native command line emits
x86_64-windowsoutput, links the Windows system libraries it needs, and uses the open-source VMProtect no-op header by default. - Network access on the first native processing run, unless
zig-windows-x86_64-0.11.0/is already present in the working directory. The pipeline downloads Zig 0.11 automatically when it is absent. - Python 3.8+ for the Python authorization service and optional differential scripts; Go 1.21+ for the Go service; Docker is optional.
- A compatible VMProtect installation/license and the corresponding commercial SDK/project files if VMProtect-backed native protection is enabled. Those commercial files are intentionally not distributed; without them, the build ships an unprotected native library.
Use the Gradle wrapper from the repository root. The command below produces the runnable obfuscator at obfuscator/build/libs/obfuscator.jar.
.\gradlew.bat :obfuscator:shadowJar --no-daemonOn the first run without arguments, the JAR writes default-config.yml to the current directory. Copy or edit that file, then invoke the configuration-file entry point:
Copy-Item obfuscator\src\main\resources\default-config.yml .\ycp.yml
# Edit input_jar, output_jar, app_name, libraries, and selectors in ycp.yml.
java -jar obfuscator\build\libs\obfuscator.jar .\ycp.ymlThe supported CLI form is:
java -jar obfuscator.jar <config_file>
The old positional CLI shown by some legacy UI code is not the current command-line entry point. Do not use it for new automation.
YAML, JSON, and TOML configuration files are accepted. Start with one of the templates in obfuscator/src/main/resources/; its selectors show the accepted matching syntax.
This minimal YAML skeleton is a useful starting point:
input_jar: ./input.jar
output_jar: ./output-protected.jar
app_name: MyApplication
libraries: []
native:
auth: false
platform: HOTSPOT
include:
- "** #public static void main(java.lang.String[])"
exclude: []
rename:
enable: false
misc:
safe_mode: false
debug:
j2ll: falselibraries must include third-party JAR, ZIP, or JMOD dependencies needed for metadata resolution. The engine also searches the current JRE/JDK archives. Begin with a small include set, retain an unprotected test artifact, and expand selectors after runtime verification.
The native.include and native.exclude selectors add @Native and @NotNative markers during transformation. You can instead put annotations directly in the application source; method annotations are handled independently of these selectors.
Add the annotation JAR to the application at compile time, then choose a backend per class or method:
import com.yumegod.obfuscation.Native;
import com.yumegod.obfuscation.NativeBackend;
import com.yumegod.obfuscation.NotNative;
@Native(backend = NativeBackend.J2LL)
final class SensitiveLogic {
static int hash(int value) {
return (value * 31) ^ 0x5a5a5a5a;
}
@Native // Defaults to J2C and overrides the class-level J2LL choice.
static int legacy(int value) {
return value + 1;
}
@NotNative // Method-level opt-out always wins.
static int keepOnJvm(int value) {
return value - 1;
}
}Selection rules are deterministic:
@NotNativeon a method excludes that method.- A method-level
@Native(backend = ...)overrides a class-level@Nativebackend. - A class-level
@Nativeapplies to its eligible methods. @NativewithoutbackendmeansNativeBackend.J2C.
J2C is the existing JNI/C++ generator and remains the default for compatibility. It shares native method registration and the final native library with J2LL methods.
J2LL is an experimental LLVM backend. The pipeline is:
JVM bytecode -> shared semantic IR -> LLVM IR -> object code -> native library -> JNI registration
The shared IR models local values, operand-stack merges, basic blocks, PHI values, branches, switches, calls, fields, arrays, allocations, casts, and throws. The J2LL runtime bridges supported object, array, field, and invocation operations through JNI.
Set debug.j2ll: true in the config to log the semantic IR and generated LLVM IR. Generated .ll files are internal build intermediates and are normally deleted after a successful run.
J2LL currently rejects JVM exception edges (try/catch), direct INVOKEDYNAMIC instructions, and interface methods. It is not a full JVM object-layout, garbage-collection, reflection, or exception-runtime implementation. Keep methods selected for J2LL small and test them as native methods on the target JRE.
The authorization services expose compatible form endpoints:
| Endpoint | Purpose |
|---|---|
POST /init_admin |
Create an application administrator once. |
POST /admin_login |
Check administrator credentials. |
POST /admin |
Run Key, Ban, Reset, or LastLogin commands. |
POST /login |
Validate an application key. |
Run exactly one local service while developing:
# Python service, port 13337
cd server_python
py -m pip install -r requirements.txt
py app.py
# Go service, port 13337
cd ..\server_go
go run main.goInitialize the first application after the service is running:
curl.exe -X POST http://localhost:13337/init_admin -d "app=MyApp" -d "password=replace-with-a-strong-password"Docker Compose exposes the Python service on port 13337 and the Go service on 13338 to avoid a collision. See README_SERVER.md, DEPLOYMENT.md, server_python/README_CN.md, and server_go/README_CN.md for service-specific operations.
admin-web/ is a separate management application with its own Spring Boot API and SQLite path. It is not automatically wired to the native protection configuration. Its build and first-run instructions are in admin-web/README.md.
The root configuration does not currently expose an active auth_url field; the authorizationURL source field is not annotated for config loading. Do not rely on an auth_url YAML key without first implementing and testing that integration.
Run the Java test suite after source changes:
.\gradlew.bat :obfuscator:test --no-daemonThe mixed-backend fixture is in tests/j2ll/. It covers JVM/J2C/J2LL arithmetic smoke cases. With an already generated pure-arithmetic LLVM module, validate it through MCJIT:
py -m pip install llvmlite
py tests\j2ll\differential_test.py path\to\basic.llFor a generated protected JAR, compare its output with the original JVM fixture:
py tests\j2ll\differential_jar_test.py <original-classes> <runner-classes> <protected.jar>Authorization-service scripts are documented in tests/README.md. These tests are smoke and differential checks, not proof of semantic equivalence for arbitrary Java programs.
- Native compilation and VMProtect integration are currently Windows-oriented; cross-platform native output is not documented as supported.
- J2LL has the restrictions listed above and emits explicit unsupported-instruction diagnostics for bytecode outside its current lowering set.
- The native output is a protection mechanism, not a security boundary. Threat models, key management, signatures, TLS, server hardening, and updates remain application responsibilities.
- The Python and Go services use SQLite. Review concurrency, backup, network exposure, authentication, and TLS requirements before production use.
- Preserve unprotected input JARs and test protected artifacts before release. Obfuscation can change reflection, serialization, framework scanning, and class-loading behavior.
Report a reproducible problem with the input bytecode shape, JDK version, target platform, configuration, and the smallest safe reproducer. For J2LL issues, include the relevant diagnostic or generated IR when it is safe to share.
YCPPlus is distributed under the MIT License. It is based on YumeCloud Protection / OpenYCP. Third-party tools and native SDK components may have their own terms; review them before redistribution or deployment.