Skip to content

Nebula.NET

Virtualización de código

Compila tus métodos de .NET más sensibles a un bytecode personalizado ejecutado por una VM incrustada — de modo que su lógica deja de existir como IL y no se puede decompilar. Nebula.NET Enterprise.

La virtualización de código es la protección más fuerte de Nebula.NET — una característica de Enterprise. (Para el porqué y el cómo en profundidad, consulta el análisis ilustrado: Código que se distribuye sin nada que leer.) Toma un método elegido, lo compila a un bytecode personalizado y reemplaza el cuerpo del método con un stub que ejecuta ese bytecode en una pequeña máquina virtual incrustada. Las instrucciones originales desaparecen: un decompilador ya no muestra tu lógica, solo una llamada a la VM. Para recuperar el método, un atacante primero debe aplicar ingeniería inversa a la propia VM — un listón drásticamente más alto que leer IL aplanado.

Qué aspecto tiene

Un método como este:

public static int Score(int a, int b)
{
    int r = 17;
    for (int i = 0; i < 8; i++) r = r * 31 + ((a >> i) & 1) ^ (b + i);
    return r & 0x7FFFFFFF;
}

se decompila, tras la virtualización, a esencialmente nada más que una llamada a la VM:

public static int Score(int a, int b)
{
    return VirtualMachine.Run(typeof(<owner>).TypeHandle, 100663302, new int[] { a, b });
}

El bucle, la aritmética, las constantes — nada de eso está ya en el IL distribuido. Vive como bytecode opaco en un recurso incrustado, ejecutado en tiempo de ejecución.

Activarla

{
  "virtualizeMethods": true,
  "virtualizeInclude": [
    "Contoso.Licensing.LicenseCheck.Validate",
    "Contoso.Crypto.KeyDerivation.Derive"
  ]
}
  • virtualizeMethods — activa la virtualización (requiere licencia de Enterprise).
  • virtualizeInclude — una lista de permitidos de métodos a virtualizar, por Namespace.Type.Method. Déjala vacía para virtualizar todos los métodos elegibles. La virtualización es más pesada que otras transformaciones, así que una lista de permitidos dirigida a tus métodos genuinamente sensibles (licenciamiento, derivación de claves, algoritmos) es la elección habitual. Descubre los nombres con nebula inspect --methods.

La virtualización se ejecuta antes de la ofuscación del flujo de control, de modo que un método virtualizado queda protegido por la VM (y cualquier stub sobrante sigue endurecido por las demás pasadas) — nunca pierdes la virtualización por activar también el flujo de control.

Qué se puede virtualizar (alcance de v1)

La virtualización es exacta en comportamiento: solo transforma métodos que puede compilar con semántica idéntica, y deja en silencio todo lo demás intacto — nunca se aplica de forma incorrecta. Un método es elegible cuando se cumplen todas estas condiciones:

  • es estático y no genérico, en un tipo no genérico;
  • no tiene controladores de excepciones (try/catch/finally);
  • sus parámetros, locales y tipo de retorno son todos de la familia de enteros de 32 bits (bool, char, byte, sbyte, short, ushort, int, uint);
  • su cuerpo usa solo aritmética de enteros, operaciones a nivel de bits, comparaciones, saltos y conversiones.

Esto se corresponde exactamente con el modelo de pila de evaluación del CLR, así que la aritmética de la VM — incluido el desbordamiento con envoltura de 32 bits — coincide con el método original con precisión. Es ideal para el código con gran carga de enteros para el que la protección más importa: validadores de licencia, lógica de código de autenticación/suma de verificación, matemáticas de claves y núcleos algorítmicos. Los métodos fuera del modelo (cadenas, tipos de objeto/referencia, long/coma flotante, llamadas, acceso a campos) se dejan para que las protejan las demás pasadas y son candidatos para una futura versión de la virtualización.

Runtime

Un ensamblado virtualizado distribuye un diminuto Nebula.Runtime.dll junto a él (la VM). Nebula lo copia a tu salida automáticamente e inyecta un cargador para que se resuelva al arrancar — sin necesidad de referencia de proyecto ni de entrada en deps.json. Nebula.Runtime apunta a .NET Standard 2.0, así que los ensamblados virtualizados se ejecutan en todos los destinos de .NET: .NET Framework 4.6.1+, .NET 6–10 y más allá.

Cuándo usarla

Recurre a la virtualización para el puñado de métodos que un atacante atacaría primero — la comprobación de licencia, la puerta “is-pro”, un algoritmo propietario. Combinada con el cifrado de cadenas y la anti-manipulación, hace que esos métodos sean inviables de revertir. Mira cómo aguanta frente a las herramientas automatizadas en Resistir la desofuscación automatizada.