Skip to content

Análisis a fondo · Nebula.NET

Cómo se crackea el licenciamiento de .NET — y cómo detenerlo

Añadir una comprobación de licencia a una app .NET lleva una tarde. Hacer que sobreviva al contacto con un atacante es la parte que la mayoría de los equipos subestima. Estos son los tres ataques que rompen las puertas de licencia — hasta los bytes individuales de IL — y la defensa concreta que exige cada uno.

By Delta1 Labs Engineering Septiembre de 2026 10 min read Licenciamiento de software

Escribiste una puerta de licencia limpia. Valida la clave, comprueba el número de puestos, pone la app en modo «Pro». Compila, funciona, la publicas. Y en un ensamblado .NET sin proteger un atacante la neutraliza en más o menos el tiempo que te llevó leer este párrafo — no porque tu lógica sea débil, sino porque la comprobación se publica como IL legible y editable, y el runtime ejecuta lo que diga el ensamblado. La cerradura está bien. Está atornillada a una puerta de cristal.

Crackear una licencia no es magia, y no es una sola técnica. Son tres, cada una dirigida a una debilidad distinta, y cada una con una defensa concreta y bien comprendida. Entiende el ataque y la protección se deduce.

Anatomía de una puerta de licencia

Aquí tienes una comprobación representativa — nada ingenuo, la forma que adopta la mayor parte del licenciamiento interno:

LicenseManager.cs
public bool IsLicensed()
{
    if (!ValidateKey(_key)) return false;          // signature / checksum
    if (SeatsInUse > _license.Seats) return false; // seat count
    return true;
}

public bool IsPro => IsLicensed() && _license.Tier >= Tier.Pro;

Cada uno de los tres ataques de abajo parte de la forma decompilada de este método — porque, como se cubre en qué recupera un decompilador, una compilación sin proteger lo entrega intacto.

Ataque 1 — Parchear la comprobación

El crack más común ni siquiera lee tu lógica; edita una instrucción. En IL, IsLicensed termina con una rama condicional que decide licenciado-o-no. El atacante abre el ensamblado en dnSpy, encuentra esa rama y la invierte — o reemplaza todo el cuerpo del método por dos bytes que significan return true. Los opcodes son diminutos y de sobra conocidos:

La única edición — bytes de opcode ILexpuesto
; invert the decision — flip the branch opcode:
  brfalse.s  (0x2C)   →   brtrue.s  (0x2D)     // one byte

; or blow the method away entirely — overwrite the body with:
  ldc.i4.1   (0x17)   ; push 1  (true)
  ret        (0x2A)   ; return it
; "IsLicensed()" now unconditionally returns true.

Eso es todo. No hace falta entender tu formato de clave. La app ahora está «licenciada» contra nada.

Defensa: anti-manipulación. Nebula inyecta una comprobación de integridad en tiempo de carga. En tiempo de compilación hace el hash de los cuerpos de los métodos protegidos y almacena los resúmenes, cifrados, en el ensamblado. Al arrancar, el componente de runtime vuelve a hacer el hash del código cargado y lo compara. Cambia un byte — invierte esa rama, reemplaza ese método — y los hashes divergen, y el ensamblado se niega a ejecutarse (o reacciona como lo configures). El propio binario detecta el ataque de parcheo.

En compilación cuerpo del método IsLicensed() hash → H₀ almacenado, cifrado En carga cuerpo parcheado 2C → 2D re-hash → H₁ recalculado H₀ ≠ H₁ manipulación detectada → detener
Figura 1 — La anti-manipulación convierte al binario en su propio testigo. El resumen de compilación y el re-hash de carga solo coinciden si no se cambió ni un byte; una rama parcheada hace saltar la comprobación.

Ataque 2 — Leer el algoritmo, escribir un generador de claves

El parcheo produce una copia crackeada. Un generador de claves produce algo peor: claves que tu propio código acepta como genuinas. Si ValidateKey es legible, un atacante la decompila, recupera el formato y la suma de verificación, y escribe un generador. No se modifica ningún archivo — cada instalación está «legítimamente» licenciada contra claves forjadas, y la anti-manipulación nunca se dispara porque no se ha manipulado nada.

