Skip to content
← Todas las publicaciones
· Delta1 Labs Nebula.NETOfuscaciónSeguridad

Report-home: saber cuándo atacan una compilación .NET protegida en el campo

Los guardias anti-tamper y anti-debug reaccionan en la máquina del usuario, pero nunca te enteras de que se dispararon. El report-home de Nebula.NET (tamperReportUrl, Pro) hace POST de un evento mínimo a tu propio endpoint en cuanto un guardia salta, así que un ataque a una compilación distribuida se convierte en una señal sobre la que puedes actuar. Aquí está cómo funciona y cómo construir el receptor.

Endureces bien una compilación .NET. Aplanamiento de flujo de control, cifrado de cadenas y métodos, anti-tamper, anti-debug, chequeos de entorno: de todo. La distribuyes. Y luego no oyes nada, lo cual te dices que es buena noticia. Pero «silencio» y «nadie ataca mi software» no son lo mismo. Cada uno de esos guardias se dispara en la máquina del cliente, reacciona allí, y no deja rastro que tú veas jamás. Un cracker se pasa un fin de semana paso a paso por tu chequeo de licencia en un depurador, tu guardia anti-debug salta una docena de veces, y no te enteras de nada de ello.

El report-home de Nebula.NET (tamperReportUrl, una función Pro) cierra esa brecha. Cuando un guardia se dispara, la app protegida también hace POST de un pequeño evento a un endpoint que tú gestionas, de modo que un ataque a una compilación en el campo se convierte en una señal en tu lado en lugar de un encogimiento de hombros. Este artículo es una inmersión profunda en qué envía, qué deliberadamente no envía, y cómo construir el receptor que convierte esos eventos en algo sobre lo que actúas.

El punto ciego de la protección del lado del cliente

Sé honesto sobre qué es un guardia en tiempo de ejecución. El anti-tamper calcula un SHA-256 de la imagen escrita en la carga y reacciona si el archivo se modificó tras la ofuscación. El anti-debug le pregunta al runtime gestionado y nativo si hay un depurador acoplado. Los chequeos de entorno buscan un perfilador CLR (CORECLR_ENABLE_PROFILING) o el parcheador en tiempo de ejecución Harmony. Cada uno es una alarma genuinamente útil, pero una alarma cuya única salida es una reacción local: terminar, lanzar, salir, o llamar a un método que nombraste.

Esa reacción protege la única máquina en la que corre. Lo que no hace es decirte nada a ti. El guardia y el atacante están solos en una habitación en el ordenador de otra persona. Te enteras de que tu software está siendo crackeado cuando aparece un keygen en un foro, no cuando salta el primer guardia antiDebug.

Sin report-homeEl guardia salta en la máquinareacciona local → proveedor ciegoProveedor: no ve nadaCon report-homeEl guardia salta → POST evento{"event":"antiDebug"} luego reaccionaTu endpoint (tamperReportUrl)el ataque se vuelve señal accionable

Qué hace realmente report-home

Establece una clave de configuración y cada guardia inyectado gana una segunda acción: antes de ejecutar su reacción, hace POST de un evento mínimo a tu URL.

{
  "obfuscate": true,
  "controlFlow": true,
  "stringEncryption": true,
  "antiTamper": true,
  "antiDebug": true,
  "environmentChecks": true,
  "tamperReportUrl": "https://telemetry.example.com/nebula-events"
}

El cuerpo es deliberadamente diminuto: solo el nombre del evento:

{ "event": "antiTamper" }

Cuatro propiedades definen el comportamiento, y cada una es una decisión de diseño que vale la pena entender:

  • Va a tu endpoint, nunca a nosotros. El POST llega a la URL que estableces en tamperReportUrl. Delta1 Labs nunca lo recibe. Esta es tu telemetría en tu servidor.
  • Solo el nombre del evento sale de la máquina. Ni fuente, ni bytes del ensamblado, ni rutas de archivo, ni datos personales o de dispositivo: solo qué guardia se disparó. No hay nada sensible que interceptar ni nada que disgustaría a una revisión de privacidad.
  • Es acotado y auto-silenciador. El envío no puede bloquear tu app ni puede lanzar hacia ella. Si tu endpoint es lento o inalcanzable, el informe se descarta y la reacción del guardia procede sin cambios. Report-home nunca se convierte en un nuevo modo de fallo.
  • Es independiente de la propia analítica de Nebula. Nebula tiene un canal anónimo de uso de la herramienta en tiempo de compilación que puedes silenciar con NEBULA_NO_TELEMETRY. Report-home no tiene nada que ver con él: es un canal en tiempo de ejecución desde tu app hacia tu servidor, controlado solo por si tamperReportUrl está establecido.

Como añade tráfico saliente desde la app protegida, report-home no es para despliegues aislados. Deja la URL sin establecer allí y los guardias siguen reaccionando localmente: simplemente no pueden telefonear a casa.

Qué guardias reportan, y qué significa cada uno

Cada guardia en tiempo de ejecución que Nebula inyecta reporta bajo su propio nombre de evento, que es lo que hace la señal útil en lugar de un único e indiferenciado «pasó algo»:

