Skip to content
← Todas las publicaciones
· Delta1 Labs .NETOfuscaciónGuía

Publicar una demo con tiempo limitado de tu app .NET

A veces quieres una compilación que simplemente deje de funcionar tras una fecha: una demo de una conferencia, una copia de evaluación, una preliminar que no debe ejecutarse en producción para siempre. Nebula.NET puede incorporar una caducidad en el propio ensamblado, aplicada desde un inicializador de módulo antes de que se ejecute tu código, con la reacción que elijas. Esto es cómo funciona y cuándo usarla en vez del licenciamiento con servidor.

No toda compilación está pensada para vivir para siempre. Una demo de una conferencia debería dejar de funcionar la semana después de la charla. Una copia de evaluación entregada a un prospecto no debería seguir ejecutándose en producción un año más tarde. Una beta acotada en el tiempo necesita un corte tajante para que los testers actualicen en vez de enviar sin querer la versión preliminar. Para todos estos casos no quieres un servidor de licencias ni cuentas: quieres que la propia compilación caduque. Nebula.NET puede compilar esa caducidad directamente en el ensamblado.

Un solo ajuste

Añades una caducidad igual que configuras cualquier otra protección — en la config de Nebula:

{
  "rename": true,
  "controlFlowObfuscation": true,
  "expiryUtc": "2026-12-31T23:59:59Z",
  "expiryReaction": "exit",
  "expiryMessage": "This evaluation build expired on 2026-12-31. Contact sales for a licensed copy."
}

Esa es toda la superficie de la funcionalidad: un instante UTC, una reacción y un mensaje opcional. Nebula inyecta la aplicación durante la ofuscación — no hay nada que añadir a tu código fuente, ni using, ni llamada a API, y por tanto nada que alguien que lea tu código decompilado pueda encontrar y eliminar por su nombre.

Dónde se ejecuta la comprobación — antes que tu código

La decisión de diseño importante es dónde vive la comprobación de fecha. Nebula la inyecta en el inicializador de módulo — el .cctor a nivel de módulo que el CLR ejecuta exactamente una vez, automáticamente, antes de tocar ningún tipo del módulo. Se ejecuta antes que Main, antes que cualquier constructor estático tuyo, antes que cualquier punto de entrada:

// inyectado en <Module>::.cctor, conceptualmente:
ldc.i8     <expiryTicks>                 // 2026-12-31T23:59:59Z como ticks UTC
call       valuetype [System.Runtime]System.DateTime [System.Runtime]System.DateTime::get_UtcNow()
call       instance int64 [System.Runtime]System.DateTime::get_Ticks()
bgt.s      EXPIRED                        // now > expiry → reacciona
// ... continúa la inicialización normal del módulo
EXPIRED:
// la reacción configurada (exit / throw / callback)

Como es un inicializador de módulo, no hay ninguna ruta de ejecución hacia tu ensamblado que lo salte. Compáralo con sembrar if (DateTime.UtcNow > …) por tus propios métodos: tendrías que recordar cada punto de entrada, y cada comprobación es una rama legible en tu código. El guardián inyectado es único, automático y añadido a nivel de IL después de que tu compilador haya terminado.

Elegir la reacción

La aplicación es tarea de Nebula; lo que sucede al caducar lo eliges tú con expiryReaction:

  • exit (por defecto) — el proceso se termina inmediatamente. Lo más simple y lo más difícil de sortear con labia; ideal para una demo pura.
  • throw — se lanza una excepción que puedes capturar en tu nivel superior y convertir en una pantalla amigable, un evento registrado o un apagado ordenado.
  • callback — Nebula invoca un método que designes, así que conservas el control total: muestra un diálogo WPF, cambia la app a un modo de solo lectura, o avisa a casa de que una demo caducó.

Una reacción de callback apunta a uno de tus propios métodos por su nombre:

{
  "expiryUtc": "2026-12-31T23:59:59Z",
  "expiryReaction": "callback",
  "expiryCallback": "MyApp.Startup.OnEvaluationExpired"
}
namespace MyApp;
static class Startup
{
    // Llamado por el guardián inyectado cuando la compilación pasa su fecha.
    public static void OnEvaluationExpired()
    {
        MessageBox.Show("Your evaluation of MyApp has ended. Visit example.com to license it.");
        Environment.Exit(0);
    }
}

El guardián llama a tu método; tú decides la experiencia. Si el método retorna, tú controlas qué pasa después — no hay un segundo comportamiento oculto.

Se combina con el resto de la protección

Una caducidad por sí sola está tan oculta como el código a su alrededor, por eso es una transformación en el mismo pipeline que todo lo demás. Ejecútala junto al renombrado, la ofuscación del flujo de control y —en Enterprise— el cifrado de métodos o la virtualización, y la comparación, la constante de caducidad y la reacción quedan enterradas en la misma salida aplanada y cifrada que el resto de tu lógica, no en una rama DateTime obvia. El guardián también es una funcionalidad licenciada (de pago): una compilación de la edición Free lo descarta en silencio en lugar de enviar una fecha a medio aplicar, así que una demo que pretendes que caduque realmente lo hace.

Cuándo recurrir al licenciamiento en su lugar

Sé honesto sobre lo que una fecha incorporada es y no es. Es disuasión para un uso honesto — hace que una demo o evaluación se detenga según lo previsto para que no se filtre a producción ni sobreviva a su propósito. No es una frontera dura contra un atacante motivado, porque toda comprobación de fecha local puede atacarse atrasando el reloj, y una compilación fija no puede extenderse, revocarse ni convertirse sin enviar otra.

Cuando el usuario tiene una cuenta y quieres gestionar su acceso a lo largo del tiempo —extender una prueba, convertirla a pago en el sitio, revocar una copia filtrada, revalidar en línea para que el reloj local no importe— eso es licenciamiento de software, no caducidad. Las dos se combinan limpiamente: envía compilaciones de evaluación con una caducidad tajante para el caso casual, y una licencia real para los clientes. Consulta añadir una prueba gratuita para la vía con servidor, y proteger tus comprobaciones de licencia una vez las tengas. Pero para una compilación desechable que simplemente deba detenerse en una fecha, una línea de config es todo el trabajo.

Prueba Nebula.NET

Endurece tu código .NET en minutos — empieza con la edición gratuita.