ValidateKey — recuperado por decompilaciónexpuesto
private static bool ValidateKey(string key)
{
    // groups of 5, Base32, last group is a checksum of the first three
    var parts = key.Split('-');
    int sum = 0;
    foreach (var p in parts.Take(3))
        foreach (char c in p) sum = sum * 33 + Decode(c);
    return Base32(sum & 0x3FFFFFF) == parts[3];   // ← the whole scheme
}

Con eso en la mano, el generador de claves tiene una docena de líneas. El problema no es la fortaleza del algoritmo — es que el algoritmo es visible.

Defensa: ocultar el algoritmo. Para esto sirve exactamente la virtualización de código. Virtualiza ValidateKey y su IL desaparece — reemplazado por una llamada a una VM embebida que ejecuta bytecode personalizado. No hay suma de verificación legible que reimplementar; recuperarla significa primero aplicar ingeniería inversa a la VM. Combínalo con el cifrado de cadenas para que el alfabeto Base32 y las máscaras mágicas no estén en el heap #US, y con el aplanado del flujo de control en el código circundante, y reconstruir el esquema pasa de una tarde a un proyecto de investigación.

«El licenciamiento es una función de seguridad. Publicar su algoritmo como IL legible es como imprimir las instrucciones para cortar la llave en el reverso de la cerradura.»

Ataque 3 — Arrancar la puerta por completo

El ataque más sutil ignora la comprobación por completo. En lugar de derrotar a IsLicensed, el atacante estudia cómo IsPro desbloquea las funciones y simplemente llama a las rutas de pago directamente, o recompila la app con el módulo de licenciamiento eliminado. Si tu control es un único booleano consultado en un único lugar, quitarlo es trivial una vez que el código es legible.

Defensa: hacer el módulo ilegible y el cableado irrastreable. Renombra todo lo interno para que no haya ningún LicenseManager.IsPro que encontrar; aplana el flujo de control para que la puerta no sea una rama limpia que eliminar; y usa la ofuscación de referencias (llamadas proxy) para que las llamadas a las funciones controladas pasen por proxies inyectados y sin marca — el atacante no puede buscar «el desbloqueo» en el grafo de llamadas. Y, crucialmente, no dejes que el cliente sea la única autoridad: combina la protección de Nebula con activación del lado del servidor para que la decisión que importa se tome donde el atacante no puede editarla.

Cada vía de ataque, y qué la cierra 1 · Parchear la rama invertir 2C→2D, o reemplazar por return true Anti-manipulación el binario se re-hashea → el desajuste detiene 2 · Generador de claves leer la suma de verificación, forjar claves Virtualización + cifrado de cadenas ningún algoritmo legible que reimplementar 3 · Arrancar la puerta eliminar el módulo, llamar a las rutas de pago Renombrado + llamadas proxy + auth de servidor sin cableado rastreable; autoridad fuera de la máquina Por capas — ninguna vía por sí sola rompe la puerta
Figura 2 — Cada ataque corresponde a una defensa. La protección real es aplicarlas todas, de modo que ninguna técnica por sí sola — y ninguna edición por sí sola — rompa la puerta.

La pila de defensa

Una puerta de licencia de .NET resistente a cracks nunca es un solo truco; es la superposición:

  • Anti-manipulación para que el binario no se pueda parchear sin que se detecte a sí mismo.
  • Virtualización en el validador para que el algoritmo no se pueda leer ni reimplementar.
  • Cifrado de cadenas + aplanado del flujo de control para que el esquema, sus constantes y sus mensajes queden ocultos.
  • Ofuscación de llamadas proxy + renombrado para que la ruta de «desbloqueo» no se pueda localizar ni extraer.
  • Activación del lado del servidor para todo lo que deba tener autoridad — para que el cliente no sea la única línea de defensa.

Nada de esto hace imposible el crackeo — nada del lado del cliente lo hace. Lo hace lo bastante caro como para que no merezca la pena, que para el software comercial es el juego entero.

Haz que tu licenciamiento aguante.

Nebula.NET endurece el código que hace cumplir tu licencia — anti-manipulación, cifrado de cadenas, flujo de control y virtualización de código Enterprise.