EventoGuardiaQué suele significar
antiTamperIntegridad de imagen en tiempo de carga (SHA-256 de la imagen escrita)El binario se modificó tras la ofuscación: una copia parcheada/crackeada, o una descarga corrupta
antiDebugDetección de depurador gestionado + nativoAlguien acopló un depurador: el movimiento clásico inicial de la ingeniería inversa dinámica
environmentDetección de perfilador CLR / parcheador HarmonyHay presente un perfilador o el parcheador en tiempo de ejecución Harmony: hooking automatizado de tus métodos
expiryGuardia de caducidad / bomba de tiempoUna compilación beta, de evaluación o con embargo corre pasado su expiryUtc

Ver un pico de antiDebug en una única versión de compilación te dice algo muy distinto de un goteo constante de antiTamper desde las máquinas de un mismo ID de cliente. Uno es ingeniería inversa activa; el otro podría ser una instalación corrupta o una red de redistribución. Distinguirlos es todo el propósito de darle a cada guardia su propio nombre.

Hacer la señal más fuerte: chequeos continuos

Report-home es más útil combinado con chequeos que corren más de una vez. Por defecto environmentChecks y antiDebug son guardias en tiempo de carga: se disparan al arranque. Un atacante paciente simplemente se acopla tras el lanzamiento. Activar los chequeos continuos cambia eso:

{
  "antiTamper": true,
  "antiDebug": true,
  "environmentChecks": true,
  "environmentChecksContinuous": true,
  "environmentChecksIntervalSeconds": 45,
  "autoProtectLicensing": true,
  "tamperReportUrl": "https://telemetry.example.com/nebula-events"
}

Con environmentChecksContinuous, la detección ya no corre solo al arranque. Se suscribe a AppDomain.AssemblyLoad, así que un perfilador o parcheador que se acopla tras el lanzamiento se atrapa en el momento en que se carga; vuelve a chequear en la entrada de los métodos que llaman a tu SDK de licenciamiento (los mismos que autoProtectLicensing encuentra y protege); y con environmentChecksIntervalSeconds vuelve a chequear en un temporizador de fondo con jitter. Cada uno de esos disparos adicionales puede reportar a casa, así que en lugar de un evento al arranque obtienes una imagen de un ataque según se desarrolla a lo largo de una sesión.

Construir el receptor

El endpoint es ordinario. Toma un pequeño POST JSON y lo registra; todo lo interesante ocurre en cómo agregas, no en el manejador. Un receptor mínimo de ASP.NET Core:

app.MapPost("/nebula-events", async (HttpContext ctx, TamperEvent evt) =>
{
    // Attribute the hit to a build/customer using signals you already have:
    // the User-Agent you set, a header you add at your CDN/gateway, or the
    // source address. The body itself carries only the event name by design.
    var record = new TamperHit(
        Event:   evt.Event,                       // "antiTamper" | "antiDebug" | "environment" | "expiry"
        AtUtc:   DateTime.UtcNow,
        Source:  ctx.Connection.RemoteIpAddress?.ToString(),
        Agent:   ctx.Request.Headers.UserAgent.ToString());

    await _hits.AppendAsync(record);              // your store of choice
    return Results.NoContent();                   // keep it cheap; the client ignores the response anyway
});

record TamperEvent(string Event);
record TamperHit(string Event, DateTime AtUtc, string? Source, string? Agent);

Dos cosas a tener en cuenta en el lado receptor. Primero, el cliente ignora tu respuesta y nunca reintenta —es disparar-y-olvidar por diseño— así que tu manejador debería ser barato y nunca debe esperar un protocolo de acuse. Segundo, trata el cuerpo como entrada no confiable: llega de software corriendo en una máquina que un atacante puede controlar, así que valida el nombre del evento contra tu conjunto conocido, limita la tasa por fuente, y nunca dejes que un payload inesperado haga nada más que registrarse y descartarse. El valor de report-home está en el agregado —un salto en antiDebug tras una versión, un grupo de antiTamper desde una región— no en confiar en ningún evento individual.

Qué es report-home, y qué no es

Report-home no detiene un crack. Los guardias hacen el detener —el anti-tamper se niega a correr un binario modificado, el anti-debug y los chequeos de entorno reaccionan a ataques dinámicos— y nada de eso es absoluto, porque toda protección del lado del cliente corre en última instancia en una máquina que el atacante controla. Lo que report-home cambia es tu visibilidad. Hoy un ataque a una compilación distribuida es invisible para ti; con tamperReportUrl establecido, es un evento fechado y nombrado en tu propio servidor, atribuible a una compilación y a menudo a un cliente. Eso convierte la ingeniería inversa de algo que descubres meses después en algo que ves ocurrir, y a lo que respondes, distribuyendo una compilación más dura, revocando una licencia filtrada, o contactando a un cliente cuyas máquinas se están encendiendo.

Establécelo en una línea, apúntalo a un endpoint que controlas, y déjalo sin establecer para destinos aislados. Consulta configuración → anti-tamper y anti-debug para el conjunto completo de opciones de guardias y reacciones, resistiendo la deofuscación para ver cómo encajan los guardias en la historia de endurecimiento mayor, o la página de producto de Nebula.NET para el panorama completo.

Prueba Nebula.NET

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