Skip to content

3.3. Running arbitrary code inside Sandbox (SSVM)

EpicPlayerA10 edited this page Sep 7, 2025 · 3 revisions

The deobfuscator includes a powerful sandboxed execution environment called SSVM that allows you to execute Java bytecode safely during the deobfuscation process. This is extremely useful for dynamic analysis, decryption routines, and runtime value calculation.

🔧 Basic Setup

There are two ways to obtain a SandBox instance:

1. Creating Your Own SandBox Instance

import uwu.narumi.deobfuscator.api.execution.SandBox;
import uwu.narumi.deobfuscator.api.context.Context;

public class MyTransformer extends Transformer {
  private SandBox sandBox = null;

  @Override
  protected void transform() throws Exception {
    // Lazily initialize sandbox
    if (sandBox == null) {
      this.sandBox = new SandBox(context());
    }
    
    // Use sandbox here...
  }
}

2. Using Global SandBox Instance

The global instance is shared across transformers and is automatically managed by the deobfuscator context. Important: the global sandbox already has all classes from the JAR loaded.

import uwu.narumi.deobfuscator.api.execution.SandBox;

public class MyTransformer extends Transformer {
  @Override
  protected void transform() throws Exception {
    // Use the global sandbox instance from context
    SandBox sandBox = context().getSandBox();
    
    // Use sandbox here...
  }
}

Key Components

  • SandBox - A wrapper for VirtualMachine with useful utilities
  • VirtualMachine - Main execution environment
  • InvocationUtil - Utility for method invocations
  • MemoryManager - Manages object memory and references
  • Helper - Loads classes into the sandbox

🎯 Common Use Cases

1. Loading Classes

import dev.xdark.ssvm.mirror.type.InstanceClass;

// Load a class by its canonical name
InstanceClass clazz = sandBox.getHelper().loadClass("com.example.MyClass");

// Alternative: Load from ClassWrapper
ClassWrapper wrapper = context().getClassesMap().get("com/example/MyClass");
InstanceClass clazz = sandBox.getHelper().loadClass(wrapper.canonicalName());

2. Invoking Static Methods

import dev.xdark.ssvm.invoke.Argument;

// Example: Invoke a decryption method
// Original bytecode: invokestatic MyClass.decrypt (JJ)J
long result = sandBox.getInvocationUtil().invokeLong(
    clazz.getMethod("decrypt", "(JJ)J"),  // Method signature
    Argument.int64(1234567890L),          // First long argument
    Argument.int64(9876543210L)           // Second long argument
);

// For methods returning objects
ObjectValue objResult = sandBox.getInvocationUtil().invokeReference(
    clazz.getMethod("createDecrypter", "(JJLjava/lang/Object;)LDecrypter;"),
    Argument.int64(key1),
    Argument.int64(key2),
    Argument.reference(sandBox.getMemoryManager().nullValue())  // null parameter
);

3. Working with Object Instances

// Get the class of an instance
InstanceClass instanceClass = (InstanceClass) sandBox.getMemoryManager().readClass(objectInstance);

// Invoke instance methods
long decryptedValue = sandBox.getInvocationUtil().invokeLong(
    instanceClass.getMethod("decrypt", "(J)J"),
    Argument.reference(objectInstance),  // 'this' reference
    Argument.int64(encryptedValue)       // Method parameter
);

⚠️ Limitations

  • Static Analysis Preferred: Use SSVM only when static analysis is insufficient
  • Performance Cost: Sandbox execution is slower than static bytecode analysis
  • Dependency Requirements: All required classes must be available in the context

The SSVM sandbox is a powerful tool for dynamic analysis, but should be used judiciously in combination with static analysis techniques for optimal performance and reliability.

📚 Additional Resources

For more examples about SSVM capabilities:

Also, the SSVM has pretty much every class documented in detail, so you just need to Ctrl+Click on the class that you want to understand and read its javadocs.